]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Apr 2009 00:34:12 +0000 (17:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Apr 2009 00:34:12 +0000 (17:34 -0700)
* 'rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  rcu: rcu_barrier VS cpu_hotplug: Ensure callbacks in dead cpu are migrated to online cpu

1725 files changed:
CREDITS
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-bus-pci
Documentation/ABI/testing/sysfs-class-regulator
Documentation/ABI/testing/sysfs-fs-ext4 [new file with mode: 0644]
Documentation/DocBook/.gitignore
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/procfs_example.c
Documentation/PCI/MSI-HOWTO.txt
Documentation/PCI/pci-iov-howto.txt [new file with mode: 0644]
Documentation/RCU/listRCU.txt
Documentation/RCU/rcu.txt
Documentation/RCU/rculist_nulls.txt
Documentation/cgroups/00-INDEX [new file with mode: 0644]
Documentation/cgroups/cgroups.txt
Documentation/cgroups/cpusets.txt
Documentation/cgroups/devices.txt
Documentation/cgroups/memcg_test.txt
Documentation/cgroups/memory.txt
Documentation/devices.txt
Documentation/fb/00-INDEX
Documentation/fb/cyblafb/bugs [deleted file]
Documentation/fb/cyblafb/credits [deleted file]
Documentation/fb/cyblafb/documentation [deleted file]
Documentation/fb/cyblafb/fb.modes [deleted file]
Documentation/fb/cyblafb/performance [deleted file]
Documentation/fb/cyblafb/todo [deleted file]
Documentation/fb/cyblafb/usage [deleted file]
Documentation/fb/cyblafb/whatsnew [deleted file]
Documentation/fb/cyblafb/whycyblafb [deleted file]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/caching/backend-api.txt [new file with mode: 0644]
Documentation/filesystems/caching/cachefiles.txt [new file with mode: 0644]
Documentation/filesystems/caching/fscache.txt [new file with mode: 0644]
Documentation/filesystems/caching/netfs-api.txt [new file with mode: 0644]
Documentation/filesystems/caching/object.txt [new file with mode: 0644]
Documentation/filesystems/caching/operations.txt [new file with mode: 0644]
Documentation/filesystems/exofs.txt [new file with mode: 0644]
Documentation/filesystems/ext3.txt
Documentation/filesystems/ext4.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/sysfs-pci.txt
Documentation/filesystems/udf.txt
Documentation/gpio.txt
Documentation/hwmon/ds1621
Documentation/hwmon/lis3lv02d
Documentation/hwmon/ltc4215 [new file with mode: 0644]
Documentation/hwmon/pcf8591 [moved from Documentation/i2c/chips/pcf8591 with 100% similarity]
Documentation/hwmon/sysfs-interface
Documentation/hwmon/w83627ehf
Documentation/ia64/kvm.txt
Documentation/kernel-parameters.txt
Documentation/lguest/lguest.c
Documentation/lockdep-design.txt
Documentation/md.txt
Documentation/misc-devices/isl29003 [new file with mode: 0644]
Documentation/networking/vxge.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/firmware.txt
Documentation/powerpc/dts-bindings/mmc-spi-slot.txt [new file with mode: 0644]
Documentation/scheduler/sched-rt-group.txt
Documentation/slow-work.txt [new file with mode: 0644]
Documentation/sysctl/00-INDEX
Documentation/sysctl/fs.txt
Documentation/sysctl/kernel.txt
Documentation/sysctl/net.txt [new file with mode: 0644]
Documentation/sysrq.txt
Documentation/vm/numa_memory_policy.txt
Documentation/vm/page_migration
Documentation/x86/x86_64/fake-numa-for-cpusets
MAINTAINERS
arch/alpha/include/asm/machvec.h
arch/alpha/include/asm/pci.h
arch/alpha/include/asm/spinlock.h
arch/alpha/include/asm/system.h
arch/alpha/include/asm/types.h
arch/alpha/include/asm/uaccess.h
arch/alpha/include/asm/xchg.h [new file with mode: 0644]
arch/alpha/kernel/Makefile
arch/alpha/kernel/err_ev6.c
arch/alpha/kernel/err_ev7.c
arch/alpha/kernel/err_marvel.c
arch/alpha/kernel/err_titan.c
arch/alpha/kernel/pci-sysfs.c [new file with mode: 0644]
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/process.c
arch/alpha/kernel/proto.h
arch/alpha/kernel/setup.c
arch/alpha/kernel/smc37c669.c
arch/alpha/kernel/srm_env.c
arch/alpha/kernel/sys_jensen.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/traps.c
arch/arm/configs/omap_ldp_defconfig
arch/arm/configs/pcm037_defconfig
arch/arm/configs/realview-smp_defconfig
arch/arm/configs/realview_defconfig
arch/arm/include/asm/spinlock.h
arch/arm/kernel/process.c
arch/arm/mach-at91/pm.c
arch/arm/mach-gemini/include/mach/system.h
arch/arm/mach-mmp/include/mach/system.h
arch/arm/mach-mx3/pcm037.c
arch/arm/mach-netx/include/mach/netx-regs.h
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/localtimer.c
arch/arm/mm/abort-ev6.S
arch/arm/mm/cache-feroceon-l2.c
arch/arm/vfp/entry.S
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpmodule.c
arch/avr32/Kconfig
arch/avr32/kernel/process.c
arch/avr32/mm/fault.c
arch/blackfin/Kconfig
arch/blackfin/kernel/process.c
arch/blackfin/mm/sram-alloc.c
arch/cris/Kconfig
arch/cris/arch-v10/kernel/process.c
arch/cris/arch-v10/kernel/time.c
arch/cris/arch-v32/Kconfig
arch/cris/arch-v32/drivers/Kconfig
arch/cris/arch-v32/kernel/process.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/arch-v32/kernel/time.c
arch/cris/arch-v32/mach-fs/Kconfig
arch/cris/include/arch-v32/arch/spinlock.h
arch/cris/kernel/process.c
arch/frv/kernel/irq-mb93091.c
arch/frv/kernel/irq-mb93093.c
arch/frv/kernel/irq-mb93493.c
arch/frv/kernel/process.c
arch/frv/kernel/time.c
arch/h8300/kernel/process.c
arch/h8300/kernel/timer/itu.c
arch/h8300/kernel/timer/timer16.c
arch/h8300/kernel/timer/timer8.c
arch/h8300/kernel/timer/tpu.c
arch/ia64/configs/generic_defconfig
arch/ia64/hp/sim/simserial.c
arch/ia64/include/asm/intrinsics.h
arch/ia64/include/asm/mmu_context.h
arch/ia64/include/asm/module.h
arch/ia64/include/asm/native/inst.h
arch/ia64/include/asm/native/patchlist.h [new file with mode: 0644]
arch/ia64/include/asm/native/pvchk_inst.h
arch/ia64/include/asm/paravirt.h
arch/ia64/include/asm/paravirt_patch.h [new file with mode: 0644]
arch/ia64/include/asm/paravirt_privop.h
arch/ia64/include/asm/smp.h
arch/ia64/include/asm/spinlock.h
arch/ia64/include/asm/timex.h
arch/ia64/include/asm/topology.h
arch/ia64/include/asm/uv/uv_hub.h
arch/ia64/include/asm/uv/uv_mmrs.h
arch/ia64/include/asm/xen/hypervisor.h
arch/ia64/include/asm/xen/inst.h
arch/ia64/include/asm/xen/interface.h
arch/ia64/include/asm/xen/minstate.h
arch/ia64/include/asm/xen/patchlist.h [new file with mode: 0644]
arch/ia64/include/asm/xen/privop.h
arch/ia64/kernel/Makefile
arch/ia64/kernel/Makefile.gate [new file with mode: 0644]
arch/ia64/kernel/acpi.c
arch/ia64/kernel/asm-offsets.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/fsys.S
arch/ia64/kernel/gate.S
arch/ia64/kernel/gate.lds.S
arch/ia64/kernel/head.S
arch/ia64/kernel/ivt.S
arch/ia64/kernel/mca.c
arch/ia64/kernel/module.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/paravirt.c
arch/ia64/kernel/paravirt_patch.c [new file with mode: 0644]
arch/ia64/kernel/paravirt_patchlist.c [new file with mode: 0644]
arch/ia64/kernel/paravirt_patchlist.h [new file with mode: 0644]
arch/ia64/kernel/paravirtentry.S
arch/ia64/kernel/patch.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/process.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/time.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/kvm/kvm-ia64.c
arch/ia64/kvm/vcpu.c
arch/ia64/kvm/vtlb.c
arch/ia64/mm/init.c
arch/ia64/mm/tlb.c
arch/ia64/scripts/pvcheck.sed
arch/ia64/sn/kernel/io_common.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/setup.c
arch/ia64/sn/kernel/sn2/prominfo_proc.c
arch/ia64/sn/kernel/sn2/sn2_smp.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/ia64/sn/pci/pcibr/pcibr_dma.c
arch/ia64/xen/Makefile
arch/ia64/xen/gate-data.S [new file with mode: 0644]
arch/ia64/xen/hypercall.S
arch/ia64/xen/time.c
arch/ia64/xen/xen_pv_ops.c
arch/m32r/kernel/process.c
arch/m32r/kernel/time.c
arch/m68k/include/asm/bootinfo.h
arch/m68k/include/asm/bootinfo_mm.h [deleted file]
arch/m68k/include/asm/bootinfo_no.h [deleted file]
arch/m68k/include/asm/bug.h
arch/m68k/include/asm/bug_mm.h [deleted file]
arch/m68k/include/asm/bug_no.h [deleted file]
arch/m68k/include/asm/bugs.h
arch/m68k/include/asm/bugs_mm.h [deleted file]
arch/m68k/include/asm/bugs_no.h [deleted file]
arch/m68k/include/asm/cache.h
arch/m68k/include/asm/cache_mm.h [deleted file]
arch/m68k/include/asm/cache_no.h [deleted file]
arch/m68k/include/asm/current.h
arch/m68k/include/asm/current_mm.h [deleted file]
arch/m68k/include/asm/current_no.h [deleted file]
arch/m68k/include/asm/div64.h
arch/m68k/include/asm/div64_mm.h [deleted file]
arch/m68k/include/asm/div64_no.h [deleted file]
arch/m68k/include/asm/dma-mapping.h
arch/m68k/include/asm/dma-mapping_mm.h [deleted file]
arch/m68k/include/asm/dma-mapping_no.h [deleted file]
arch/m68k/include/asm/elf.h
arch/m68k/include/asm/elf_mm.h [deleted file]
arch/m68k/include/asm/elf_no.h [deleted file]
arch/m68k/include/asm/fb.h
arch/m68k/include/asm/fb_mm.h [deleted file]
arch/m68k/include/asm/fb_no.h [deleted file]
arch/m68k/include/asm/fpu.h
arch/m68k/include/asm/fpu_mm.h [deleted file]
arch/m68k/include/asm/fpu_no.h [deleted file]
arch/m68k/include/asm/hw_irq.h
arch/m68k/include/asm/hw_irq_mm.h [deleted file]
arch/m68k/include/asm/hw_irq_no.h [deleted file]
arch/m68k/include/asm/kmap_types.h
arch/m68k/include/asm/kmap_types_mm.h [deleted file]
arch/m68k/include/asm/kmap_types_no.h [deleted file]
arch/m68k/include/asm/m532xsim.h
arch/m68k/include/asm/mc146818rtc.h
arch/m68k/include/asm/mc146818rtc_mm.h [deleted file]
arch/m68k/include/asm/mc146818rtc_no.h [deleted file]
arch/m68k/include/asm/mcfpci.h [deleted file]
arch/m68k/include/asm/mmu.h
arch/m68k/include/asm/mmu_context.h
arch/m68k/include/asm/mmu_context_mm.h [deleted file]
arch/m68k/include/asm/mmu_context_no.h [deleted file]
arch/m68k/include/asm/mmu_mm.h [deleted file]
arch/m68k/include/asm/mmu_no.h [deleted file]
arch/m68k/include/asm/module.h
arch/m68k/include/asm/module_mm.h [deleted file]
arch/m68k/include/asm/module_no.h [deleted file]
arch/m68k/include/asm/page_offset.h
arch/m68k/include/asm/page_offset_mm.h [deleted file]
arch/m68k/include/asm/page_offset_no.h [deleted file]
arch/m68k/include/asm/pci.h
arch/m68k/include/asm/pci_mm.h [deleted file]
arch/m68k/include/asm/pci_no.h [deleted file]
arch/m68k/include/asm/pgalloc.h
arch/m68k/include/asm/pgalloc_mm.h [deleted file]
arch/m68k/include/asm/pgalloc_no.h [deleted file]
arch/m68k/include/asm/pgtable_no.h
arch/m68k/include/asm/rtc.h
arch/m68k/include/asm/scatterlist.h
arch/m68k/include/asm/scatterlist_mm.h [deleted file]
arch/m68k/include/asm/scatterlist_no.h [deleted file]
arch/m68k/include/asm/segment.h
arch/m68k/include/asm/segment_mm.h [deleted file]
arch/m68k/include/asm/segment_no.h [deleted file]
arch/m68k/include/asm/timex.h
arch/m68k/include/asm/timex_mm.h [deleted file]
arch/m68k/include/asm/timex_no.h [deleted file]
arch/m68k/include/asm/tlbflush.h
arch/m68k/include/asm/tlbflush_mm.h [deleted file]
arch/m68k/include/asm/tlbflush_no.h [deleted file]
arch/m68k/include/asm/ucontext.h
arch/m68k/include/asm/ucontext_mm.h [deleted file]
arch/m68k/include/asm/ucontext_no.h [deleted file]
arch/m68k/include/asm/unaligned.h
arch/m68k/include/asm/unaligned_mm.h [deleted file]
arch/m68k/include/asm/unaligned_no.h [deleted file]
arch/m68k/kernel/process.c
arch/m68k/kernel/time.c
arch/m68knommu/Makefile
arch/m68knommu/kernel/dma.c
arch/m68knommu/kernel/irq.c
arch/m68knommu/kernel/process.c
arch/m68knommu/mm/init.c
arch/m68knommu/platform/5249/config.c
arch/m68knommu/platform/5307/config.c
arch/m68knommu/platform/5407/config.c
arch/m68knommu/platform/coldfire/Makefile
arch/m68knommu/platform/coldfire/clk.c [new file with mode: 0644]
arch/mips/Kconfig
arch/mips/cobalt/irq.c
arch/mips/emma/markeins/irq.c
arch/mips/include/asm/mach-bcm47xx/gpio.h
arch/mips/include/asm/mach-ip27/topology.h
arch/mips/include/asm/spinlock.h
arch/mips/include/asm/unistd.h
arch/mips/jazz/irq.c
arch/mips/kernel/cevt-bcm1480.c
arch/mips/kernel/cevt-sb1250.c
arch/mips/kernel/i8253.c
arch/mips/kernel/i8259.c
arch/mips/kernel/process.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/lasat/interrupt.c
arch/mips/lemote/lm2e/irq.c
arch/mips/mm/highmem.c
arch/mips/sgi-ip27/ip27-nmi.c
arch/mips/sgi-ip27/ip27-smp.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sni/rm200.c
arch/mips/vr41xx/common/irq.c
arch/mn10300/kernel/process.c
arch/mn10300/kernel/time.c
arch/parisc/Kconfig
arch/parisc/Makefile
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/cacheflush.h
arch/parisc/include/asm/elf.h
arch/parisc/include/asm/ftrace.h [new file with mode: 0644]
arch/parisc/include/asm/page.h
arch/parisc/include/asm/pdc.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/smp.h
arch/parisc/include/asm/spinlock.h
arch/parisc/kernel/Makefile
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c
arch/parisc/kernel/ftrace.c [new file with mode: 0644]
arch/parisc/kernel/irq.c
arch/parisc/kernel/module.c
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/process.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/smp.c
arch/parisc/kernel/stacktrace.c [new file with mode: 0644]
arch/parisc/kernel/syscall.S
arch/parisc/kernel/time.c
arch/parisc/kernel/traps.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/boot/dts/mpc832x_rdb.dts
arch/powerpc/include/asm/highmem.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/ps3.h
arch/powerpc/include/asm/spinlock.h
arch/powerpc/include/asm/suspend.h
arch/powerpc/include/asm/topology.h
arch/powerpc/kernel/msi.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/rtas_flash.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/vio.c
arch/powerpc/platforms/83xx/mpc832x_rdb.c
arch/powerpc/platforms/85xx/mpc85xx_cds.c
arch/powerpc/platforms/8xx/m8xx_setup.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/ps3/os-area.c
arch/powerpc/platforms/ps3/platform.h
arch/powerpc/platforms/ps3/setup.c
arch/powerpc/platforms/ps3/time.c
arch/powerpc/sysdev/bestcomm/Kconfig
arch/powerpc/sysdev/cpm1.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/fsl_soc.h
arch/s390/Kconfig
arch/s390/Kconfig.debug
arch/s390/hypfs/hypfs_diag.c
arch/s390/include/asm/cio.h
arch/s390/include/asm/smp.h
arch/s390/include/asm/spinlock.h
arch/s390/kernel/process.c
arch/sh/Kconfig
arch/sh/include/asm/spinlock.h
arch/sh/include/asm/topology.h
arch/sh/kernel/process_32.c
arch/sh/kernel/process_64.c
arch/sh/kernel/time_64.c
arch/sh/kernel/timers/timer-cmt.c
arch/sh/kernel/timers/timer-mtu2.c
arch/sh/kernel/timers/timer-tmu.c
arch/sparc/Kconfig
arch/sparc/Kconfig.debug
arch/sparc/include/asm/mmu_context_64.h
arch/sparc/include/asm/smp_64.h
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/include/asm/system_32.h
arch/sparc/include/asm/topology_64.h
arch/sparc/kernel/ds.c
arch/sparc/kernel/head_64.S
arch/sparc/kernel/irq_32.c
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/led.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/nmi.c
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/prom_64.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/mm/highmem.c
arch/sparc/mm/init_64.c
arch/sparc/mm/srmmu.c
arch/um/drivers/net_kern.c
arch/um/drivers/pcap_user.h
arch/um/drivers/port.h
arch/um/drivers/ssl.h
arch/um/drivers/stdio_console.h
arch/um/drivers/ubd_kern.c
arch/um/drivers/xterm.h
arch/um/include/asm/irq_vectors.h
arch/um/include/asm/mmu.h
arch/um/include/asm/pda.h
arch/um/include/asm/pgalloc.h
arch/um/include/asm/pgtable-3level.h
arch/um/include/shared/frame_kern.h
arch/um/include/shared/initrd.h
arch/um/include/shared/irq_kern.h
arch/um/include/shared/mem_kern.h
arch/um/include/shared/ubd_user.h
arch/um/kernel/Makefile
arch/um/kernel/config.c.in
arch/um/kernel/process.c
arch/um/kernel/syscall.c
arch/um/os-Linux/start_up.c
arch/um/sys-i386/asm/archparam.h
arch/um/sys-i386/shared/sysdep/checksum.h
arch/um/sys-i386/sys_call_table.S
arch/um/sys-ia64/sysdep/ptrace.h
arch/um/sys-ia64/sysdep/sigcontext.h
arch/um/sys-ia64/sysdep/syscalls.h
arch/um/sys-ppc/miscthings.c
arch/um/sys-ppc/ptrace.c
arch/um/sys-ppc/ptrace_user.c
arch/um/sys-ppc/shared/sysdep/ptrace.h
arch/um/sys-ppc/shared/sysdep/sigcontext.h
arch/um/sys-ppc/shared/sysdep/syscalls.h
arch/um/sys-ppc/sigcontext.c
arch/um/sys-x86_64/asm/archparam.h
arch/um/sys-x86_64/asm/module.h
arch/um/sys-x86_64/mem.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/boot/memory.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/lguest_hcall.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/suspend_32.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/uv/uv_mmrs.h
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/cpu/mtrr/if.c
arch/x86/kernel/irqinit_32.c
arch/x86/kernel/irqinit_64.c
arch/x86/kernel/mfgpt_32.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/setup.c
arch/x86/kernel/syscall_table_32.S
arch/x86/kernel/time_64.c
arch/x86/kernel/vmiclock_32.c
arch/x86/lguest/boot.c
arch/x86/lguest/i386_head.S
arch/x86/mm/highmem_32.c
arch/x86/mm/iomap_32.c
arch/x86/pci/early.c
arch/x86/pci/fixup.c
arch/x86/pci/i386.c
arch/x86/pci/legacy.c
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/mmconfig_64.c
arch/x86/power/cpu_32.c
arch/x86/power/cpu_64.c
arch/x86/power/hibernate_64.c
arch/xtensa/Kconfig
arch/xtensa/Makefile
arch/xtensa/configs/s6105_defconfig [new file with mode: 0644]
arch/xtensa/include/asm/cacheflush.h
arch/xtensa/include/asm/dma.h
arch/xtensa/include/asm/flat.h [new file with mode: 0644]
arch/xtensa/include/asm/gpio.h [new file with mode: 0644]
arch/xtensa/include/asm/io.h
arch/xtensa/include/asm/irq.h
arch/xtensa/include/asm/mmu.h
arch/xtensa/include/asm/mmu_context.h
arch/xtensa/include/asm/nommu.h [new file with mode: 0644]
arch/xtensa/include/asm/nommu_context.h [new file with mode: 0644]
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/platform.h
arch/xtensa/include/asm/processor.h
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/head.S
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/platform.c
arch/xtensa/kernel/process.c
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/traps.c
arch/xtensa/kernel/vectors.S
arch/xtensa/kernel/vmlinux.lds.S
arch/xtensa/mm/Makefile
arch/xtensa/mm/init.c
arch/xtensa/mm/misc.S
arch/xtensa/mm/mmu.c [new file with mode: 0644]
arch/xtensa/platforms/iss/console.c
arch/xtensa/platforms/s6105/Makefile [new file with mode: 0644]
arch/xtensa/platforms/s6105/device.c [new file with mode: 0644]
arch/xtensa/platforms/s6105/include/platform/gpio.h [new file with mode: 0644]
arch/xtensa/platforms/s6105/include/platform/hardware.h [new file with mode: 0644]
arch/xtensa/platforms/s6105/include/platform/serial.h [new file with mode: 0644]
arch/xtensa/platforms/s6105/setup.c [new file with mode: 0644]
arch/xtensa/platforms/xt2000/include/platform/hardware.h
arch/xtensa/variants/s6000/Makefile [new file with mode: 0644]
arch/xtensa/variants/s6000/gpio.c [new file with mode: 0644]
arch/xtensa/variants/s6000/include/variant/core.h [new file with mode: 0644]
arch/xtensa/variants/s6000/include/variant/hardware.h [new file with mode: 0644]
arch/xtensa/variants/s6000/include/variant/irq.h [new file with mode: 0644]
arch/xtensa/variants/s6000/include/variant/tie-asm.h [new file with mode: 0644]
arch/xtensa/variants/s6000/include/variant/tie.h [new file with mode: 0644]
arch/xtensa/variants/s6000/irq.c [new file with mode: 0644]
block/blk-softirq.c
crypto/async_tx/async_tx.c
crypto/async_tx/async_xor.c
crypto/shash.c
crypto/xor.c
drivers/acpi/ac.c
drivers/acpi/battery.c
drivers/acpi/button.c
drivers/acpi/fan.c
drivers/acpi/pci_root.c
drivers/acpi/processor_core.c
drivers/acpi/sbs.c
drivers/acpi/thermal.c
drivers/acpi/video.c
drivers/ata/Kconfig
drivers/auxdisplay/Kconfig
drivers/base/cpu.c
drivers/base/iommu.c
drivers/base/power/main.c
drivers/base/sys.c
drivers/block/aoe/aoecmd.c
drivers/block/floppy.c
drivers/block/hd.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/ps3vram.c
drivers/block/xsysace.c
drivers/char/amiserial.c
drivers/char/bsr.c
drivers/char/cyclades.c
drivers/char/hpet.c
drivers/char/hw_random/timeriomem-rng.c
drivers/char/ip2/ip2main.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/istallion.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/random.c
drivers/char/stallion.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/sysrq.c
drivers/char/tty_audit.c
drivers/char/tty_io.c
drivers/char/tty_ldisc.c
drivers/crypto/hifn_795x.c
drivers/crypto/ixp4xx_crypto.c
drivers/dma/Kconfig
drivers/dma/dmaengine.c
drivers/dma/dmatest.c
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
drivers/dma/fsldma.c
drivers/dma/ioat_dma.c
drivers/dma/iop-adma.c
drivers/dma/ipu/ipu_idmac.c
drivers/dma/ipu/ipu_irq.c
drivers/dma/mv_xor.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/amd8111_edac.c [new file with mode: 0644]
drivers/edac/amd8111_edac.h [new file with mode: 0644]
drivers/edac/amd8131_edac.c [new file with mode: 0644]
drivers/edac/amd8131_edac.h [new file with mode: 0644]
drivers/edac/edac_core.h
drivers/edac/edac_pci.c
drivers/edac/ppc4xx_edac.c [new file with mode: 0644]
drivers/edac/ppc4xx_edac.h [new file with mode: 0644]
drivers/firmware/dmi_scan.c
drivers/gpio/Kconfig
drivers/gpio/gpiolib.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_debug.c
drivers/gpu/drm/i915/i915_gem_debugfs.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sdvo_regs.h
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-a4tech.c
drivers/hid/hid-apple.c
drivers/hid/hid-belkin.c
drivers/hid/hid-cherry.c
drivers/hid/hid-chicony.c
drivers/hid/hid-core.c
drivers/hid/hid-cypress.c
drivers/hid/hid-drff.c [new file with mode: 0644]
drivers/hid/hid-dummy.c [deleted file]
drivers/hid/hid-ezkey.c
drivers/hid/hid-gaff.c
drivers/hid/hid-gyration.c
drivers/hid/hid-ids.h
drivers/hid/hid-kensington.c [new file with mode: 0644]
drivers/hid/hid-kye.c [new file with mode: 0644]
drivers/hid/hid-lg.c
drivers/hid/hid-microsoft.c
drivers/hid/hid-monterey.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-petalynx.c
drivers/hid/hid-pl.c
drivers/hid/hid-samsung.c
drivers/hid/hid-sony.c
drivers/hid/hid-sunplus.c
drivers/hid/hid-tmff.c
drivers/hid/hid-topseed.c
drivers/hid/hid-zpff.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbhid.h
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ds1621.c
drivers/hwmon/f75375s.c
drivers/hwmon/fschmd.c
drivers/hwmon/hdaps.c
drivers/hwmon/hp_accel.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h
drivers/hwmon/lis3lv02d_spi.c [new file with mode: 0644]
drivers/hwmon/lm95241.c [new file with mode: 0644]
drivers/hwmon/ltc4215.c [new file with mode: 0644]
drivers/hwmon/pcf8591.c [moved from drivers/i2c/chips/pcf8591.c with 96% similarity]
drivers/hwmon/w83627ehf.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/alim15x3.c
drivers/ide/at91_ide.c
drivers/ide/au1xxx-ide.c
drivers/ide/cmd64x.c
drivers/ide/cs5530.c
drivers/ide/cs5536.c
drivers/ide/falconide.c
drivers/ide/gayle.c
drivers/ide/hpt366.c
drivers/ide/ht6560b.c
drivers/ide/icside.c
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-dma-sff.c
drivers/ide/ide-dma.c
drivers/ide/ide-eh.c
drivers/ide/ide-floppy.c
drivers/ide/ide-floppy_ioctl.c
drivers/ide/ide-generic.c
drivers/ide/ide-h8300.c
drivers/ide/ide-io-std.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-pm.c
drivers/ide/ide-probe.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide-timings.c
drivers/ide/ide-xfer-mode.c
drivers/ide/ide_arm.c [deleted file]
drivers/ide/it821x.c
drivers/ide/ns87415.c
drivers/ide/pdc202xx_old.c
drivers/ide/pmac.c
drivers/ide/q40ide.c
drivers/ide/qd65xx.c
drivers/ide/sc1200.c
drivers/ide/scc_pata.c
drivers/ide/sgiioc4.c
drivers/ide/siimage.c
drivers/ide/sl82c105.c
drivers/ide/tc86c001.c
drivers/ide/trm290.c
drivers/ide/tx4938ide.c
drivers/ide/tx4939ide.c
drivers/input/Kconfig
drivers/input/input.c
drivers/input/mouse/gpio_mouse.c
drivers/input/mouse/hgpk.c
drivers/input/touchscreen/ads7846.c
drivers/isdn/capi/capi.c
drivers/isdn/hardware/eicon/divasi.c
drivers/isdn/mISDN/Kconfig
drivers/isdn/mISDN/l1oip_codec.c
drivers/leds/Kconfig
drivers/leds/leds-pca9532.c
drivers/lguest/core.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/lg.h
drivers/lguest/lguest_device.c
drivers/lguest/page_tables.c
drivers/lguest/segments.c
drivers/lguest/x86/core.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/bitmap.c
drivers/md/bitmap.h [moved from include/linux/raid/bitmap.h with 100% similarity]
drivers/md/dm-bio-list.h
drivers/md/dm-bio-record.h
drivers/md/dm-crypt.c
drivers/md/dm-exception-store.c
drivers/md/dm-exception-store.h
drivers/md/dm-io.c
drivers/md/dm-log.c
drivers/md/dm-path-selector.c
drivers/md/dm-raid1.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-snap-transient.c
drivers/md/dm-snap.c
drivers/md/dm-snap.h [deleted file]
drivers/md/dm-table.c
drivers/md/dm-target.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/faulty.c
drivers/md/linear.c
drivers/md/linear.h [moved from include/linux/raid/linear.h with 95% similarity]
drivers/md/md.c
drivers/md/md.h [moved from include/linux/raid/md_k.h with 83% similarity]
drivers/md/mktables.c
drivers/md/multipath.c
drivers/md/multipath.h [moved from include/linux/raid/multipath.h with 96% similarity]
drivers/md/raid0.c
drivers/md/raid0.h [moved from include/linux/raid/raid0.h with 96% similarity]
drivers/md/raid1.c
drivers/md/raid1.h [moved from include/linux/raid/raid1.h with 99% similarity]
drivers/md/raid10.c
drivers/md/raid10.h [moved from include/linux/raid/raid10.h with 99% similarity]
drivers/md/raid5.c
drivers/md/raid5.h [moved from include/linux/raid/raid5.h with 81% similarity]
drivers/md/raid6algos.c
drivers/md/raid6altivec.uc
drivers/md/raid6int.uc
drivers/md/raid6mmx.c
drivers/md/raid6recov.c
drivers/md/raid6sse1.c
drivers/md/raid6sse2.c
drivers/md/raid6test/Makefile
drivers/md/raid6test/test.c
drivers/md/raid6x86.h
drivers/media/common/tuners/Kconfig
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/drx397xD.c
drivers/media/video/cpia.c
drivers/message/i2o/i2o_proc.c
drivers/mfd/Kconfig
drivers/mfd/twl4030-core.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/eeprom/at24.c
drivers/misc/eeprom/at25.c
drivers/misc/hpilo.c
drivers/misc/hpilo.h
drivers/misc/isl29003.c [new file with mode: 0644]
drivers/misc/sgi-gru/Makefile
drivers/misc/sgi-gru/gru_instructions.h
drivers/misc/sgi-gru/grufault.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/gruhandles.c [new file with mode: 0644]
drivers/misc/sgi-gru/gruhandles.h
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-gru/grukservices.h
drivers/misc/sgi-gru/grumain.c
drivers/misc/sgi-gru/gruprocfs.c
drivers/misc/sgi-gru/grutables.h
drivers/misc/sgi-gru/grutlbpurge.c
drivers/misc/sgi-xp/xpc.h
drivers/misc/sgi-xp/xpc_channel.c
drivers/misc/sgi-xp/xpc_main.c
drivers/misc/sgi-xp/xpc_sn2.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/mmc/card/sdio_uart.c
drivers/mmc/core/core.c
drivers/mmc/host/Kconfig
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/tests/mtd_oobtest.c
drivers/mtd/tests/mtd_readtest.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/bonding/bond_main.c
drivers/net/dm9000.c
drivers/net/dnet.c
drivers/net/fec_mpc52xx.c
drivers/net/fsl_pq_mdio.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/hamradio/dmascc.c
drivers/net/hamradio/yam.c
drivers/net/hamradio/yam1200.h [deleted file]
drivers/net/hamradio/yam9600.h [deleted file]
drivers/net/igb/e1000_phy.c
drivers/net/igb/igb_ethtool.c
drivers/net/igb/igb_main.c
drivers/net/irda/vlsi_ir.c
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_common.h
drivers/net/ixgbe/ixgbe_dcb_nl.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_type.h
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/en_rx.c
drivers/net/mlx4/sense.c
drivers/net/netconsole.c
drivers/net/ni5010.c
drivers/net/niu.c
drivers/net/pcmcia/ositech.h [deleted file]
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/phy/phy.c
drivers/net/qlge/qlge_ethtool.c
drivers/net/r8169.c
drivers/net/sb1250-mac.c
drivers/net/sfc/efx.c
drivers/net/skfp/h/hwmtm.h
drivers/net/tc35815.c
drivers/net/tg3.c
drivers/net/tokenring/3c359.c
drivers/net/tokenring/3c359.h
drivers/net/tokenring/3c359_microcode.h [deleted file]
drivers/net/ucc_geth.c
drivers/net/ucc_geth.h
drivers/net/ucc_geth_ethtool.c
drivers/net/usb/hso.c
drivers/net/usb/kaweth.c
drivers/net/vxge/Makefile [new file with mode: 0644]
drivers/net/vxge/vxge-config.c [new file with mode: 0644]
drivers/net/vxge/vxge-config.h [new file with mode: 0644]
drivers/net/vxge/vxge-ethtool.c [new file with mode: 0644]
drivers/net/vxge/vxge-ethtool.h [new file with mode: 0644]
drivers/net/vxge/vxge-main.c [new file with mode: 0644]
drivers/net/vxge/vxge-main.h [new file with mode: 0644]
drivers/net/vxge/vxge-reg.h [new file with mode: 0644]
drivers/net/vxge/vxge-traffic.c [new file with mode: 0644]
drivers/net/vxge/vxge-traffic.h [new file with mode: 0644]
drivers/net/vxge/vxge-version.h [new file with mode: 0644]
drivers/net/wan/farsync.c
drivers/net/wireless/airo.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/zd1201.c
drivers/of/base.c
drivers/oprofile/buffer_sync.c
drivers/parisc/asp.c
drivers/parisc/ccio-dma.c
drivers/parisc/dino.c
drivers/parisc/eisa.c
drivers/parisc/eisa_enumerator.c
drivers/parisc/iosapic.c
drivers/parisc/led.c
drivers/parport/parport_serial.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/bus.c
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/fakephp.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_acpi.c
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_pci.c
drivers/pci/intel-iommu.c
drivers/pci/iov.c [new file with mode: 0644]
drivers/pci/msi.c
drivers/pci/msi.h
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv_acpi.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_bus.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/search.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pci/slot.c
drivers/pcmcia/pxa2xx_cm_x255.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/pnp/pnpbios/core.c
drivers/power/bq27x00_battery.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/bq24022.c
drivers/regulator/core.c
drivers/regulator/da903x.c
drivers/regulator/fixed.c
drivers/regulator/pcf50633-regulator.c
drivers/regulator/twl4030-regulator.c [new file with mode: 0644]
drivers/regulator/virtual.c
drivers/regulator/wm8350-regulator.c
drivers/regulator/wm8400-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-efi.c [new file with mode: 0644]
drivers/rtc/rtc-generic.c [new file with mode: 0644]
drivers/rtc/rtc-lib.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-parisc.c [deleted file]
drivers/rtc/rtc-ppc.c [deleted file]
drivers/rtc/rtc-proc.c
drivers/rtc/rtc-ps3.c [new file with mode: 0644]
drivers/rtc/rtc-v3020.c
drivers/rtc/rtc-wm8350.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_proc.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/net/qeth_core_offl.c [deleted file]
drivers/s390/net/qeth_core_offl.h [deleted file]
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_fc.c
drivers/scsi/Kconfig
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_proc.c
drivers/serial/Kconfig
drivers/serial/mcf.c
drivers/serial/serial_core.c
drivers/spi/spi_gpio.c
drivers/spi/spi_mpc83xx.c
drivers/staging/Kconfig
drivers/staging/comedi/Kconfig
drivers/staging/go7007/Kconfig
drivers/staging/otus/hal/hpmain.c
drivers/staging/panel/Kconfig
drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
drivers/staging/rtl8187se/r8180_core.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/gadget/Kconfig
drivers/usb/serial/ChangeLog.history
drivers/usb/serial/Kconfig
drivers/usb/serial/usb-serial.c
drivers/usb/storage/isd200.c
drivers/usb/wusbcore/devconnect.c
drivers/usb/wusbcore/security.c
drivers/uwb/Kconfig
drivers/video/68328fb.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amba-clcd.c
drivers/video/amifb.c
drivers/video/arkfb.c
drivers/video/asiliantfb.c
drivers/video/aty/mach64_accel.c
drivers/video/aty/mach64_cursor.c
drivers/video/aty/radeon_pm.c
drivers/video/backlight/backlight.c
drivers/video/backlight/lcd.c
drivers/video/cirrusfb.c
drivers/video/console/fbcon.c
drivers/video/cyblafb.c [deleted file]
drivers/video/efifb.c
drivers/video/fb_defio.c
drivers/video/fbmem.c
drivers/video/nvidia/nv_setup.c
drivers/video/nvidia/nv_type.h
drivers/video/nvidia/nvidia.c
drivers/video/omap/hwa742.c
drivers/video/omap/omapfb_main.c
drivers/video/s1d13xxxfb.c
drivers/video/s3c-fb.c [new file with mode: 0644]
drivers/video/sgivwfb.c
drivers/video/skeletonfb.c
drivers/video/sm501fb.c
drivers/video/sstfb.c
drivers/video/stifb.c
drivers/video/sunxvr500.c
drivers/video/tdfxfb.c
drivers/video/tgafb.c
drivers/video/tridentfb.c
drivers/video/uvesafb.c
drivers/video/valkyriefb.c
drivers/video/vesafb.c
drivers/video/vfb.c
drivers/video/via/accel.c
drivers/video/via/viafbdev.c
drivers/virtio/virtio_ring.c
drivers/w1/w1_io.c
drivers/watchdog/hpwdt.c
drivers/xen/Kconfig
drivers/xen/manage.c
firmware/3com/3C359.bin.ihex [new file with mode: 0644]
firmware/Makefile
firmware/WHENCE
firmware/ositech/Xilinx7OD.bin.ihex [new file with mode: 0644]
firmware/yam/1200.bin.ihex [new file with mode: 0644]
firmware/yam/9600.bin.ihex [new file with mode: 0644]
fs/Kconfig
fs/Makefile
fs/adfs/super.c
fs/affs/super.c
fs/afs/Kconfig
fs/afs/Makefile
fs/afs/cache.c
fs/afs/cache.h
fs/afs/cell.c
fs/afs/file.c
fs/afs/inode.c
fs/afs/internal.h
fs/afs/main.c
fs/afs/mntpt.c
fs/afs/proc.c
fs/afs/vlocation.c
fs/afs/volume.c
fs/afs/write.c
fs/autofs4/autofs_i.h
fs/autofs4/dev-ioctl.c
fs/autofs4/expire.c
fs/autofs4/root.c
fs/befs/linuxvfs.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_som.c
fs/bio.c
fs/block_dev.c
fs/btrfs/Makefile
fs/btrfs/acl.c
fs/btrfs/async-thread.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-ref.c [new file with mode: 0644]
fs/btrfs/delayed-ref.h [new file with mode: 0644]
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/extent_map.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-cache.h [new file with mode: 0644]
fs/btrfs/inode-item.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/locking.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-defrag.c
fs/btrfs/tree-log.c
fs/btrfs/tree-log.h
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/buffer.c
fs/cachefiles/Kconfig [new file with mode: 0644]
fs/cachefiles/Makefile [new file with mode: 0644]
fs/cachefiles/bind.c [new file with mode: 0644]
fs/cachefiles/daemon.c [new file with mode: 0644]
fs/cachefiles/interface.c [new file with mode: 0644]
fs/cachefiles/internal.h [new file with mode: 0644]
fs/cachefiles/key.c [new file with mode: 0644]
fs/cachefiles/main.c [new file with mode: 0644]
fs/cachefiles/namei.c [new file with mode: 0644]
fs/cachefiles/proc.c [new file with mode: 0644]
fs/cachefiles/rdwr.c [new file with mode: 0644]
fs/cachefiles/security.c [new file with mode: 0644]
fs/cachefiles/xattr.c [new file with mode: 0644]
fs/cifs/cifs_debug.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/compat.c
fs/compat_ioctl.c
fs/cramfs/inode.c
fs/cramfs/uncompress.c
fs/dcache.c
fs/drop_caches.c
fs/ecryptfs/keystore.c
fs/ecryptfs/messaging.c
fs/efs/super.c
fs/eventfd.c
fs/eventpoll.c
fs/exec.c
fs/exofs/BUGS [new file with mode: 0644]
fs/exofs/Kbuild [new file with mode: 0644]
fs/exofs/Kconfig [new file with mode: 0644]
fs/exofs/common.h [new file with mode: 0644]
fs/exofs/dir.c [new file with mode: 0644]
fs/exofs/exofs.h [new file with mode: 0644]
fs/exofs/file.c [new file with mode: 0644]
fs/exofs/inode.c [new file with mode: 0644]
fs/exofs/namei.c [new file with mode: 0644]
fs/exofs/osd.c [new file with mode: 0644]
fs/exofs/super.c [new file with mode: 0644]
fs/exofs/symlink.c [new file with mode: 0644]
fs/ext2/acl.c
fs/ext3/acl.c
fs/ext3/dir.c
fs/ext3/file.c
fs/ext3/inode.c
fs/ext3/ioctl.c
fs/ext3/namei.c
fs/ext4/Kconfig
fs/ext4/acl.c
fs/ext4/balloc.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_extents.h
fs/ext4/ext4_i.h
fs/ext4/ext4_sb.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/namei.c
fs/ext4/resize.c
fs/ext4/super.c
fs/fat/inode.c
fs/file_table.c
fs/fs-writeback.c
fs/fs_struct.c [new file with mode: 0644]
fs/fscache/Kconfig [new file with mode: 0644]
fs/fscache/Makefile [new file with mode: 0644]
fs/fscache/cache.c [new file with mode: 0644]
fs/fscache/cookie.c [new file with mode: 0644]
fs/fscache/fsdef.c [new file with mode: 0644]
fs/fscache/histogram.c [new file with mode: 0644]
fs/fscache/internal.h [new file with mode: 0644]
fs/fscache/main.c [new file with mode: 0644]
fs/fscache/netfs.c [new file with mode: 0644]
fs/fscache/object.c [new file with mode: 0644]
fs/fscache/operation.c [new file with mode: 0644]
fs/fscache/page.c [new file with mode: 0644]
fs/fscache/proc.c [new file with mode: 0644]
fs/fscache/stats.c [new file with mode: 0644]
fs/fuse/dir.c
fs/fuse/file.c
fs/generic_acl.c
fs/gfs2/acl.c
fs/gfs2/ops_file.c
fs/hfs/super.c
fs/hfsplus/options.c
fs/hfsplus/super.c
fs/hpfs/super.c
fs/hppfs/hppfs.c
fs/hugetlbfs/inode.c
fs/internal.h
fs/isofs/inode.c
fs/jbd/commit.c
fs/jbd/journal.c
fs/jbd/transaction.c
fs/jbd2/commit.c
fs/jbd2/revoke.c
fs/jbd2/transaction.c
fs/jffs2/acl.c
fs/jfs/acl.c
fs/jfs/jfs_debug.c
fs/lockd/clntlock.c
fs/lockd/mon.c
fs/lockd/svc.c
fs/minix/inode.c
fs/mpage.c
fs/namei.c
fs/namespace.c
fs/nfs/Kconfig
fs/nfs/Makefile
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/fscache-index.c [new file with mode: 0644]
fs/nfs/fscache.c [new file with mode: 0644]
fs/nfs/fscache.h [new file with mode: 0644]
fs/nfs/getroot.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/iostat.h
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/pagelist.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
fs/ntfs/dir.c
fs/ntfs/inode.c
fs/ntfs/layout.h
fs/ntfs/logfile.h
fs/ntfs/mft.c
fs/ntfs/super.c
fs/ntfs/usnjrnl.h
fs/ocfs2/acl.c
fs/ocfs2/alloc.c
fs/ocfs2/alloc.h
fs/ocfs2/aops.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/heartbeat.h
fs/ocfs2/cluster/nodemanager.c
fs/ocfs2/dir.c
fs/ocfs2/dir.h
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/dlm/dlmdebug.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmthread.c
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/export.c
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/localalloc.c
fs/ocfs2/mmap.c
fs/ocfs2/namei.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/ocfs2/ocfs2_lockid.h
fs/ocfs2/suballoc.c
fs/ocfs2/suballoc.h
fs/ocfs2/super.c
fs/ocfs2/xattr.c
fs/ocfs2/xattr.h
fs/omfs/inode.c
fs/open.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode-alloc.txt [deleted file]
fs/proc/inode.c
fs/proc/internal.h
fs/proc/meminfo.c
fs/proc/nommu.c
fs/proc/proc_tty.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/proc/uptime.c
fs/qnx4/inode.c
fs/quota/dquot.c
fs/ramfs/file-nommu.c
fs/ramfs/inode.c
fs/read_write.c
fs/reiserfs/Kconfig
fs/reiserfs/procfs.c
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c
fs/seq_file.c
fs/splice.c
fs/squashfs/super.c
fs/super.c
fs/sysfs/bin.c
fs/sysv/inode.c
fs/ubifs/Kconfig
fs/ubifs/file.c
fs/udf/balloc.c
fs/udf/dir.c
fs/udf/directory.c
fs/udf/ecma_167.h
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/misc.c
fs/udf/namei.c
fs/udf/osta_udf.h
fs/udf/partition.c
fs/udf/super.c
fs/udf/truncate.c
fs/udf/udf_i.h
fs/udf/udf_sb.h
fs/udf/udfdecl.h
fs/udf/udfend.h
fs/udf/udftime.c
fs/udf/unicode.c
fs/ufs/super.c
fs/xfs/Makefile
fs/xfs/linux-2.6/mutex.h [deleted file]
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_quotaops.c [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_super.h
fs/xfs/linux-2.6/xfs_sync.h
fs/xfs/linux-2.6/xfs_vnode.h
fs/xfs/quota/xfs_dquot.c
fs/xfs/quota/xfs_dquot.h
fs/xfs/quota/xfs_qm.c
fs/xfs/quota/xfs_qm.h
fs/xfs/quota/xfs_qm_bhv.c
fs/xfs/quota/xfs_qm_syscalls.c
fs/xfs/quota/xfs_quota_priv.h
fs/xfs/quota/xfs_trans_dquot.c
fs/xfs/support/debug.c
fs/xfs/support/uuid.c
fs/xfs/support/uuid.h
fs/xfs/xfs_ag.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_btree.c
fs/xfs/xfs_btree.h
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_da_btree.h
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_dinode.h
fs/xfs/xfs_dir2.c
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_dir2_data.h
fs/xfs/xfs_dir2_leaf.c
fs/xfs/xfs_dir2_node.c
fs/xfs/xfs_dir2_sf.c
fs/xfs/xfs_extfree_item.h
fs/xfs/xfs_filestream.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_ialloc_btree.c
fs/xfs/xfs_ialloc_btree.h
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.h
fs/xfs/xfs_iomap.h
fs/xfs/xfs_itable.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qmops.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_item.c
fs/xfs/xfs_trans_space.h
fs/xfs/xfs_types.h
fs/xfs/xfs_utils.c
fs/xfs/xfs_vnodeops.c
fs/xfs/xfs_vnodeops.h
include/asm-frv/highmem.h
include/asm-generic/dma-mapping.h [deleted file]
include/asm-generic/gpio.h
include/asm-generic/topology.h
include/asm-m32r/spinlock.h
include/asm-mn10300/highmem.h
include/drm/drm_crtc_helper.h
include/drm/drm_os_linux.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/async_tx.h
include/linux/auto_dev-ioctl.h
include/linux/auto_fs.h
include/linux/binfmts.h
include/linux/bootmem.h
include/linux/buffer_head.h
include/linux/cgroup.h
include/linux/compat.h
include/linux/cpu.h
include/linux/cpuset.h
include/linux/device-mapper.h
include/linux/dm-dirty-log.h
include/linux/dma_remapping.h
include/linux/dmaengine.h
include/linux/dmi.h
include/linux/dw_dmac.h
include/linux/eventfd.h
include/linux/ext3_fs.h
include/linux/fb.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/fscache-cache.h [new file with mode: 0644]
include/linux/fscache.h [new file with mode: 0644]
include/linux/fsl_devices.h
include/linux/hdreg.h
include/linux/hid.h
include/linux/highmem.h
include/linux/i2c/at24.h
include/linux/i2c/twl4030.h
include/linux/ide.h
include/linux/idr.h
include/linux/intel-iommu.h
include/linux/interrupt.h
include/linux/iommu.h
include/linux/ipmi_smi.h
include/linux/irq.h
include/linux/irqflags.h
include/linux/jbd.h
include/linux/jbd2.h
include/linux/kernel.h
include/linux/libata.h
include/linux/lockdep.h
include/linux/loop.h
include/linux/memcontrol.h
include/linux/memory.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/host.h
include/linux/mmzone.h
include/linux/mnt_namespace.h
include/linux/mpage.h
include/linux/msi.h
include/linux/mutex.h
include/linux/netpoll.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_iostat.h
include/linux/nfs_xdr.h
include/linux/nsproxy.h
include/linux/page-debug-flags.h [new file with mode: 0644]
include/linux/page-flags.h
include/linux/page_cgroup.h
include/linux/pagemap.h
include/linux/pagevec.h
include/linux/pci-acpi.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pci_regs.h
include/linux/pcieport_if.h
include/linux/poison.h
include/linux/proc_fs.h
include/linux/ptrace.h
include/linux/pwm.h
include/linux/raid/md.h [deleted file]
include/linux/raid/md_u.h
include/linux/raid/pq.h [moved from drivers/md/raid6.h with 86% similarity]
include/linux/raid/xor.h
include/linux/regulator/bq24022.h
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/regulator/fixed.h
include/linux/regulator/machine.h
include/linux/reiserfs_acl.h
include/linux/rtc-v3020.h
include/linux/rtc.h
include/linux/sched.h
include/linux/seq_file.h
include/linux/skbuff.h
include/linux/slow-work.h [new file with mode: 0644]
include/linux/smp.h
include/linux/spi/eeprom.h
include/linux/spi/spi_gpio.h
include/linux/spinlock.h
include/linux/string.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/xprt.h
include/linux/suspend.h
include/linux/swap.h
include/linux/synclink.h
include/linux/syscalls.h
include/linux/timer.h
include/linux/timeriomem-rng.h
include/linux/tracehook.h
include/linux/tty_driver.h
include/linux/usb/wusb.h
include/linux/wait.h
include/linux/workqueue.h
include/linux/writeback.h
include/net/tcp.h
include/video/aty128.h
include/video/cirrus.h
include/video/newport.h
include/video/radeon.h
include/video/s1d13xxxfb.h
init/Kconfig
init/do_mounts.c
init/do_mounts.h
init/do_mounts_md.c
init/initramfs.c
init/main.c
ipc/ipc_sysctl.c
ipc/mqueue.c
ipc/shm.c
kernel/Makefile
kernel/auditsc.c
kernel/cgroup.c
kernel/cgroup_debug.c
kernel/cpu.c
kernel/cpuset.c
kernel/exec_domain.c
kernel/exit.c
kernel/fork.c
kernel/irq/Makefile
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/pm.c [new file with mode: 0644]
kernel/kexec.c
kernel/kmod.c
kernel/kthread.c
kernel/lockdep.c
kernel/lockdep_internals.h
kernel/lockdep_proc.c
kernel/lockdep_states.h [new file with mode: 0644]
kernel/mutex-debug.c
kernel/mutex-debug.h
kernel/mutex.c
kernel/mutex.h
kernel/ns_cgroup.c
kernel/panic.c
kernel/pid.c
kernel/pid_namespace.c
kernel/power/disk.c
kernel/power/main.c
kernel/power/snapshot.c
kernel/power/swsusp.c
kernel/printk.c
kernel/ptrace.c
kernel/rcutorture.c
kernel/relay.c
kernel/sched.c
kernel/sched_cpupri.h
kernel/sched_features.h
kernel/signal.c
kernel/slow-work.c [new file with mode: 0644]
kernel/smp.c
kernel/softirq.c
kernel/spinlock.c
kernel/stop_machine.c
kernel/sys.c
kernel/sysctl.c
kernel/timer.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
kernel/utsname_sysctl.c
kernel/workqueue.c
lib/Kconfig.debug
lib/cpumask.c
lib/dma-debug.c
lib/idr.c
lib/locking-selftest.c
lib/rbtree.c
mm/Kconfig
mm/Kconfig.debug [new file with mode: 0644]
mm/Makefile
mm/allocpercpu.c
mm/debug-pagealloc.c [new file with mode: 0644]
mm/filemap.c
mm/filemap_xip.c
mm/highmem.c
mm/hugetlb.c
mm/internal.h
mm/memcontrol.c
mm/memory.c
mm/migrate.c
mm/mmap.c
mm/nommu.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_cgroup.c
mm/pdflush.c
mm/readahead.c
mm/shmem.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/swap.c
mm/truncate.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/Kconfig
net/appletalk/atalk_proc.c
net/atm/mpoa_proc.c
net/atm/proc.c
net/bluetooth/rfcomm/tty.c
net/can/bcm.c
net/can/proc.c
net/core/dev.c
net/core/ethtool.c
net/core/netpoll.c
net/core/pktgen.c
net/core/skbuff.c
net/core/sock.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/tcp.c
net/ipv4/tcp_output.c
net/ipv6/Kconfig
net/ipv6/netfilter/ip6_tables.c
net/irda/ircomm/ircomm_tty.c
net/irda/irproc.c
net/llc/llc_proc.c
net/mac80211/Kconfig
net/netfilter/Kconfig
net/netfilter/nf_conntrack_irc.c
net/netfilter/xt_cluster.c
net/phonet/Kconfig
net/rds/ib.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/ib_rdma.c
net/rds/ib_recv.c
net/rds/iw.c
net/rds/iw.h
net/rds/iw_cm.c
net/rds/iw_rdma.c
net/rds/iw_recv.c
net/rds/rds.h
net/rds/send.c
net/sctp/protocol.c
net/sunrpc/Kconfig
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/stats.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtsock.c
net/unix/af_unix.c
net/wimax/Kconfig
scripts/package/buildtar
security/device_cgroup.c
security/security.c
security/tomoyo/realpath.c
sound/core/info.c
sound/oss/pss.c
sound/sh/aica.c
sound/soc/blackfin/Kconfig

diff --git a/CREDITS b/CREDITS
index e8b7d36611e5ade69bb9524618752aa36820f3c9..2520ba620ff12a482e385b0c34403fe044ba0027 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -495,6 +495,11 @@ S: Kopmansg 2
 S: 411 13  Goteborg
 S: Sweden
 
+N: Paul Bristow
+E: paul@paulbristow.net
+W: http://paulbristow.net/linux/idefloppy.html
+D: Maintainer of IDE/ATAPI floppy driver
+
 N: Dominik Brodowski
 E: linux@brodo.de
 W: http://www.brodo.de/
@@ -1407,8 +1412,8 @@ P: 1024D/77D4FC9B F5C5 1C20 1DFC DEC3 3107  54A4 2332 ADFC 77D4 FC9B
 D: National Language Support
 D: Linux Internationalization Project
 D: German Localization for Linux and GNU software
-S: Kriemhildring 12a
-S: 65795 Hattersheim am Main
+S: Auf der Fittel 18
+S: 53347 Alfter
 S: Germany
 
 N: Christoph Hellwig
@@ -2642,6 +2647,10 @@ S: C/ Mieses 20, 9-B
 S: Valladolid 47009
 S: Spain
 
+N: Gadi Oxman
+E: gadio@netvision.net.il
+D: Original author and maintainer of IDE/ATAPI floppy/tape drivers
+
 N: Greg Page
 E: gpage@sovereign.org
 D: IPX development and support
@@ -3571,6 +3580,12 @@ N: Dirk Verworner
 D: Co-author of German book ``Linux-Kernel-Programmierung''
 D: Co-founder of Berlin Linux User Group
 
+N: Riku Voipio
+E: riku.voipio@iki.fi
+D: Author of PCA9532 LED and Fintek f75375s hwmon driver
+D: Some random ARM board patches
+S: Finland
+
 N: Patrick Volkerding
 E: volkerdi@ftp.cdrom.com
 D: Produced the Slackware distribution, updated the SVGAlib
index 2a39aeba1464b8f66ed9cfe1dc7f20d40bbeb15f..d05737aaa84ba1a4ff9606386b652d62bbee63f4 100644 (file)
@@ -86,6 +86,8 @@ cachetlb.txt
        - describes the cache/TLB flushing interfaces Linux uses.
 cdrom/
        - directory with information on the CD-ROM drivers that Linux has.
+cgroups/
+       - cgroups features, including cpusets and memory controller.
 connector/
        - docs on the netlink based userspace<->kernel space communication mod.
 console/
@@ -98,8 +100,6 @@ cpu-load.txt
        - document describing how CPU load statistics are collected.
 cpuidle/
        - info on CPU_IDLE, CPU idle state management subsystem.
-cpusets.txt
-       - documents the cpusets feature; assign CPUs and Mem to a set of tasks.
 cputopology.txt
        - documentation on how CPU topology info is exported via sysfs.
 cris/
index e638e15a8895abef445cedccb2df273f1e3ad0e1..97ad190e13af0586a528bbb7e6dfb10e748eddcd 100644 (file)
@@ -41,6 +41,49 @@ Description:
                for the device and attempt to bind to it.  For example:
                # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id
 
+What:          /sys/bus/pci/drivers/.../remove_id
+Date:          February 2009
+Contact:       Chris Wright <chrisw@sous-sol.org>
+Description:
+               Writing a device ID to this file will remove an ID
+               that was dynamically added via the new_id sysfs entry.
+               The format for the device ID is:
+               VVVV DDDD SVVV SDDD CCCC MMMM.  That is Vendor ID, Device
+               ID, Subsystem Vendor ID, Subsystem Device ID, Class,
+               and Class Mask.  The Vendor ID and Device ID fields are
+               required, the rest are optional.  After successfully
+               removing an ID, the driver will no longer support the
+               device.  This is useful to ensure auto probing won't
+               match the driver to the device.  For example:
+               # echo "8086 10f5" > /sys/bus/pci/drivers/foo/remove_id
+
+What:          /sys/bus/pci/rescan
+Date:          January 2009
+Contact:       Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+               Writing a non-zero value to this attribute will
+               force a rescan of all PCI buses in the system, and
+               re-discover previously removed devices.
+               Depends on CONFIG_HOTPLUG.
+
+What:          /sys/bus/pci/devices/.../remove
+Date:          January 2009
+Contact:       Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+               Writing a non-zero value to this attribute will
+               hot-remove the PCI device and any of its children.
+               Depends on CONFIG_HOTPLUG.
+
+What:          /sys/bus/pci/devices/.../rescan
+Date:          January 2009
+Contact:       Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+               Writing a non-zero value to this attribute will
+               force a rescan of the device's parent bus and all
+               child buses, and re-discover devices removed earlier
+               from this part of the device tree.
+               Depends on CONFIG_HOTPLUG.
+
 What:          /sys/bus/pci/devices/.../vpd
 Date:          February 2008
 Contact:       Ben Hutchings <bhutchings@solarflare.com>
@@ -52,3 +95,30 @@ Description:
                that some devices may have malformatted data.  If the
                underlying VPD has a writable section then the
                corresponding section of this file will be writable.
+
+What:          /sys/bus/pci/devices/.../virtfnN
+Date:          March 2009
+Contact:       Yu Zhao <yu.zhao@intel.com>
+Description:
+               This symbolic link appears when hardware supports the SR-IOV
+               capability and the Physical Function driver has enabled it.
+               The symbolic link points to the PCI device sysfs entry of the
+               Virtual Function whose index is N (0...MaxVFs-1).
+
+What:          /sys/bus/pci/devices/.../dep_link
+Date:          March 2009
+Contact:       Yu Zhao <yu.zhao@intel.com>
+Description:
+               This symbolic link appears when hardware supports the SR-IOV
+               capability and the Physical Function driver has enabled it,
+               and this device has vendor specific dependencies with others.
+               The symbolic link points to the PCI device sysfs entry of
+               Physical Function this device depends on.
+
+What:          /sys/bus/pci/devices/.../physfn
+Date:          March 2009
+Contact:       Yu Zhao <yu.zhao@intel.com>
+Description:
+               This symbolic link appears when a device is a Virtual Function.
+               The symbolic link points to the PCI device sysfs entry of the
+               Physical Function this device associates with.
index 873ef1fc1569ae1fe0733c4691fa58947ae8c434..e091fa8737929966b0939e1a96e4e9fe05d89c39 100644 (file)
@@ -4,8 +4,8 @@ KernelVersion:  2.6.26
 Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Some regulator directories will contain a field called
-               state. This reports the regulator enable status, for
-               regulators which can report that value.
+               state. This reports the regulator enable control, for
+               regulators which can report that input value.
 
                This will be one of the following strings:
 
@@ -14,16 +14,54 @@ Description:
                'unknown'
 
                'enabled' means the regulator output is ON and is supplying
-               power to the system.
+               power to the system (assuming no error prevents it).
 
                'disabled' means the regulator output is OFF and is not
-               supplying power to the system..
+               supplying power to the system (unless some non-Linux
+               control has enabled it).
 
                'unknown' means software cannot determine the state, or
                the reported state is invalid.
 
                NOTE: this field can be used in conjunction with microvolts
-               and microamps to determine regulator output levels.
+               or microamps to determine configured regulator output levels.
+
+
+What:          /sys/class/regulator/.../status
+Description:
+               Some regulator directories will contain a field called
+               "status". This reports the current regulator status, for
+               regulators which can report that output value.
+
+               This will be one of the following strings:
+
+                       off
+                       on
+                       error
+                       fast
+                       normal
+                       idle
+                       standby
+
+               "off" means the regulator is not supplying power to the
+               system.
+
+               "on" means the regulator is supplying power to the system,
+               and the regulator can't report a detailed operation mode.
+
+               "error" indicates an out-of-regulation status such as being
+               disabled due to thermal shutdown, or voltage being unstable
+               because of problems with the input power supply.
+
+               "fast", "normal", "idle", and "standby" are all detailed
+               regulator operation modes (described elsewhere).  They
+               imply "on", but provide more detail.
+
+               Note that regulator status is a function of many inputs,
+               not limited to control inputs from Linux.  For example,
+               the actual load presented may trigger "error" status; or
+               a regulator may be enabled by another user, even though
+               Linux did not enable it.
 
 
 What:          /sys/class/regulator/.../type
@@ -58,7 +96,7 @@ Description:
                Some regulator directories will contain a field called
                microvolts. This holds the regulator output voltage setting
                measured in microvolts (i.e. E-6 Volts), for regulators
-               which can report that voltage.
+               which can report the control input for voltage.
 
                NOTE: This value should not be used to determine the regulator
                output voltage level as this value is the same regardless of
@@ -73,7 +111,7 @@ Description:
                Some regulator directories will contain a field called
                microamps. This holds the regulator output current limit
                setting measured in microamps (i.e. E-6 Amps), for regulators
-               which can report that current.
+               which can report the control input for a current limit.
 
                NOTE: This value should not be used to determine the regulator
                output current level as this value is the same regardless of
@@ -87,7 +125,7 @@ Contact:     Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Some regulator directories will contain a field called
                opmode. This holds the current regulator operating mode,
-               for regulators which can report it.
+               for regulators which can report that control input value.
 
                The opmode value can be one of the following strings:
 
@@ -101,7 +139,8 @@ Description:
 
                NOTE: This value should not be used to determine the regulator
                output operating mode as this value is the same regardless of
-               whether the regulator is enabled or disabled.
+               whether the regulator is enabled or disabled.  A "status"
+               attribute may be available to determine the actual mode.
 
 
 What:          /sys/class/regulator/.../min_microvolts
diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4
new file mode 100644 (file)
index 0000000..4e79074
--- /dev/null
@@ -0,0 +1,81 @@
+What:          /sys/fs/ext4/<disk>/mb_stats
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+                Controls whether the multiblock allocator should
+                collect statistics, which are shown during the unmount.
+                1 means to collect statistics, 0 means not to collect
+                statistics
+
+What:          /sys/fs/ext4/<disk>/mb_group_prealloc
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               The multiblock allocator will round up allocation
+               requests to a multiple of this tuning parameter if the
+               stripe size is not set in the ext4 superblock
+
+What:          /sys/fs/ext4/<disk>/mb_max_to_scan
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               The maximum number of extents the multiblock allocator
+               will search to find the best extent
+
+What:          /sys/fs/ext4/<disk>/mb_min_to_scan
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               The minimum number of extents the multiblock allocator
+               will search to find the best extent
+
+What:          /sys/fs/ext4/<disk>/mb_order2_req
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               Tuning parameter which controls the minimum size for 
+               requests (as a power of 2) where the buddy cache is
+               used
+
+What:          /sys/fs/ext4/<disk>/mb_stream_req
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               Files which have fewer blocks than this tunable
+               parameter will have their blocks allocated out of a
+               block group specific preallocation pool, so that small
+               files are packed closely together.  Each large file
+                will have its blocks allocated out of its own unique
+                preallocation pool.
+
+What:          /sys/fs/ext4/<disk>/inode_readahead
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               Tuning parameter which controls the maximum number of
+               inode table blocks that ext4's inode table readahead
+               algorithm will pre-read into the buffer cache
+
+What:          /sys/fs/ext4/<disk>/delayed_allocation_blocks
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               This file is read-only and shows the number of blocks
+               that are dirty in the page cache, but which do not
+               have their location in the filesystem allocated yet.
+
+What:          /sys/fs/ext4/<disk>/lifetime_write_kbytes
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               This file is read-only and shows the number of kilobytes
+               of data that have been written to this filesystem since it was
+               created.
+
+What:          /sys/fs/ext4/<disk>/session_write_kbytes
+Date:          March 2008
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               This file is read-only and shows the number of
+               kilobytes of data that have been written to this
+               filesystem since it was mounted.
index c102c02ecf896059e410ff9f867b69cccd537fa5..c6def352fe39e667bd884e1e518872bc962aaf41 100644 (file)
@@ -4,3 +4,7 @@
 *.html
 *.9.gz
 *.9
+*.aux
+*.dvi
+*.log
+*.out
index bc962cda650485aea9cddcced9823ef39a3252b6..58c194572c763c8cfcba3e6c607f91220115e977 100644 (file)
@@ -199,6 +199,7 @@ X!Edrivers/pci/hotplug.c
 -->
 !Edrivers/pci/probe.c
 !Edrivers/pci/rom.c
+!Edrivers/pci/iov.c
      </sect1>
      <sect1><title>PCI Hotplug Support Library</title>
 !Edrivers/pci/hotplug/pci_hotplug_core.c
index 8c6396e4bf311901a19fd717500c422eeba4869a..a5b11793b1e0167bf32d1b1a19d13aca7a424aa5 100644 (file)
@@ -117,9 +117,6 @@ static int __init init_procfs_example(void)
                rv = -ENOMEM;
                goto out;
        }
-       
-       example_dir->owner = THIS_MODULE;
-       
        /* create jiffies using convenience function */
        jiffies_file = create_proc_read_entry("jiffies", 
                                              0444, example_dir, 
@@ -130,8 +127,6 @@ static int __init init_procfs_example(void)
                goto no_jiffies;
        }
 
-       jiffies_file->owner = THIS_MODULE;
-
        /* create foo and bar files using same callback
         * functions 
         */
@@ -146,7 +141,6 @@ static int __init init_procfs_example(void)
        foo_file->data = &foo_data;
        foo_file->read_proc = proc_read_foobar;
        foo_file->write_proc = proc_write_foobar;
-       foo_file->owner = THIS_MODULE;
                
        bar_file = create_proc_entry("bar", 0644, example_dir);
        if(bar_file == NULL) {
@@ -159,7 +153,6 @@ static int __init init_procfs_example(void)
        bar_file->data = &bar_data;
        bar_file->read_proc = proc_read_foobar;
        bar_file->write_proc = proc_write_foobar;
-       bar_file->owner = THIS_MODULE;
                
        /* create symlink */
        symlink = proc_symlink("jiffies_too", example_dir, 
@@ -169,8 +162,6 @@ static int __init init_procfs_example(void)
                goto no_symlink;
        }
 
-       symlink->owner = THIS_MODULE;
-
        /* everything OK */
        printk(KERN_INFO "%s %s initialised\n",
               MODULE_NAME, MODULE_VERS);
index 256defd7e1742be45497e1bcc8912d493241c5af..dcf7acc720e18bb68c572e38c6913863b5ead701 100644 (file)
        Revised Feb 12, 2004 by Martine Silbermann
                email: Martine.Silbermann@hp.com
        Revised Jun 25, 2004 by Tom L Nguyen
+       Revised Jul  9, 2008 by Matthew Wilcox <willy@linux.intel.com>
+               Copyright 2003, 2008 Intel Corporation
 
 1. About this guide
 
-This guide describes the basics of Message Signaled Interrupts (MSI),
-the advantages of using MSI over traditional interrupt mechanisms,
-and how to enable your driver to use MSI or MSI-X. Also included is
-a Frequently Asked Questions (FAQ) section.
-
-1.1 Terminology
-
-PCI devices can be single-function or multi-function.  In either case,
-when this text talks about enabling or disabling MSI on a "device
-function," it is referring to one specific PCI device and function and
-not to all functions on a PCI device (unless the PCI device has only
-one function).
-
-2. Copyright 2003 Intel Corporation
-
-3. What is MSI/MSI-X?
-
-Message Signaled Interrupt (MSI), as described in the PCI Local Bus
-Specification Revision 2.3 or later, is an optional feature, and a
-required feature for PCI Express devices. MSI enables a device function
-to request service by sending an Inbound Memory Write on its PCI bus to
-the FSB as a Message Signal Interrupt transaction. Because MSI is
-generated in the form of a Memory Write, all transaction conditions,
-such as a Retry, Master-Abort, Target-Abort or normal completion, are
-supported.
-
-A PCI device that supports MSI must also support pin IRQ assertion
-interrupt mechanism to provide backward compatibility for systems that
-do not support MSI. In systems which support MSI, the bus driver is
-responsible for initializing the message address and message data of
-the device function's MSI/MSI-X capability structure during device
-initial configuration.
-
-An MSI capable device function indicates MSI support by implementing
-the MSI/MSI-X capability structure in its PCI capability list. The
-device function may implement both the MSI capability structure and
-the MSI-X capability structure; however, the bus driver should not
-enable both.
-
-The MSI capability structure contains Message Control register,
-Message Address register and Message Data register. These registers
-provide the bus driver control over MSI. The Message Control register
-indicates the MSI capability supported by the device. The Message
-Address register specifies the target address and the Message Data
-register specifies the characteristics of the message. To request
-service, the device function writes the content of the Message Data
-register to the target address. The device and its software driver
-are prohibited from writing to these registers.
-
-The MSI-X capability structure is an optional extension to MSI. It
-uses an independent and separate capability structure. There are
-some key advantages to implementing the MSI-X capability structure
-over the MSI capability structure as described below.
-
-       - Support a larger maximum number of vectors per function.
-
-       - Provide the ability for system software to configure
-       each vector with an independent message address and message
-       data, specified by a table that resides in Memory Space.
-
-        - MSI and MSI-X both support per-vector masking. Per-vector
-       masking is an optional extension of MSI but a required
-       feature for MSI-X. Per-vector masking provides the kernel the
-       ability to mask/unmask a single MSI while running its
-       interrupt service routine. If per-vector masking is
-       not supported, then the device driver should provide the
-       hardware/software synchronization to ensure that the device
-       generates MSI when the driver wants it to do so.
-
-4. Why use MSI?
-
-As a benefit to the simplification of board design, MSI allows board
-designers to remove out-of-band interrupt routing. MSI is another
-step towards a legacy-free environment.
-
-Due to increasing pressure on chipset and processor packages to
-reduce pin count, the need for interrupt pins is expected to
-diminish over time. Devices, due to pin constraints, may implement
-messages to increase performance.
-
-PCI Express endpoints uses INTx emulation (in-band messages) instead
-of IRQ pin assertion. Using INTx emulation requires interrupt
-sharing among devices connected to the same node (PCI bridge) while
-MSI is unique (non-shared) and does not require BIOS configuration
-support. As a result, the PCI Express technology requires MSI
-support for better interrupt performance.
-
-Using MSI enables the device functions to support two or more
-vectors, which can be configured to target different CPUs to
-increase scalability.
-
-5. Configuring a driver to use MSI/MSI-X
-
-By default, the kernel will not enable MSI/MSI-X on all devices that
-support this capability. The CONFIG_PCI_MSI kernel option
-must be selected to enable MSI/MSI-X support.
-
-5.1 Including MSI/MSI-X support into the kernel
-
-To allow MSI/MSI-X capable device drivers to selectively enable
-MSI/MSI-X (using pci_enable_msi()/pci_enable_msix() as described
-below), the VECTOR based scheme needs to be enabled by setting
-CONFIG_PCI_MSI during kernel config.
-
-Since the target of the inbound message is the local APIC, providing
-CONFIG_X86_LOCAL_APIC must be enabled as well as CONFIG_PCI_MSI.
-
-5.2 Configuring for MSI support
-
-Due to the non-contiguous fashion in vector assignment of the
-existing Linux kernel, this version does not support multiple
-messages regardless of a device function is capable of supporting
-more than one vector. To enable MSI on a device function's MSI
-capability structure requires a device driver to call the function
-pci_enable_msi() explicitly.
-
-5.2.1 API pci_enable_msi
+This guide describes the basics of Message Signaled Interrupts (MSIs),
+the advantages of using MSI over traditional interrupt mechanisms, how
+to change your driver to use MSI or MSI-X and some basic diagnostics to
+try if a device doesn't support MSIs.
 
-int pci_enable_msi(struct pci_dev *dev)
 
-With this new API, a device driver that wants to have MSI
-enabled on its device function must call this API to enable MSI.
-A successful call will initialize the MSI capability structure
-with ONE vector, regardless of whether a device function is
-capable of supporting multiple messages. This vector replaces the
-pre-assigned dev->irq with a new MSI vector. To avoid a conflict
-of the new assigned vector with existing pre-assigned vector requires
-a device driver to call this API before calling request_irq().
+2. What are MSIs?
 
-5.2.2 API pci_disable_msi
+A Message Signaled Interrupt is a write from the device to a special
+address which causes an interrupt to be received by the CPU.
 
-void pci_disable_msi(struct pci_dev *dev)
+The MSI capability was first specified in PCI 2.2 and was later enhanced
+in PCI 3.0 to allow each interrupt to be masked individually.  The MSI-X
+capability was also introduced with PCI 3.0.  It supports more interrupts
+per device than MSI and allows interrupts to be independently configured.
 
-This API should always be used to undo the effect of pci_enable_msi()
-when a device driver is unloading. This API restores dev->irq with
-the pre-assigned IOAPIC vector and switches a device's interrupt
-mode to PCI pin-irq assertion/INTx emulation mode.
-
-Note that a device driver should always call free_irq() on the MSI vector
-that it has done request_irq() on before calling this API. Failure to do
-so results in a BUG_ON() and a device will be left with MSI enabled and
-leaks its vector.
-
-5.2.3 MSI mode vs. legacy mode diagram
-
-The below diagram shows the events which switch the interrupt
-mode on the MSI-capable device function between MSI mode and
-PIN-IRQ assertion mode.
-
-        ------------   pci_enable_msi   ------------------------
-       |            | <=============== |                        |
-       | MSI MODE   |                  | PIN-IRQ ASSERTION MODE |
-       |            | ===============> |                        |
-        ------------   pci_disable_msi  ------------------------
-
-
-Figure 1. MSI Mode vs. Legacy Mode
-
-In Figure 1, a device operates by default in legacy mode. Legacy
-in this context means PCI pin-irq assertion or PCI-Express INTx
-emulation. A successful MSI request (using pci_enable_msi()) switches
-a device's interrupt mode to MSI mode. A pre-assigned IOAPIC vector
-stored in dev->irq will be saved by the PCI subsystem and a new
-assigned MSI vector will replace dev->irq.
-
-To return back to its default mode, a device driver should always call
-pci_disable_msi() to undo the effect of pci_enable_msi(). Note that a
-device driver should always call free_irq() on the MSI vector it has
-done request_irq() on before calling pci_disable_msi(). Failure to do
-so results in a BUG_ON() and a device will be left with MSI enabled and
-leaks its vector. Otherwise, the PCI subsystem restores a device's
-dev->irq with a pre-assigned IOAPIC vector and marks the released
-MSI vector as unused.
-
-Once being marked as unused, there is no guarantee that the PCI
-subsystem will reserve this MSI vector for a device. Depending on
-the availability of current PCI vector resources and the number of
-MSI/MSI-X requests from other drivers, this MSI may be re-assigned.
-
-For the case where the PCI subsystem re-assigns this MSI vector to
-another driver, a request to switch back to MSI mode may result
-in being assigned a different MSI vector or a failure if no more
-vectors are available.
-
-5.3 Configuring for MSI-X support
-
-Due to the ability of the system software to configure each vector of
-the MSI-X capability structure with an independent message address
-and message data, the non-contiguous fashion in vector assignment of
-the existing Linux kernel has no impact on supporting multiple
-messages on an MSI-X capable device functions. To enable MSI-X on
-a device function's MSI-X capability structure requires its device
-driver to call the function pci_enable_msix() explicitly.
-
-The function pci_enable_msix(), once invoked, enables either
-all or nothing, depending on the current availability of PCI vector
-resources. If the PCI vector resources are available for the number
-of vectors requested by a device driver, this function will configure
-the MSI-X table of the MSI-X capability structure of a device with
-requested messages. To emphasize this reason, for example, a device
-may be capable for supporting the maximum of 32 vectors while its
-software driver usually may request 4 vectors. It is recommended
-that the device driver should call this function once during the
-initialization phase of the device driver.
-
-Unlike the function pci_enable_msi(), the function pci_enable_msix()
-does not replace the pre-assigned IOAPIC dev->irq with a new MSI
-vector because the PCI subsystem writes the 1:1 vector-to-entry mapping
-into the field vector of each element contained in a second argument.
-Note that the pre-assigned IOAPIC dev->irq is valid only if the device
-operates in PIN-IRQ assertion mode. In MSI-X mode, any attempt at
-using dev->irq by the device driver to request for interrupt service
-may result in unpredictable behavior.
-
-For each MSI-X vector granted, a device driver is responsible for calling
-other functions like request_irq(), enable_irq(), etc. to enable
-this vector with its corresponding interrupt service handler. It is
-a device driver's choice to assign all vectors with the same
-interrupt service handler or each vector with a unique interrupt
-service handler.
-
-5.3.1 Handling MMIO address space of MSI-X Table
-
-The PCI 3.0 specification has implementation notes that MMIO address
-space for a device's MSI-X structure should be isolated so that the
-software system can set different pages for controlling accesses to the
-MSI-X structure. The implementation of MSI support requires the PCI
-subsystem, not a device driver, to maintain full control of the MSI-X
-table/MSI-X PBA (Pending Bit Array) and MMIO address space of the MSI-X
-table/MSI-X PBA.  A device driver should not access the MMIO address
-space of the MSI-X table/MSI-X PBA.
-
-5.3.2 API pci_enable_msix
+Devices may support both MSI and MSI-X, but only one can be enabled at
+a time.
 
-int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
 
-This API enables a device driver to request the PCI subsystem
-to enable MSI-X messages on its hardware device. Depending on
-the availability of PCI vectors resources, the PCI subsystem enables
-either all or none of the requested vectors.
+3. Why use MSIs?
+
+There are three reasons why using MSIs can give an advantage over
+traditional pin-based interrupts.
+
+Pin-based PCI interrupts are often shared amongst several devices.
+To support this, the kernel must call each interrupt handler associated
+with an interrupt, which leads to reduced performance for the system as
+a whole.  MSIs are never shared, so this problem cannot arise.
+
+When a device writes data to memory, then raises a pin-based interrupt,
+it is possible that the interrupt may arrive before all the data has
+arrived in memory (this becomes more likely with devices behind PCI-PCI
+bridges).  In order to ensure that all the data has arrived in memory,
+the interrupt handler must read a register on the device which raised
+the interrupt.  PCI transaction ordering rules require that all the data
+arrives in memory before the value can be returned from the register.
+Using MSIs avoids this problem as the interrupt-generating write cannot
+pass the data writes, so by the time the interrupt is raised, the driver
+knows that all the data has arrived in memory.
+
+PCI devices can only support a single pin-based interrupt per function.
+Often drivers have to query the device to find out what event has
+occurred, slowing down interrupt handling for the common case.  With
+MSIs, a device can support more interrupts, allowing each interrupt
+to be specialised to a different purpose.  One possible design gives
+infrequent conditions (such as errors) their own interrupt which allows
+the driver to handle the normal interrupt handling path more efficiently.
+Other possible designs include giving one interrupt to each packet queue
+in a network card or each port in a storage controller.
+
+
+4. How to use MSIs
+
+PCI devices are initialised to use pin-based interrupts.  The device
+driver has to set up the device to use MSI or MSI-X.  Not all machines
+support MSIs correctly, and for those machines, the APIs described below
+will simply fail and the device will continue to use pin-based interrupts.
+
+4.1 Include kernel support for MSIs
+
+To support MSI or MSI-X, the kernel must be built with the CONFIG_PCI_MSI
+option enabled.  This option is only available on some architectures,
+and it may depend on some other options also being set.  For example,
+on x86, you must also enable X86_UP_APIC or SMP in order to see the
+CONFIG_PCI_MSI option.
+
+4.2 Using MSI
+
+Most of the hard work is done for the driver in the PCI layer.  It simply
+has to request that the PCI layer set up the MSI capability for this
+device.
+
+4.2.1 pci_enable_msi
+
+int pci_enable_msi(struct pci_dev *dev)
+
+A successful call will allocate ONE interrupt to the device, regardless
+of how many MSIs the device supports.  The device will be switched from
+pin-based interrupt mode to MSI mode.  The dev->irq number is changed
+to a new number which represents the message signaled interrupt.
+This function should be called before the driver calls request_irq()
+since enabling MSIs disables the pin-based IRQ and the driver will not
+receive interrupts on the old interrupt.
+
+4.2.2 pci_enable_msi_block
+
+int pci_enable_msi_block(struct pci_dev *dev, int count)
+
+This variation on the above call allows a device driver to request multiple
+MSIs.  The MSI specification only allows interrupts to be allocated in
+powers of two, up to a maximum of 2^5 (32).
+
+If this function returns 0, it has succeeded in allocating at least as many
+interrupts as the driver requested (it may have allocated more in order
+to satisfy the power-of-two requirement).  In this case, the function
+enables MSI on this device and updates dev->irq to be the lowest of
+the new interrupts assigned to it.  The other interrupts assigned to
+the device are in the range dev->irq to dev->irq + count - 1.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.  If this function returns a positive number, it will be
+less than 'count' and indicate the number of interrupts that could have
+been allocated.  In neither case will the irq value have been
+updated, nor will the device have been switched into MSI mode.
+
+The device driver must decide what action to take if
+pci_enable_msi_block() returns a value less than the number asked for.
+Some devices can make use of fewer interrupts than the maximum they
+request; in this case the driver should call pci_enable_msi_block()
+again.  Note that it is not guaranteed to succeed, even when the
+'count' has been reduced to the value returned from a previous call to
+pci_enable_msi_block().  This is because there are multiple constraints
+on the number of vectors that can be allocated; pci_enable_msi_block()
+will return as soon as it finds any constraint that doesn't allow the
+call to succeed.
+
+4.2.3 pci_disable_msi
+
+void pci_disable_msi(struct pci_dev *dev)
 
-Argument 'dev' points to the device (pci_dev) structure.
+This function should be used to undo the effect of pci_enable_msi() or
+pci_enable_msi_block().  Calling it restores dev->irq to the pin-based
+interrupt number and frees the previously allocated message signaled
+interrupt(s).  The interrupt may subsequently be assigned to another
+device, so drivers should not cache the value of dev->irq.
 
-Argument 'entries' is a pointer to an array of msix_entry structs.
-The number of entries is indicated in argument 'nvec'.
-struct msix_entry is defined in /driver/pci/msi.h:
+A device driver must always call free_irq() on the interrupt(s)
+for which it has called request_irq() before calling this function.
+Failure to do so will result in a BUG_ON(), the device will be left with
+MSI enabled and will leak its vector.
+
+4.3 Using MSI-X
+
+The MSI-X capability is much more flexible than the MSI capability.
+It supports up to 2048 interrupts, each of which can be controlled
+independently.  To support this flexibility, drivers must use an array of
+`struct msix_entry':
 
 struct msix_entry {
        u16     vector; /* kernel uses to write alloc vector */
        u16     entry; /* driver uses to specify entry */
 };
 
-A device driver is responsible for initializing the field 'entry' of
-each element with a unique entry supported by MSI-X table. Otherwise,
--EINVAL will be returned as a result. A successful return of zero
-indicates the PCI subsystem completed initializing each of the requested
-entries of the MSI-X table with message address and message data.
-Last but not least, the PCI subsystem will write the 1:1
-vector-to-entry mapping into the field 'vector' of each element. A
-device driver is responsible for keeping track of allocated MSI-X
-vectors in its internal data structure.
-
-A return of zero indicates that the number of MSI-X vectors was
-successfully allocated. A return of greater than zero indicates
-MSI-X vector shortage. Or a return of less than zero indicates
-a failure. This failure may be a result of duplicate entries
-specified in second argument, or a result of no available vector,
-or a result of failing to initialize MSI-X table entries.
-
-5.3.3 API pci_disable_msix
+This allows for the device to use these interrupts in a sparse fashion;
+for example it could use interrupts 3 and 1027 and allocate only a
+two-element array.  The driver is expected to fill in the 'entry' value
+in each element of the array to indicate which entries it wants the kernel
+to assign interrupts for.  It is invalid to fill in two entries with the
+same number.
+
+4.3.1 pci_enable_msix
+
+int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
+
+Calling this function asks the PCI subsystem to allocate 'nvec' MSIs.
+The 'entries' argument is a pointer to an array of msix_entry structs
+which should be at least 'nvec' entries in size.  On success, the
+function will return 0 and the device will have been switched into
+MSI-X interrupt mode.  The 'vector' elements in each entry will have
+been filled in with the interrupt number.  The driver should then call
+request_irq() for each 'vector' that it decides to use.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to allocate any more MSI-X interrupts for
+this device.  If it returns a positive number, it indicates the maximum
+number of interrupt vectors that could have been allocated. See example
+below.
+
+This function, in contrast with pci_enable_msi(), does not adjust
+dev->irq.  The device will not generate interrupts for this interrupt
+number once MSI-X is enabled.  The device driver is responsible for
+keeping track of the interrupts assigned to the MSI-X vectors so it can
+free them again later.
+
+Device drivers should normally call this function once per device
+during the initialization phase.
+
+It is ideal if drivers can cope with a variable number of MSI-X interrupts,
+there are many reasons why the platform may not be able to provide the
+exact number a driver asks for.
+
+A request loop to achieve that might look like:
+
+static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
+{
+       while (nvec >= FOO_DRIVER_MINIMUM_NVEC) {
+               rc = pci_enable_msix(adapter->pdev,
+                                    adapter->msix_entries, nvec);
+               if (rc > 0)
+                       nvec = rc;
+               else
+                       return rc;
+       }
+
+       return -ENOSPC;
+}
+
+4.3.2 pci_disable_msix
 
 void pci_disable_msix(struct pci_dev *dev)
 
-This API should always be used to undo the effect of pci_enable_msix()
-when a device driver is unloading. Note that a device driver should
-always call free_irq() on all MSI-X vectors it has done request_irq()
-on before calling this API. Failure to do so results in a BUG_ON() and
-a device will be left with MSI-X enabled and leaks its vectors.
-
-5.3.4 MSI-X mode vs. legacy mode diagram
-
-The below diagram shows the events which switch the interrupt
-mode on the MSI-X capable device function between MSI-X mode and
-PIN-IRQ assertion mode (legacy).
-
-        ------------   pci_enable_msix(,,n) ------------------------
-       |            | <===============     |                        |
-       | MSI-X MODE |                      | PIN-IRQ ASSERTION MODE |
-       |            | ===============>     |                        |
-        ------------   pci_disable_msix     ------------------------
-
-Figure 2. MSI-X Mode vs. Legacy Mode
-
-In Figure 2, a device operates by default in legacy mode. A
-successful MSI-X request (using pci_enable_msix()) switches a
-device's interrupt mode to MSI-X mode. A pre-assigned IOAPIC vector
-stored in dev->irq will be saved by the PCI subsystem; however,
-unlike MSI mode, the PCI subsystem will not replace dev->irq with
-assigned MSI-X vector because the PCI subsystem already writes the 1:1
-vector-to-entry mapping into the field 'vector' of each element
-specified in second argument.
-
-To return back to its default mode, a device driver should always call
-pci_disable_msix() to undo the effect of pci_enable_msix(). Note that
-a device driver should always call free_irq() on all MSI-X vectors it
-has done request_irq() on before calling pci_disable_msix(). Failure
-to do so results in a BUG_ON() and a device will be left with MSI-X
-enabled and leaks its vectors. Otherwise, the PCI subsystem switches a
-device function's interrupt mode from MSI-X mode to legacy mode and
-marks all allocated MSI-X vectors as unused.
-
-Once being marked as unused, there is no guarantee that the PCI
-subsystem will reserve these MSI-X vectors for a device. Depending on
-the availability of current PCI vector resources and the number of
-MSI/MSI-X requests from other drivers, these MSI-X vectors may be
-re-assigned.
-
-For the case where the PCI subsystem re-assigned these MSI-X vectors
-to other drivers, a request to switch back to MSI-X mode may result
-being assigned with another set of MSI-X vectors or a failure if no
-more vectors are available.
-
-5.4 Handling function implementing both MSI and MSI-X capabilities
-
-For the case where a function implements both MSI and MSI-X
-capabilities, the PCI subsystem enables a device to run either in MSI
-mode or MSI-X mode but not both. A device driver determines whether it
-wants MSI or MSI-X enabled on its hardware device. Once a device
-driver requests for MSI, for example, it is prohibited from requesting
-MSI-X; in other words, a device driver is not permitted to ping-pong
-between MSI mod MSI-X mode during a run-time.
-
-5.5 Hardware requirements for MSI/MSI-X support
-
-MSI/MSI-X support requires support from both system hardware and
-individual hardware device functions.
-
-5.5.1 Required x86 hardware support
-
-Since the target of MSI address is the local APIC CPU, enabling
-MSI/MSI-X support in the Linux kernel is dependent on whether existing
-system hardware supports local APIC. Users should verify that their
-system supports local APIC operation by testing that it runs when
-CONFIG_X86_LOCAL_APIC=y.
-
-In SMP environment, CONFIG_X86_LOCAL_APIC is automatically set;
-however, in UP environment, users must manually set
-CONFIG_X86_LOCAL_APIC. Once CONFIG_X86_LOCAL_APIC=y, setting
-CONFIG_PCI_MSI enables the VECTOR based scheme and the option for
-MSI-capable device drivers to selectively enable MSI/MSI-X.
-
-Note that CONFIG_X86_IO_APIC setting is irrelevant because MSI/MSI-X
-vector is allocated new during runtime and MSI/MSI-X support does not
-depend on BIOS support. This key independency enables MSI/MSI-X
-support on future IOxAPIC free platforms.
-
-5.5.2 Device hardware support
-
-The hardware device function supports MSI by indicating the
-MSI/MSI-X capability structure on its PCI capability list. By
-default, this capability structure will not be initialized by
-the kernel to enable MSI during the system boot. In other words,
-the device function is running on its default pin assertion mode.
-Note that in many cases the hardware supporting MSI have bugs,
-which may result in system hangs. The software driver of specific
-MSI-capable hardware is responsible for deciding whether to call
-pci_enable_msi or not. A return of zero indicates the kernel
-successfully initialized the MSI/MSI-X capability structure of the
-device function. The device function is now running on MSI/MSI-X mode.
-
-5.6 How to tell whether MSI/MSI-X is enabled on device function
-
-At the driver level, a return of zero from the function call of
-pci_enable_msi()/pci_enable_msix() indicates to a device driver that
-its device function is initialized successfully and ready to run in
-MSI/MSI-X mode.
-
-At the user level, users can use the command 'cat /proc/interrupts'
-to display the vectors allocated for devices and their interrupt
-MSI/MSI-X modes ("PCI-MSI"/"PCI-MSI-X"). Below shows MSI mode is
-enabled on a SCSI Adaptec 39320D Ultra320 controller.
-
-           CPU0       CPU1
-  0:     324639          0    IO-APIC-edge  timer
-  1:       1186          0    IO-APIC-edge  i8042
-  2:          0          0          XT-PIC  cascade
- 12:       2797          0    IO-APIC-edge  i8042
- 14:       6543          0    IO-APIC-edge  ide0
- 15:          1          0    IO-APIC-edge  ide1
-169:          0          0   IO-APIC-level  uhci-hcd
-185:          0          0   IO-APIC-level  uhci-hcd
-193:        138         10         PCI-MSI  aic79xx
-201:         30          0         PCI-MSI  aic79xx
-225:         30          0   IO-APIC-level  aic7xxx
-233:         30          0   IO-APIC-level  aic7xxx
-NMI:          0          0
-LOC:     324553     325068
-ERR:          0
-MIS:          0
-
-6. MSI quirks
-
-Several PCI chipsets or devices are known to not support MSI.
-The PCI stack provides 3 possible levels of MSI disabling:
-* on a single device
-* on all devices behind a specific bridge
-* globally
-
-6.1. Disabling MSI on a single device
-
-Under some circumstances it might be required to disable MSI on a
-single device.  This may be achieved by either not calling pci_enable_msi()
-or all, or setting the pci_dev->no_msi flag before (most of the time
-in a quirk).
-
-6.2. Disabling MSI below a bridge
-
-The vast majority of MSI quirks are required by PCI bridges not
-being able to route MSI between busses. In this case, MSI have to be
-disabled on all devices behind this bridge. It is achieves by setting
-the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge
-subordinate bus. There is no need to set the same flag on bridges that
-are below the broken bridge. When pci_enable_msi() is called to enable
-MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
-flag in all parent busses of the device.
-
-Some bridges actually support dynamic MSI support enabling/disabling
-by changing some bits in their PCI configuration space (especially
-the Hypertransport chipsets such as the nVidia nForce and Serverworks
-HT2000). It may then be required to update the NO_MSI flag on the
-corresponding devices in the sysfs hierarchy. To enable MSI support
-on device "0000:00:0e", do:
-
-       echo 1 > /sys/bus/pci/devices/0000:00:0e/msi_bus
-
-To disable MSI support, echo 0 instead of 1. Note that it should be
-used with caution since changing this value might break interrupts.
-
-6.3. Disabling MSI globally
-
-Some extreme cases may require to disable MSI globally on the system.
-For now, the only known case is a Serverworks PCI-X chipsets (MSI are
-not supported on several busses that are not all connected to the
-chipset in the Linux PCI hierarchy). In the vast majority of other
-cases, disabling only behind a specific bridge is enough.
-
-For debugging purpose, the user may also pass pci=nomsi on the kernel
-command-line to explicitly disable MSI globally. But, once the appro-
-priate quirks are added to the kernel, this option should not be
-required anymore.
-
-6.4. Finding why MSI cannot be enabled on a device
-
-Assuming that MSI are not enabled on a device, you should look at
-dmesg to find messages that quirks may output when disabling MSI
-on some devices, some bridges or even globally.
-Then, lspci -t gives the list of bridges above a device. Reading
-/sys/bus/pci/devices/0000:00:0e/msi_bus will tell you whether MSI
-are enabled (1) or disabled (0). In 0 is found in a single bridge
-msi_bus file above the device, MSI cannot be enabled.
-
-7. FAQ
-
-Q1. Are there any limitations on using the MSI?
-
-A1. If the PCI device supports MSI and conforms to the
-specification and the platform supports the APIC local bus,
-then using MSI should work.
-
-Q2. Will it work on all the Pentium processors (P3, P4, Xeon,
-AMD processors)? In P3 IPI's are transmitted on the APIC local
-bus and in P4 and Xeon they are transmitted on the system
-bus. Are there any implications with this?
-
-A2. MSI support enables a PCI device sending an inbound
-memory write (0xfeexxxxx as target address) on its PCI bus
-directly to the FSB. Since the message address has a
-redirection hint bit cleared, it should work.
-
-Q3. The target address 0xfeexxxxx will be translated by the
-Host Bridge into an interrupt message. Are there any
-limitations on the chipsets such as Intel 8xx, Intel e7xxx,
-or VIA?
-
-A3. If these chipsets support an inbound memory write with
-target address set as 0xfeexxxxx, as conformed to PCI
-specification 2.3 or latest, then it should work.
-
-Q4. From the driver point of view, if the MSI is lost because
-of errors occurring during inbound memory write, then it may
-wait forever. Is there a mechanism for it to recover?
-
-A4. Since the target of the transaction is an inbound memory
-write, all transaction termination conditions (Retry,
-Master-Abort, Target-Abort, or normal completion) are
-supported. A device sending an MSI must abide by all the PCI
-rules and conditions regarding that inbound memory write. So,
-if a retry is signaled it must retry, etc... We believe that
-the recommendation for Abort is also a retry (refer to PCI
-specification 2.3 or latest).
+This API should be used to undo the effect of pci_enable_msix().  It frees
+the previously allocated message signaled interrupts.  The interrupts may
+subsequently be assigned to another device, so drivers should not cache
+the value of the 'vector' elements over a call to pci_disable_msix().
+
+A device driver must always call free_irq() on the interrupt(s)
+for which it has called request_irq() before calling this function.
+Failure to do so will result in a BUG_ON(), the device will be left with
+MSI enabled and will leak its vector.
+
+4.3.3 The MSI-X Table
+
+The MSI-X capability specifies a BAR and offset within that BAR for the
+MSI-X Table.  This address is mapped by the PCI subsystem, and should not
+be accessed directly by the device driver.  If the driver wishes to
+mask or unmask an interrupt, it should call disable_irq() / enable_irq().
+
+4.4 Handling devices implementing both MSI and MSI-X capabilities
+
+If a device implements both MSI and MSI-X capabilities, it can
+run in either MSI mode or MSI-X mode but not both simultaneously.
+This is a requirement of the PCI spec, and it is enforced by the
+PCI layer.  Calling pci_enable_msi() when MSI-X is already enabled or
+pci_enable_msix() when MSI is already enabled will result in an error.
+If a device driver wishes to switch between MSI and MSI-X at runtime,
+it must first quiesce the device, then switch it back to pin-interrupt
+mode, before calling pci_enable_msi() or pci_enable_msix() and resuming
+operation.  This is not expected to be a common operation but may be
+useful for debugging or testing during development.
+
+4.5 Considerations when using MSIs
+
+4.5.1 Choosing between MSI-X and MSI
+
+If your device supports both MSI-X and MSI capabilities, you should use
+the MSI-X facilities in preference to the MSI facilities.  As mentioned
+above, MSI-X supports any number of interrupts between 1 and 2048.
+In constrast, MSI is restricted to a maximum of 32 interrupts (and
+must be a power of two).  In addition, the MSI interrupt vectors must
+be allocated consecutively, so the system may not be able to allocate
+as many vectors for MSI as it could for MSI-X.  On some platforms, MSI
+interrupts must all be targetted at the same set of CPUs whereas MSI-X
+interrupts can all be targetted at different CPUs.
+
+4.5.2 Spinlocks
+
+Most device drivers have a per-device spinlock which is taken in the
+interrupt handler.  With pin-based interrupts or a single MSI, it is not
+necessary to disable interrupts (Linux guarantees the same interrupt will
+not be re-entered).  If a device uses multiple interrupts, the driver
+must disable interrupts while the lock is held.  If the device sends
+a different interrupt, the driver will deadlock trying to recursively
+acquire the spinlock.
+
+There are two solutions.  The first is to take the lock with
+spin_lock_irqsave() or spin_lock_irq() (see
+Documentation/DocBook/kernel-locking).  The second is to specify
+IRQF_DISABLED to request_irq() so that the kernel runs the entire
+interrupt routine with interrupts disabled.
+
+If your MSI interrupt routine does not hold the lock for the whole time
+it is running, the first solution may be best.  The second solution is
+normally preferred as it avoids making two transitions from interrupt
+disabled to enabled and back again.
+
+4.6 How to tell whether MSI/MSI-X is enabled on a device
+
+Using 'lspci -v' (as root) may show some devices with "MSI", "Message
+Signalled Interrupts" or "MSI-X" capabilities.  Each of these capabilities
+has an 'Enable' flag which will be followed with either "+" (enabled)
+or "-" (disabled).
+
+
+5. MSI quirks
+
+Several PCI chipsets or devices are known not to support MSIs.
+The PCI stack provides three ways to disable MSIs:
+
+1. globally
+2. on all devices behind a specific bridge
+3. on a single device
+
+5.1. Disabling MSIs globally
+
+Some host chipsets simply don't support MSIs properly.  If we're
+lucky, the manufacturer knows this and has indicated it in the ACPI
+FADT table.  In this case, Linux will automatically disable MSIs.
+Some boards don't include this information in the table and so we have
+to detect them ourselves.  The complete list of these is found near the
+quirk_disable_all_msi() function in drivers/pci/quirks.c.
+
+If you have a board which has problems with MSIs, you can pass pci=nomsi
+on the kernel command line to disable MSIs on all devices.  It would be
+in your best interests to report the problem to linux-pci@vger.kernel.org
+including a full 'lspci -v' so we can add the quirks to the kernel.
+
+5.2. Disabling MSIs below a bridge
+
+Some PCI bridges are not able to route MSIs between busses properly.
+In this case, MSIs must be disabled on all devices behind the bridge.
+
+Some bridges allow you to enable MSIs by changing some bits in their
+PCI configuration space (especially the Hypertransport chipsets such
+as the nVidia nForce and Serverworks HT2000).  As with host chipsets,
+Linux mostly knows about them and automatically enables MSIs if it can.
+If you have a bridge which Linux doesn't yet know about, you can enable
+MSIs in configuration space using whatever method you know works, then
+enable MSIs on that bridge by doing:
+
+       echo 1 > /sys/bus/pci/devices/$bridge/msi_bus
+
+where $bridge is the PCI address of the bridge you've enabled (eg
+0000:00:0e.0).
+
+To disable MSIs, echo 0 instead of 1.  Changing this value should be
+done with caution as it can break interrupt handling for all devices
+below this bridge.
+
+Again, please notify linux-pci@vger.kernel.org of any bridges that need
+special handling.
+
+5.3. Disabling MSIs on a single device
+
+Some devices are known to have faulty MSI implementations.  Usually this
+is handled in the individual device driver but occasionally it's necessary
+to handle this with a quirk.  Some drivers have an option to disable use
+of MSI.  While this is a convenient workaround for the driver author,
+it is not good practise, and should not be emulated.
+
+5.4. Finding why MSIs are disabled on a device
+
+From the above three sections, you can see that there are many reasons
+why MSIs may not be enabled for a given device.  Your first step should
+be to examine your dmesg carefully to determine whether MSIs are enabled
+for your machine.  You should also check your .config to be sure you
+have enabled CONFIG_PCI_MSI.
+
+Then, 'lspci -t' gives the list of bridges above a device.  Reading
+/sys/bus/pci/devices/*/msi_bus will tell you whether MSI are enabled (1)
+or disabled (0).  If 0 is found in any of the msi_bus files belonging
+to bridges between the PCI root and the device, MSIs are disabled.
+
+It is also worth checking the device driver to see whether it supports MSIs.
+For example, it may contain calls to pci_enable_msi(), pci_enable_msix() or
+pci_enable_msi_block().
diff --git a/Documentation/PCI/pci-iov-howto.txt b/Documentation/PCI/pci-iov-howto.txt
new file mode 100644 (file)
index 0000000..fc73ef5
--- /dev/null
@@ -0,0 +1,99 @@
+               PCI Express I/O Virtualization Howto
+               Copyright (C) 2009 Intel Corporation
+                   Yu Zhao <yu.zhao@intel.com>
+
+
+1. Overview
+
+1.1 What is SR-IOV
+
+Single Root I/O Virtualization (SR-IOV) is a PCI Express Extended
+capability which makes one physical device appear as multiple virtual
+devices. The physical device is referred to as Physical Function (PF)
+while the virtual devices are referred to as Virtual Functions (VF).
+Allocation of the VF can be dynamically controlled by the PF via
+registers encapsulated in the capability. By default, this feature is
+not enabled and the PF behaves as traditional PCIe device. Once it's
+turned on, each VF's PCI configuration space can be accessed by its own
+Bus, Device and Function Number (Routing ID). And each VF also has PCI
+Memory Space, which is used to map its register set. VF device driver
+operates on the register set so it can be functional and appear as a
+real existing PCI device.
+
+2. User Guide
+
+2.1 How can I enable SR-IOV capability
+
+The device driver (PF driver) will control the enabling and disabling
+of the capability via API provided by SR-IOV core. If the hardware
+has SR-IOV capability, loading its PF driver would enable it and all
+VFs associated with the PF.
+
+2.2 How can I use the Virtual Functions
+
+The VF is treated as hot-plugged PCI devices in the kernel, so they
+should be able to work in the same way as real PCI devices. The VF
+requires device driver that is same as a normal PCI device's.
+
+3. Developer Guide
+
+3.1 SR-IOV API
+
+To enable SR-IOV capability:
+       int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+       'nr_virtfn' is number of VFs to be enabled.
+
+To disable SR-IOV capability:
+       void pci_disable_sriov(struct pci_dev *dev);
+
+To notify SR-IOV core of Virtual Function Migration:
+       irqreturn_t pci_sriov_migration(struct pci_dev *dev);
+
+3.2 Usage example
+
+Following piece of code illustrates the usage of the SR-IOV API.
+
+static int __devinit dev_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       pci_enable_sriov(dev, NR_VIRTFN);
+
+       ...
+
+       return 0;
+}
+
+static void __devexit dev_remove(struct pci_dev *dev)
+{
+       pci_disable_sriov(dev);
+
+       ...
+}
+
+static int dev_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       ...
+
+       return 0;
+}
+
+static int dev_resume(struct pci_dev *dev)
+{
+       ...
+
+       return 0;
+}
+
+static void dev_shutdown(struct pci_dev *dev)
+{
+       ...
+}
+
+static struct pci_driver dev_driver = {
+       .name =         "SR-IOV Physical Function driver",
+       .id_table =     dev_id_table,
+       .probe =        dev_probe,
+       .remove =       __devexit_p(dev_remove),
+       .suspend =      dev_suspend,
+       .resume =       dev_resume,
+       .shutdown =     dev_shutdown,
+};
index 1fd175368a875107892f72f412a980e9a93f7d77..4349c1487e919ce0e49702313229027a18bc7245 100644 (file)
@@ -118,7 +118,7 @@ Following are the RCU equivalents for these two functions:
                list_for_each_entry(e, list, list) {
                        if (!audit_compare_rule(rule, &e->rule)) {
                                list_del_rcu(&e->list);
-                               call_rcu(&e->rcu, audit_free_rule, e);
+                               call_rcu(&e->rcu, audit_free_rule);
                                return 0;
                        }
                }
@@ -206,7 +206,7 @@ RCU ("read-copy update") its name.  The RCU code is as follows:
                                ne->rule.action = newaction;
                                ne->rule.file_count = newfield_count;
                                list_replace_rcu(e, ne);
-                               call_rcu(&e->rcu, audit_free_rule, e);
+                               call_rcu(&e->rcu, audit_free_rule);
                                return 0;
                        }
                }
@@ -283,7 +283,7 @@ flag under the spinlock as follows:
                                list_del_rcu(&e->list);
                                e->deleted = 1;
                                spin_unlock(&e->lock);
-                               call_rcu(&e->rcu, audit_free_rule, e);
+                               call_rcu(&e->rcu, audit_free_rule);
                                return 0;
                        }
                }
index 95821a29ae418b6b275b01869fd40e29900baadf..7aa2002ade7780515de469435ab5bfc65d2f3176 100644 (file)
@@ -81,7 +81,7 @@ o     I hear that RCU needs work in order to support realtime kernels?
        This work is largely completed.  Realtime-friendly RCU can be
        enabled via the CONFIG_PREEMPT_RCU kernel configuration parameter.
        However, work is in progress for enabling priority boosting of
-       preempted RCU read-side critical sections.This is needed if you
+       preempted RCU read-side critical sections.  This is needed if you
        have CPU-bound realtime threads.
 
 o      Where can I find more information on RCU?
index 239f542d48baa9425f29a54b6b43f00468d986c2..6389dec33459e84228ef43a00f9d80be158bab5d 100644 (file)
@@ -21,7 +21,7 @@ if (obj) {
   /*
    * Because a writer could delete object, and a writer could
    * reuse these object before the RCU grace period, we
-   * must check key after geting the reference on object
+   * must check key after getting the reference on object
    */
   if (obj->key != key) { // not the object we expected
      put_ref(obj);
@@ -117,7 +117,7 @@ a race (some writer did a delete and/or a move of an object
 to another chain) checking the final 'nulls' value if
 the lookup met the end of chain. If final 'nulls' value
 is not the slot number, then we must restart the lookup at
-the begining. If the object was moved to same chain,
+the beginning. If the object was moved to the same chain,
 then the reader doesnt care : It might eventually
 scan the list again without harm.
 
diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX
new file mode 100644 (file)
index 0000000..3f58fa3
--- /dev/null
@@ -0,0 +1,18 @@
+00-INDEX
+       - this file
+cgroups.txt
+       - Control Groups definition, implementation details, examples and API.
+cpuacct.txt
+       - CPU Accounting Controller; account CPU usage for groups of tasks.
+cpusets.txt
+       - documents the cpusets feature; assign CPUs and Mem to a set of tasks.
+devices.txt
+       - Device Whitelist Controller; description, interface and security.
+freezer-subsystem.txt
+       - checkpointing; rationale to not use signals, interface.
+memcg_test.txt
+       - Memory Resource Controller; implementation details.
+memory.txt
+       - Memory Resource Controller; design, accounting, interface, testing.
+resource_counter.txt
+       - Resource Counter API.
index 93feb8444489686b1a9874da9c964f388d5ed316..6eb1a97e88ce887c9628843aa664d55aca59071d 100644 (file)
@@ -56,7 +56,7 @@ hierarchy, and a set of subsystems; each subsystem has system-specific
 state attached to each cgroup in the hierarchy.  Each hierarchy has
 an instance of the cgroup virtual filesystem associated with it.
 
-At any one time there may be multiple active hierachies of task
+At any one time there may be multiple active hierarchies of task
 cgroups. Each hierarchy is a partition of all tasks in the system.
 
 User level code may create and destroy cgroups by name in an
@@ -124,10 +124,10 @@ following lines:
                                / \
                        Prof (15%) students (5%)
 
-Browsers like firefox/lynx go into the WWW network class, while (k)nfsd go
+Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd go
 into NFS network class.
 
-At the same time firefox/lynx will share an appropriate CPU/Memory class
+At the same time Firefox/Lynx will share an appropriate CPU/Memory class
 depending on who launched it (prof/student).
 
 With the ability to classify tasks differently for different resources
@@ -325,7 +325,7 @@ and then start a subshell 'sh' in that cgroup:
 Creating, modifying, using the cgroups can be done through the cgroup
 virtual filesystem.
 
-To mount a cgroup hierarchy will all available subsystems, type:
+To mount a cgroup hierarchy with all available subsystems, type:
 # mount -t cgroup xxx /dev/cgroup
 
 The "xxx" is not interpreted by the cgroup code, but will appear in
@@ -333,12 +333,23 @@ The "xxx" is not interpreted by the cgroup code, but will appear in
 
 To mount a cgroup hierarchy with just the cpuset and numtasks
 subsystems, type:
-# mount -t cgroup -o cpuset,numtasks hier1 /dev/cgroup
+# mount -t cgroup -o cpuset,memory hier1 /dev/cgroup
 
 To change the set of subsystems bound to a mounted hierarchy, just
 remount with different options:
+# mount -o remount,cpuset,ns hier1 /dev/cgroup
 
-# mount -o remount,cpuset,ns  /dev/cgroup
+Now memory is removed from the hierarchy and ns is added.
+
+Note this will add ns to the hierarchy but won't remove memory or
+cpuset, because the new options are appended to the old ones:
+# mount -o remount,ns /dev/cgroup
+
+To Specify a hierarchy's release_agent:
+# mount -t cgroup -o cpuset,release_agent="/sbin/cpuset_release_agent" \
+  xxx /dev/cgroup
+
+Note that specifying 'release_agent' more than once will return failure.
 
 Note that changing the set of subsystems is currently only supported
 when the hierarchy consists of a single (root) cgroup. Supporting
@@ -349,6 +360,11 @@ Then under /dev/cgroup you can find a tree that corresponds to the
 tree of the cgroups in the system. For instance, /dev/cgroup
 is the cgroup that holds the whole system.
 
+If you want to change the value of release_agent:
+# echo "/sbin/new_release_agent" > /dev/cgroup/release_agent
+
+It can also be changed via remount.
+
 If you want to create a new cgroup under /dev/cgroup:
 # cd /dev/cgroup
 # mkdir my_cgroup
@@ -476,11 +492,13 @@ cgroup->parent is still valid. (Note - can also be called for a
 newly-created cgroup if an error occurs after this subsystem's
 create() method has been called for the new cgroup).
 
-void pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
+int pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
 
 Called before checking the reference count on each subsystem. This may
 be useful for subsystems which have some extra references even if
-there are not tasks in the cgroup.
+there are not tasks in the cgroup. If pre_destroy() returns error code,
+rmdir() will fail with it. From this behavior, pre_destroy() can be
+called multiple times against a cgroup.
 
 int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
               struct task_struct *task)
@@ -521,7 +539,7 @@ always handled well.
 void post_clone(struct cgroup_subsys *ss, struct cgroup *cgrp)
 (cgroup_mutex held by caller)
 
-Called at the end of cgroup_clone() to do any paramater
+Called at the end of cgroup_clone() to do any parameter
 initialization which might be required before a task could attach.  For
 example in cpusets, no task may attach before 'cpus' and 'mems' are set
 up.
index 0611e9528c7c236c3dbdeb3038e762664614dec5..f9ca389dddf49a7f1bc80c7e724b4a2ffa7e1ba4 100644 (file)
@@ -131,7 +131,7 @@ Cpusets extends these two mechanisms as follows:
  - The hierarchy of cpusets can be mounted at /dev/cpuset, for
    browsing and manipulation from user space.
  - A cpuset may be marked exclusive, which ensures that no other
-   cpuset (except direct ancestors and descendents) may contain
+   cpuset (except direct ancestors and descendants) may contain
    any overlapping CPUs or Memory Nodes.
  - You can list all the tasks (by pid) attached to any cpuset.
 
@@ -226,7 +226,7 @@ nodes with memory--using the cpuset_track_online_nodes() hook.
 --------------------------------
 
 If a cpuset is cpu or mem exclusive, no other cpuset, other than
-a direct ancestor or descendent, may share any of the same CPUs or
+a direct ancestor or descendant, may share any of the same CPUs or
 Memory Nodes.
 
 A cpuset that is mem_exclusive *or* mem_hardwall is "hardwalled",
@@ -427,7 +427,7 @@ child cpusets have this flag enabled.
 When doing this, you don't usually want to leave any unpinned tasks in
 the top cpuset that might use non-trivial amounts of CPU, as such tasks
 may be artificially constrained to some subset of CPUs, depending on
-the particulars of this flag setting in descendent cpusets.  Even if
+the particulars of this flag setting in descendant cpusets.  Even if
 such a task could use spare CPU cycles in some other CPUs, the kernel
 scheduler might not consider the possibility of load balancing that
 task to that underused CPU.
@@ -531,9 +531,9 @@ be idle.
 
 Of course it takes some searching cost to find movable tasks and/or
 idle CPUs, the scheduler might not search all CPUs in the domain
-everytime.  In fact, in some architectures, the searching ranges on
+every time.  In fact, in some architectures, the searching ranges on
 events are limited in the same socket or node where the CPU locates,
-while the load balance on tick searchs all.
+while the load balance on tick searches all.
 
 For example, assume CPU Z is relatively far from CPU X.  Even if CPU Z
 is idle while CPU X and the siblings are busy, scheduler can't migrate
@@ -601,7 +601,7 @@ its new cpuset, then the task will continue to use whatever subset
 of MPOL_BIND nodes are still allowed in the new cpuset.  If the task
 was using MPOL_BIND and now none of its MPOL_BIND nodes are allowed
 in the new cpuset, then the task will be essentially treated as if it
-was MPOL_BIND bound to the new cpuset (even though its numa placement,
+was MPOL_BIND bound to the new cpuset (even though its NUMA placement,
 as queried by get_mempolicy(), doesn't change).  If a task is moved
 from one cpuset to another, then the kernel will adjust the tasks
 memory placement, as above, the next time that the kernel attempts
index 7cc6e6a60672c9e247d63a313d279a3a1739e3e2..57ca4c89fe5c089aa6d8b9050fa5b2597e4f62b3 100644 (file)
@@ -42,7 +42,7 @@ suffice, but we can decide the best way to adequately restrict
 movement as people get some experience with this.  We may just want
 to require CAP_SYS_ADMIN, which at least is a separate bit from
 CAP_MKNOD.  We may want to just refuse moving to a cgroup which
-isn't a descendent of the current one.  Or we may want to use
+isn't a descendant of the current one.  Or we may want to use
 CAP_MAC_ADMIN, since we really are trying to lock down root.
 
 CAP_SYS_ADMIN is needed to modify the whitelist or move another
index 523a9c16c400526e31d05a1aadee8164ef768800..72db89ed0609c8582d24e0fa54f72c10f4c8af96 100644 (file)
@@ -1,5 +1,5 @@
 Memory Resource Controller(Memcg)  Implementation Memo.
-Last Updated: 2009/1/19
+Last Updated: 2009/1/20
 Base Kernel Version: based on 2.6.29-rc2.
 
 Because VM is getting complex (one of reasons is memcg...), memcg's behavior
@@ -356,7 +356,25 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
        (Shell-B)
        # move all tasks in /cgroup/test to /cgroup
        # /sbin/swapoff -a
-       # rmdir /test/cgroup
+       # rmdir /cgroup/test
        # kill malloc task.
 
        Of course, tmpfs v.s. swapoff test should be tested, too.
+
+ 9.8 OOM-Killer
+       Out-of-memory caused by memcg's limit will kill tasks under
+       the memcg. When hierarchy is used, a task under hierarchy
+       will be killed by the kernel.
+       In this case, panic_on_oom shouldn't be invoked and tasks
+       in other groups shouldn't be killed.
+
+       It's not difficult to cause OOM under memcg as following.
+       Case A) when you can swapoff
+       #swapoff -a
+       #echo 50M > /memory.limit_in_bytes
+       run 51M of malloc
+
+       Case B) when you use mem+swap limitation.
+       #echo 50M > memory.limit_in_bytes
+       #echo 50M > memory.memsw.limit_in_bytes
+       run 51M of malloc
index e1501964df1e4ddb46c8a1e704d197de870e3d49..a98a7fe7aabb6aa165c0d334770123ac41ebf9a4 100644 (file)
@@ -302,7 +302,7 @@ will be charged as a new owner of it.
        unevictable             - # of pages cannot be reclaimed.(mlocked etc)
 
        Below is depend on CONFIG_DEBUG_VM.
-       inactive_ratio          - VM inernal parameter. (see mm/page_alloc.c)
+       inactive_ratio          - VM internal parameter. (see mm/page_alloc.c)
        recent_rotated_anon     - VM internal parameter. (see mm/vmscan.c)
        recent_rotated_file     - VM internal parameter. (see mm/vmscan.c)
        recent_scanned_anon     - VM internal parameter. (see mm/vmscan.c)
index 62254d4510c6c8e716733d9a46d12dd17c7052b1..327de1624759ccbc4a5d25527a5b93d4a1918fe0 100644 (file)
@@ -1,7 +1,7 @@
 
                    LINUX ALLOCATED DEVICES (2.6+ version)
 
-            Maintained by Torben Mathiasen <device@lanana.org>
+            Maintained by Alan Cox <device@lanana.org>
 
                      Last revised: 29 November 2006
 
@@ -67,6 +67,11 @@ up to date.  Due to the number of registrations I have to maintain it
 in "batch mode", so there is likely additional registrations that
 haven't been listed yet.
 
+Fourth, remember that Linux now has extensive support for dynamic allocation
+of device numbering and can use sysfs and udev to handle the naming needs.
+There are still some exceptions in the serial and boot device area. Before
+asking for a device number make sure you actually need one.
+
 Finally, sometimes I have to play "namespace police."  Please don't be
 offended.  I often get submissions for /dev names that would be bound
 to cause conflicts down the road.  I am trying to avoid getting in a
@@ -101,7 +106,7 @@ Your cooperation is appreciated.
                  0 = /dev/ram0         First RAM disk
                  1 = /dev/ram1         Second RAM disk
                    ...
-               250 = /dev/initrd       Initial RAM disk {2.6}
+               250 = /dev/initrd       Initial RAM disk
 
                Older kernels had /dev/ramdisk (1, 1) here.
                /dev/initrd refers to a RAM disk which was preloaded
@@ -340,7 +345,7 @@ Your cooperation is appreciated.
                 14 = /dev/touchscreen/ucb1x00  UCB 1x00 touchscreen
                 15 = /dev/touchscreen/mk712    MK712 touchscreen
                128 = /dev/beep         Fancy beep device
-               129 = /dev/modreq       Kernel module load request {2.6}
+               129 =
                130 = /dev/watchdog     Watchdog timer port
                131 = /dev/temperature  Machine internal temperature
                132 = /dev/hwtrap       Hardware fault trap
@@ -350,10 +355,10 @@ Your cooperation is appreciated.
                139 = /dev/openprom     SPARC OpenBoot PROM
                140 = /dev/relay8       Berkshire Products Octal relay card
                141 = /dev/relay16      Berkshire Products ISO-16 relay card
-               142 = /dev/msr          x86 model-specific registers {2.6}
+               142 =
                143 = /dev/pciconf      PCI configuration space
                144 = /dev/nvram        Non-volatile configuration RAM
-               145 = /dev/hfmodem      Soundcard shortwave modem control {2.6}
+               145 = /dev/hfmodem      Soundcard shortwave modem control
                146 = /dev/graphics     Linux/SGI graphics device
                147 = /dev/opengl       Linux/SGI OpenGL pipe
                148 = /dev/gfx          Linux/SGI graphics effects device
@@ -435,6 +440,9 @@ Your cooperation is appreciated.
                228 = /dev/hpet         HPET driver
                229 = /dev/fuse         Fuse (virtual filesystem in user-space)
                230 = /dev/midishare    MidiShare driver
+               231 = /dev/snapshot     System memory snapshot device
+               232 = /dev/kvm          Kernel-based virtual machine (hardware virtualization extensions)
+               233 = /dev/kmview       View-OS A process with a view
                240-254                 Reserved for local use
                255                     Reserved for MISC_DYNAMIC_MINOR
 
@@ -466,10 +474,7 @@ Your cooperation is appreciated.
                The device names specified are proposed -- if there
                are "standard" names for these devices, please let me know.
 
- 12 block      MSCDEX CD-ROM callback support {2.6}
-                 0 = /dev/dos_cd0      First MSCDEX CD-ROM
-                 1 = /dev/dos_cd1      Second MSCDEX CD-ROM
-                   ...
+ 12 block
 
  13 char       Input core
                  0 = /dev/input/js0    First joystick
@@ -498,7 +503,7 @@ Your cooperation is appreciated.
                  2 = /dev/midi00       First MIDI port
                  3 = /dev/dsp          Digital audio
                  4 = /dev/audio        Sun-compatible digital audio
-                 6 = /dev/sndstat      Sound card status information {2.6}
+                 6 =
                  7 = /dev/audioctl     SPARC audio control device
                  8 = /dev/sequencer2   Sequencer -- alternate device
                 16 = /dev/mixer1       Second soundcard mixer control
@@ -510,14 +515,7 @@ Your cooperation is appreciated.
                 34 = /dev/midi02       Third MIDI port
                 50 = /dev/midi03       Fourth MIDI port
 
- 14 block      BIOS harddrive callback support {2.6}
-                 0 = /dev/dos_hda      First BIOS harddrive whole disk
-                64 = /dev/dos_hdb      Second BIOS harddrive whole disk
-               128 = /dev/dos_hdc      Third BIOS harddrive whole disk
-               192 = /dev/dos_hdd      Fourth BIOS harddrive whole disk
-
-               Partitions are handled in the same way as IDE disks
-               (see major number 3).
+ 14 block
 
  15 char       Joystick
                  0 = /dev/js0          First analog joystick
@@ -535,14 +533,14 @@ Your cooperation is appreciated.
  16 block      GoldStar CD-ROM
                  0 = /dev/gscd         GoldStar CD-ROM
 
- 17 char       Chase serial card
+ 17 char       OBSOLETE (was Chase serial card)
                  0 = /dev/ttyH0        First Chase port
                  1 = /dev/ttyH1        Second Chase port
                    ...
  17 block      Optics Storage CD-ROM
                  0 = /dev/optcd        Optics Storage CD-ROM
 
- 18 char       Chase serial card - alternate devices
+ 18 char       OBSOLETE (was Chase serial card - alternate devices)
                  0 = /dev/cuh0         Callout device for ttyH0
                  1 = /dev/cuh1         Callout device for ttyH1
                    ...
@@ -644,8 +642,7 @@ Your cooperation is appreciated.
                  2 = /dev/sbpcd2       Panasonic CD-ROM controller 0 unit 2
                  3 = /dev/sbpcd3       Panasonic CD-ROM controller 0 unit 3
 
- 26 char       Quanta WinVision frame grabber {2.6}
-                 0 = /dev/wvisfgrab    Quanta WinVision frame grabber
+ 26 char
 
  26 block      Second Matsushita (Panasonic/SoundBlaster) CD-ROM
                  0 = /dev/sbpcd4       Panasonic CD-ROM controller 1 unit 0
@@ -872,7 +869,7 @@ Your cooperation is appreciated.
                and "user level packet I/O."  This board is also
                accessible as a standard networking "eth" device.
 
- 38 block      Reserved for Linux/AP+
+ 38 block      OBSOLETE (was Linux/AP+)
 
  39 char       ML-16P experimental I/O board
                  0 = /dev/ml16pa-a0    First card, first analog channel
@@ -892,29 +889,16 @@ Your cooperation is appreciated.
                 50 = /dev/ml16pb-c1    Second card, second counter/timer
                 51 = /dev/ml16pb-c2    Second card, third counter/timer
                      ...
- 39 block      Reserved for Linux/AP+
+ 39 block
 
- 40 char       Matrox Meteor frame grabber {2.6}
-                 0 = /dev/mmetfgrab    Matrox Meteor frame grabber
+ 40 char
 
- 40 block      Syquest EZ135 parallel port removable drive
-                 0 = /dev/eza          Parallel EZ135 drive, whole disk
-
-               This device is obsolete and will be removed in a
-               future version of Linux.  It has been replaced with
-               the parallel port IDE disk driver at major number 45.
-               Partitions are handled in the same way as IDE disks
-               (see major number 3).
+ 40 block
 
  41 char       Yet Another Micro Monitor
                  0 = /dev/yamm         Yet Another Micro Monitor
 
- 41 block      MicroSolutions BackPack parallel port CD-ROM
-                 0 = /dev/bpcd         BackPack CD-ROM
-
-               This device is obsolete and will be removed in a
-               future version of Linux.  It has been replaced with
-               the parallel port ATAPI CD-ROM driver at major number 46.
+ 41 block
 
  42 char       Demo/sample use
 
@@ -1681,13 +1665,7 @@ Your cooperation is appreciated.
                disks (see major number 3) except that the limit on
                partitions is 15.
 
- 93 char       IBM Smart Capture Card frame grabber {2.6}
-                 0 = /dev/iscc0        First Smart Capture Card
-                 1 = /dev/iscc1        Second Smart Capture Card
-                   ...
-               128 = /dev/isccctl0     First Smart Capture Card control
-               129 = /dev/isccctl1     Second Smart Capture Card control
-                   ...
+ 93 char
 
  93 block      NAND Flash Translation Layer filesystem
                  0 = /dev/nftla        First NFTL layer
@@ -1695,10 +1673,7 @@ Your cooperation is appreciated.
                    ...
                240 = /dev/nftlp        16th NTFL layer
 
- 94 char       miroVIDEO DC10/30 capture/playback device {2.6}
-                 0 = /dev/dcxx0        First capture card
-                 1 = /dev/dcxx1        Second capture card
-                   ...
+ 94 char
 
  94 block      IBM S/390 DASD block storage
                  0 = /dev/dasda First DASD device, major
@@ -1791,11 +1766,7 @@ Your cooperation is appreciated.
                    ...
                 15 = /dev/amiraid/ar?p15 15th partition
 
-102 char       Philips SAA5249 Teletext signal decoder {2.6}
-                 0 = /dev/tlk0         First Teletext decoder
-                 1 = /dev/tlk1         Second Teletext decoder
-                 2 = /dev/tlk2         Third Teletext decoder
-                 3 = /dev/tlk3         Fourth Teletext decoder
+102 char
 
 102 block      Compressed block device
                  0 = /dev/cbd/a        First compressed block device, whole device
@@ -1916,10 +1887,7 @@ Your cooperation is appreciated.
                DAC960 (see major number 48) except that the limit on
                partitions is 15.
 
-111 char       Philips SAA7146-based audio/video card {2.6}
-                 0 = /dev/av0          First A/V card
-                 1 = /dev/av1          Second A/V card
-                   ...
+111 char
 
 111 block      Compaq Next Generation Drive Array, eighth controller
                  0 = /dev/cciss/c7d0   First logical drive, whole disk
@@ -2079,8 +2047,8 @@ Your cooperation is appreciated.
                    ...
 
 119 char       VMware virtual network control
-                 0 = /dev/vmnet0       1st virtual network
-                 1 = /dev/vmnet1       2nd virtual network
+                 0 = /dev/vnet0        1st virtual network
+                 1 = /dev/vnet1        2nd virtual network
                    ...
 
 120-127 char   LOCAL/EXPERIMENTAL USE
@@ -2450,7 +2418,7 @@ Your cooperation is appreciated.
                  2 = /dev/raw/raw2     Second raw I/O device
                    ...
 
-163 char       UNASSIGNED (was Radio Tech BIM-XXX-RS232 radio modem - see 51)
+163 char
 
 164 char       Chase Research AT/PCI-Fast serial card
                  0 = /dev/ttyCH0       AT/PCI-Fast board 0, port 0
@@ -2542,6 +2510,12 @@ Your cooperation is appreciated.
                  1 = /dev/clanvi1      Second cLAN adapter
                    ...
 
+179 block       MMC block devices
+                 0 = /dev/mmcblk0      First SD/MMC card
+                 1 = /dev/mmcblk0p1    First partition on first MMC card
+                 8 = /dev/mmcblk1      Second SD/MMC card
+                   ...
+
 179 char       CCube DVXChip-based PCI products
                  0 = /dev/dvxirq0      First DVX device
                  1 = /dev/dvxirq1      Second DVX device
@@ -2560,6 +2534,9 @@ Your cooperation is appreciated.
                 96 = /dev/usb/hiddev0  1st USB HID device
                    ...
                111 = /dev/usb/hiddev15 16th USB HID device
+               112 = /dev/usb/auer0    1st auerswald ISDN device
+                   ...
+               127 = /dev/usb/auer15   16th auerswald ISDN device
                128 = /dev/usb/brlvgr0  First Braille Voyager device
                    ...
                131 = /dev/usb/brlvgr3  Fourth Braille Voyager device
@@ -2810,6 +2787,16 @@ Your cooperation is appreciated.
                    ...
                 190 = /dev/ttyUL3              Xilinx uartlite - port 3
                 191 = /dev/xvc0                Xen virtual console - port 0
+                192 = /dev/ttyPZ0              pmac_zilog - port 0
+                   ...
+                195 = /dev/ttyPZ3              pmac_zilog - port 3
+                196 = /dev/ttyTX0              TX39/49 serial port 0
+                   ...
+                204 = /dev/ttyTX7              TX39/49 serial port 7
+                205 = /dev/ttySC0              SC26xx serial port 0
+                206 = /dev/ttySC1              SC26xx serial port 1
+                207 = /dev/ttySC2              SC26xx serial port 2
+                208 = /dev/ttySC3              SC26xx serial port 3
 
 205 char       Low-density serial ports (alternate device)
                  0 = /dev/culu0                Callout device for ttyLU0
@@ -3145,6 +3132,14 @@ Your cooperation is appreciated.
                  1 = /dev/blockrom1    Second ROM card's translation layer interface
                  ...
 
+259 block      Block Extended Major
+                 Used dynamically to hold additional partition minor
+                 numbers and allow large numbers of partitions per device
+
+259 char       FPGA configuration interfaces
+                 0 = /dev/icap0        First Xilinx internal configuration
+                 1 = /dev/icap1        Second Xilinx internal configuration
+
 260 char       OSD (Object-based-device) SCSI Device
                  0 = /dev/osd0         First OSD Device
                  1 = /dev/osd1         Second OSD Device
index caabbd395e6194c117444e538605af9582c7c392..a618fd99c9f0164298cd343ce404d04f3d38cd40 100644 (file)
@@ -11,8 +11,6 @@ aty128fb.txt
        - info on the ATI Rage128 frame buffer driver.
 cirrusfb.txt
        - info on the driver for Cirrus Logic chipsets.
-cyblafb/
-       - directory with documentation files related to the cyblafb driver.
 deferred_io.txt
        - an introduction to deferred IO.
 fbcon.txt
diff --git a/Documentation/fb/cyblafb/bugs b/Documentation/fb/cyblafb/bugs
deleted file mode 100644 (file)
index 9443a6d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Bugs
-====
-
-I currently don't know of any bug. Please do send reports to:
- - linux-fbdev-devel@lists.sourceforge.net
- - Knut_Petersen@t-online.de.
-
-
-Untested features
-=================
-
-All LCD stuff is untested. If it worked in tridentfb, it should work in
-cyblafb. Please test and report the results to Knut_Petersen@t-online.de.
diff --git a/Documentation/fb/cyblafb/credits b/Documentation/fb/cyblafb/credits
deleted file mode 100644 (file)
index 0eb3b44..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Thanks to
-=========
-   *   Alan Hourihane, for writing the X trident driver
-   *   Jani Monoses, for writing the tridentfb driver
-   *   Antonino A. Daplas, for review of the first published
-       version of cyblafb and some code
-   *   Jochen Hein, for testing and a helpfull bug report
diff --git a/Documentation/fb/cyblafb/documentation b/Documentation/fb/cyblafb/documentation
deleted file mode 100644 (file)
index bb1aac0..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Available Documentation
-=======================
-
-Apollo PLE 133 Chipset VT8601A North Bridge Datasheet, Rev. 1.82, October 22,
-2001, available from VIA:
-
-       http://www.viavpsd.com/product/6/15/DS8601A182.pdf
-
-The datasheet is incomplete, some registers that need to be programmed are not
-explained at all and important bits are listed as "reserved". But you really
-need the datasheet to understand the code.  "p. xxx" comments refer to page
-numbers of this document.
-
-XFree/XOrg drivers are available and of good quality, looking at the code
-there is a good idea if the datasheet does not provide enough information
-or if the datasheet seems to be wrong.
-
diff --git a/Documentation/fb/cyblafb/fb.modes b/Documentation/fb/cyblafb/fb.modes
deleted file mode 100644 (file)
index fe0e522..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-#
-#   Sample fb.modes file
-#
-#      Provides an incomplete list of working modes for
-#      the cyberblade/i1 graphics core.
-#
-#      The value 4294967256 is used instead of -40. Of course, -40 is not
-#      a really reasonable value, but chip design does not always follow
-#      logic. Believe me, it's ok, and it's the way the BIOS does it.
-#
-#      fbset requires 4294967256 in fb.modes and -40 as an argument to
-#      the -t parameter. That's also not too reasonable, and it might change
-#      in the future or might even be differt for your current version.
-#
-
-mode "640x480-50"
-    geometry 640 480 2048 4096 8
-    timings 47619 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-60"
-    geometry 640 480 2048 4096 8
-    timings 39682 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-70"
-    geometry 640 480 2048 4096 8
-    timings 34013 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-72"
-    geometry 640 480 2048 4096 8
-    timings 33068 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-75"
-    geometry 640 480 2048 4096 8
-    timings 31746 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-80"
-    geometry 640 480 2048 4096 8
-    timings 29761 4294967256 24 17 0 216 3
-endmode
-
-mode "640x480-85"
-    geometry 640 480 2048 4096 8
-    timings 28011 4294967256 24 17 0 216 3
-endmode
-
-mode "800x600-50"
-    geometry 800 600 2048 4096 8
-    timings 30303 96 24 14 0 136 11
-endmode
-
-mode "800x600-60"
-    geometry 800 600 2048 4096 8
-    timings 25252 96 24 14 0 136 11
-endmode
-
-mode "800x600-70"
-    geometry 800 600 2048 4096 8
-    timings 21645 96 24 14 0 136 11
-endmode
-
-mode "800x600-72"
-    geometry 800 600 2048 4096 8
-    timings 21043 96 24 14 0 136 11
-endmode
-
-mode "800x600-75"
-    geometry 800 600 2048 4096 8
-    timings 20202 96 24 14 0 136 11
-endmode
-
-mode "800x600-80"
-    geometry 800 600 2048 4096 8
-    timings 18939 96 24 14 0 136 11
-endmode
-
-mode "800x600-85"
-    geometry 800 600 2048 4096 8
-    timings 17825 96 24 14 0 136 11
-endmode
-
-mode "1024x768-50"
-    geometry 1024 768 2048 4096 8
-    timings 19054 144 24 29 0 120 3
-endmode
-
-mode "1024x768-60"
-    geometry 1024 768 2048 4096 8
-    timings 15880 144 24 29 0 120 3
-endmode
-
-mode "1024x768-70"
-    geometry 1024 768 2048 4096 8
-    timings 13610 144 24 29 0 120 3
-endmode
-
-mode "1024x768-72"
-    geometry 1024 768 2048 4096 8
-    timings 13232 144 24 29 0 120 3
-endmode
-
-mode "1024x768-75"
-    geometry 1024 768 2048 4096 8
-    timings 12703 144 24 29 0 120 3
-endmode
-
-mode "1024x768-80"
-    geometry 1024 768 2048 4096 8
-    timings 11910 144 24 29 0 120 3
-endmode
-
-mode "1024x768-85"
-    geometry 1024 768 2048 4096 8
-    timings 11209 144 24 29 0 120 3
-endmode
-
-mode "1280x1024-50"
-    geometry 1280 1024 2048 4096 8
-    timings 11114 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-60"
-    geometry 1280 1024 2048 4096 8
-    timings 9262 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-70"
-    geometry 1280 1024 2048 4096 8
-    timings 7939 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-72"
-    geometry 1280 1024 2048 4096 8
-    timings 7719 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-75"
-    geometry 1280 1024 2048 4096 8
-    timings 7410 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-80"
-    geometry 1280 1024 2048 4096 8
-    timings 6946 232 16 39 0 160 3
-endmode
-
-mode "1280x1024-85"
-    geometry 1280 1024 2048 4096 8
-    timings 6538 232 16 39 0 160 3
-endmode
diff --git a/Documentation/fb/cyblafb/performance b/Documentation/fb/cyblafb/performance
deleted file mode 100644 (file)
index 8d15d5d..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-Speed
-=====
-
-CyBlaFB is much faster than tridentfb and vesafb. Compare the performance data
-for mode 1280x1024-[8,16,32]@61 Hz.
-
-Test 1: Cat a file with 2000 lines of 0 characters.
-Test 2: Cat a file with 2000 lines of 80 characters.
-Test 3: Cat a file with 2000 lines of 160 characters.
-
-All values show system time use in seconds, kernel 2.6.12 was used for
-the measurements. 2.6.13 is a bit slower, 2.6.14 hopefully will include a
-patch that speeds up kernel bitblitting a lot ( > 20%).
-
-+-----------+-----------------------------------------------------+
-|          |                   not accelerated                   |
-| TRIDENTFB +-----------------+-----------------+-----------------+
-| of 2.6.12 |     8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  4.31 |   4.33 |   6.05 |  12.81 |  ----  |  ----  |
-|    Test 2 |  67.94 |  5.44 | 123.16 |  14.79 |  ----  |  ----  |
-|    Test 3 | 131.36 |  6.55 | 240.12 |  16.76 |  ----  |  ----  |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments |                |                 | completely bro- |
-|          |                 |                 | ken, monitor    |
-|          |                 |                 | switches off    |
-+-----------+-----------------+-----------------+-----------------+
-
-
-+-----------+-----------------------------------------------------+
-|          |                     accelerated                     |
-| TRIDENTFB +-----------------+-----------------+-----------------+
-| of 2.6.12 |     8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  ----  | ----  |  20.62 |   1.22 |  ----  |  ----  |
-|    Test 2 |  ----  | ----  |  22.61 |   3.19 |  ----  |  ----  |
-|    Test 3 |  ----  | ----  |  24.59 |   5.16 |  ----  |  ----  |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments | broken, writing | broken, ok only | completely bro- |
-|          | to wrong places | if bgcolor is   | ken, monitor    |
-|          | on screen + bug | black, bug in   | switches off    |
-|          | in fillrect()   | fillrect()      |                 |
-+-----------+-----------------+-----------------+-----------------+
-
-
-+-----------+-----------------------------------------------------+
-|          |                   not accelerated                   |
-|   VESAFB  +-----------------+-----------------+-----------------+
-| of 2.6.12 |     8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  4.26 |   3.76 |   5.99 |   7.23 |  ----  |  ----  |
-|    Test 2 |  65.65 |  4.89 | 120.88 |   9.08 |  ----  |  ----  |
-|    Test 3 | 126.91 |  5.94 | 235.77 |  11.03 |  ----  |  ----  |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments | vga=0x307       | vga=0x31a      | vga=0x31b not   |
-|          | fh=80kHz        | fh=80kHz        | supported by    |
-|          | fv=75kHz        | fv=75kHz        | video BIOS and  |
-|          |                 |                 | hardware        |
-+-----------+-----------------+-----------------+-----------------+
-
-
-+-----------+-----------------------------------------------------+
-|          |                     accelerated                     |
-|  CYBLAFB  +-----------------+-----------------+-----------------+
-|          |      8 bpp      |     16 bpp      |     32 bpp      |
-|          | noypan |   ypan | noypan |   ypan | noypan |   ypan |
-+-----------+--------+--------+--------+--------+--------+--------+
-|    Test 1 |  8.02 |   0.23 |  19.04 |   0.61 |  57.12 |   2.74 |
-|    Test 2 |  8.38 |   0.55 |  19.39 |   0.92 |  57.54 |   3.13 |
-|    Test 3 |  8.73 |   0.86 |  19.74 |   1.24 |  57.95 |   3.51 |
-+-----------+--------+--------+--------+--------+--------+--------+
-|  Comments |                |                 |                 |
-|          |                 |                 |                 |
-|          |                 |                 |                 |
-|          |                 |                 |                 |
-+-----------+-----------------+-----------------+-----------------+
diff --git a/Documentation/fb/cyblafb/todo b/Documentation/fb/cyblafb/todo
deleted file mode 100644 (file)
index c5f6d0e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-TODO / Missing features
-=======================
-
-Verify LCD stuff               "stretch" and "center" options are
-                               completely untested ... this code needs to be
-                               verified. As I don't have access to such
-                               hardware, please contact me if you are
-                               willing run some tests.
-
-Interlaced video modes         The reason that interleaved
-                               modes are disabled is that I do not know
-                               the meaning of the vertical interlace
-                               parameter. Also the datasheet mentions a
-                               bit d8 of a horizontal interlace parameter,
-                               but nowhere the lower 8 bits. Please help
-                               if you can.
-
-low-res double scan modes      Who needs it?
-
-accelerated color blitting     Who needs it? The console driver does use color
-                               blitting for nothing but drawing the penguine,
-                               everything else is done using color expanding
-                               blitting of 1bpp character bitmaps.
-
-ioctls                         Who needs it?
-
-TV-out                         Will be done later. Use "vga= " at boot time
-                               to set a suitable video mode.
-
-???                            Feel free to contact me if you have any
-                               feature requests
diff --git a/Documentation/fb/cyblafb/usage b/Documentation/fb/cyblafb/usage
deleted file mode 100644 (file)
index a39bb3d..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-CyBlaFB is a framebuffer driver for the Cyberblade/i1 graphics core integrated
-into the VIA Apollo PLE133 (aka vt8601) south bridge. It is developed and
-tested using a VIA EPIA 5000 board.
-
-Cyblafb - compiled into the kernel or as a module?
-==================================================
-
-You might compile cyblafb either as a module or compile it permanently into the
-kernel.
-
-Unless you have a real reason to do so you should not compile both vesafb and
-cyblafb permanently into the kernel. It's possible and it helps during the
-developement cycle, but it's useless and will at least block some otherwise
-usefull memory for ordinary users.
-
-Selecting Modes
-===============
-
-       Startup Mode
-       ============
-
-       First of all, you might use the "vga=???" boot parameter as it is
-       documented in vesafb.txt and svga.txt. Cyblafb will detect the video
-       mode selected and will use the geometry and timings found by
-       inspecting the hardware registers.
-
-               video=cyblafb vga=0x317
-
-       Alternatively you might use a combination of the mode, ref and bpp
-       parameters. If you compiled the driver into the kernel, add something
-       like this to the kernel command line:
-
-               video=cyblafb:1280x1024,bpp=16,ref=50 ...
-
-       If you compiled the driver as a module, the same mode would be
-       selected by the following command:
-
-               modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
-
-       None of the modes possible to select as startup modes are affected by
-       the problems described at the end of the next subsection.
-
-       For all startup modes cyblafb chooses a virtual x resolution of 2048,
-       the only exception is mode 1280x1024 in combination with 32 bpp. This
-       allows ywrap scrolling for all those modes if rotation is 0 or 2, and
-       also fast scrolling if rotation is 1 or 3. The default virtual y reso-
-       lution is 4096 for bpp == 8, 2048 for bpp==16 and 1024 for bpp == 32,
-       again with the only exception of 1280x1024 at 32 bpp.
-
-       Please do set your video memory size to 8 Mb in the Bios setup. Other
-       values will work, but performace is decreased for a lot of modes.
-
-       Mode changes using fbset
-       ========================
-
-       You might use fbset to change the video mode, see "man fbset". Cyblafb
-       generally does assume that you know what you are doing. But it does
-       some checks, especially those that are needed to prevent you from
-       damaging your hardware.
-
-               - only 8, 16, 24 and 32 bpp video modes are accepted
-               - interlaced video modes are not accepted
-               - double scan video modes are not accepted
-               - if a flat panel is found, cyblafb does not allow you
-                 to program a resolution higher than the physical
-                 resolution of the flat panel monitor
-               - cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp
-                 and (currently) 24 bit modes use a doubled vclk internally,
-                 the dotclock limit as seen by fbset is 115 MHz for those
-                 modes and 230 MHz for 8 and 16 bpp modes.
-               - cyblafb will allow you to select very high resolutions as
-                 long as the hardware can be programmed to these modes. The
-                 documented limit 1600x1200 is not enforced, but don't expect
-                 perfect signal quality.
-
-       Any request that violates the rules given above will be either changed
-       to something the hardware supports or an error value will be returned.
-
-       If you program a virtual y resolution higher than the hardware limit,
-       cyblafb will silently decrease that value to the highest possible
-       value. The same is true for a virtual x resolution that is not
-       supported by the hardware. Cyblafb tries to adapt vyres first because
-       vxres decides if ywrap scrolling is possible or not.
-
-       Attempts to disable acceleration are ignored, I believe that this is
-       safe.
-
-       Some video modes that should work do not work as expected. If you use
-       the standard fb.modes, fbset 640x480-60 will program that mode, but
-       you will see a vertical area, about two characters wide, with only
-       much darker characters than the other characters on the screen.
-       Cyblafb does allow that mode to be set, as it does not violate the
-       official specifications. It would need a lot of code to reliably sort
-       out all invalid modes, playing around with the margin values will
-       give a valid mode quickly. And if cyblafb would detect such an invalid
-       mode, should it silently alter the requested values or should it
-       report an error? Both options have some pros and cons. As stated
-       above, none of the startup modes are affected, and if you set
-       verbosity to 1 or higher, cyblafb will print the fbset command that
-       would be needed to program that mode using fbset.
-
-
-Other Parameters
-================
-
-
-crt            don't autodetect, assume monitor connected to
-               standard VGA connector
-
-fp             don't autodetect, assume flat panel display
-               connected to flat panel monitor interface
-
-nativex        inform driver about native x resolution of
-               flat panel monitor connected to special
-               interface (should be autodetected)
-
-stretch        stretch image to adapt low resolution modes to
-               higer resolutions of flat panel monitors
-               connected to special interface
-
-center         center image to adapt low resolution modes to
-               higer resolutions of flat panel monitors
-               connected to special interface
-
-memsize        use if autodetected memsize is wrong ...
-               should never be necessary
-
-nopcirr        disable PCI read retry
-nopciwr        disable PCI write retry
-nopcirb        disable PCI read bursts
-nopciwb        disable PCI write bursts
-
-bpp            bpp for specified modes
-               valid values: 8 || 16 || 24 || 32
-
-ref            refresh rate for specified mode
-               valid values: 50 <= ref <= 85
-
-mode           640x480 or 800x600 or 1024x768 or 1280x1024
-               if not specified, the startup mode will be detected
-               and used, so you might also use the vga=??? parameter
-               described in vesafb.txt. If you do not specify a mode,
-               bpp and ref parameters are ignored.
-
-verbosity      0 is the default, increase to at least 2 for every
-               bug report!
-
-Development hints
-=================
-
-It's much faster do compile a module and to load the new version after
-unloading the old module than to compile a new kernel and to reboot. So if you
-try to work on cyblafb, it might be a good idea to use cyblafb as a module.
-In real life, fast often means dangerous, and that's also the case here. If
-you introduce a serious bug when cyblafb is compiled into the kernel, the
-kernel will lock or oops with a high probability before the file system is
-mounted, and the danger for your data is low. If you load a broken own version
-of cyblafb on a running system, the danger for the integrity of the file
-system is much higher as you might need a hard reset afterwards. Decide
-yourself.
-
-Module unloading, the vfb method
-================================
-
-If you want to unload/reload cyblafb using the virtual framebuffer, you need
-to enable vfb support in the kernel first. After that, load the modules as
-shown below:
-
-       modprobe vfb vfb_enable=1
-       modprobe fbcon
-       modprobe cyblafb
-       fbset -fb /dev/fb1 1280x1024-60 -vyres 2662
-       con2fb /dev/fb1 /dev/tty1
-       ...
-
-If you now made some changes to cyblafb and want to reload it, you might do it
-as show below:
-
-       con2fb /dev/fb0 /dev/tty1
-       ...
-       rmmod cyblafb
-       modprobe cyblafb
-       con2fb /dev/fb1 /dev/tty1
-       ...
-
-Of course, you might choose another mode, and most certainly you also want to
-map some other /dev/tty* to the real framebuffer device. You might also choose
-to compile fbcon as a kernel module or place it permanently in the kernel.
-
-I do not know of any way to unload fbcon, and fbcon will prevent the
-framebuffer device loaded first from unloading. [If there is a way, then
-please add a description here!]
-
-Module unloading, the vesafb method
-===================================
-
-Configure the kernel:
-
-       <*> Support for frame buffer devices
-       [*]   VESA VGA graphics support
-       <M>   Cyberblade/i1 support
-
-Add e.g. "video=vesafb:ypan vga=0x307" to the kernel parameters. The ypan
-parameter is important, choose any vga parameter you like as long as it is
-a graphics mode.
-
-After booting, load cyblafb without any mode and bpp parameter and assign
-cyblafb to individual ttys using con2fb, e.g.:
-
-       modprobe cyblafb
-       con2fb /dev/fb1 /dev/tty1
-
-Unloading cyblafb works without problems after you assign vesafb to all
-ttys again, e.g.:
-
-       con2fb /dev/fb0 /dev/tty1
-       rmmod cyblafb
diff --git a/Documentation/fb/cyblafb/whatsnew b/Documentation/fb/cyblafb/whatsnew
deleted file mode 100644 (file)
index 76c07a2..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-0.62
-====
-
-      - the vesafb parameter has been removed as I decided to allow the
-       feature without any special parameter.
-
-      - Cyblafb does not use the vga style of panning any longer, now the
-       "right view" register in the graphics engine IO space is used. Without
-       that change it was impossible to use all available memory, and without
-       access to all available memory it is impossible to ywrap.
-
-      - The imageblit function now uses hardware acceleration for all font
-        widths. Hardware blitting across pixel column 2048 is broken in the
-       cyberblade/i1 graphics core, but we work around that hardware bug.
-
-      - modes with vxres != xres are supported now.
-
-      - ywrap scrolling is supported now and the default. This is a big
-        performance gain.
-
-      - default video modes use vyres > yres and vxres > xres to allow
-        almost optimal scrolling speed for normal and rotated screens
-
-      - some features mainly usefull for debugging the upper layers of the
-        framebuffer system have been added, have a look at the code
-
-      - fixed: Oops after unloading cyblafb when reading /proc/io*
-
-      - we work around some bugs of the higher framebuffer layers.
diff --git a/Documentation/fb/cyblafb/whycyblafb b/Documentation/fb/cyblafb/whycyblafb
deleted file mode 100644 (file)
index a123bc1..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-I tried the following framebuffer drivers:
-
-       - TRIDENTFB is full of bugs. Acceleration is broken for Blade3D
-         graphics cores like the cyberblade/i1. It claims to support a great
-         number of devices, but documentation for most of these devices is
-         unfortunately not available. There is _no_ reason to use tridentfb
-         for cyberblade/i1 + CRT users. VESAFB is faster, and the one
-         advantage, mode switching, is broken in tridentfb.
-
-       - VESAFB is used by many distributions as a standard. Vesafb does
-         not support mode switching. VESAFB is a bit faster than the working
-         configurations of TRIDENTFB, but it is still too slow, even if you
-         use ypan.
-
-       - EPIAFB (you'll find it on sourceforge) supports the Cyberblade/i1
-         graphics core, but it still has serious bugs and developement seems
-         to have stopped. This is the one driver with TV-out support. If you
-         do need this feature, try epiafb.
-
-None of these drivers was a real option for me.
-
-I believe that is unreasonable to change code that announces to support 20
-devices if I only have more or less sufficient documentation for exactly one
-of these. The risk of breaking device foo while fixing device bar is too high.
-
-So I decided to start CyBlaFB as a stripped down tridentfb.
-
-All code specific to other Trident chips has been removed. After that there
-were a lot of cosmetic changes to increase the readability of the code. All
-register names were changed to those mnemonics used in the datasheet. Function
-and macro names were changed if they hindered easy understanding of the code.
-
-After that I debugged the code and implemented some new features. I'll try to
-give a little summary of the main changes:
-
-       - calculation of vertical and horizontal timings was fixed
-
-       - video signal quality has been improved dramatically
-
-       - acceleration:
-
-               - fillrect and copyarea were fixed and reenabled
-
-               - color expanding imageblit was newly implemented, color
-                 imageblit (only used to draw the penguine) still uses the
-                 generic code.
-
-               - init of the acceleration engine was improved and moved to a
-                 place where it really works ...
-
-               - sync function has a timeout now and tries to reset and
-                 reinit the accel engine if necessary
-
-               - fewer slow copyarea calls when doing ypan scrolling by using
-                 undocumented bit d21 of screen start address stored in
-                 CR2B[5]. BIOS does use it also, so this should be safe.
-
-       - cyblafb rejects any attempt to set modes that would cause vclk
-         values above reasonable 230 MHz. 32bit modes use a clock
-         multiplicator of 2, so fbset does show the correct values for
-         pixclock but not for vclk in this case. The fbset limit is 115 MHz
-         for 32 bpp modes.
-
-       - cyblafb rejects modes known to be broken or unimplemented (all
-         interlaced modes, all doublescan modes for now)
-
-       - cyblafb now works independant of the video mode in effect at startup
-         time (tridentfb does not init all needed registers to reasonable
-         values)
-
-       - switching between video modes does work reliably now
-
-       - the first video mode now is the one selected on startup using the
-         vga=???? mechanism or any of
-               - 640x480, 800x600, 1024x768, 1280x1024
-               - 8, 16, 24 or 32 bpp
-               - refresh between 50 Hz and 85 Hz, 1 Hz steps (1280x1024-32
-                 is limited to 63Hz)
-
-       - pci retry and pci burst mode are settable (try to disable if you
-         experience latency problems)
-
-       - built as a module cyblafb might be unloaded and reloaded using
-         the vfb module and con2vt or might be used together with vesafb
-
index 5e02b83ac12b6e19842f18a4c5017b4a0ee8ab31..39246fc11257af2c68402aa1ad5192e530e4f618 100644 (file)
@@ -255,6 +255,16 @@ Who:       Jan Engelhardt <jengelh@computergmbh.de>
 
 ---------------------------
 
+What:  GPIO autorequest on gpio_direction_{input,output}() in gpiolib
+When:  February 2010
+Why:   All callers should use explicit gpio_request()/gpio_free().
+       The autorequest mechanism in gpiolib was provided mostly as a
+       migration aid for legacy GPIO interfaces (for SOC based GPIOs).
+       Those users have now largely migrated.  Platforms implementing
+       the GPIO interfaces without using gpiolib will see no changes.
+Who:   David Brownell <dbrownell@users.sourceforge.net>
+---------------------------
+
 What:  b43 support for firmware revision < 410
 When:  The schedule was July 2008, but it was decided that we are going to keep the
         code as long as there are no major maintanance headaches.
@@ -273,13 +283,6 @@ Who:       Glauber Costa <gcosta@redhat.com>
 
 ---------------------------
 
-What:  remove HID compat support
-When:  2.6.29
-Why:   needed only as a temporary solution until distros fix themselves up
-Who:   Jiri Slaby <jirislaby@gmail.com>
-
----------------------------
-
 What: print_fn_descriptor_symbol()
 When: October 2009
 Why:  The %pF vsprintf format provides the same functionality in a
@@ -311,6 +314,18 @@ Who:       Vlad Yasevich <vladislav.yasevich@hp.com>
 
 ---------------------------
 
+What:  Ability for non root users to shm_get hugetlb pages based on mlock
+       resource limits
+When:  2.6.31
+Why:   Non root users need to be part of /proc/sys/vm/hugetlb_shm_group or
+       have CAP_IPC_LOCK to be able to allocate shm segments backed by
+       huge pages.  The mlock based rlimit check to allow shm hugetlb is
+       inconsistent with mmap based allocations.  Hence it is being
+       deprecated.
+Who:   Ravikiran Thirumalai <kiran@scalex86.org>
+
+---------------------------
+
 What:  CONFIG_THERMAL_HWMON
 When:  January 2009
 Why:   This option was introduced just to allow older lm-sensors userspace
@@ -380,3 +395,35 @@ Why:       The defines and typedefs (hw_interrupt_type, no_irq_type, irq_desc_t)
        have been kept around for migration reasons. After more than two years
        it's time to remove them finally
 Who:   Thomas Gleixner <tglx@linutronix.de>
+
+---------------------------
+
+What:  fakephp and associated sysfs files in /sys/bus/pci/slots/
+When:  2011
+Why:   In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to
+       represent a machine's physical PCI slots. The change in semantics
+       had userspace implications, as the hotplug core no longer allowed
+       drivers to create multiple sysfs files per physical slot (required
+       for multi-function devices, e.g.). fakephp was seen as a developer's
+       tool only, and its interface changed. Too late, we learned that
+       there were some users of the fakephp interface.
+
+       In 2.6.30, the original fakephp interface was restored. At the same
+       time, the PCI core gained the ability that fakephp provided, namely
+       function-level hot-remove and hot-add.
+
+       Since the PCI core now provides the same functionality, exposed in:
+
+               /sys/bus/pci/rescan
+               /sys/bus/pci/devices/.../remove
+               /sys/bus/pci/devices/.../rescan
+
+       there is no functional reason to maintain fakephp as well.
+
+       We will keep the existing module so that 'modprobe fakephp' will
+       present the old /sys/bus/pci/slots/... interface for compatibility,
+       but users are urged to migrate their applications to the API above.
+
+       After a reasonable transition period, we will remove the legacy
+       fakephp interface.
+Who:   Alex Chiang <achiang@hp.com>
index 4e78ce6778435aacf321de21baffe4095739f2e9..76efe5b71d7d8f744739a129f4b5333b898acf5c 100644 (file)
@@ -505,7 +505,7 @@ prototypes:
        void (*open)(struct vm_area_struct*);
        void (*close)(struct vm_area_struct*);
        int (*fault)(struct vm_area_struct*, struct vm_fault *);
-       int (*page_mkwrite)(struct vm_area_struct *, struct page *);
+       int (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *);
        int (*access)(struct vm_area_struct *, unsigned long, void*, int, int);
 
 locking rules:
diff --git a/Documentation/filesystems/caching/backend-api.txt b/Documentation/filesystems/caching/backend-api.txt
new file mode 100644 (file)
index 0000000..382d52c
--- /dev/null
@@ -0,0 +1,658 @@
+                         ==========================
+                         FS-CACHE CACHE BACKEND API
+                         ==========================
+
+The FS-Cache system provides an API by which actual caches can be supplied to
+FS-Cache for it to then serve out to network filesystems and other interested
+parties.
+
+This API is declared in <linux/fscache-cache.h>.
+
+
+====================================
+INITIALISING AND REGISTERING A CACHE
+====================================
+
+To start off, a cache definition must be initialised and registered for each
+cache the backend wants to make available.  For instance, CacheFS does this in
+the fill_super() operation on mounting.
+
+The cache definition (struct fscache_cache) should be initialised by calling:
+
+       void fscache_init_cache(struct fscache_cache *cache,
+                               struct fscache_cache_ops *ops,
+                               const char *idfmt,
+                               ...);
+
+Where:
+
+ (*) "cache" is a pointer to the cache definition;
+
+ (*) "ops" is a pointer to the table of operations that the backend supports on
+     this cache; and
+
+ (*) "idfmt" is a format and printf-style arguments for constructing a label
+     for the cache.
+
+
+The cache should then be registered with FS-Cache by passing a pointer to the
+previously initialised cache definition to:
+
+       int fscache_add_cache(struct fscache_cache *cache,
+                             struct fscache_object *fsdef,
+                             const char *tagname);
+
+Two extra arguments should also be supplied:
+
+ (*) "fsdef" which should point to the object representation for the FS-Cache
+     master index in this cache.  Netfs primary index entries will be created
+     here.  FS-Cache keeps the caller's reference to the index object if
+     successful and will release it upon withdrawal of the cache.
+
+ (*) "tagname" which, if given, should be a text string naming this cache.  If
+     this is NULL, the identifier will be used instead.  For CacheFS, the
+     identifier is set to name the underlying block device and the tag can be
+     supplied by mount.
+
+This function may return -ENOMEM if it ran out of memory or -EEXIST if the tag
+is already in use.  0 will be returned on success.
+
+
+=====================
+UNREGISTERING A CACHE
+=====================
+
+A cache can be withdrawn from the system by calling this function with a
+pointer to the cache definition:
+
+       void fscache_withdraw_cache(struct fscache_cache *cache);
+
+In CacheFS's case, this is called by put_super().
+
+
+========
+SECURITY
+========
+
+The cache methods are executed one of two contexts:
+
+ (1) that of the userspace process that issued the netfs operation that caused
+     the cache method to be invoked, or
+
+ (2) that of one of the processes in the FS-Cache thread pool.
+
+In either case, this may not be an appropriate context in which to access the
+cache.
+
+The calling process's fsuid, fsgid and SELinux security identities may need to
+be masqueraded for the duration of the cache driver's access to the cache.
+This is left to the cache to handle; FS-Cache makes no effort in this regard.
+
+
+===================================
+CONTROL AND STATISTICS PRESENTATION
+===================================
+
+The cache may present data to the outside world through FS-Cache's interfaces
+in sysfs and procfs - the former for control and the latter for statistics.
+
+A sysfs directory called /sys/fs/fscache/<cachetag>/ is created if CONFIG_SYSFS
+is enabled.  This is accessible through the kobject struct fscache_cache::kobj
+and is for use by the cache as it sees fit.
+
+
+========================
+RELEVANT DATA STRUCTURES
+========================
+
+ (*) Index/Data file FS-Cache representation cookie:
+
+       struct fscache_cookie {
+               struct fscache_object_def       *def;
+               struct fscache_netfs            *netfs;
+               void                            *netfs_data;
+               ...
+       };
+
+     The fields that might be of use to the backend describe the object
+     definition, the netfs definition and the netfs's data for this cookie.
+     The object definition contain functions supplied by the netfs for loading
+     and matching index entries; these are required to provide some of the
+     cache operations.
+
+
+ (*) In-cache object representation:
+
+       struct fscache_object {
+               int                             debug_id;
+               enum {
+                       FSCACHE_OBJECT_RECYCLING,
+                       ...
+               }                               state;
+               spinlock_t                      lock
+               struct fscache_cache            *cache;
+               struct fscache_cookie           *cookie;
+               ...
+       };
+
+     Structures of this type should be allocated by the cache backend and
+     passed to FS-Cache when requested by the appropriate cache operation.  In
+     the case of CacheFS, they're embedded in CacheFS's internal object
+     structures.
+
+     The debug_id is a simple integer that can be used in debugging messages
+     that refer to a particular object.  In such a case it should be printed
+     using "OBJ%x" to be consistent with FS-Cache.
+
+     Each object contains a pointer to the cookie that represents the object it
+     is backing.  An object should retired when put_object() is called if it is
+     in state FSCACHE_OBJECT_RECYCLING.  The fscache_object struct should be
+     initialised by calling fscache_object_init(object).
+
+
+ (*) FS-Cache operation record:
+
+       struct fscache_operation {
+               atomic_t                usage;
+               struct fscache_object   *object;
+               unsigned long           flags;
+       #define FSCACHE_OP_EXCLUSIVE
+               void (*processor)(struct fscache_operation *op);
+               void (*release)(struct fscache_operation *op);
+               ...
+       };
+
+     FS-Cache has a pool of threads that it uses to give CPU time to the
+     various asynchronous operations that need to be done as part of driving
+     the cache.  These are represented by the above structure.  The processor
+     method is called to give the op CPU time, and the release method to get
+     rid of it when its usage count reaches 0.
+
+     An operation can be made exclusive upon an object by setting the
+     appropriate flag before enqueuing it with fscache_enqueue_operation().  If
+     an operation needs more processing time, it should be enqueued again.
+
+
+ (*) FS-Cache retrieval operation record:
+
+       struct fscache_retrieval {
+               struct fscache_operation op;
+               struct address_space    *mapping;
+               struct list_head        *to_do;
+               ...
+       };
+
+     A structure of this type is allocated by FS-Cache to record retrieval and
+     allocation requests made by the netfs.  This struct is then passed to the
+     backend to do the operation.  The backend may get extra refs to it by
+     calling fscache_get_retrieval() and refs may be discarded by calling
+     fscache_put_retrieval().
+
+     A retrieval operation can be used by the backend to do retrieval work.  To
+     do this, the retrieval->op.processor method pointer should be set
+     appropriately by the backend and fscache_enqueue_retrieval() called to
+     submit it to the thread pool.  CacheFiles, for example, uses this to queue
+     page examination when it detects PG_lock being cleared.
+
+     The to_do field is an empty list available for the cache backend to use as
+     it sees fit.
+
+
+ (*) FS-Cache storage operation record:
+
+       struct fscache_storage {
+               struct fscache_operation op;
+               pgoff_t                 store_limit;
+               ...
+       };
+
+     A structure of this type is allocated by FS-Cache to record outstanding
+     writes to be made.  FS-Cache itself enqueues this operation and invokes
+     the write_page() method on the object at appropriate times to effect
+     storage.
+
+
+================
+CACHE OPERATIONS
+================
+
+The cache backend provides FS-Cache with a table of operations that can be
+performed on the denizens of the cache.  These are held in a structure of type:
+
+       struct fscache_cache_ops
+
+ (*) Name of cache provider [mandatory]:
+
+       const char *name
+
+     This isn't strictly an operation, but should be pointed at a string naming
+     the backend.
+
+
+ (*) Allocate a new object [mandatory]:
+
+       struct fscache_object *(*alloc_object)(struct fscache_cache *cache,
+                                              struct fscache_cookie *cookie)
+
+     This method is used to allocate a cache object representation to back a
+     cookie in a particular cache.  fscache_object_init() should be called on
+     the object to initialise it prior to returning.
+
+     This function may also be used to parse the index key to be used for
+     multiple lookup calls to turn it into a more convenient form.  FS-Cache
+     will call the lookup_complete() method to allow the cache to release the
+     form once lookup is complete or aborted.
+
+
+ (*) Look up and create object [mandatory]:
+
+       void (*lookup_object)(struct fscache_object *object)
+
+     This method is used to look up an object, given that the object is already
+     allocated and attached to the cookie.  This should instantiate that object
+     in the cache if it can.
+
+     The method should call fscache_object_lookup_negative() as soon as
+     possible if it determines the object doesn't exist in the cache.  If the
+     object is found to exist and the netfs indicates that it is valid then
+     fscache_obtained_object() should be called once the object is in a
+     position to have data stored in it.  Similarly, fscache_obtained_object()
+     should also be called once a non-present object has been created.
+
+     If a lookup error occurs, fscache_object_lookup_error() should be called
+     to abort the lookup of that object.
+
+
+ (*) Release lookup data [mandatory]:
+
+       void (*lookup_complete)(struct fscache_object *object)
+
+     This method is called to ask the cache to release any resources it was
+     using to perform a lookup.
+
+
+ (*) Increment object refcount [mandatory]:
+
+       struct fscache_object *(*grab_object)(struct fscache_object *object)
+
+     This method is called to increment the reference count on an object.  It
+     may fail (for instance if the cache is being withdrawn) by returning NULL.
+     It should return the object pointer if successful.
+
+
+ (*) Lock/Unlock object [mandatory]:
+
+       void (*lock_object)(struct fscache_object *object)
+       void (*unlock_object)(struct fscache_object *object)
+
+     These methods are used to exclusively lock an object.  It must be possible
+     to schedule with the lock held, so a spinlock isn't sufficient.
+
+
+ (*) Pin/Unpin object [optional]:
+
+       int (*pin_object)(struct fscache_object *object)
+       void (*unpin_object)(struct fscache_object *object)
+
+     These methods are used to pin an object into the cache.  Once pinned an
+     object cannot be reclaimed to make space.  Return -ENOSPC if there's not
+     enough space in the cache to permit this.
+
+
+ (*) Update object [mandatory]:
+
+       int (*update_object)(struct fscache_object *object)
+
+     This is called to update the index entry for the specified object.  The
+     new information should be in object->cookie->netfs_data.  This can be
+     obtained by calling object->cookie->def->get_aux()/get_attr().
+
+
+ (*) Discard object [mandatory]:
+
+       void (*drop_object)(struct fscache_object *object)
+
+     This method is called to indicate that an object has been unbound from its
+     cookie, and that the cache should release the object's resources and
+     retire it if it's in state FSCACHE_OBJECT_RECYCLING.
+
+     This method should not attempt to release any references held by the
+     caller.  The caller will invoke the put_object() method as appropriate.
+
+
+ (*) Release object reference [mandatory]:
+
+       void (*put_object)(struct fscache_object *object)
+
+     This method is used to discard a reference to an object.  The object may
+     be freed when all the references to it are released.
+
+
+ (*) Synchronise a cache [mandatory]:
+
+       void (*sync)(struct fscache_cache *cache)
+
+     This is called to ask the backend to synchronise a cache with its backing
+     device.
+
+
+ (*) Dissociate a cache [mandatory]:
+
+       void (*dissociate_pages)(struct fscache_cache *cache)
+
+     This is called to ask a cache to perform any page dissociations as part of
+     cache withdrawal.
+
+
+ (*) Notification that the attributes on a netfs file changed [mandatory]:
+
+       int (*attr_changed)(struct fscache_object *object);
+
+     This is called to indicate to the cache that certain attributes on a netfs
+     file have changed (for example the maximum size a file may reach).  The
+     cache can read these from the netfs by calling the cookie's get_attr()
+     method.
+
+     The cache may use the file size information to reserve space on the cache.
+     It should also call fscache_set_store_limit() to indicate to FS-Cache the
+     highest byte it's willing to store for an object.
+
+     This method may return -ve if an error occurred or the cache object cannot
+     be expanded.  In such a case, the object will be withdrawn from service.
+
+     This operation is run asynchronously from FS-Cache's thread pool, and
+     storage and retrieval operations from the netfs are excluded during the
+     execution of this operation.
+
+
+ (*) Reserve cache space for an object's data [optional]:
+
+       int (*reserve_space)(struct fscache_object *object, loff_t size);
+
+     This is called to request that cache space be reserved to hold the data
+     for an object and the metadata used to track it.  Zero size should be
+     taken as request to cancel a reservation.
+
+     This should return 0 if successful, -ENOSPC if there isn't enough space
+     available, or -ENOMEM or -EIO on other errors.
+
+     The reservation may exceed the current size of the object, thus permitting
+     future expansion.  If the amount of space consumed by an object would
+     exceed the reservation, it's permitted to refuse requests to allocate
+     pages, but not required.  An object may be pruned down to its reservation
+     size if larger than that already.
+
+
+ (*) Request page be read from cache [mandatory]:
+
+       int (*read_or_alloc_page)(struct fscache_retrieval *op,
+                                 struct page *page,
+                                 gfp_t gfp)
+
+     This is called to attempt to read a netfs page from the cache, or to
+     reserve a backing block if not.  FS-Cache will have done as much checking
+     as it can before calling, but most of the work belongs to the backend.
+
+     If there's no page in the cache, then -ENODATA should be returned if the
+     backend managed to reserve a backing block; -ENOBUFS or -ENOMEM if it
+     didn't.
+
+     If there is suitable data in the cache, then a read operation should be
+     queued and 0 returned.  When the read finishes, fscache_end_io() should be
+     called.
+
+     The fscache_mark_pages_cached() should be called for the page if any cache
+     metadata is retained.  This will indicate to the netfs that the page needs
+     explicit uncaching.  This operation takes a pagevec, thus allowing several
+     pages to be marked at once.
+
+     The retrieval record pointed to by op should be retained for each page
+     queued and released when I/O on the page has been formally ended.
+     fscache_get/put_retrieval() are available for this purpose.
+
+     The retrieval record may be used to get CPU time via the FS-Cache thread
+     pool.  If this is desired, the op->op.processor should be set to point to
+     the appropriate processing routine, and fscache_enqueue_retrieval() should
+     be called at an appropriate point to request CPU time.  For instance, the
+     retrieval routine could be enqueued upon the completion of a disk read.
+     The to_do field in the retrieval record is provided to aid in this.
+
+     If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS
+     returned if possible or fscache_end_io() called with a suitable error
+     code..
+
+
+ (*) Request pages be read from cache [mandatory]:
+
+       int (*read_or_alloc_pages)(struct fscache_retrieval *op,
+                                  struct list_head *pages,
+                                  unsigned *nr_pages,
+                                  gfp_t gfp)
+
+     This is like the read_or_alloc_page() method, except it is handed a list
+     of pages instead of one page.  Any pages on which a read operation is
+     started must be added to the page cache for the specified mapping and also
+     to the LRU.  Such pages must also be removed from the pages list and
+     *nr_pages decremented per page.
+
+     If there was an error such as -ENOMEM, then that should be returned; else
+     if one or more pages couldn't be read or allocated, then -ENOBUFS should
+     be returned; else if one or more pages couldn't be read, then -ENODATA
+     should be returned.  If all the pages are dispatched then 0 should be
+     returned.
+
+
+ (*) Request page be allocated in the cache [mandatory]:
+
+       int (*allocate_page)(struct fscache_retrieval *op,
+                            struct page *page,
+                            gfp_t gfp)
+
+     This is like the read_or_alloc_page() method, except that it shouldn't
+     read from the cache, even if there's data there that could be retrieved.
+     It should, however, set up any internal metadata required such that
+     the write_page() method can write to the cache.
+
+     If there's no backing block available, then -ENOBUFS should be returned
+     (or -ENOMEM if there were other problems).  If a block is successfully
+     allocated, then the netfs page should be marked and 0 returned.
+
+
+ (*) Request pages be allocated in the cache [mandatory]:
+
+       int (*allocate_pages)(struct fscache_retrieval *op,
+                             struct list_head *pages,
+                             unsigned *nr_pages,
+                             gfp_t gfp)
+
+     This is an multiple page version of the allocate_page() method.  pages and
+     nr_pages should be treated as for the read_or_alloc_pages() method.
+
+
+ (*) Request page be written to cache [mandatory]:
+
+       int (*write_page)(struct fscache_storage *op,
+                         struct page *page);
+
+     This is called to write from a page on which there was a previously
+     successful read_or_alloc_page() call or similar.  FS-Cache filters out
+     pages that don't have mappings.
+
+     This method is called asynchronously from the FS-Cache thread pool.  It is
+     not required to actually store anything, provided -ENODATA is then
+     returned to the next read of this page.
+
+     If an error occurred, then a negative error code should be returned,
+     otherwise zero should be returned.  FS-Cache will take appropriate action
+     in response to an error, such as withdrawing this object.
+
+     If this method returns success then FS-Cache will inform the netfs
+     appropriately.
+
+
+ (*) Discard retained per-page metadata [mandatory]:
+
+       void (*uncache_page)(struct fscache_object *object, struct page *page)
+
+     This is called when a netfs page is being evicted from the pagecache.  The
+     cache backend should tear down any internal representation or tracking it
+     maintains for this page.
+
+
+==================
+FS-CACHE UTILITIES
+==================
+
+FS-Cache provides some utilities that a cache backend may make use of:
+
+ (*) Note occurrence of an I/O error in a cache:
+
+       void fscache_io_error(struct fscache_cache *cache)
+
+     This tells FS-Cache that an I/O error occurred in the cache.  After this
+     has been called, only resource dissociation operations (object and page
+     release) will be passed from the netfs to the cache backend for the
+     specified cache.
+
+     This does not actually withdraw the cache.  That must be done separately.
+
+
+ (*) Invoke the retrieval I/O completion function:
+
+       void fscache_end_io(struct fscache_retrieval *op, struct page *page,
+                           int error);
+
+     This is called to note the end of an attempt to retrieve a page.  The
+     error value should be 0 if successful and an error otherwise.
+
+
+ (*) Set highest store limit:
+
+       void fscache_set_store_limit(struct fscache_object *object,
+                                    loff_t i_size);
+
+     This sets the limit FS-Cache imposes on the highest byte it's willing to
+     try and store for a netfs.  Any page over this limit is automatically
+     rejected by fscache_read_alloc_page() and co with -ENOBUFS.
+
+
+ (*) Mark pages as being cached:
+
+       void fscache_mark_pages_cached(struct fscache_retrieval *op,
+                                      struct pagevec *pagevec);
+
+     This marks a set of pages as being cached.  After this has been called,
+     the netfs must call fscache_uncache_page() to unmark the pages.
+
+
+ (*) Perform coherency check on an object:
+
+       enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
+                                               const void *data,
+                                               uint16_t datalen);
+
+     This asks the netfs to perform a coherency check on an object that has
+     just been looked up.  The cookie attached to the object will determine the
+     netfs to use.  data and datalen should specify where the auxiliary data
+     retrieved from the cache can be found.
+
+     One of three values will be returned:
+
+       (*) FSCACHE_CHECKAUX_OKAY
+
+           The coherency data indicates the object is valid as is.
+
+       (*) FSCACHE_CHECKAUX_NEEDS_UPDATE
+
+           The coherency data needs updating, but otherwise the object is
+           valid.
+
+       (*) FSCACHE_CHECKAUX_OBSOLETE
+
+           The coherency data indicates that the object is obsolete and should
+           be discarded.
+
+
+ (*) Initialise a freshly allocated object:
+
+       void fscache_object_init(struct fscache_object *object);
+
+     This initialises all the fields in an object representation.
+
+
+ (*) Indicate the destruction of an object:
+
+       void fscache_object_destroyed(struct fscache_cache *cache);
+
+     This must be called to inform FS-Cache that an object that belonged to a
+     cache has been destroyed and deallocated.  This will allow continuation
+     of the cache withdrawal process when it is stopped pending destruction of
+     all the objects.
+
+
+ (*) Indicate negative lookup on an object:
+
+       void fscache_object_lookup_negative(struct fscache_object *object);
+
+     This is called to indicate to FS-Cache that a lookup process for an object
+     found a negative result.
+
+     This changes the state of an object to permit reads pending on lookup
+     completion to go off and start fetching data from the netfs server as it's
+     known at this point that there can't be any data in the cache.
+
+     This may be called multiple times on an object.  Only the first call is
+     significant - all subsequent calls are ignored.
+
+
+ (*) Indicate an object has been obtained:
+
+       void fscache_obtained_object(struct fscache_object *object);
+
+     This is called to indicate to FS-Cache that a lookup process for an object
+     produced a positive result, or that an object was created.  This should
+     only be called once for any particular object.
+
+     This changes the state of an object to indicate:
+
+       (1) if no call to fscache_object_lookup_negative() has been made on
+           this object, that there may be data available, and that reads can
+           now go and look for it; and
+
+        (2) that writes may now proceed against this object.
+
+
+ (*) Indicate that object lookup failed:
+
+       void fscache_object_lookup_error(struct fscache_object *object);
+
+     This marks an object as having encountered a fatal error (usually EIO)
+     and causes it to move into a state whereby it will be withdrawn as soon
+     as possible.
+
+
+ (*) Get and release references on a retrieval record:
+
+       void fscache_get_retrieval(struct fscache_retrieval *op);
+       void fscache_put_retrieval(struct fscache_retrieval *op);
+
+     These two functions are used to retain a retrieval record whilst doing
+     asynchronous data retrieval and block allocation.
+
+
+ (*) Enqueue a retrieval record for processing.
+
+       void fscache_enqueue_retrieval(struct fscache_retrieval *op);
+
+     This enqueues a retrieval record for processing by the FS-Cache thread
+     pool.  One of the threads in the pool will invoke the retrieval record's
+     op->op.processor callback function.  This function may be called from
+     within the callback function.
+
+
+ (*) List of object state names:
+
+       const char *fscache_object_states[];
+
+     For debugging purposes, this may be used to turn the state that an object
+     is in into a text string for display purposes.
diff --git a/Documentation/filesystems/caching/cachefiles.txt b/Documentation/filesystems/caching/cachefiles.txt
new file mode 100644 (file)
index 0000000..c78a49b
--- /dev/null
@@ -0,0 +1,501 @@
+              ===============================================
+              CacheFiles: CACHE ON ALREADY MOUNTED FILESYSTEM
+              ===============================================
+
+Contents:
+
+ (*) Overview.
+
+ (*) Requirements.
+
+ (*) Configuration.
+
+ (*) Starting the cache.
+
+ (*) Things to avoid.
+
+ (*) Cache culling.
+
+ (*) Cache structure.
+
+ (*) Security model and SELinux.
+
+ (*) A note on security.
+
+ (*) Statistical information.
+
+ (*) Debugging.
+
+
+========
+OVERVIEW
+========
+
+CacheFiles is a caching backend that's meant to use as a cache a directory on
+an already mounted filesystem of a local type (such as Ext3).
+
+CacheFiles uses a userspace daemon to do some of the cache management - such as
+reaping stale nodes and culling.  This is called cachefilesd and lives in
+/sbin.
+
+The filesystem and data integrity of the cache are only as good as those of the
+filesystem providing the backing services.  Note that CacheFiles does not
+attempt to journal anything since the journalling interfaces of the various
+filesystems are very specific in nature.
+
+CacheFiles creates a misc character device - "/dev/cachefiles" - that is used
+to communication with the daemon.  Only one thing may have this open at once,
+and whilst it is open, a cache is at least partially in existence.  The daemon
+opens this and sends commands down it to control the cache.
+
+CacheFiles is currently limited to a single cache.
+
+CacheFiles attempts to maintain at least a certain percentage of free space on
+the filesystem, shrinking the cache by culling the objects it contains to make
+space if necessary - see the "Cache Culling" section.  This means it can be
+placed on the same medium as a live set of data, and will expand to make use of
+spare space and automatically contract when the set of data requires more
+space.
+
+
+============
+REQUIREMENTS
+============
+
+The use of CacheFiles and its daemon requires the following features to be
+available in the system and in the cache filesystem:
+
+       - dnotify.
+
+       - extended attributes (xattrs).
+
+       - openat() and friends.
+
+       - bmap() support on files in the filesystem (FIBMAP ioctl).
+
+       - The use of bmap() to detect a partial page at the end of the file.
+
+It is strongly recommended that the "dir_index" option is enabled on Ext3
+filesystems being used as a cache.
+
+
+=============
+CONFIGURATION
+=============
+
+The cache is configured by a script in /etc/cachefilesd.conf.  These commands
+set up cache ready for use.  The following script commands are available:
+
+ (*) brun <N>%
+ (*) bcull <N>%
+ (*) bstop <N>%
+ (*) frun <N>%
+ (*) fcull <N>%
+ (*) fstop <N>%
+
+       Configure the culling limits.  Optional.  See the section on culling
+       The defaults are 7% (run), 5% (cull) and 1% (stop) respectively.
+
+       The commands beginning with a 'b' are file space (block) limits, those
+       beginning with an 'f' are file count limits.
+
+ (*) dir <path>
+
+       Specify the directory containing the root of the cache.  Mandatory.
+
+ (*) tag <name>
+
+       Specify a tag to FS-Cache to use in distinguishing multiple caches.
+       Optional.  The default is "CacheFiles".
+
+ (*) debug <mask>
+
+       Specify a numeric bitmask to control debugging in the kernel module.
+       Optional.  The default is zero (all off).  The following values can be
+       OR'd into the mask to collect various information:
+
+               1       Turn on trace of function entry (_enter() macros)
+               2       Turn on trace of function exit (_leave() macros)
+               4       Turn on trace of internal debug points (_debug())
+
+       This mask can also be set through sysfs, eg:
+
+               echo 5 >/sys/modules/cachefiles/parameters/debug
+
+
+==================
+STARTING THE CACHE
+==================
+
+The cache is started by running the daemon.  The daemon opens the cache device,
+configures the cache and tells it to begin caching.  At that point the cache
+binds to fscache and the cache becomes live.
+
+The daemon is run as follows:
+
+       /sbin/cachefilesd [-d]* [-s] [-n] [-f <configfile>]
+
+The flags are:
+
+ (*) -d
+
+       Increase the debugging level.  This can be specified multiple times and
+       is cumulative with itself.
+
+ (*) -s
+
+       Send messages to stderr instead of syslog.
+
+ (*) -n
+
+       Don't daemonise and go into background.
+
+ (*) -f <configfile>
+
+       Use an alternative configuration file rather than the default one.
+
+
+===============
+THINGS TO AVOID
+===============
+
+Do not mount other things within the cache as this will cause problems.  The
+kernel module contains its own very cut-down path walking facility that ignores
+mountpoints, but the daemon can't avoid them.
+
+Do not create, rename or unlink files and directories in the cache whilst the
+cache is active, as this may cause the state to become uncertain.
+
+Renaming files in the cache might make objects appear to be other objects (the
+filename is part of the lookup key).
+
+Do not change or remove the extended attributes attached to cache files by the
+cache as this will cause the cache state management to get confused.
+
+Do not create files or directories in the cache, lest the cache get confused or
+serve incorrect data.
+
+Do not chmod files in the cache.  The module creates things with minimal
+permissions to prevent random users being able to access them directly.
+
+
+=============
+CACHE CULLING
+=============
+
+The cache may need culling occasionally to make space.  This involves
+discarding objects from the cache that have been used less recently than
+anything else.  Culling is based on the access time of data objects.  Empty
+directories are culled if not in use.
+
+Cache culling is done on the basis of the percentage of blocks and the
+percentage of files available in the underlying filesystem.  There are six
+"limits":
+
+ (*) brun
+ (*) frun
+
+     If the amount of free space and the number of available files in the cache
+     rises above both these limits, then culling is turned off.
+
+ (*) bcull
+ (*) fcull
+
+     If the amount of available space or the number of available files in the
+     cache falls below either of these limits, then culling is started.
+
+ (*) bstop
+ (*) fstop
+
+     If the amount of available space or the number of available files in the
+     cache falls below either of these limits, then no further allocation of
+     disk space or files is permitted until culling has raised things above
+     these limits again.
+
+These must be configured thusly:
+
+       0 <= bstop < bcull < brun < 100
+       0 <= fstop < fcull < frun < 100
+
+Note that these are percentages of available space and available files, and do
+_not_ appear as 100 minus the percentage displayed by the "df" program.
+
+The userspace daemon scans the cache to build up a table of cullable objects.
+These are then culled in least recently used order.  A new scan of the cache is
+started as soon as space is made in the table.  Objects will be skipped if
+their atimes have changed or if the kernel module says it is still using them.
+
+
+===============
+CACHE STRUCTURE
+===============
+
+The CacheFiles module will create two directories in the directory it was
+given:
+
+ (*) cache/
+
+ (*) graveyard/
+
+The active cache objects all reside in the first directory.  The CacheFiles
+kernel module moves any retired or culled objects that it can't simply unlink
+to the graveyard from which the daemon will actually delete them.
+
+The daemon uses dnotify to monitor the graveyard directory, and will delete
+anything that appears therein.
+
+
+The module represents index objects as directories with the filename "I..." or
+"J...".  Note that the "cache/" directory is itself a special index.
+
+Data objects are represented as files if they have no children, or directories
+if they do.  Their filenames all begin "D..." or "E...".  If represented as a
+directory, data objects will have a file in the directory called "data" that
+actually holds the data.
+
+Special objects are similar to data objects, except their filenames begin
+"S..." or "T...".
+
+
+If an object has children, then it will be represented as a directory.
+Immediately in the representative directory are a collection of directories
+named for hash values of the child object keys with an '@' prepended.  Into
+this directory, if possible, will be placed the representations of the child
+objects:
+
+       INDEX     INDEX      INDEX                             DATA FILES
+       ========= ========== ================================= ================
+       cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400
+       cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400/@75/Es0g000w...DB1ry
+       cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400/@75/Es0g000w...N22ry
+       cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400/@75/Es0g000w...FP1ry
+
+
+If the key is so long that it exceeds NAME_MAX with the decorations added on to
+it, then it will be cut into pieces, the first few of which will be used to
+make a nest of directories, and the last one of which will be the objects
+inside the last directory.  The names of the intermediate directories will have
+'+' prepended:
+
+       J1223/@23/+xy...z/+kl...m/Epqr
+
+
+Note that keys are raw data, and not only may they exceed NAME_MAX in size,
+they may also contain things like '/' and NUL characters, and so they may not
+be suitable for turning directly into a filename.
+
+To handle this, CacheFiles will use a suitably printable filename directly and
+"base-64" encode ones that aren't directly suitable.  The two versions of
+object filenames indicate the encoding:
+
+       OBJECT TYPE     PRINTABLE       ENCODED
+       =============== =============== ===============
+       Index           "I..."          "J..."
+       Data            "D..."          "E..."
+       Special         "S..."          "T..."
+
+Intermediate directories are always "@" or "+" as appropriate.
+
+
+Each object in the cache has an extended attribute label that holds the object
+type ID (required to distinguish special objects) and the auxiliary data from
+the netfs.  The latter is used to detect stale objects in the cache and update
+or retire them.
+
+
+Note that CacheFiles will erase from the cache any file it doesn't recognise or
+any file of an incorrect type (such as a FIFO file or a device file).
+
+
+==========================
+SECURITY MODEL AND SELINUX
+==========================
+
+CacheFiles is implemented to deal properly with the LSM security features of
+the Linux kernel and the SELinux facility.
+
+One of the problems that CacheFiles faces is that it is generally acting on
+behalf of a process, and running in that process's context, and that includes a
+security context that is not appropriate for accessing the cache - either
+because the files in the cache are inaccessible to that process, or because if
+the process creates a file in the cache, that file may be inaccessible to other
+processes.
+
+The way CacheFiles works is to temporarily change the security context (fsuid,
+fsgid and actor security label) that the process acts as - without changing the
+security context of the process when it the target of an operation performed by
+some other process (so signalling and suchlike still work correctly).
+
+
+When the CacheFiles module is asked to bind to its cache, it:
+
+ (1) Finds the security label attached to the root cache directory and uses
+     that as the security label with which it will create files.  By default,
+     this is:
+
+       cachefiles_var_t
+
+ (2) Finds the security label of the process which issued the bind request
+     (presumed to be the cachefilesd daemon), which by default will be:
+
+       cachefilesd_t
+
+     and asks LSM to supply a security ID as which it should act given the
+     daemon's label.  By default, this will be:
+
+       cachefiles_kernel_t
+
+     SELinux transitions the daemon's security ID to the module's security ID
+     based on a rule of this form in the policy.
+
+       type_transition <daemon's-ID> kernel_t : process <module's-ID>;
+
+     For instance:
+
+       type_transition cachefilesd_t kernel_t : process cachefiles_kernel_t;
+
+
+The module's security ID gives it permission to create, move and remove files
+and directories in the cache, to find and access directories and files in the
+cache, to set and access extended attributes on cache objects, and to read and
+write files in the cache.
+
+The daemon's security ID gives it only a very restricted set of permissions: it
+may scan directories, stat files and erase files and directories.  It may
+not read or write files in the cache, and so it is precluded from accessing the
+data cached therein; nor is it permitted to create new files in the cache.
+
+
+There are policy source files available in:
+
+       http://people.redhat.com/~dhowells/fscache/cachefilesd-0.8.tar.bz2
+
+and later versions.  In that tarball, see the files:
+
+       cachefilesd.te
+       cachefilesd.fc
+       cachefilesd.if
+
+They are built and installed directly by the RPM.
+
+If a non-RPM based system is being used, then copy the above files to their own
+directory and run:
+
+       make -f /usr/share/selinux/devel/Makefile
+       semodule -i cachefilesd.pp
+
+You will need checkpolicy and selinux-policy-devel installed prior to the
+build.
+
+
+By default, the cache is located in /var/fscache, but if it is desirable that
+it should be elsewhere, than either the above policy files must be altered, or
+an auxiliary policy must be installed to label the alternate location of the
+cache.
+
+For instructions on how to add an auxiliary policy to enable the cache to be
+located elsewhere when SELinux is in enforcing mode, please see:
+
+       /usr/share/doc/cachefilesd-*/move-cache.txt
+
+When the cachefilesd rpm is installed; alternatively, the document can be found
+in the sources.
+
+
+==================
+A NOTE ON SECURITY
+==================
+
+CacheFiles makes use of the split security in the task_struct.  It allocates
+its own task_security structure, and redirects current->act_as to point to it
+when it acts on behalf of another process, in that process's context.
+
+The reason it does this is that it calls vfs_mkdir() and suchlike rather than
+bypassing security and calling inode ops directly.  Therefore the VFS and LSM
+may deny the CacheFiles access to the cache data because under some
+circumstances the caching code is running in the security context of whatever
+process issued the original syscall on the netfs.
+
+Furthermore, should CacheFiles create a file or directory, the security
+parameters with that object is created (UID, GID, security label) would be
+derived from that process that issued the system call, thus potentially
+preventing other processes from accessing the cache - including CacheFiles's
+cache management daemon (cachefilesd).
+
+What is required is to temporarily override the security of the process that
+issued the system call.  We can't, however, just do an in-place change of the
+security data as that affects the process as an object, not just as a subject.
+This means it may lose signals or ptrace events for example, and affects what
+the process looks like in /proc.
+
+So CacheFiles makes use of a logical split in the security between the
+objective security (task->sec) and the subjective security (task->act_as).  The
+objective security holds the intrinsic security properties of a process and is
+never overridden.  This is what appears in /proc, and is what is used when a
+process is the target of an operation by some other process (SIGKILL for
+example).
+
+The subjective security holds the active security properties of a process, and
+may be overridden.  This is not seen externally, and is used whan a process
+acts upon another object, for example SIGKILLing another process or opening a
+file.
+
+LSM hooks exist that allow SELinux (or Smack or whatever) to reject a request
+for CacheFiles to run in a context of a specific security label, or to create
+files and directories with another security label.
+
+
+=======================
+STATISTICAL INFORMATION
+=======================
+
+If FS-Cache is compiled with the following option enabled:
+
+       CONFIG_CACHEFILES_HISTOGRAM=y
+
+then it will gather certain statistics and display them through a proc file.
+
+ (*) /proc/fs/cachefiles/histogram
+
+       cat /proc/fs/cachefiles/histogram
+       JIFS  SECS  LOOKUPS   MKDIRS    CREATES
+       ===== ===== ========= ========= =========
+
+     This shows the breakdown of the number of times each amount of time
+     between 0 jiffies and HZ-1 jiffies a variety of tasks took to run.  The
+     columns are as follows:
+
+       COLUMN          TIME MEASUREMENT
+       =======         =======================================================
+       LOOKUPS         Length of time to perform a lookup on the backing fs
+       MKDIRS          Length of time to perform a mkdir on the backing fs
+       CREATES         Length of time to perform a create on the backing fs
+
+     Each row shows the number of events that took a particular range of times.
+     Each step is 1 jiffy in size.  The JIFS column indicates the particular
+     jiffy range covered, and the SECS field the equivalent number of seconds.
+
+
+=========
+DEBUGGING
+=========
+
+If CONFIG_CACHEFILES_DEBUG is enabled, the CacheFiles facility can have runtime
+debugging enabled by adjusting the value in:
+
+       /sys/module/cachefiles/parameters/debug
+
+This is a bitmask of debugging streams to enable:
+
+       BIT     VALUE   STREAM                          POINT
+       ======= ======= =============================== =======================
+       0       1       General                         Function entry trace
+       1       2                                       Function exit trace
+       2       4                                       General
+
+The appropriate set of values should be OR'd together and the result written to
+the control file.  For example:
+
+       echo $((1|4|8)) >/sys/module/cachefiles/parameters/debug
+
+will turn on all function entry debugging.
diff --git a/Documentation/filesystems/caching/fscache.txt b/Documentation/filesystems/caching/fscache.txt
new file mode 100644 (file)
index 0000000..9e94b94
--- /dev/null
@@ -0,0 +1,333 @@
+                         ==========================
+                         General Filesystem Caching
+                         ==========================
+
+========
+OVERVIEW
+========
+
+This facility is a general purpose cache for network filesystems, though it
+could be used for caching other things such as ISO9660 filesystems too.
+
+FS-Cache mediates between cache backends (such as CacheFS) and network
+filesystems:
+
+       +---------+
+       |         |                        +--------------+
+       |   NFS   |--+                     |              |
+       |         |  |                 +-->|   CacheFS    |
+       +---------+  |   +----------+  |   |  /dev/hda5   |
+                    |   |          |  |   +--------------+
+       +---------+  +-->|          |  |
+       |         |      |          |--+
+       |   AFS   |----->| FS-Cache |
+       |         |      |          |--+
+       +---------+  +-->|          |  |
+                    |   |          |  |   +--------------+
+       +---------+  |   +----------+  |   |              |
+       |         |  |                 +-->|  CacheFiles  |
+       |  ISOFS  |--+                     |  /var/cache  |
+       |         |                        +--------------+
+       +---------+
+
+Or to look at it another way, FS-Cache is a module that provides a caching
+facility to a network filesystem such that the cache is transparent to the
+user:
+
+       +---------+
+       |         |
+       | Server  |
+       |         |
+       +---------+
+            |                  NETWORK
+       ~~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+            |
+            |           +----------+
+            V           |          |
+       +---------+      |          |
+       |         |      |          |
+       |   NFS   |----->| FS-Cache |
+       |         |      |          |--+
+       +---------+      |          |  |   +--------------+   +--------------+
+            |           |          |  |   |              |   |              |
+            V           +----------+  +-->|  CacheFiles  |-->|  Ext3        |
+       +---------+                        |  /var/cache  |   |  /dev/sda6   |
+       |         |                        +--------------+   +--------------+
+       |   VFS   |                                ^                     ^
+       |         |                                |                     |
+       +---------+                                +--------------+      |
+            |                  KERNEL SPACE                      |      |
+       ~~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|~~~~~~|~~~~
+            |                  USER SPACE                        |      |
+            V                                                    |      |
+       +---------+                                           +--------------+
+       |         |                                           |              |
+       | Process |                                           | cachefilesd  |
+       |         |                                           |              |
+       +---------+                                           +--------------+
+
+
+FS-Cache does not follow the idea of completely loading every netfs file
+opened in its entirety into a cache before permitting it to be accessed and
+then serving the pages out of that cache rather than the netfs inode because:
+
+ (1) It must be practical to operate without a cache.
+
+ (2) The size of any accessible file must not be limited to the size of the
+     cache.
+
+ (3) The combined size of all opened files (this includes mapped libraries)
+     must not be limited to the size of the cache.
+
+ (4) The user should not be forced to download an entire file just to do a
+     one-off access of a small portion of it (such as might be done with the
+     "file" program).
+
+It instead serves the cache out in PAGE_SIZE chunks as and when requested by
+the netfs('s) using it.
+
+
+FS-Cache provides the following facilities:
+
+ (1) More than one cache can be used at once.  Caches can be selected
+     explicitly by use of tags.
+
+ (2) Caches can be added / removed at any time.
+
+ (3) The netfs is provided with an interface that allows either party to
+     withdraw caching facilities from a file (required for (2)).
+
+ (4) The interface to the netfs returns as few errors as possible, preferring
+     rather to let the netfs remain oblivious.
+
+ (5) Cookies are used to represent indices, files and other objects to the
+     netfs.  The simplest cookie is just a NULL pointer - indicating nothing
+     cached there.
+
+ (6) The netfs is allowed to propose - dynamically - any index hierarchy it
+     desires, though it must be aware that the index search function is
+     recursive, stack space is limited, and indices can only be children of
+     indices.
+
+ (7) Data I/O is done direct to and from the netfs's pages.  The netfs
+     indicates that page A is at index B of the data-file represented by cookie
+     C, and that it should be read or written.  The cache backend may or may
+     not start I/O on that page, but if it does, a netfs callback will be
+     invoked to indicate completion.  The I/O may be either synchronous or
+     asynchronous.
+
+ (8) Cookies can be "retired" upon release.  At this point FS-Cache will mark
+     them as obsolete and the index hierarchy rooted at that point will get
+     recycled.
+
+ (9) The netfs provides a "match" function for index searches.  In addition to
+     saying whether a match was made or not, this can also specify that an
+     entry should be updated or deleted.
+
+(10) As much as possible is done asynchronously.
+
+
+FS-Cache maintains a virtual indexing tree in which all indices, files, objects
+and pages are kept.  Bits of this tree may actually reside in one or more
+caches.
+
+                                           FSDEF
+                                             |
+                        +------------------------------------+
+                        |                                    |
+                       NFS                                  AFS
+                        |                                    |
+           +--------------------------+                +-----------+
+           |                          |                |           |
+        homedir                     mirror          afs.org   redhat.com
+           |                          |                            |
+     +------------+           +---------------+              +----------+
+     |            |           |               |              |          |
+   00001        00002       00007           00125        vol00001   vol00002
+     |            |           |               |                         |
+ +---+---+     +-----+      +---+      +------+------+            +-----+----+
+ |   |   |     |     |      |   |      |      |      |            |     |    |
+PG0 PG1 PG2   PG0  XATTR   PG0 PG1   DIRENT DIRENT DIRENT        R/W   R/O  Bak
+                     |                                            |
+                    PG0                                       +-------+
+                                                              |       |
+                                                            00001   00003
+                                                              |
+                                                          +---+---+
+                                                          |   |   |
+                                                         PG0 PG1 PG2
+
+In the example above, you can see two netfs's being backed: NFS and AFS.  These
+have different index hierarchies:
+
+ (*) The NFS primary index contains per-server indices.  Each server index is
+     indexed by NFS file handles to get data file objects.  Each data file
+     objects can have an array of pages, but may also have further child
+     objects, such as extended attributes and directory entries.  Extended
+     attribute objects themselves have page-array contents.
+
+ (*) The AFS primary index contains per-cell indices.  Each cell index contains
+     per-logical-volume indices.  Each of volume index contains up to three
+     indices for the read-write, read-only and backup mirrors of those volumes.
+     Each of these contains vnode data file objects, each of which contains an
+     array of pages.
+
+The very top index is the FS-Cache master index in which individual netfs's
+have entries.
+
+Any index object may reside in more than one cache, provided it only has index
+children.  Any index with non-index object children will be assumed to only
+reside in one cache.
+
+
+The netfs API to FS-Cache can be found in:
+
+       Documentation/filesystems/caching/netfs-api.txt
+
+The cache backend API to FS-Cache can be found in:
+
+       Documentation/filesystems/caching/backend-api.txt
+
+A description of the internal representations and object state machine can be
+found in:
+
+       Documentation/filesystems/caching/object.txt
+
+
+=======================
+STATISTICAL INFORMATION
+=======================
+
+If FS-Cache is compiled with the following options enabled:
+
+       CONFIG_FSCACHE_STATS=y
+       CONFIG_FSCACHE_HISTOGRAM=y
+
+then it will gather certain statistics and display them through a number of
+proc files.
+
+ (*) /proc/fs/fscache/stats
+
+     This shows counts of a number of events that can happen in FS-Cache:
+
+       CLASS   EVENT   MEANING
+       ======= ======= =======================================================
+       Cookies idx=N   Number of index cookies allocated
+               dat=N   Number of data storage cookies allocated
+               spc=N   Number of special cookies allocated
+       Objects alc=N   Number of objects allocated
+               nal=N   Number of object allocation failures
+               avl=N   Number of objects that reached the available state
+               ded=N   Number of objects that reached the dead state
+       ChkAux  non=N   Number of objects that didn't have a coherency check
+               ok=N    Number of objects that passed a coherency check
+               upd=N   Number of objects that needed a coherency data update
+               obs=N   Number of objects that were declared obsolete
+       Pages   mrk=N   Number of pages marked as being cached
+               unc=N   Number of uncache page requests seen
+       Acquire n=N     Number of acquire cookie requests seen
+               nul=N   Number of acq reqs given a NULL parent
+               noc=N   Number of acq reqs rejected due to no cache available
+               ok=N    Number of acq reqs succeeded
+               nbf=N   Number of acq reqs rejected due to error
+               oom=N   Number of acq reqs failed on ENOMEM
+       Lookups n=N     Number of lookup calls made on cache backends
+               neg=N   Number of negative lookups made
+               pos=N   Number of positive lookups made
+               crt=N   Number of objects created by lookup
+       Updates n=N     Number of update cookie requests seen
+               nul=N   Number of upd reqs given a NULL parent
+               run=N   Number of upd reqs granted CPU time
+       Relinqs n=N     Number of relinquish cookie requests seen
+               nul=N   Number of rlq reqs given a NULL parent
+               wcr=N   Number of rlq reqs waited on completion of creation
+       AttrChg n=N     Number of attribute changed requests seen
+               ok=N    Number of attr changed requests queued
+               nbf=N   Number of attr changed rejected -ENOBUFS
+               oom=N   Number of attr changed failed -ENOMEM
+               run=N   Number of attr changed ops given CPU time
+       Allocs  n=N     Number of allocation requests seen
+               ok=N    Number of successful alloc reqs
+               wt=N    Number of alloc reqs that waited on lookup completion
+               nbf=N   Number of alloc reqs rejected -ENOBUFS
+               ops=N   Number of alloc reqs submitted
+               owt=N   Number of alloc reqs waited for CPU time
+       Retrvls n=N     Number of retrieval (read) requests seen
+               ok=N    Number of successful retr reqs
+               wt=N    Number of retr reqs that waited on lookup completion
+               nod=N   Number of retr reqs returned -ENODATA
+               nbf=N   Number of retr reqs rejected -ENOBUFS
+               int=N   Number of retr reqs aborted -ERESTARTSYS
+               oom=N   Number of retr reqs failed -ENOMEM
+               ops=N   Number of retr reqs submitted
+               owt=N   Number of retr reqs waited for CPU time
+       Stores  n=N     Number of storage (write) requests seen
+               ok=N    Number of successful store reqs
+               agn=N   Number of store reqs on a page already pending storage
+               nbf=N   Number of store reqs rejected -ENOBUFS
+               oom=N   Number of store reqs failed -ENOMEM
+               ops=N   Number of store reqs submitted
+               run=N   Number of store reqs granted CPU time
+       Ops     pend=N  Number of times async ops added to pending queues
+               run=N   Number of times async ops given CPU time
+               enq=N   Number of times async ops queued for processing
+               dfr=N   Number of async ops queued for deferred release
+               rel=N   Number of async ops released
+               gc=N    Number of deferred-release async ops garbage collected
+
+
+ (*) /proc/fs/fscache/histogram
+
+       cat /proc/fs/fscache/histogram
+       JIFS  SECS  OBJ INST  OP RUNS   OBJ RUNS  RETRV DLY RETRIEVLS
+       ===== ===== ========= ========= ========= ========= =========
+
+     This shows the breakdown of the number of times each amount of time
+     between 0 jiffies and HZ-1 jiffies a variety of tasks took to run.  The
+     columns are as follows:
+
+       COLUMN          TIME MEASUREMENT
+       =======         =======================================================
+       OBJ INST        Length of time to instantiate an object
+       OP RUNS         Length of time a call to process an operation took
+       OBJ RUNS        Length of time a call to process an object event took
+       RETRV DLY       Time between an requesting a read and lookup completing
+       RETRIEVLS       Time between beginning and end of a retrieval
+
+     Each row shows the number of events that took a particular range of times.
+     Each step is 1 jiffy in size.  The JIFS column indicates the particular
+     jiffy range covered, and the SECS field the equivalent number of seconds.
+
+
+=========
+DEBUGGING
+=========
+
+If CONFIG_FSCACHE_DEBUG is enabled, the FS-Cache facility can have runtime
+debugging enabled by adjusting the value in:
+
+       /sys/module/fscache/parameters/debug
+
+This is a bitmask of debugging streams to enable:
+
+       BIT     VALUE   STREAM                          POINT
+       ======= ======= =============================== =======================
+       0       1       Cache management                Function entry trace
+       1       2                                       Function exit trace
+       2       4                                       General
+       3       8       Cookie management               Function entry trace
+       4       16                                      Function exit trace
+       5       32                                      General
+       6       64      Page handling                   Function entry trace
+       7       128                                     Function exit trace
+       8       256                                     General
+       9       512     Operation management            Function entry trace
+       10      1024                                    Function exit trace
+       11      2048                                    General
+
+The appropriate set of values should be OR'd together and the result written to
+the control file.  For example:
+
+       echo $((1|8|64)) >/sys/module/fscache/parameters/debug
+
+will turn on all function entry debugging.
diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt
new file mode 100644 (file)
index 0000000..4db125b
--- /dev/null
@@ -0,0 +1,778 @@
+                       ===============================
+                       FS-CACHE NETWORK FILESYSTEM API
+                       ===============================
+
+There's an API by which a network filesystem can make use of the FS-Cache
+facilities.  This is based around a number of principles:
+
+ (1) Caches can store a number of different object types.  There are two main
+     object types: indices and files.  The first is a special type used by
+     FS-Cache to make finding objects faster and to make retiring of groups of
+     objects easier.
+
+ (2) Every index, file or other object is represented by a cookie.  This cookie
+     may or may not have anything associated with it, but the netfs doesn't
+     need to care.
+
+ (3) Barring the top-level index (one entry per cached netfs), the index
+     hierarchy for each netfs is structured according the whim of the netfs.
+
+This API is declared in <linux/fscache.h>.
+
+This document contains the following sections:
+
+        (1) Network filesystem definition
+        (2) Index definition
+        (3) Object definition
+        (4) Network filesystem (un)registration
+        (5) Cache tag lookup
+        (6) Index registration
+        (7) Data file registration
+        (8) Miscellaneous object registration
+        (9) Setting the data file size
+       (10) Page alloc/read/write
+       (11) Page uncaching
+       (12) Index and data file update
+       (13) Miscellaneous cookie operations
+       (14) Cookie unregistration
+       (15) Index and data file invalidation
+       (16) FS-Cache specific page flags.
+
+
+=============================
+NETWORK FILESYSTEM DEFINITION
+=============================
+
+FS-Cache needs a description of the network filesystem.  This is specified
+using a record of the following structure:
+
+       struct fscache_netfs {
+               uint32_t                        version;
+               const char                      *name;
+               struct fscache_cookie           *primary_index;
+               ...
+       };
+
+This first two fields should be filled in before registration, and the third
+will be filled in by the registration function; any other fields should just be
+ignored and are for internal use only.
+
+The fields are:
+
+ (1) The name of the netfs (used as the key in the toplevel index).
+
+ (2) The version of the netfs (if the name matches but the version doesn't, the
+     entire in-cache hierarchy for this netfs will be scrapped and begun
+     afresh).
+
+ (3) The cookie representing the primary index will be allocated according to
+     another parameter passed into the registration function.
+
+For example, kAFS (linux/fs/afs/) uses the following definitions to describe
+itself:
+
+       struct fscache_netfs afs_cache_netfs = {
+               .version        = 0,
+               .name           = "afs",
+       };
+
+
+================
+INDEX DEFINITION
+================
+
+Indices are used for two purposes:
+
+ (1) To aid the finding of a file based on a series of keys (such as AFS's
+     "cell", "volume ID", "vnode ID").
+
+ (2) To make it easier to discard a subset of all the files cached based around
+     a particular key - for instance to mirror the removal of an AFS volume.
+
+However, since it's unlikely that any two netfs's are going to want to define
+their index hierarchies in quite the same way, FS-Cache tries to impose as few
+restraints as possible on how an index is structured and where it is placed in
+the tree.  The netfs can even mix indices and data files at the same level, but
+it's not recommended.
+
+Each index entry consists of a key of indeterminate length plus some auxilliary
+data, also of indeterminate length.
+
+There are some limits on indices:
+
+ (1) Any index containing non-index objects should be restricted to a single
+     cache.  Any such objects created within an index will be created in the
+     first cache only.  The cache in which an index is created can be
+     controlled by cache tags (see below).
+
+ (2) The entry data must be atomically journallable, so it is limited to about
+     400 bytes at present.  At least 400 bytes will be available.
+
+ (3) The depth of the index tree should be judged with care as the search
+     function is recursive.  Too many layers will run the kernel out of stack.
+
+
+=================
+OBJECT DEFINITION
+=================
+
+To define an object, a structure of the following type should be filled out:
+
+       struct fscache_cookie_def
+       {
+               uint8_t name[16];
+               uint8_t type;
+
+               struct fscache_cache_tag *(*select_cache)(
+                       const void *parent_netfs_data,
+                       const void *cookie_netfs_data);
+
+               uint16_t (*get_key)(const void *cookie_netfs_data,
+                                   void *buffer,
+                                   uint16_t bufmax);
+
+               void (*get_attr)(const void *cookie_netfs_data,
+                                uint64_t *size);
+
+               uint16_t (*get_aux)(const void *cookie_netfs_data,
+                                   void *buffer,
+                                   uint16_t bufmax);
+
+               enum fscache_checkaux (*check_aux)(void *cookie_netfs_data,
+                                                  const void *data,
+                                                  uint16_t datalen);
+
+               void (*get_context)(void *cookie_netfs_data, void *context);
+
+               void (*put_context)(void *cookie_netfs_data, void *context);
+
+               void (*mark_pages_cached)(void *cookie_netfs_data,
+                                         struct address_space *mapping,
+                                         struct pagevec *cached_pvec);
+
+               void (*now_uncached)(void *cookie_netfs_data);
+       };
+
+This has the following fields:
+
+ (1) The type of the object [mandatory].
+
+     This is one of the following values:
+
+       (*) FSCACHE_COOKIE_TYPE_INDEX
+
+           This defines an index, which is a special FS-Cache type.
+
+       (*) FSCACHE_COOKIE_TYPE_DATAFILE
+
+           This defines an ordinary data file.
+
+       (*) Any other value between 2 and 255
+
+           This defines an extraordinary object such as an XATTR.
+
+ (2) The name of the object type (NUL terminated unless all 16 chars are used)
+     [optional].
+
+ (3) A function to select the cache in which to store an index [optional].
+
+     This function is invoked when an index needs to be instantiated in a cache
+     during the instantiation of a non-index object.  Only the immediate index
+     parent for the non-index object will be queried.  Any indices above that
+     in the hierarchy may be stored in multiple caches.  This function does not
+     need to be supplied for any non-index object or any index that will only
+     have index children.
+
+     If this function is not supplied or if it returns NULL then the first
+     cache in the parent's list will be chosed, or failing that, the first
+     cache in the master list.
+
+ (4) A function to retrieve an object's key from the netfs [mandatory].
+
+     This function will be called with the netfs data that was passed to the
+     cookie acquisition function and the maximum length of key data that it may
+     provide.  It should write the required key data into the given buffer and
+     return the quantity it wrote.
+
+ (5) A function to retrieve attribute data from the netfs [optional].
+
+     This function will be called with the netfs data that was passed to the
+     cookie acquisition function.  It should return the size of the file if
+     this is a data file.  The size may be used to govern how much cache must
+     be reserved for this file in the cache.
+
+     If the function is absent, a file size of 0 is assumed.
+
+ (6) A function to retrieve auxilliary data from the netfs [optional].
+
+     This function will be called with the netfs data that was passed to the
+     cookie acquisition function and the maximum length of auxilliary data that
+     it may provide.  It should write the auxilliary data into the given buffer
+     and return the quantity it wrote.
+
+     If this function is absent, the auxilliary data length will be set to 0.
+
+     The length of the auxilliary data buffer may be dependent on the key
+     length.  A netfs mustn't rely on being able to provide more than 400 bytes
+     for both.
+
+ (7) A function to check the auxilliary data [optional].
+
+     This function will be called to check that a match found in the cache for
+     this object is valid.  For instance with AFS it could check the auxilliary
+     data against the data version number returned by the server to determine
+     whether the index entry in a cache is still valid.
+
+     If this function is absent, it will be assumed that matching objects in a
+     cache are always valid.
+
+     If present, the function should return one of the following values:
+
+       (*) FSCACHE_CHECKAUX_OKAY               - the entry is okay as is
+       (*) FSCACHE_CHECKAUX_NEEDS_UPDATE       - the entry requires update
+       (*) FSCACHE_CHECKAUX_OBSOLETE           - the entry should be deleted
+
+     This function can also be used to extract data from the auxilliary data in
+     the cache and copy it into the netfs's structures.
+
+ (8) A pair of functions to manage contexts for the completion callback
+     [optional].
+
+     The cache read/write functions are passed a context which is then passed
+     to the I/O completion callback function.  To ensure this context remains
+     valid until after the I/O completion is called, two functions may be
+     provided: one to get an extra reference on the context, and one to drop a
+     reference to it.
+
+     If the context is not used or is a type of object that won't go out of
+     scope, then these functions are not required.  These functions are not
+     required for indices as indices may not contain data.  These functions may
+     be called in interrupt context and so may not sleep.
+
+ (9) A function to mark a page as retaining cache metadata [optional].
+
+     This is called by the cache to indicate that it is retaining in-memory
+     information for this page and that the netfs should uncache the page when
+     it has finished.  This does not indicate whether there's data on the disk
+     or not.  Note that several pages at once may be presented for marking.
+
+     The PG_fscache bit is set on the pages before this function would be
+     called, so the function need not be provided if this is sufficient.
+
+     This function is not required for indices as they're not permitted data.
+
+(10) A function to unmark all the pages retaining cache metadata [mandatory].
+
+     This is called by FS-Cache to indicate that a backing store is being
+     unbound from a cookie and that all the marks on the pages should be
+     cleared to prevent confusion.  Note that the cache will have torn down all
+     its tracking information so that the pages don't need to be explicitly
+     uncached.
+
+     This function is not required for indices as they're not permitted data.
+
+
+===================================
+NETWORK FILESYSTEM (UN)REGISTRATION
+===================================
+
+The first step is to declare the network filesystem to the cache.  This also
+involves specifying the layout of the primary index (for AFS, this would be the
+"cell" level).
+
+The registration function is:
+
+       int fscache_register_netfs(struct fscache_netfs *netfs);
+
+It just takes a pointer to the netfs definition.  It returns 0 or an error as
+appropriate.
+
+For kAFS, registration is done as follows:
+
+       ret = fscache_register_netfs(&afs_cache_netfs);
+
+The last step is, of course, unregistration:
+
+       void fscache_unregister_netfs(struct fscache_netfs *netfs);
+
+
+================
+CACHE TAG LOOKUP
+================
+
+FS-Cache permits the use of more than one cache.  To permit particular index
+subtrees to be bound to particular caches, the second step is to look up cache
+representation tags.  This step is optional; it can be left entirely up to
+FS-Cache as to which cache should be used.  The problem with doing that is that
+FS-Cache will always pick the first cache that was registered.
+
+To get the representation for a named tag:
+
+       struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name);
+
+This takes a text string as the name and returns a representation of a tag.  It
+will never return an error.  It may return a dummy tag, however, if it runs out
+of memory; this will inhibit caching with this tag.
+
+Any representation so obtained must be released by passing it to this function:
+
+       void fscache_release_cache_tag(struct fscache_cache_tag *tag);
+
+The tag will be retrieved by FS-Cache when it calls the object definition
+operation select_cache().
+
+
+==================
+INDEX REGISTRATION
+==================
+
+The third step is to inform FS-Cache about part of an index hierarchy that can
+be used to locate files.  This is done by requesting a cookie for each index in
+the path to the file:
+
+       struct fscache_cookie *
+       fscache_acquire_cookie(struct fscache_cookie *parent,
+                              const struct fscache_object_def *def,
+                              void *netfs_data);
+
+This function creates an index entry in the index represented by parent,
+filling in the index entry by calling the operations pointed to by def.
+
+Note that this function never returns an error - all errors are handled
+internally.  It may, however, return NULL to indicate no cookie.  It is quite
+acceptable to pass this token back to this function as the parent to another
+acquisition (or even to the relinquish cookie, read page and write page
+functions - see below).
+
+Note also that no indices are actually created in a cache until a non-index
+object needs to be created somewhere down the hierarchy.  Furthermore, an index
+may be created in several different caches independently at different times.
+This is all handled transparently, and the netfs doesn't see any of it.
+
+For example, with AFS, a cell would be added to the primary index.  This index
+entry would have a dependent inode containing a volume location index for the
+volume mappings within this cell:
+
+       cell->cache =
+               fscache_acquire_cookie(afs_cache_netfs.primary_index,
+                                      &afs_cell_cache_index_def,
+                                      cell);
+
+Then when a volume location was accessed, it would be entered into the cell's
+index and an inode would be allocated that acts as a volume type and hash chain
+combination:
+
+       vlocation->cache =
+               fscache_acquire_cookie(cell->cache,
+                                      &afs_vlocation_cache_index_def,
+                                      vlocation);
+
+And then a particular flavour of volume (R/O for example) could be added to
+that index, creating another index for vnodes (AFS inode equivalents):
+
+       volume->cache =
+               fscache_acquire_cookie(vlocation->cache,
+                                      &afs_volume_cache_index_def,
+                                      volume);
+
+
+======================
+DATA FILE REGISTRATION
+======================
+
+The fourth step is to request a data file be created in the cache.  This is
+identical to index cookie acquisition.  The only difference is that the type in
+the object definition should be something other than index type.
+
+       vnode->cache =
+               fscache_acquire_cookie(volume->cache,
+                                      &afs_vnode_cache_object_def,
+                                      vnode);
+
+
+=================================
+MISCELLANEOUS OBJECT REGISTRATION
+=================================
+
+An optional step is to request an object of miscellaneous type be created in
+the cache.  This is almost identical to index cookie acquisition.  The only
+difference is that the type in the object definition should be something other
+than index type.  Whilst the parent object could be an index, it's more likely
+it would be some other type of object such as a data file.
+
+       xattr->cache =
+               fscache_acquire_cookie(vnode->cache,
+                                      &afs_xattr_cache_object_def,
+                                      xattr);
+
+Miscellaneous objects might be used to store extended attributes or directory
+entries for example.
+
+
+==========================
+SETTING THE DATA FILE SIZE
+==========================
+
+The fifth step is to set the physical attributes of the file, such as its size.
+This doesn't automatically reserve any space in the cache, but permits the
+cache to adjust its metadata for data tracking appropriately:
+
+       int fscache_attr_changed(struct fscache_cookie *cookie);
+
+The cache will return -ENOBUFS if there is no backing cache or if there is no
+space to allocate any extra metadata required in the cache.  The attributes
+will be accessed with the get_attr() cookie definition operation.
+
+Note that attempts to read or write data pages in the cache over this size may
+be rebuffed with -ENOBUFS.
+
+This operation schedules an attribute adjustment to happen asynchronously at
+some point in the future, and as such, it may happen after the function returns
+to the caller.  The attribute adjustment excludes read and write operations.
+
+
+=====================
+PAGE READ/ALLOC/WRITE
+=====================
+
+And the sixth step is to store and retrieve pages in the cache.  There are
+three functions that are used to do this.
+
+Note:
+
+ (1) A page should not be re-read or re-allocated without uncaching it first.
+
+ (2) A read or allocated page must be uncached when the netfs page is released
+     from the pagecache.
+
+ (3) A page should only be written to the cache if previous read or allocated.
+
+This permits the cache to maintain its page tracking in proper order.
+
+
+PAGE READ
+---------
+
+Firstly, the netfs should ask FS-Cache to examine the caches and read the
+contents cached for a particular page of a particular file if present, or else
+allocate space to store the contents if not:
+
+       typedef
+       void (*fscache_rw_complete_t)(struct page *page,
+                                     void *context,
+                                     int error);
+
+       int fscache_read_or_alloc_page(struct fscache_cookie *cookie,
+                                      struct page *page,
+                                      fscache_rw_complete_t end_io_func,
+                                      void *context,
+                                      gfp_t gfp);
+
+The cookie argument must specify a cookie for an object that isn't an index,
+the page specified will have the data loaded into it (and is also used to
+specify the page number), and the gfp argument is used to control how any
+memory allocations made are satisfied.
+
+If the cookie indicates the inode is not cached:
+
+ (1) The function will return -ENOBUFS.
+
+Else if there's a copy of the page resident in the cache:
+
+ (1) The mark_pages_cached() cookie operation will be called on that page.
+
+ (2) The function will submit a request to read the data from the cache's
+     backing device directly into the page specified.
+
+ (3) The function will return 0.
+
+ (4) When the read is complete, end_io_func() will be invoked with:
+
+     (*) The netfs data supplied when the cookie was created.
+
+     (*) The page descriptor.
+
+     (*) The context argument passed to the above function.  This will be
+         maintained with the get_context/put_context functions mentioned above.
+
+     (*) An argument that's 0 on success or negative for an error code.
+
+     If an error occurs, it should be assumed that the page contains no usable
+     data.
+
+     end_io_func() will be called in process context if the read is results in
+     an error, but it might be called in interrupt context if the read is
+     successful.
+
+Otherwise, if there's not a copy available in cache, but the cache may be able
+to store the page:
+
+ (1) The mark_pages_cached() cookie operation will be called on that page.
+
+ (2) A block may be reserved in the cache and attached to the object at the
+     appropriate place.
+
+ (3) The function will return -ENODATA.
+
+This function may also return -ENOMEM or -EINTR, in which case it won't have
+read any data from the cache.
+
+
+PAGE ALLOCATE
+-------------
+
+Alternatively, if there's not expected to be any data in the cache for a page
+because the file has been extended, a block can simply be allocated instead:
+
+       int fscache_alloc_page(struct fscache_cookie *cookie,
+                              struct page *page,
+                              gfp_t gfp);
+
+This is similar to the fscache_read_or_alloc_page() function, except that it
+never reads from the cache.  It will return 0 if a block has been allocated,
+rather than -ENODATA as the other would.  One or the other must be performed
+before writing to the cache.
+
+The mark_pages_cached() cookie operation will be called on the page if
+successful.
+
+
+PAGE WRITE
+----------
+
+Secondly, if the netfs changes the contents of the page (either due to an
+initial download or if a user performs a write), then the page should be
+written back to the cache:
+
+       int fscache_write_page(struct fscache_cookie *cookie,
+                              struct page *page,
+                              gfp_t gfp);
+
+The cookie argument must specify a data file cookie, the page specified should
+contain the data to be written (and is also used to specify the page number),
+and the gfp argument is used to control how any memory allocations made are
+satisfied.
+
+The page must have first been read or allocated successfully and must not have
+been uncached before writing is performed.
+
+If the cookie indicates the inode is not cached then:
+
+ (1) The function will return -ENOBUFS.
+
+Else if space can be allocated in the cache to hold this page:
+
+ (1) PG_fscache_write will be set on the page.
+
+ (2) The function will submit a request to write the data to cache's backing
+     device directly from the page specified.
+
+ (3) The function will return 0.
+
+ (4) When the write is complete PG_fscache_write is cleared on the page and
+     anyone waiting for that bit will be woken up.
+
+Else if there's no space available in the cache, -ENOBUFS will be returned.  It
+is also possible for the PG_fscache_write bit to be cleared when no write took
+place if unforeseen circumstances arose (such as a disk error).
+
+Writing takes place asynchronously.
+
+
+MULTIPLE PAGE READ
+------------------
+
+A facility is provided to read several pages at once, as requested by the
+readpages() address space operation:
+
+       int fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
+                                       struct address_space *mapping,
+                                       struct list_head *pages,
+                                       int *nr_pages,
+                                       fscache_rw_complete_t end_io_func,
+                                       void *context,
+                                       gfp_t gfp);
+
+This works in a similar way to fscache_read_or_alloc_page(), except:
+
+ (1) Any page it can retrieve data for is removed from pages and nr_pages and
+     dispatched for reading to the disk.  Reads of adjacent pages on disk may
+     be merged for greater efficiency.
+
+ (2) The mark_pages_cached() cookie operation will be called on several pages
+     at once if they're being read or allocated.
+
+ (3) If there was an general error, then that error will be returned.
+
+     Else if some pages couldn't be allocated or read, then -ENOBUFS will be
+     returned.
+
+     Else if some pages couldn't be read but were allocated, then -ENODATA will
+     be returned.
+
+     Otherwise, if all pages had reads dispatched, then 0 will be returned, the
+     list will be empty and *nr_pages will be 0.
+
+ (4) end_io_func will be called once for each page being read as the reads
+     complete.  It will be called in process context if error != 0, but it may
+     be called in interrupt context if there is no error.
+
+Note that a return of -ENODATA, -ENOBUFS or any other error does not preclude
+some of the pages being read and some being allocated.  Those pages will have
+been marked appropriately and will need uncaching.
+
+
+==============
+PAGE UNCACHING
+==============
+
+To uncache a page, this function should be called:
+
+       void fscache_uncache_page(struct fscache_cookie *cookie,
+                                 struct page *page);
+
+This function permits the cache to release any in-memory representation it
+might be holding for this netfs page.  This function must be called once for
+each page on which the read or write page functions above have been called to
+make sure the cache's in-memory tracking information gets torn down.
+
+Note that pages can't be explicitly deleted from the a data file.  The whole
+data file must be retired (see the relinquish cookie function below).
+
+Furthermore, note that this does not cancel the asynchronous read or write
+operation started by the read/alloc and write functions, so the page
+invalidation and release functions must use:
+
+       bool fscache_check_page_write(struct fscache_cookie *cookie,
+                                     struct page *page);
+
+to see if a page is being written to the cache, and:
+
+       void fscache_wait_on_page_write(struct fscache_cookie *cookie,
+                                       struct page *page);
+
+to wait for it to finish if it is.
+
+
+==========================
+INDEX AND DATA FILE UPDATE
+==========================
+
+To request an update of the index data for an index or other object, the
+following function should be called:
+
+       void fscache_update_cookie(struct fscache_cookie *cookie);
+
+This function will refer back to the netfs_data pointer stored in the cookie by
+the acquisition function to obtain the data to write into each revised index
+entry.  The update method in the parent index definition will be called to
+transfer the data.
+
+Note that partial updates may happen automatically at other times, such as when
+data blocks are added to a data file object.
+
+
+===============================
+MISCELLANEOUS COOKIE OPERATIONS
+===============================
+
+There are a number of operations that can be used to control cookies:
+
+ (*) Cookie pinning:
+
+       int fscache_pin_cookie(struct fscache_cookie *cookie);
+       void fscache_unpin_cookie(struct fscache_cookie *cookie);
+
+     These operations permit data cookies to be pinned into the cache and to
+     have the pinning removed.  They are not permitted on index cookies.
+
+     The pinning function will return 0 if successful, -ENOBUFS in the cookie
+     isn't backed by a cache, -EOPNOTSUPP if the cache doesn't support pinning,
+     -ENOSPC if there isn't enough space to honour the operation, -ENOMEM or
+     -EIO if there's any other problem.
+
+ (*) Data space reservation:
+
+       int fscache_reserve_space(struct fscache_cookie *cookie, loff_t size);
+
+     This permits a netfs to request cache space be reserved to store up to the
+     given amount of a file.  It is permitted to ask for more than the current
+     size of the file to allow for future file expansion.
+
+     If size is given as zero then the reservation will be cancelled.
+
+     The function will return 0 if successful, -ENOBUFS in the cookie isn't
+     backed by a cache, -EOPNOTSUPP if the cache doesn't support reservations,
+     -ENOSPC if there isn't enough space to honour the operation, -ENOMEM or
+     -EIO if there's any other problem.
+
+     Note that this doesn't pin an object in a cache; it can still be culled to
+     make space if it's not in use.
+
+
+=====================
+COOKIE UNREGISTRATION
+=====================
+
+To get rid of a cookie, this function should be called.
+
+       void fscache_relinquish_cookie(struct fscache_cookie *cookie,
+                                      int retire);
+
+If retire is non-zero, then the object will be marked for recycling, and all
+copies of it will be removed from all active caches in which it is present.
+Not only that but all child objects will also be retired.
+
+If retire is zero, then the object may be available again when next the
+acquisition function is called.  Retirement here will overrule the pinning on a
+cookie.
+
+One very important note - relinquish must NOT be called for a cookie unless all
+the cookies for "child" indices, objects and pages have been relinquished
+first.
+
+
+================================
+INDEX AND DATA FILE INVALIDATION
+================================
+
+There is no direct way to invalidate an index subtree or a data file.  To do
+this, the caller should relinquish and retire the cookie they have, and then
+acquire a new one.
+
+
+===========================
+FS-CACHE SPECIFIC PAGE FLAG
+===========================
+
+FS-Cache makes use of a page flag, PG_private_2, for its own purpose.  This is
+given the alternative name PG_fscache.
+
+PG_fscache is used to indicate that the page is known by the cache, and that
+the cache must be informed if the page is going to go away.  It's an indication
+to the netfs that the cache has an interest in this page, where an interest may
+be a pointer to it, resources allocated or reserved for it, or I/O in progress
+upon it.
+
+The netfs can use this information in methods such as releasepage() to
+determine whether it needs to uncache a page or update it.
+
+Furthermore, if this bit is set, releasepage() and invalidatepage() operations
+will be called on a page to get rid of it, even if PG_private is not set.  This
+allows caching to attempted on a page before read_cache_pages() to be called
+after fscache_read_or_alloc_pages() as the former will try and release pages it
+was given under certain circumstances.
+
+This bit does not overlap with such as PG_private.  This means that FS-Cache
+can be used with a filesystem that uses the block buffering code.
+
+There are a number of operations defined on this flag:
+
+       int PageFsCache(struct page *page);
+       void SetPageFsCache(struct page *page)
+       void ClearPageFsCache(struct page *page)
+       int TestSetPageFsCache(struct page *page)
+       int TestClearPageFsCache(struct page *page)
+
+These functions are bit test, bit set, bit clear, bit test and set and bit
+test and clear operations on PG_fscache.
diff --git a/Documentation/filesystems/caching/object.txt b/Documentation/filesystems/caching/object.txt
new file mode 100644 (file)
index 0000000..e8b0a35
--- /dev/null
@@ -0,0 +1,313 @@
+            ====================================================
+            IN-KERNEL CACHE OBJECT REPRESENTATION AND MANAGEMENT
+            ====================================================
+
+By: David Howells <dhowells@redhat.com>
+
+Contents:
+
+ (*) Representation
+
+ (*) Object management state machine.
+
+     - Provision of cpu time.
+     - Locking simplification.
+
+ (*) The set of states.
+
+ (*) The set of events.
+
+
+==============
+REPRESENTATION
+==============
+
+FS-Cache maintains an in-kernel representation of each object that a netfs is
+currently interested in.  Such objects are represented by the fscache_cookie
+struct and are referred to as cookies.
+
+FS-Cache also maintains a separate in-kernel representation of the objects that
+a cache backend is currently actively caching.  Such objects are represented by
+the fscache_object struct.  The cache backends allocate these upon request, and
+are expected to embed them in their own representations.  These are referred to
+as objects.
+
+There is a 1:N relationship between cookies and objects.  A cookie may be
+represented by multiple objects - an index may exist in more than one cache -
+or even by no objects (it may not be cached).
+
+Furthermore, both cookies and objects are hierarchical.  The two hierarchies
+correspond, but the cookies tree is a superset of the union of the object trees
+of multiple caches:
+
+           NETFS INDEX TREE               :      CACHE 1     :      CACHE 2
+                                          :                  :
+                                          :   +-----------+  :
+                                 +----------->|  IObject  |  :
+             +-----------+       |        :   +-----------+  :
+             |  ICookie  |-------+        :         |        :
+             +-----------+       |        :         |        :   +-----------+
+                   |             +------------------------------>|  IObject  |
+                   |                      :         |        :   +-----------+
+                   |                      :         V        :         |
+                   |                      :   +-----------+  :         |
+                   V             +----------->|  IObject  |  :         |
+             +-----------+       |        :   +-----------+  :         |
+             |  ICookie  |-------+        :         |        :         V
+             +-----------+       |        :         |        :   +-----------+
+                   |             +------------------------------>|  IObject  |
+             +-----+-----+                :         |        :   +-----------+
+             |           |                :         |        :         |
+             V           |                :         V        :         |
+       +-----------+     |                :   +-----------+  :         |
+       |  ICookie  |------------------------->|  IObject  |  :         |
+       +-----------+     |                :   +-----------+  :         |
+             |           V                :         |        :         V
+             |     +-----------+          :         |        :   +-----------+
+             |     |  ICookie  |-------------------------------->|  IObject  |
+             |     +-----------+          :         |        :   +-----------+
+             V           |                :         V        :         |
+       +-----------+     |                :   +-----------+  :         |
+       |  DCookie  |------------------------->|  DObject  |  :         |
+       +-----------+     |                :   +-----------+  :         |
+                         |                :                  :         |
+                 +-------+-------+        :                  :         |
+                 |               |        :                  :         |
+                 V               V        :                  :         V
+           +-----------+   +-----------+  :                  :   +-----------+
+           |  DCookie  |   |  DCookie  |------------------------>|  DObject  |
+           +-----------+   +-----------+  :                  :   +-----------+
+                                          :                  :
+
+In the above illustration, ICookie and IObject represent indices and DCookie
+and DObject represent data storage objects.  Indices may have representation in
+multiple caches, but currently, non-index objects may not.  Objects of any type
+may also be entirely unrepresented.
+
+As far as the netfs API goes, the netfs is only actually permitted to see
+pointers to the cookies.  The cookies themselves and any objects attached to
+those cookies are hidden from it.
+
+
+===============================
+OBJECT MANAGEMENT STATE MACHINE
+===============================
+
+Within FS-Cache, each active object is managed by its own individual state
+machine.  The state for an object is kept in the fscache_object struct, in
+object->state.  A cookie may point to a set of objects that are in different
+states.
+
+Each state has an action associated with it that is invoked when the machine
+wakes up in that state.  There are four logical sets of states:
+
+ (1) Preparation: states that wait for the parent objects to become ready.  The
+     representations are hierarchical, and it is expected that an object must
+     be created or accessed with respect to its parent object.
+
+ (2) Initialisation: states that perform lookups in the cache and validate
+     what's found and that create on disk any missing metadata.
+
+ (3) Normal running: states that allow netfs operations on objects to proceed
+     and that update the state of objects.
+
+ (4) Termination: states that detach objects from their netfs cookies, that
+     delete objects from disk, that handle disk and system errors and that free
+     up in-memory resources.
+
+
+In most cases, transitioning between states is in response to signalled events.
+When a state has finished processing, it will usually set the mask of events in
+which it is interested (object->event_mask) and relinquish the worker thread.
+Then when an event is raised (by calling fscache_raise_event()), if the event
+is not masked, the object will be queued for processing (by calling
+fscache_enqueue_object()).
+
+
+PROVISION OF CPU TIME
+---------------------
+
+The work to be done by the various states is given CPU time by the threads of
+the slow work facility (see Documentation/slow-work.txt).  This is used in
+preference to the workqueue facility because:
+
+ (1) Threads may be completely occupied for very long periods of time by a
+     particular work item.  These state actions may be doing sequences of
+     synchronous, journalled disk accesses (lookup, mkdir, create, setxattr,
+     getxattr, truncate, unlink, rmdir, rename).
+
+ (2) Threads may do little actual work, but may rather spend a lot of time
+     sleeping on I/O.  This means that single-threaded and 1-per-CPU-threaded
+     workqueues don't necessarily have the right numbers of threads.
+
+
+LOCKING SIMPLIFICATION
+----------------------
+
+Because only one worker thread may be operating on any particular object's
+state machine at once, this simplifies the locking, particularly with respect
+to disconnecting the netfs's representation of a cache object (fscache_cookie)
+from the cache backend's representation (fscache_object) - which may be
+requested from either end.
+
+
+=================
+THE SET OF STATES
+=================
+
+The object state machine has a set of states that it can be in.  There are
+preparation states in which the object sets itself up and waits for its parent
+object to transit to a state that allows access to its children:
+
+ (1) State FSCACHE_OBJECT_INIT.
+
+     Initialise the object and wait for the parent object to become active.  In
+     the cache, it is expected that it will not be possible to look an object
+     up from the parent object, until that parent object itself has been looked
+     up.
+
+There are initialisation states in which the object sets itself up and accesses
+disk for the object metadata:
+
+ (2) State FSCACHE_OBJECT_LOOKING_UP.
+
+     Look up the object on disk, using the parent as a starting point.
+     FS-Cache expects the cache backend to probe the cache to see whether this
+     object is represented there, and if it is, to see if it's valid (coherency
+     management).
+
+     The cache should call fscache_object_lookup_negative() to indicate lookup
+     failure for whatever reason, and should call fscache_obtained_object() to
+     indicate success.
+
+     At the completion of lookup, FS-Cache will let the netfs go ahead with
+     read operations, no matter whether the file is yet cached.  If not yet
+     cached, read operations will be immediately rejected with ENODATA until
+     the first known page is uncached - as to that point there can be no data
+     to be read out of the cache for that file that isn't currently also held
+     in the pagecache.
+
+ (3) State FSCACHE_OBJECT_CREATING.
+
+     Create an object on disk, using the parent as a starting point.  This
+     happens if the lookup failed to find the object, or if the object's
+     coherency data indicated what's on disk is out of date.  In this state,
+     FS-Cache expects the cache to create
+
+     The cache should call fscache_obtained_object() if creation completes
+     successfully, fscache_object_lookup_negative() otherwise.
+
+     At the completion of creation, FS-Cache will start processing write
+     operations the netfs has queued for an object.  If creation failed, the
+     write ops will be transparently discarded, and nothing recorded in the
+     cache.
+
+There are some normal running states in which the object spends its time
+servicing netfs requests:
+
+ (4) State FSCACHE_OBJECT_AVAILABLE.
+
+     A transient state in which pending operations are started, child objects
+     are permitted to advance from FSCACHE_OBJECT_INIT state, and temporary
+     lookup data is freed.
+
+ (5) State FSCACHE_OBJECT_ACTIVE.
+
+     The normal running state.  In this state, requests the netfs makes will be
+     passed on to the cache.
+
+ (6) State FSCACHE_OBJECT_UPDATING.
+
+     The state machine comes here to update the object in the cache from the
+     netfs's records.  This involves updating the auxiliary data that is used
+     to maintain coherency.
+
+And there are terminal states in which an object cleans itself up, deallocates
+memory and potentially deletes stuff from disk:
+
+ (7) State FSCACHE_OBJECT_LC_DYING.
+
+     The object comes here if it is dying because of a lookup or creation
+     error.  This would be due to a disk error or system error of some sort.
+     Temporary data is cleaned up, and the parent is released.
+
+ (8) State FSCACHE_OBJECT_DYING.
+
+     The object comes here if it is dying due to an error, because its parent
+     cookie has been relinquished by the netfs or because the cache is being
+     withdrawn.
+
+     Any child objects waiting on this one are given CPU time so that they too
+     can destroy themselves.  This object waits for all its children to go away
+     before advancing to the next state.
+
+ (9) State FSCACHE_OBJECT_ABORT_INIT.
+
+     The object comes to this state if it was waiting on its parent in
+     FSCACHE_OBJECT_INIT, but its parent died.  The object will destroy itself
+     so that the parent may proceed from the FSCACHE_OBJECT_DYING state.
+
+(10) State FSCACHE_OBJECT_RELEASING.
+(11) State FSCACHE_OBJECT_RECYCLING.
+
+     The object comes to one of these two states when dying once it is rid of
+     all its children, if it is dying because the netfs relinquished its
+     cookie.  In the first state, the cached data is expected to persist, and
+     in the second it will be deleted.
+
+(12) State FSCACHE_OBJECT_WITHDRAWING.
+
+     The object transits to this state if the cache decides it wants to
+     withdraw the object from service, perhaps to make space, but also due to
+     error or just because the whole cache is being withdrawn.
+
+(13) State FSCACHE_OBJECT_DEAD.
+
+     The object transits to this state when the in-memory object record is
+     ready to be deleted.  The object processor shouldn't ever see an object in
+     this state.
+
+
+THE SET OF EVENTS
+-----------------
+
+There are a number of events that can be raised to an object state machine:
+
+ (*) FSCACHE_OBJECT_EV_UPDATE
+
+     The netfs requested that an object be updated.  The state machine will ask
+     the cache backend to update the object, and the cache backend will ask the
+     netfs for details of the change through its cookie definition ops.
+
+ (*) FSCACHE_OBJECT_EV_CLEARED
+
+     This is signalled in two circumstances:
+
+     (a) when an object's last child object is dropped and
+
+     (b) when the last operation outstanding on an object is completed.
+
+     This is used to proceed from the dying state.
+
+ (*) FSCACHE_OBJECT_EV_ERROR
+
+     This is signalled when an I/O error occurs during the processing of some
+     object.
+
+ (*) FSCACHE_OBJECT_EV_RELEASE
+ (*) FSCACHE_OBJECT_EV_RETIRE
+
+     These are signalled when the netfs relinquishes a cookie it was using.
+     The event selected depends on whether the netfs asks for the backing
+     object to be retired (deleted) or retained.
+
+ (*) FSCACHE_OBJECT_EV_WITHDRAW
+
+     This is signalled when the cache backend wants to withdraw an object.
+     This means that the object will have to be detached from the netfs's
+     cookie.
+
+Because the withdrawing releasing/retiring events are all handled by the object
+state machine, it doesn't matter if there's a collision with both ends trying
+to sever the connection at the same time.  The state machine can just pick
+which one it wants to honour, and that effects the other.
diff --git a/Documentation/filesystems/caching/operations.txt b/Documentation/filesystems/caching/operations.txt
new file mode 100644 (file)
index 0000000..b6b070c
--- /dev/null
@@ -0,0 +1,213 @@
+                      ================================
+                      ASYNCHRONOUS OPERATIONS HANDLING
+                      ================================
+
+By: David Howells <dhowells@redhat.com>
+
+Contents:
+
+ (*) Overview.
+
+ (*) Operation record initialisation.
+
+ (*) Parameters.
+
+ (*) Procedure.
+
+ (*) Asynchronous callback.
+
+
+========
+OVERVIEW
+========
+
+FS-Cache has an asynchronous operations handling facility that it uses for its
+data storage and retrieval routines.  Its operations are represented by
+fscache_operation structs, though these are usually embedded into some other
+structure.
+
+This facility is available to and expected to be be used by the cache backends,
+and FS-Cache will create operations and pass them off to the appropriate cache
+backend for completion.
+
+To make use of this facility, <linux/fscache-cache.h> should be #included.
+
+
+===============================
+OPERATION RECORD INITIALISATION
+===============================
+
+An operation is recorded in an fscache_operation struct:
+
+       struct fscache_operation {
+               union {
+                       struct work_struct fast_work;
+                       struct slow_work slow_work;
+               };
+               unsigned long           flags;
+               fscache_operation_processor_t processor;
+               ...
+       };
+
+Someone wanting to issue an operation should allocate something with this
+struct embedded in it.  They should initialise it by calling:
+
+       void fscache_operation_init(struct fscache_operation *op,
+                                   fscache_operation_release_t release);
+
+with the operation to be initialised and the release function to use.
+
+The op->flags parameter should be set to indicate the CPU time provision and
+the exclusivity (see the Parameters section).
+
+The op->fast_work, op->slow_work and op->processor flags should be set as
+appropriate for the CPU time provision (see the Parameters section).
+
+FSCACHE_OP_WAITING may be set in op->flags prior to each submission of the
+operation and waited for afterwards.
+
+
+==========
+PARAMETERS
+==========
+
+There are a number of parameters that can be set in the operation record's flag
+parameter.  There are three options for the provision of CPU time in these
+operations:
+
+ (1) The operation may be done synchronously (FSCACHE_OP_MYTHREAD).  A thread
+     may decide it wants to handle an operation itself without deferring it to
+     another thread.
+
+     This is, for example, used in read operations for calling readpages() on
+     the backing filesystem in CacheFiles.  Although readpages() does an
+     asynchronous data fetch, the determination of whether pages exist is done
+     synchronously - and the netfs does not proceed until this has been
+     determined.
+
+     If this option is to be used, FSCACHE_OP_WAITING must be set in op->flags
+     before submitting the operation, and the operating thread must wait for it
+     to be cleared before proceeding:
+
+               wait_on_bit(&op->flags, FSCACHE_OP_WAITING,
+                           fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+
+
+ (2) The operation may be fast asynchronous (FSCACHE_OP_FAST), in which case it
+     will be given to keventd to process.  Such an operation is not permitted
+     to sleep on I/O.
+
+     This is, for example, used by CacheFiles to copy data from a backing fs
+     page to a netfs page after the backing fs has read the page in.
+
+     If this option is used, op->fast_work and op->processor must be
+     initialised before submitting the operation:
+
+               INIT_WORK(&op->fast_work, do_some_work);
+
+
+ (3) The operation may be slow asynchronous (FSCACHE_OP_SLOW), in which case it
+     will be given to the slow work facility to process.  Such an operation is
+     permitted to sleep on I/O.
+
+     This is, for example, used by FS-Cache to handle background writes of
+     pages that have just been fetched from a remote server.
+
+     If this option is used, op->slow_work and op->processor must be
+     initialised before submitting the operation:
+
+               fscache_operation_init_slow(op, processor)
+
+
+Furthermore, operations may be one of two types:
+
+ (1) Exclusive (FSCACHE_OP_EXCLUSIVE).  Operations of this type may not run in
+     conjunction with any other operation on the object being operated upon.
+
+     An example of this is the attribute change operation, in which the file
+     being written to may need truncation.
+
+ (2) Shareable.  Operations of this type may be running simultaneously.  It's
+     up to the operation implementation to prevent interference between other
+     operations running at the same time.
+
+
+=========
+PROCEDURE
+=========
+
+Operations are used through the following procedure:
+
+ (1) The submitting thread must allocate the operation and initialise it
+     itself.  Normally this would be part of a more specific structure with the
+     generic op embedded within.
+
+ (2) The submitting thread must then submit the operation for processing using
+     one of the following two functions:
+
+       int fscache_submit_op(struct fscache_object *object,
+                             struct fscache_operation *op);
+
+       int fscache_submit_exclusive_op(struct fscache_object *object,
+                                       struct fscache_operation *op);
+
+     The first function should be used to submit non-exclusive ops and the
+     second to submit exclusive ones.  The caller must still set the
+     FSCACHE_OP_EXCLUSIVE flag.
+
+     If successful, both functions will assign the operation to the specified
+     object and return 0.  -ENOBUFS will be returned if the object specified is
+     permanently unavailable.
+
+     The operation manager will defer operations on an object that is still
+     undergoing lookup or creation.  The operation will also be deferred if an
+     operation of conflicting exclusivity is in progress on the object.
+
+     If the operation is asynchronous, the manager will retain a reference to
+     it, so the caller should put their reference to it by passing it to:
+
+       void fscache_put_operation(struct fscache_operation *op);
+
+ (3) If the submitting thread wants to do the work itself, and has marked the
+     operation with FSCACHE_OP_MYTHREAD, then it should monitor
+     FSCACHE_OP_WAITING as described above and check the state of the object if
+     necessary (the object might have died whilst the thread was waiting).
+
+     When it has finished doing its processing, it should call
+     fscache_put_operation() on it.
+
+ (4) The operation holds an effective lock upon the object, preventing other
+     exclusive ops conflicting until it is released.  The operation can be
+     enqueued for further immediate asynchronous processing by adjusting the
+     CPU time provisioning option if necessary, eg:
+
+       op->flags &= ~FSCACHE_OP_TYPE;
+       op->flags |= ~FSCACHE_OP_FAST;
+
+     and calling:
+
+       void fscache_enqueue_operation(struct fscache_operation *op)
+
+     This can be used to allow other things to have use of the worker thread
+     pools.
+
+
+=====================
+ASYNCHRONOUS CALLBACK
+=====================
+
+When used in asynchronous mode, the worker thread pool will invoke the
+processor method with a pointer to the operation.  This should then get at the
+container struct by using container_of():
+
+       static void fscache_write_op(struct fscache_operation *_op)
+       {
+               struct fscache_storage *op =
+                       container_of(_op, struct fscache_storage, op);
+       ...
+       }
+
+The caller holds a reference on the operation, and will invoke
+fscache_put_operation() when the processor function returns.  The processor
+function is at liberty to call fscache_enqueue_operation() or to take extra
+references.
diff --git a/Documentation/filesystems/exofs.txt b/Documentation/filesystems/exofs.txt
new file mode 100644 (file)
index 0000000..0ced74c
--- /dev/null
@@ -0,0 +1,176 @@
+===============================================================================
+WHAT IS EXOFS?
+===============================================================================
+
+exofs is a file system that uses an OSD and exports the API of a normal Linux
+file system. Users access exofs like any other local file system, and exofs
+will in turn issue commands to the local OSD initiator.
+
+OSD is a new T10 command set that views storage devices not as a large/flat
+array of sectors but as a container of objects, each having a length, quota,
+time attributes and more. Each object is addressed by a 64bit ID, and is
+contained in a 64bit ID partition. Each object has associated attributes
+attached to it, which are integral part of the object and provide metadata about
+the object. The standard defines some common obligatory attributes, but user
+attributes can be added as needed.
+
+===============================================================================
+ENVIRONMENT
+===============================================================================
+
+To use this file system, you need to have an object store to run it on.  You
+may download a target from:
+http://open-osd.org
+
+See Documentation/scsi/osd.txt for how to setup a working osd environment.
+
+===============================================================================
+USAGE
+===============================================================================
+
+1. Download and compile exofs and open-osd initiator:
+  You need an external Kernel source tree or kernel headers from your
+  distribution. (anything based on 2.6.26 or later).
+
+  a. download open-osd including exofs source using:
+     [parent-directory]$ git clone git://git.open-osd.org/open-osd.git
+
+  b. Build the library module like this:
+     [parent-directory]$ make -C KSRC=$(KER_DIR) open-osd
+
+     This will build both the open-osd initiator as well as the exofs kernel
+     module. Use whatever parameters you compiled your Kernel with and
+     $(KER_DIR) above pointing to the Kernel you compile against. See the file
+     open-osd/top-level-Makefile for an example.
+
+2. Get the OSD initiator and target set up properly, and login to the target.
+  See Documentation/scsi/osd.txt for farther instructions. Also see ./do-osd
+  for example script that does all these steps.
+
+3. Insmod the exofs.ko module:
+   [exofs]$ insmod exofs.ko
+
+4. Make sure the directory where you want to mount exists. If not, create it.
+   (For example, mkdir /mnt/exofs)
+
+5. At first run you will need to invoke the mkfs.exofs application
+
+   As an example, this will create the file system on:
+   /dev/osd0 partition ID 65536
+
+   mkfs.exofs --pid=65536 --format /dev/osd0
+
+   The --format is optional if not specified no OSD_FORMAT will be
+   preformed and a clean file system will be created in the specified pid,
+   in the available space of the target. (Use --format=size_in_meg to limit
+   the total LUN space available)
+
+   If pid already exist it will be deleted and a new one will be created in it's
+   place. Be careful.
+
+   An exofs lives inside a single OSD partition. You can create multiple exofs
+   filesystems on the same device using multiple pids.
+
+   (run mkfs.exofs without any parameters for usage help message)
+
+6. Mount the file system.
+
+   For example, to mount /dev/osd0, partition ID 0x10000 on /mnt/exofs:
+
+       mount -t exofs -o pid=65536 /dev/osd0 /mnt/exofs/
+
+7. For reference (See do-exofs example script):
+       do-exofs start - an example of how to perform the above steps.
+       do-exofs stop -  an example of how to unmount the file system.
+       do-exofs format - an example of how to format and mkfs a new exofs.
+
+8. Extra compilation flags (uncomment in fs/exofs/Kbuild):
+       CONFIG_EXOFS_DEBUG - for debug messages and extra checks.
+
+===============================================================================
+exofs mount options
+===============================================================================
+Similar to any mount command:
+       mount -t exofs -o exofs_options /dev/osdX mount_exofs_directory
+
+Where:
+    -t exofs: specifies the exofs file system
+
+    /dev/osdX: X is a decimal number. /dev/osdX was created after a successful
+               login into an OSD target.
+
+    mount_exofs_directory: The directory to mount the file system on
+
+    exofs specific options: Options are separated by commas (,)
+               pid=<integer> - The partition number to mount/create as
+                                container of the filesystem.
+                                This option is mandatory
+                to=<integer>  - Timeout in ticks for a single command
+                                default is (60 * HZ) [for debugging only]
+
+===============================================================================
+DESIGN
+===============================================================================
+
+* The file system control block (AKA on-disk superblock) resides in an object
+  with a special ID (defined in common.h).
+  Information included in the file system control block is used to fill the
+  in-memory superblock structure at mount time. This object is created before
+  the file system is used by mkexofs.c It contains information such as:
+       - The file system's magic number
+       - The next inode number to be allocated
+
+* Each file resides in its own object and contains the data (and it will be
+  possible to extend the file over multiple objects, though this has not been
+  implemented yet).
+
+* A directory is treated as a file, and essentially contains a list of <file
+  name, inode #> pairs for files that are found in that directory. The object
+  IDs correspond to the files' inode numbers and will be allocated according to
+  a bitmap (stored in a separate object). Now they are allocated using a
+  counter.
+
+* Each file's control block (AKA on-disk inode) is stored in its object's
+  attributes. This applies to both regular files and other types (directories,
+  device files, symlinks, etc.).
+
+* Credentials are generated per object (inode and superblock) when they is
+  created in memory (read off disk or created). The credential works for all
+  operations and is used as long as the object remains in memory.
+
+* Async OSD operations are used whenever possible, but the target may execute
+  them out of order. The operations that concern us are create, delete,
+  readpage, writepage, update_inode, and truncate. The following pairs of
+  operations should execute in the order written, and we need to prevent them
+  from executing in reverse order:
+       - The following are handled with the OBJ_CREATED and OBJ_2BCREATED
+         flags. OBJ_CREATED is set when we know the object exists on the OSD -
+         in create's callback function, and when we successfully do a read_inode.
+         OBJ_2BCREATED is set in the beginning of the create function, so we
+         know that we should wait.
+               - create/delete: delete should wait until the object is created
+                 on the OSD.
+               - create/readpage: readpage should be able to return a page
+                 full of zeroes in this case. If there was a write already
+                 en-route (i.e. create, writepage, readpage) then the page
+                 would be locked, and so it would really be the same as
+                 create/writepage.
+               - create/writepage: if writepage is called for a sync write, it
+                 should wait until the object is created on the OSD.
+                 Otherwise, it should just return.
+               - create/truncate: truncate should wait until the object is
+                 created on the OSD.
+               - create/update_inode: update_inode should wait until the
+                 object is created on the OSD.
+       - Handled by VFS locks:
+               - readpage/delete: shouldn't happen because of page lock.
+               - writepage/delete: shouldn't happen because of page lock.
+               - readpage/writepage: shouldn't happen because of page lock.
+
+===============================================================================
+LICENSE/COPYRIGHT
+===============================================================================
+The exofs file system is based on ext2 v0.5b (distributed with the Linux kernel
+version 2.6.10).  All files include the original copyrights, and the license
+is GPL version 2 (only version 2, as is true for the Linux kernel).  The
+Linux kernel can be downloaded from www.kernel.org.
index e5f3833a6ef8f53c3b22adf48d57b84e2a24ba0c..570f9bd9be2becb3fee1c7869d9c911226690dc4 100644 (file)
@@ -14,6 +14,11 @@ Options
 When mounting an ext3 filesystem, the following option are accepted:
 (*) == default
 
+ro                     Mount filesystem read only. Note that ext3 will replay
+                       the journal (and thus write to the partition) even when
+                       mounted "read only". Mount options "ro,noload" can be
+                       used to prevent writes to the filesystem.
+
 journal=update         Update the ext3 file system's journal to the current
                        format.
 
@@ -27,7 +32,9 @@ journal_dev=devnum    When the external journal device's major/minor numbers
                        identified through its new major/minor numbers encoded
                        in devnum.
 
-noload                 Don't load the journal on mounting.
+noload                 Don't load the journal on mounting. Note that this forces
+                       mount of inconsistent filesystem, which can lead to
+                       various problems.
 
 data=journal           All data are committed into the journal prior to being
                        written into the main file system.
@@ -92,9 +99,12 @@ nocheck
 
 debug                  Extra debugging information is sent to syslog.
 
-errors=remount-ro(*)   Remount the filesystem read-only on an error.
+errors=remount-ro      Remount the filesystem read-only on an error.
 errors=continue                Keep going on a filesystem error.
 errors=panic           Panic and halt the machine if an error occurs.
+                       (These mount options override the errors behavior
+                       specified in the superblock, which can be
+                       configured using tune2fs.)
 
 data_err=ignore(*)     Just print an error message if an error occurs
                        in a file data buffer in ordered mode.
index cec829bc7291623da6189de984fedd753ce51450..97882df0486567c229bb0ee867752da15b24089f 100644 (file)
@@ -85,7 +85,7 @@ Note: More extensive information for getting started with ext4 can be
 * extent format more robust in face of on-disk corruption due to magics,
 * internal redundancy in tree
 * improved file allocation (multi-block alloc)
-* fix 32000 subdirectory limit
+* lift 32000 subdirectory limit imposed by i_links_count[1]
 * nsec timestamps for mtime, atime, ctime, create time
 * inode version field on disk (NFSv4, Lustre)
 * reduced e2fsck time via uninit_bg feature
@@ -100,6 +100,9 @@ Note: More extensive information for getting started with ext4 can be
 * efficent new ordered mode in JBD2 and ext4(avoid using buffer head to force
   the ordering)
 
+[1] Filesystems with a block size of 1k may see a limit imposed by the
+directory hash tree having a maximum depth of two.
+
 2.2 Candidate features for future inclusion
 
 * Online defrag (patches available but not well tested)
@@ -180,8 +183,8 @@ commit=nrsec        (*)     Ext4 can be told to sync all its data and metadata
                        performance.
 
 barrier=<0|1(*)>       This enables/disables the use of write barriers in
-                       the jbd code.  barrier=0 disables, barrier=1 enables.
-                       This also requires an IO stack which can support
+barrier(*)             the jbd code.  barrier=0 disables, barrier=1 enables.
+nobarrier              This also requires an IO stack which can support
                        barriers, and if jbd gets an error on a barrier
                        write, it will disable again with a warning.
                        Write barriers enforce proper on-disk ordering
@@ -189,6 +192,9 @@ barrier=<0|1(*)>    This enables/disables the use of write barriers in
                        safe to use, at some performance penalty.  If
                        your disks are battery-backed in one way or another,
                        disabling barriers may safely improve performance.
+                       The mount options "barrier" and "nobarrier" can
+                       also be used to enable or disable barriers, for
+                       consistency with other ext4 mount options.
 
 inode_readahead=n      This tuning parameter controls the maximum
                        number of inode table blocks that ext4's inode
@@ -310,6 +316,24 @@ journal_ioprio=prio        The I/O priority (from 0 to 7, where 0 is the
                        a slightly higher priority than the default I/O
                        priority.
 
+auto_da_alloc(*)       Many broken applications don't use fsync() when 
+noauto_da_alloc                replacing existing files via patterns such as
+                       fd = open("foo.new")/write(fd,..)/close(fd)/
+                       rename("foo.new", "foo"), or worse yet,
+                       fd = open("foo", O_TRUNC)/write(fd,..)/close(fd).
+                       If auto_da_alloc is enabled, ext4 will detect
+                       the replace-via-rename and replace-via-truncate
+                       patterns and force that any delayed allocation
+                       blocks are allocated such that at the next
+                       journal commit, in the default data=ordered
+                       mode, the data blocks of the new file are forced
+                       to disk before the rename() operation is
+                       commited.  This provides roughly the same level
+                       of guarantees as ext3, and avoids the
+                       "zero-length" problem that can happen when a
+                       system crashes before the delayed allocation
+                       blocks are forced to disk.
+
 Data Mode
 =========
 There are 3 different data modes:
index 830bad7cce0f946ba356e7aff283775d270063f1..ce84cfc9eae0a923f7aca7ae1e03797a7a7bea7e 100644 (file)
@@ -5,6 +5,7 @@
                   Bodo Bauer <bb@ricochet.net>
 
 2.4.x update     Jorge Nerin <comandante@zaralinux.com>      November 14 2000
+move /proc/sys   Shen Feng <shen@cn.fujitsu.com>                   April 1 2009
 ------------------------------------------------------------------------------
 Version 1.3                                              Kernel version 2.2.12
                                              Kernel version 2.4.0-test11-pre4
@@ -26,25 +27,17 @@ Table of Contents
   1.6  Parallel port info in /proc/parport
   1.7  TTY info in /proc/tty
   1.8  Miscellaneous kernel statistics in /proc/stat
+  1.9 Ext4 file system parameters
 
   2    Modifying System Parameters
-  2.1  /proc/sys/fs - File system data
-  2.2  /proc/sys/fs/binfmt_misc - Miscellaneous binary formats
-  2.3  /proc/sys/kernel - general kernel parameters
-  2.4  /proc/sys/vm - The virtual memory subsystem
-  2.5  /proc/sys/dev - Device specific parameters
-  2.6  /proc/sys/sunrpc - Remote procedure calls
-  2.7  /proc/sys/net - Networking stuff
-  2.8  /proc/sys/net/ipv4 - IPV4 settings
-  2.9  Appletalk
-  2.10 IPX
-  2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem
-  2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
-  2.13 /proc/<pid>/oom_score - Display current oom-killer score
-  2.14 /proc/<pid>/io - Display the IO accounting fields
-  2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
-  2.16 /proc/<pid>/mountinfo - Information about mounts
-  2.17 /proc/sys/fs/epoll - Configuration options for the epoll interface
+
+  3    Per-Process Parameters
+  3.1  /proc/<pid>/oom_adj - Adjust the oom-killer score
+  3.2  /proc/<pid>/oom_score - Display current oom-killer score
+  3.3  /proc/<pid>/io - Display the IO accounting fields
+  3.4  /proc/<pid>/coredump_filter - Core dump filtering settings
+  3.5  /proc/<pid>/mountinfo - Information about mounts
+
 
 ------------------------------------------------------------------------------
 Preface
@@ -940,27 +933,6 @@ Table 1-10: Files in /proc/fs/ext4/<devname>
  File            Content                                        
  mb_groups       details of multiblock allocator buddy cache of free blocks
  mb_history      multiblock allocation history
- stats           controls whether the multiblock allocator should start
-                 collecting statistics, which are shown during the unmount
- group_prealloc  the multiblock allocator will round up allocation
-                 requests to a multiple of this tuning parameter if the
-                 stripe size is not set in the ext4 superblock
- max_to_scan     The maximum number of extents the multiblock allocator
-                 will search to find the best extent
- min_to_scan     The minimum number of extents the multiblock allocator
-                 will search to find the best extent
- order2_req      Tuning parameter which controls the minimum size for 
-                 requests (as a power of 2) where the buddy cache is
-                 used
- stream_req      Files which have fewer blocks than this tunable
-                 parameter will have their blocks allocated out of a
-                 block group specific preallocation pool, so that small
-                 files are packed closely together.  Each large file
-                 will have its blocks allocated out of its own unique
-                 preallocation pool.
-inode_readahead  Tuning parameter which controls the maximum number of
-                 inode table blocks that ext4's inode table readahead
-                 algorithm will pre-read into the buffer cache
 ..............................................................................
 
 
@@ -1011,1021 +983,24 @@ review the kernel documentation in the directory /usr/src/linux/Documentation.
 This chapter  is  heavily  based  on the documentation included in the pre 2.2
 kernels, and became part of it in version 2.2.1 of the Linux kernel.
 
-2.1 /proc/sys/fs - File system data
------------------------------------
-
-This subdirectory  contains  specific  file system, file handle, inode, dentry
-and quota information.
-
-Currently, these files are in /proc/sys/fs:
-
-dentry-state
-------------
-
-Status of  the  directory  cache.  Since  directory  entries  are  dynamically
-allocated and  deallocated,  this  file indicates the current status. It holds
-six values, in which the last two are not used and are always zero. The others
-are listed in table 2-1.
-
-
-Table 2-1: Status files of the directory cache 
-..............................................................................
- File       Content                                                            
- nr_dentry  Almost always zero                                                 
- nr_unused  Number of unused cache entries                                     
- age_limit  
-            in seconds after the entry may be reclaimed, when memory is short 
- want_pages internally                                                         
-..............................................................................
-
-dquot-nr and dquot-max
-----------------------
-
-The file dquot-max shows the maximum number of cached disk quota entries.
-
-The file  dquot-nr  shows  the  number of allocated disk quota entries and the
-number of free disk quota entries.
-
-If the number of available cached disk quotas is very low and you have a large
-number of simultaneous system users, you might want to raise the limit.
-
-file-nr and file-max
---------------------
-
-The kernel  allocates file handles dynamically, but doesn't free them again at
-this time.
-
-The value  in  file-max  denotes  the  maximum number of file handles that the
-Linux kernel will allocate. When you get a lot of error messages about running
-out of  file handles, you might want to raise this limit. The default value is
-10% of  RAM in kilobytes.  To  change it, just  write the new number  into the
-file:
-
-  # cat /proc/sys/fs/file-max 
-  4096 
-  # echo 8192 > /proc/sys/fs/file-max 
-  # cat /proc/sys/fs/file-max 
-  8192 
-
-
-This method  of  revision  is  useful  for  all customizable parameters of the
-kernel - simply echo the new value to the corresponding file.
-
-Historically, the three values in file-nr denoted the number of allocated file
-handles,  the number of  allocated but  unused file  handles, and  the maximum
-number of file handles. Linux 2.6 always  reports 0 as the number of free file
-handles -- this  is not an error,  it just means that the  number of allocated
-file handles exactly matches the number of used file handles.
-
-Attempts to  allocate more  file descriptors than  file-max are  reported with
-printk, look for "VFS: file-max limit <number> reached".
-
-inode-state and inode-nr
-------------------------
-
-The file inode-nr contains the first two items from inode-state, so we'll skip
-to that file...
-
-inode-state contains  two  actual numbers and five dummy values. The numbers
-are nr_inodes and nr_free_inodes (in order of appearance).
-
-nr_inodes
-~~~~~~~~~
-
-Denotes the  number  of  inodes the system has allocated. This number will
-grow and shrink dynamically.
-
-nr_open
--------
-
-Denotes the maximum number of file-handles a process can
-allocate. Default value is 1024*1024 (1048576) which should be
-enough for most machines. Actual limit depends on RLIMIT_NOFILE
-resource limit.
-
-nr_free_inodes
---------------
-
-Represents the  number of free inodes. Ie. The number of inuse inodes is
-(nr_inodes - nr_free_inodes).
-
-aio-nr and aio-max-nr
----------------------
-
-aio-nr is the running total of the number of events specified on the
-io_setup system call for all currently active aio contexts.  If aio-nr
-reaches aio-max-nr then io_setup will fail with EAGAIN.  Note that
-raising aio-max-nr does not result in the pre-allocation or re-sizing
-of any kernel data structures.
-
-2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats
------------------------------------------------------------
-
-Besides these  files, there is the subdirectory /proc/sys/fs/binfmt_misc. This
-handles the kernel support for miscellaneous binary formats.
-
-Binfmt_misc provides  the ability to register additional binary formats to the
-Kernel without  compiling  an additional module/kernel. Therefore, binfmt_misc
-needs to  know magic numbers at the beginning or the filename extension of the
-binary.
-
-It works by maintaining a linked list of structs that contain a description of
-a binary  format,  including  a  magic  with size (or the filename extension),
-offset and  mask,  and  the  interpreter name. On request it invokes the given
-interpreter with  the  original  program  as  argument,  as  binfmt_java  and
-binfmt_em86 and  binfmt_mz  do.  Since binfmt_misc does not define any default
-binary-formats, you have to register an additional binary-format.
-
-There are two general files in binfmt_misc and one file per registered format.
-The two general files are register and status.
-
-Registering a new binary format
--------------------------------
-
-To register a new binary format you have to issue the command
-
-  echo :name:type:offset:magic:mask:interpreter: > /proc/sys/fs/binfmt_misc/register 
-
-
-
-with appropriate  name (the name for the /proc-dir entry), offset (defaults to
-0, if  omitted),  magic, mask (which can be omitted, defaults to all 0xff) and
-last but  not  least,  the  interpreter that is to be invoked (for example and
-testing /bin/echo).  Type  can be M for usual magic matching or E for filename
-extension matching (give extension in place of magic).
-
-Check or reset the status of the binary format handler
-------------------------------------------------------
-
-If you  do a cat on the file /proc/sys/fs/binfmt_misc/status, you will get the
-current status (enabled/disabled) of binfmt_misc. Change the status by echoing
-0 (disables)  or  1  (enables)  or  -1  (caution:  this  clears all previously
-registered binary  formats)  to status. For example echo 0 > status to disable
-binfmt_misc (temporarily).
-
-Status of a single handler
---------------------------
-
-Each registered  handler has an entry in /proc/sys/fs/binfmt_misc. These files
-perform the  same function as status, but their scope is limited to the actual
-binary format.  By  cating this file, you also receive all related information
-about the interpreter/magic of the binfmt.
-
-Example usage of binfmt_misc (emulate binfmt_java)
---------------------------------------------------
-
-  cd /proc/sys/fs/binfmt_misc  
-  echo ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' > register  
-  echo ':HTML:E::html::/usr/local/java/bin/appletviewer:' > register  
-  echo ':Applet:M::<!--applet::/usr/local/java/bin/appletviewer:' > register 
-  echo ':DEXE:M::\x0eDEX::/usr/bin/dosexec:' > register 
-
-
-These four  lines  add  support  for  Java  executables and Java applets (like
-binfmt_java, additionally  recognizing the .html extension with no need to put
-<!--applet> to  every  applet  file).  You  have  to  install  the JDK and the
-shell-script /usr/local/java/bin/javawrapper  too.  It  works  around  the
-brokenness of  the Java filename handling. To add a Java binary, just create a
-link to the class-file somewhere in the path.
-
-2.3 /proc/sys/kernel - general kernel parameters
-------------------------------------------------
-
-This directory  reflects  general  kernel  behaviors. As I've said before, the
-contents depend  on  your  configuration.  Here you'll find the most important
-files, along with descriptions of what they mean and how to use them.
-
-acct
-----
-
-The file contains three values; highwater, lowwater, and frequency.
-
-It exists  only  when  BSD-style  process  accounting is enabled. These values
-control its behavior. If the free space on the file system where the log lives
-goes below  lowwater  percentage,  accounting  suspends.  If  it  goes  above
-highwater percentage,  accounting  resumes. Frequency determines how often you
-check the amount of free space (value is in seconds). Default settings are: 4,
-2, and  30.  That is, suspend accounting if there is less than 2 percent free;
-resume it  if we have a value of 3 or more percent; consider information about
-the amount of free space valid for 30 seconds
-
-ctrl-alt-del
-------------
-
-When the value in this file is 0, ctrl-alt-del is trapped and sent to the init
-program to  handle a graceful restart. However, when the value is greater that
-zero, Linux's  reaction  to  this key combination will be an immediate reboot,
-without syncing its dirty buffers.
-
-[NOTE]
-    When a  program  (like  dosemu)  has  the  keyboard  in  raw  mode,  the
-    ctrl-alt-del is  intercepted  by  the  program  before it ever reaches the
-    kernel tty  layer,  and  it is up to the program to decide what to do with
-    it.
-
-domainname and hostname
------------------------
-
-These files  can  be controlled to set the NIS domainname and hostname of your
-box. For the classic darkstar.frop.org a simple:
-
-  # echo "darkstar" > /proc/sys/kernel/hostname 
-  # echo "frop.org" > /proc/sys/kernel/domainname 
-
-
-would suffice to set your hostname and NIS domainname.
-
-osrelease, ostype and version
------------------------------
-
-The names make it pretty obvious what these fields contain:
-
-  > cat /proc/sys/kernel/osrelease 
-  2.2.12 
-   
-  > cat /proc/sys/kernel/ostype 
-  Linux 
-   
-  > cat /proc/sys/kernel/version 
-  #4 Fri Oct 1 12:41:14 PDT 1999 
-
-
-The files  osrelease and ostype should be clear enough. Version needs a little
-more clarification.  The  #4 means that this is the 4th kernel built from this
-source base and the date after it indicates the time the kernel was built. The
-only way to tune these values is to rebuild the kernel.
-
-panic
------
-
-The value  in  this  file  represents  the  number of seconds the kernel waits
-before rebooting  on  a  panic.  When  you  use  the  software  watchdog,  the
-recommended setting  is  60. If set to 0, the auto reboot after a kernel panic
-is disabled, which is the default setting.
-
-printk
-------
-
-The four values in printk denote
-* console_loglevel,
-* default_message_loglevel,
-* minimum_console_loglevel and
-* default_console_loglevel
-respectively.
-
-These values  influence  printk()  behavior  when  printing  or  logging error
-messages, which  come  from  inside  the  kernel.  See  syslog(2)  for  more
-information on the different log levels.
-
-console_loglevel
-----------------
-
-Messages with a higher priority than this will be printed to the console.
-
-default_message_level
----------------------
-
-Messages without an explicit priority will be printed with this priority.
-
-minimum_console_loglevel
-------------------------
-
-Minimum (highest) value to which the console_loglevel can be set.
-
-default_console_loglevel
-------------------------
-
-Default value for console_loglevel.
-
-sg-big-buff
------------
-
-This file  shows  the size of the generic SCSI (sg) buffer. At this point, you
-can't tune  it  yet,  but  you  can  change  it  at  compile  time  by editing
-include/scsi/sg.h and changing the value of SG_BIG_BUFF.
-
-If you use a scanner with SANE (Scanner Access Now Easy) you might want to set
-this to a higher value. Refer to the SANE documentation on this issue.
-
-modprobe
---------
-
-The location  where  the  modprobe  binary  is  located.  The kernel uses this
-program to load modules on demand.
-
-unknown_nmi_panic
------------------
-
-The value in this file affects behavior of handling NMI. When the value is
-non-zero, unknown NMI is trapped and then panic occurs. At that time, kernel
-debugging information is displayed on console.
-
-NMI switch that most IA32 servers have fires unknown NMI up, for example.
-If a system hangs up, try pressing the NMI switch.
-
-panic_on_unrecovered_nmi
-------------------------
-
-The default Linux behaviour on an NMI of either memory or unknown is to continue
-operation. For many environments such as scientific computing it is preferable
-that the box is taken out and the error dealt with than an uncorrected
-parity/ECC error get propogated.
-
-A small number of systems do generate NMI's for bizarre random reasons such as
-power management so the default is off. That sysctl works like the existing
-panic controls already in that directory.
-
-nmi_watchdog
-------------
-
-Enables/Disables the NMI watchdog on x86 systems.  When the value is non-zero
-the NMI watchdog is enabled and will continuously test all online cpus to
-determine whether or not they are still functioning properly. Currently,
-passing "nmi_watchdog=" parameter at boot time is required for this function
-to work.
-
-If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the
-NMI watchdog shares registers with oprofile. By disabling the NMI watchdog,
-oprofile may have more registers to utilize.
-
-msgmni
-------
-
-Maximum number of message queue ids on the system.
-This value scales to the amount of lowmem. It is automatically recomputed
-upon memory add/remove or ipc namespace creation/removal.
-When a value is written into this file, msgmni's value becomes fixed, i.e. it
-is not recomputed anymore when one of the above events occurs.
-Use auto_msgmni to change this behavior.
-
-auto_msgmni
------------
-
-Enables/Disables automatic recomputing of msgmni upon memory add/remove or
-upon ipc namespace creation/removal (see the msgmni description above).
-Echoing "1" into this file enables msgmni automatic recomputing.
-Echoing "0" turns it off.
-auto_msgmni default value is 1.
-
-
-2.4 /proc/sys/vm - The virtual memory subsystem
------------------------------------------------
-
-Please see: Documentation/sysctls/vm.txt for a description of these
+Please see: Documentation/sysctls/ directory for descriptions of these
 entries.
 
+------------------------------------------------------------------------------
+Summary
+------------------------------------------------------------------------------
+Certain aspects  of  kernel  behavior  can be modified at runtime, without the
+need to  recompile  the kernel, or even to reboot the system. The files in the
+/proc/sys tree  can  not only be read, but also modified. You can use the echo
+command to write value into these files, thereby changing the default settings
+of the kernel.
+------------------------------------------------------------------------------
 
-2.5 /proc/sys/dev - Device specific parameters
-----------------------------------------------
-
-Currently there is only support for CDROM drives, and for those, there is only
-one read-only  file containing information about the CD-ROM drives attached to
-the system:
-
-  >cat /proc/sys/dev/cdrom/info 
-  CD-ROM information, Id: cdrom.c 2.55 1999/04/25 
-   
-  drive name:             sr0     hdb 
-  drive speed:            32      40 
-  drive # of slots:       1       0 
-  Can close tray:         1       1 
-  Can open tray:          1       1 
-  Can lock tray:          1       1 
-  Can change speed:       1       1 
-  Can select disk:        0       1 
-  Can read multisession:  1       1 
-  Can read MCN:           1       1 
-  Reports media changed:  1       1 
-  Can play audio:         1       1 
-
-
-You see two drives, sr0 and hdb, along with a list of their features.
-
-2.6 /proc/sys/sunrpc - Remote procedure calls
----------------------------------------------
-
-This directory  contains four files, which enable or disable debugging for the
-RPC functions NFS, NFS-daemon, RPC and NLM. The default values are 0. They can
-be set to one to turn debugging on. (The default value is 0 for each)
-
-2.7 /proc/sys/net - Networking stuff
-------------------------------------
-
-The interface  to  the  networking  parts  of  the  kernel  is  located  in
-/proc/sys/net. Table  2-3  shows all possible subdirectories. You may see only
-some of them, depending on your kernel's configuration.
-
-
-Table 2-3: Subdirectories in /proc/sys/net 
-..............................................................................
- Directory Content             Directory  Content            
- core      General parameter   appletalk  Appletalk protocol 
- unix      Unix domain sockets netrom     NET/ROM            
- 802       E802 protocol       ax25       AX25               
- ethernet  Ethernet protocol   rose       X.25 PLP layer     
- ipv4      IP version 4        x25        X.25 protocol      
- ipx       IPX                 token-ring IBM token ring     
- bridge    Bridging            decnet     DEC net            
- ipv6      IP version 6                   
-..............................................................................
-
-We will  concentrate  on IP networking here. Since AX15, X.25, and DEC Net are
-only minor players in the Linux world, we'll skip them in this chapter. You'll
-find some  short  info on Appletalk and IPX further on in this chapter. Review
-the online  documentation  and the kernel source to get a detailed view of the
-parameters for  those  protocols.  In  this  section  we'll  discuss  the
-subdirectories printed  in  bold letters in the table above. As default values
-are suitable for most needs, there is no need to change these values.
-
-/proc/sys/net/core - Network core options
------------------------------------------
-
-rmem_default
-------------
-
-The default setting of the socket receive buffer in bytes.
-
-rmem_max
---------
-
-The maximum receive socket buffer size in bytes.
-
-wmem_default
-------------
-
-The default setting (in bytes) of the socket send buffer.
-
-wmem_max
---------
-
-The maximum send socket buffer size in bytes.
-
-message_burst and message_cost
-------------------------------
-
-These parameters  are used to limit the warning messages written to the kernel
-log from  the  networking  code.  They  enforce  a  rate  limit  to  make  a
-denial-of-service attack  impossible. A higher message_cost factor, results in
-fewer messages that will be written. Message_burst controls when messages will
-be dropped.  The  default  settings  limit  warning messages to one every five
-seconds.
-
-warnings
---------
-
-This controls console messages from the networking stack that can occur because
-of problems on the network like duplicate address or bad checksums. Normally,
-this should be enabled, but if the problem persists the messages can be
-disabled.
-
-netdev_budget
--------------
-
-Maximum number of packets taken from all interfaces in one polling cycle (NAPI
-poll). In one polling cycle interfaces which are registered to polling are
-probed in a round-robin manner. The limit of packets in one such probe can be
-set per-device via sysfs class/net/<device>/weight .
-
-netdev_max_backlog
-------------------
-
-Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
-receives packets faster than kernel can process them.
-
-optmem_max
-----------
-
-Maximum ancillary buffer size allowed per socket. Ancillary data is a sequence
-of struct cmsghdr structures with appended data.
-
-/proc/sys/net/unix - Parameters for Unix domain sockets
--------------------------------------------------------
-
-There are  only  two  files  in this subdirectory. They control the delays for
-deleting and destroying socket descriptors.
-
-2.8 /proc/sys/net/ipv4 - IPV4 settings
---------------------------------------
-
-IP version  4  is  still the most used protocol in Unix networking. It will be
-replaced by  IP version 6 in the next couple of years, but for the moment it's
-the de  facto  standard  for  the  internet  and  is  used  in most networking
-environments around  the  world.  Because  of the importance of this protocol,
-we'll have a deeper look into the subtree controlling the behavior of the IPv4
-subsystem of the Linux kernel.
-
-Let's start with the entries in /proc/sys/net/ipv4.
-
-ICMP settings
--------------
-
-icmp_echo_ignore_all and icmp_echo_ignore_broadcasts
-----------------------------------------------------
-
-Turn on (1) or off (0), if the kernel should ignore all ICMP ECHO requests, or
-just those to broadcast and multicast addresses.
-
-Please note that if you accept ICMP echo requests with a broadcast/multi\-cast
-destination address  your  network  may  be  used as an exploder for denial of
-service packet flooding attacks to other hosts.
-
-icmp_destunreach_rate, icmp_echoreply_rate, icmp_paramprob_rate and icmp_timeexeed_rate
----------------------------------------------------------------------------------------
-
-Sets limits  for  sending  ICMP  packets  to specific targets. A value of zero
-disables all  limiting.  Any  positive  value sets the maximum package rate in
-hundredth of a second (on Intel systems).
-
-IP settings
------------
-
-ip_autoconfig
--------------
-
-This file contains the number one if the host received its IP configuration by
-RARP, BOOTP, DHCP or a similar mechanism. Otherwise it is zero.
-
-ip_default_ttl
---------------
-
-TTL (Time  To  Live) for IPv4 interfaces. This is simply the maximum number of
-hops a packet may travel.
-
-ip_dynaddr
-----------
-
-Enable dynamic  socket  address rewriting on interface address change. This is
-useful for dialup interface with changing IP addresses.
-
-ip_forward
-----------
-
-Enable or  disable forwarding of IP packages between interfaces. Changing this
-value resets  all other parameters to their default values. They differ if the
-kernel is configured as host or router.
-
-ip_local_port_range
--------------------
-
-Range of  ports  used  by  TCP  and UDP to choose the local port. Contains two
-numbers, the  first  number  is the lowest port, the second number the highest
-local port.  Default  is  1024-4999.  Should  be  changed  to  32768-61000 for
-high-usage systems.
-
-ip_no_pmtu_disc
----------------
-
-Global switch  to  turn  path  MTU  discovery off. It can also be set on a per
-socket basis by the applications or on a per route basis.
-
-ip_masq_debug
--------------
-
-Enable/disable debugging of IP masquerading.
-
-IP fragmentation settings
--------------------------
-
-ipfrag_high_trash and ipfrag_low_trash
---------------------------------------
-
-Maximum memory  used to reassemble IP fragments. When ipfrag_high_thresh bytes
-of memory  is  allocated  for  this  purpose,  the  fragment handler will toss
-packets until ipfrag_low_thresh is reached.
-
-ipfrag_time
------------
-
-Time in seconds to keep an IP fragment in memory.
-
-TCP settings
-------------
-
-tcp_ecn
--------
-
-This file controls the use of the ECN bit in the IPv4 headers. This is a new
-feature about Explicit Congestion Notification, but some routers and firewalls
-block traffic that has this bit set, so it could be necessary to echo 0 to
-/proc/sys/net/ipv4/tcp_ecn if you want to talk to these sites. For more info
-you could read RFC2481.
-
-tcp_retrans_collapse
---------------------
-
-Bug-to-bug compatibility with some broken printers. On retransmit, try to send
-larger packets to work around bugs in certain TCP stacks. Can be turned off by
-setting it to zero.
-
-tcp_keepalive_probes
---------------------
-
-Number of  keep  alive  probes  TCP  sends  out,  until  it  decides  that the
-connection is broken.
-
-tcp_keepalive_time
-------------------
-
-How often  TCP  sends out keep alive messages, when keep alive is enabled. The
-default is 2 hours.
-
-tcp_syn_retries
----------------
-
-Number of  times  initial  SYNs  for  a  TCP  connection  attempt  will  be
-retransmitted. Should  not  be  higher  than 255. This is only the timeout for
-outgoing connections,  for  incoming  connections the number of retransmits is
-defined by tcp_retries1.
-
-tcp_sack
---------
-
-Enable select acknowledgments after RFC2018.
-
-tcp_timestamps
---------------
-
-Enable timestamps as defined in RFC1323.
-
-tcp_stdurg
-----------
-
-Enable the  strict  RFC793 interpretation of the TCP urgent pointer field. The
-default is  to  use  the  BSD  compatible interpretation of the urgent pointer
-pointing to the first byte after the urgent data. The RFC793 interpretation is
-to have  it  point  to  the last byte of urgent data. Enabling this option may
-lead to interoperability problems. Disabled by default.
-
-tcp_syncookies
---------------
-
-Only valid  when  the  kernel  was  compiled  with CONFIG_SYNCOOKIES. Send out
-syncookies when  the  syn backlog queue of a socket overflows. This is to ward
-off the common 'syn flood attack'. Disabled by default.
-
-Note that  the  concept  of a socket backlog is abandoned. This means the peer
-may not  receive  reliable  error  messages  from  an  over loaded server with
-syncookies enabled.
-
-tcp_window_scaling
-------------------
-
-Enable window scaling as defined in RFC1323.
-
-tcp_fin_timeout
----------------
-
-The length  of  time  in  seconds  it  takes to receive a final FIN before the
-socket is  always  closed.  This  is  strictly  a  violation  of  the  TCP
-specification, but required to prevent denial-of-service attacks.
-
-tcp_max_ka_probes
------------------
-
-Indicates how  many  keep alive probes are sent per slow timer run. Should not
-be set too high to prevent bursts.
-
-tcp_max_syn_backlog
--------------------
-
-Length of  the per socket backlog queue. Since Linux 2.2 the backlog specified
-in listen(2)  only  specifies  the  length  of  the  backlog  queue of already
-established sockets. When more connection requests arrive Linux starts to drop
-packets. When  syncookies  are  enabled the packets are still answered and the
-maximum queue is effectively ignored.
-
-tcp_retries1
-------------
-
-Defines how  often  an  answer  to  a  TCP connection request is retransmitted
-before giving up.
-
-tcp_retries2
-------------
-
-Defines how often a TCP packet is retransmitted before giving up.
-
-Interface specific settings
----------------------------
-
-In the directory /proc/sys/net/ipv4/conf you'll find one subdirectory for each
-interface the  system  knows about and one directory calls all. Changes in the
-all subdirectory  affect  all  interfaces,  whereas  changes  in  the  other
-subdirectories affect  only  one  interface.  All  directories  have  the same
-entries:
-
-accept_redirects
-----------------
-
-This switch  decides  if the kernel accepts ICMP redirect messages or not. The
-default is 'yes' if the kernel is configured for a regular host and 'no' for a
-router configuration.
-
-accept_source_route
--------------------
-
-Should source  routed  packages  be  accepted  or  declined.  The  default  is
-dependent on  the  kernel  configuration.  It's 'yes' for routers and 'no' for
-hosts.
-
-bootp_relay
-~~~~~~~~~~~
-
-Accept packets  with source address 0.b.c.d with destinations not to this host
-as local ones. It is supposed that a BOOTP relay daemon will catch and forward
-such packets.
-
-The default  is  0,  since this feature is not implemented yet (kernel version
-2.2.12).
-
-forwarding
-----------
-
-Enable or disable IP forwarding on this interface.
-
-log_martians
-------------
-
-Log packets with source addresses with no known route to kernel log.
-
-mc_forwarding
--------------
-
-Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE and a
-multicast routing daemon is required.
-
-proxy_arp
----------
-
-Does (1) or does not (0) perform proxy ARP.
-
-rp_filter
----------
-
-Integer value determines if a source validation should be made. 1 means yes, 0
-means no.  Disabled by default, but local/broadcast address spoofing is always
-on.
-
-If you  set this to 1 on a router that is the only connection for a network to
-the net,  it  will  prevent  spoofing  attacks  against your internal networks
-(external addresses  can  still  be  spoofed), without the need for additional
-firewall rules.
-
-secure_redirects
-----------------
-
-Accept ICMP  redirect  messages  only  for gateways, listed in default gateway
-list. Enabled by default.
-
-shared_media
-------------
-
-If it  is  not  set  the kernel does not assume that different subnets on this
-device can communicate directly. Default setting is 'yes'.
-
-send_redirects
---------------
-
-Determines whether to send ICMP redirects to other hosts.
-
-Routing settings
-----------------
-
-The directory  /proc/sys/net/ipv4/route  contains  several  file  to  control
-routing issues.
-
-error_burst and error_cost
---------------------------
-
-These  parameters  are used to limit how many ICMP destination unreachable to 
-send  from  the  host  in question. ICMP destination unreachable messages are 
-sent  when  we  cannot reach  the next hop while trying to transmit a packet. 
-It  will also print some error messages to kernel logs if someone is ignoring 
-our   ICMP  redirects.  The  higher  the  error_cost  factor  is,  the  fewer 
-destination  unreachable  and error messages will be let through. Error_burst 
-controls  when  destination  unreachable  messages and error messages will be
-dropped. The default settings limit warning messages to five every second.
-
-flush
------
-
-Writing to this file results in a flush of the routing cache.
-
-gc_elasticity, gc_interval, gc_min_interval_ms, gc_timeout, gc_thresh
----------------------------------------------------------------------
-
-Values to  control  the  frequency  and  behavior  of  the  garbage collection
-algorithm for the routing cache. gc_min_interval is deprecated and replaced
-by gc_min_interval_ms.
-
-
-max_size
---------
-
-Maximum size  of  the routing cache. Old entries will be purged once the cache
-reached has this size.
-
-redirect_load, redirect_number
-------------------------------
-
-Factors which  determine  if  more ICPM redirects should be sent to a specific
-host. No  redirects  will be sent once the load limit or the maximum number of
-redirects has been reached.
-
-redirect_silence
-----------------
-
-Timeout for redirects. After this period redirects will be sent again, even if
-this has been stopped, because the load or number limit has been reached.
-
-Network Neighbor handling
--------------------------
-
-Settings about how to handle connections with direct neighbors (nodes attached
-to the same link) can be found in the directory /proc/sys/net/ipv4/neigh.
-
-As we  saw  it  in  the  conf directory, there is a default subdirectory which
-holds the  default  values, and one directory for each interface. The contents
-of the  directories  are identical, with the single exception that the default
-settings contain additional options to set garbage collection parameters.
-
-In the interface directories you'll find the following entries:
-
-base_reachable_time, base_reachable_time_ms
--------------------------------------------
-
-A base  value  used for computing the random reachable time value as specified
-in RFC2461.
-
-Expression of base_reachable_time, which is deprecated, is in seconds.
-Expression of base_reachable_time_ms is in milliseconds.
-
-retrans_time, retrans_time_ms
------------------------------
-
-The time between retransmitted Neighbor Solicitation messages.
-Used for address resolution and to determine if a neighbor is
-unreachable.
-
-Expression of retrans_time, which is deprecated, is in 1/100 seconds (for
-IPv4) or in jiffies (for IPv6).
-Expression of retrans_time_ms is in milliseconds.
-
-unres_qlen
-----------
-
-Maximum queue  length  for a pending arp request - the number of packets which
-are accepted from other layers while the ARP address is still resolved.
-
-anycast_delay
--------------
-
-Maximum for  random  delay  of  answers  to  neighbor solicitation messages in
-jiffies (1/100  sec). Not yet implemented (Linux does not have anycast support
-yet).
-
-ucast_solicit
--------------
-
-Maximum number of retries for unicast solicitation.
-
-mcast_solicit
--------------
-
-Maximum number of retries for multicast solicitation.
-
-delay_first_probe_time
-----------------------
-
-Delay for  the  first  time  probe  if  the  neighbor  is  reachable.  (see
-gc_stale_time)
-
-locktime
---------
-
-An ARP/neighbor  entry  is only replaced with a new one if the old is at least
-locktime old. This prevents ARP cache thrashing.
-
-proxy_delay
------------
-
-Maximum time  (real  time is random [0..proxytime]) before answering to an ARP
-request for  which  we have an proxy ARP entry. In some cases, this is used to
-prevent network flooding.
-
-proxy_qlen
-----------
-
-Maximum queue length of the delayed proxy arp timer. (see proxy_delay).
-
-app_solicit
-----------
-
-Determines the  number of requests to send to the user level ARP daemon. Use 0
-to turn off.
-
-gc_stale_time
--------------
-
-Determines how  often  to  check  for stale ARP entries. After an ARP entry is
-stale it  will  be resolved again (which is useful when an IP address migrates
-to another  machine).  When  ucast_solicit is greater than 0 it first tries to
-send an  ARP  packet  directly  to  the  known  host  When  that  fails  and
-mcast_solicit is greater than 0, an ARP request is broadcasted.
-
-2.9 Appletalk
--------------
-
-The /proc/sys/net/appletalk  directory  holds the Appletalk configuration data
-when Appletalk is loaded. The configurable parameters are:
-
-aarp-expiry-time
-----------------
-
-The amount  of  time  we keep an ARP entry before expiring it. Used to age out
-old hosts.
-
-aarp-resolve-time
------------------
-
-The amount of time we will spend trying to resolve an Appletalk address.
-
-aarp-retransmit-limit
----------------------
-
-The number of times we will retransmit a query before giving up.
-
-aarp-tick-time
---------------
-
-Controls the rate at which expires are checked.
-
-The directory  /proc/net/appletalk  holds the list of active Appletalk sockets
-on a machine.
-
-The fields  indicate  the DDP type, the local address (in network:node format)
-the remote  address,  the  size of the transmit pending queue, the size of the
-received queue  (bytes waiting for applications to read) the state and the uid
-owning the socket.
-
-/proc/net/atalk_iface lists  all  the  interfaces  configured for appletalk.It
-shows the  name  of the interface, its Appletalk address, the network range on
-that address  (or  network number for phase 1 networks), and the status of the
-interface.
-
-/proc/net/atalk_route lists  each  known  network  route.  It lists the target
-(network) that the route leads to, the router (may be directly connected), the
-route flags, and the device the route is using.
-
-2.10 IPX
---------
-
-The IPX protocol has no tunable values in proc/sys/net.
-
-The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
-socket giving  the  local  and  remote  addresses  in  Novell  format (that is
-network:node:port). In  accordance  with  the  strange  Novell  tradition,
-everything but the port is in hex. Not_Connected is displayed for sockets that
-are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
-the number  of  bytes  pending  for  transmission  and  reception.  The  state
-indicates the  state  the  socket  is  in and the uid is the owning uid of the
-socket.
-
-The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
-it gives  the network number, the node number, and indicates if the network is
-the primary  network.  It  also  indicates  which  device  it  is bound to (or
-Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
-supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
-IPX.
-
-The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
-gives the  destination  network, the router node (or Directly) and the network
-address of the router (or Connected) for internal networks.
-
-2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem
-----------------------------------------------------------
-
-The "mqueue"  filesystem provides  the necessary kernel features to enable the
-creation of a  user space  library that  implements  the  POSIX message queues
-API (as noted by the  MSG tag in the  POSIX 1003.1-2001 version  of the System
-Interfaces specification.)
-
-The "mqueue" filesystem contains values for determining/setting  the amount of
-resources used by the file system.
-
-/proc/sys/fs/mqueue/queues_max is a read/write  file for  setting/getting  the
-maximum number of message queues allowed on the system.
-
-/proc/sys/fs/mqueue/msg_max  is  a  read/write file  for  setting/getting  the
-maximum number of messages in a queue value.  In fact it is the limiting value
-for another (user) limit which is set in mq_open invocation. This attribute of
-a queue must be less or equal then msg_max.
-
-/proc/sys/fs/mqueue/msgsize_max is  a read/write  file for setting/getting the
-maximum  message size value (it is every  message queue's attribute set during
-its creation).
+------------------------------------------------------------------------------
+CHAPTER 3: PER-PROCESS PARAMETERS
+------------------------------------------------------------------------------
 
-2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
+3.1 /proc/<pid>/oom_adj - Adjust the oom-killer score
 ------------------------------------------------------
 
 This file can be used to adjust the score used to select which processes
@@ -2062,25 +1037,15 @@ The task with the highest badness score is then selected and its children
 are killed, process itself will be killed in an OOM situation when it does
 not have children or some of them disabled oom like described above.
 
-2.13 /proc/<pid>/oom_score - Display current oom-killer score
+3.2 /proc/<pid>/oom_score - Display current oom-killer score
 -------------------------------------------------------------
 
-------------------------------------------------------------------------------
 This file can be used to check the current score used by the oom-killer is for
 any given <pid>. Use it together with /proc/<pid>/oom_adj to tune which
 process should be killed in an out-of-memory situation.
 
-------------------------------------------------------------------------------
-Summary
-------------------------------------------------------------------------------
-Certain aspects  of  kernel  behavior  can be modified at runtime, without the
-need to  recompile  the kernel, or even to reboot the system. The files in the
-/proc/sys tree  can  not only be read, but also modified. You can use the echo
-command to write value into these files, thereby changing the default settings
-of the kernel.
-------------------------------------------------------------------------------
 
-2.14  /proc/<pid>/io - Display the IO accounting fields
+3.3  /proc/<pid>/io - Display the IO accounting fields
 -------------------------------------------------------
 
 This file contains IO statistics for each running process
@@ -2182,7 +1147,7 @@ those 64-bit counters, process A could see an intermediate result.
 More information about this can be found within the taskstats documentation in
 Documentation/accounting.
 
-2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
+3.4 /proc/<pid>/coredump_filter - Core dump filtering settings
 ---------------------------------------------------------------
 When a process is dumped, all anonymous memory is written to a core file as
 long as the size of the core file isn't limited. But sometimes we don't want
@@ -2226,7 +1191,7 @@ For example:
   $ echo 0x7 > /proc/self/coredump_filter
   $ ./some_program
 
-2.16   /proc/<pid>/mountinfo - Information about mounts
+3.5    /proc/<pid>/mountinfo - Information about mounts
 --------------------------------------------------------
 
 This file contains lines of the form:
@@ -2263,30 +1228,3 @@ For more information on mount propagation see:
 
   Documentation/filesystems/sharedsubtree.txt
 
-2.17   /proc/sys/fs/epoll - Configuration options for the epoll interface
---------------------------------------------------------
-
-This directory contains configuration options for the epoll(7) interface.
-
-max_user_instances
-------------------
-
-This is the maximum number of epoll file descriptors that a single user can
-have open at a given time. The default value is 128, and should be enough
-for normal users.
-
-max_user_watches
-----------------
-
-Every epoll file descriptor can store a number of files to be monitored
-for event readiness. Each one of these monitored files constitutes a "watch".
-This configuration option sets the maximum number of "watches" that are
-allowed for each user.
-Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
-on a 64bit one.
-The current default value for  max_user_watches  is the 1/32 of the available
-low memory, divided for the "watch" cost in bytes.
-
-
-------------------------------------------------------------------------------
-
index 9f8740ca3f3bc514d9f5426168eb5b2273b96d42..26e4b8bc53ee097b0660650b83d276751855b1ea 100644 (file)
@@ -12,6 +12,7 @@ that support it.  For example, a given bus might look like this:
      |   |-- enable
      |   |-- irq
      |   |-- local_cpus
+     |   |-- remove
      |   |-- resource
      |   |-- resource0
      |   |-- resource1
@@ -36,6 +37,7 @@ files, each with their own function.
        enable             Whether the device is enabled (ascii, rw)
        irq                IRQ number (ascii, ro)
        local_cpus         nearby CPU mask (cpumask, ro)
+       remove             remove device from kernel's list (ascii, wo)
        resource                   PCI resource host addresses (ascii, ro)
        resource0..N       PCI resource N, if present (binary, mmap)
        resource0_wc..N_wc  PCI WC map resource N, if prefetchable (binary, mmap)
@@ -46,6 +48,7 @@ files, each with their own function.
 
   ro - read only file
   rw - file is readable and writable
+  wo - write only file
   mmap - file is mmapable
   ascii - file contains ascii text
   binary - file contains binary data
@@ -73,6 +76,13 @@ that the device must be enabled for a rom read to return data succesfully.
 In the event a driver is not bound to the device, it can be enabled using the
 'enable' file, documented above.
 
+The 'remove' file is used to remove the PCI device, by writing a non-zero
+integer to the file.  This does not involve any kind of hot-plug functionality,
+e.g. powering off the device.  The device is removed from the kernel's list of
+PCI devices, the sysfs directory for it is removed, and the device will be
+removed from any drivers attached to it. Removal of PCI root buses is
+disallowed.
+
 Accessing legacy resources through sysfs
 ----------------------------------------
 
index fde829a756e6510a9d5cd4d56c981e204151fa8c..902b95d0ee511a95825dc61193347ce72cb6a5d2 100644 (file)
@@ -24,6 +24,8 @@ The following mount options are supported:
 
        gid=            Set the default group.
        umask=          Set the default umask.
+       mode=           Set the default file permissions.
+       dmode=          Set the default directory permissions.
        uid=            Set the default user.
        bs=             Set the block size.
        unhide          Show otherwise hidden files.
index b1b9887012478f9b654edaa90bcdd13e72a9f20e..145c25a170c7abf6e0e489fba4c00b4784759dca 100644 (file)
@@ -123,7 +123,10 @@ platform-specific implementation issue.
 
 Using GPIOs
 -----------
-One of the first things to do with a GPIO, often in board setup code when
+The first thing a system should do with a GPIO is allocate it, using
+the gpio_request() call; see later.
+
+One of the next things to do with a GPIO, often in board setup code when
 setting up a platform_device using the GPIO, is mark its direction:
 
        /* set as input or output, returning 0 or negative errno */
@@ -141,8 +144,8 @@ This helps avoid signal glitching during system startup.
 
 For compatibility with legacy interfaces to GPIOs, setting the direction
 of a GPIO implicitly requests that GPIO (see below) if it has not been
-requested already.  That compatibility may be removed in the future;
-explicitly requesting GPIOs is strongly preferred.
+requested already.  That compatibility is being removed from the optional
+gpiolib framework.
 
 Setting the direction can fail if the GPIO number is invalid, or when
 that particular GPIO can't be used in that mode.  It's generally a bad
@@ -195,7 +198,7 @@ This requires sleeping, which can't be done from inside IRQ handlers.
 
 Platforms that support this type of GPIO distinguish them from other GPIOs
 by returning nonzero from this call (which requires a valid GPIO number,
-either explicitly or implicitly requested):
+which should have been previously allocated with gpio_request):
 
        int gpio_cansleep(unsigned gpio);
 
@@ -212,10 +215,9 @@ for GPIOs that can't be accessed from IRQ handlers, these calls act the
 same as the spinlock-safe calls.
 
 
-Claiming and Releasing GPIOs (OPTIONAL)
----------------------------------------
+Claiming and Releasing GPIOs
+----------------------------
 To help catch system configuration errors, two calls are defined.
-However, many platforms don't currently support this mechanism.
 
        /* request GPIO, returning 0 or negative errno.
         * non-null labels may be useful for diagnostics.
@@ -244,13 +246,6 @@ Some platforms may also use knowledge about what GPIOs are active for
 power management, such as by powering down unused chip sectors and, more
 easily, gating off unused clocks.
 
-These two calls are optional because not not all current Linux platforms
-offer such functionality in their GPIO support; a valid implementation
-could return success for all gpio_request() calls.  Unlike the other calls,
-the state they represent doesn't normally match anything from a hardware
-register; it's just a software bitmap which clearly is not necessary for
-correct operation of hardware or (bug free) drivers.
-
 Note that requesting a GPIO does NOT cause it to be configured in any
 way; it just marks that GPIO as in use.  Separate code must handle any
 pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
index 1fee6f1e6bc5574102b04d13d5ed1fd1396f0641..5e97f333c4df547e79507631a5b848578409f3d6 100644 (file)
@@ -49,12 +49,9 @@ of up to +/- 0.5 degrees even when compared against precise temperature
 readings. Be sure to have a high vs. low temperature limit gap of al least
 1.0 degree Celsius to avoid Tout "bouncing", though!
 
-As for alarms, you can read the alarm status of the DS1621 via the 'alarms'
-/sys file interface. The result consists mainly of bit 6 and 5 of the
-configuration register of the chip; bit 6 (0x40 or 64) is the high alarm
-bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or
-low limits are met or exceeded and are reset by the module as soon as the
-respective temperature ranges are left.
+The alarm bits are set when the high or low limits are met or exceeded and
+are reset by the module as soon as the respective temperature ranges are
+left.
 
 The alarm registers are in no way suitable to find out about the actual
 status of Tout. They will only tell you about its history, whether or not
@@ -64,45 +61,3 @@ with neither of the alarms set.
 
 Temperature conversion of the DS1621 takes up to 1000ms; internal access to
 non-volatile registers may last for 10ms or below.
-
-High Accuracy Temperature Reading
----------------------------------
-
-As said before, the temperature issued via the 9-bit i2c-bus data is
-somewhat arbitrary. Internally, the temperature conversion is of a
-different kind that is explained (not so...) well in the DS1621 data sheet.
-To cut the long story short: Inside the DS1621 there are two oscillators,
-both of them biassed by a temperature coefficient.
-
-Higher resolution of the temperature reading can be achieved using the
-internal projection, which means taking account of REG_COUNT and REG_SLOPE
-(the driver manages them):
-
-Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature
-Resolution on the DS1620' and App Note 105: 'High Resolution Temperature
-Measurement with Dallas Direct-to-Digital Temperature Sensors'
-
-- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs)
-- The resulting value is TEMP_READ.
-- Then, read REG_COUNT.
-- And then, REG_SLOPE.
-
-      TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE)
-
-Note that this is what the DONE bit in the DS1621 configuration register is
-good for: Internally, one temperature conversion takes up to 1000ms. Before
-that conversion is complete you will not be able to read valid things out
-of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now,
-tells you whether the conversion is complete ("done", in plain English) and
-thus, whether the values you read are good or not.
-
-The DS1621 has two modes of operation: "Continuous" conversion, which can
-be understood as the default stand-alone mode where the chip gets the
-temperature and controls external devices via its Tout pin or tells other
-i2c's about it if they care. The other mode is called "1SHOT", that means
-that it only figures out about the temperature when it is explicitly told
-to do so; this can be seen as power saving mode.
-
-Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop
-the continuous conversions until the contents of these registers are valid,
-or, in 1SHOT mode, you have to have one conversion made.
index 287f8c902656db40353954b967b06503d517dc70..effe949a7282cccd600365bffe78dd70541b9aa3 100644 (file)
@@ -1,11 +1,11 @@
 Kernel driver lis3lv02d
-==================
+=======================
 
 Supported chips:
 
   * STMicroelectronics LIS3LV02DL and LIS3LV02DQ
 
-Author:
+Authors:
         Yan Burman <burman.yan@gmail.com>
        Eric Piel <eric.piel@tremplin-utc.net>
 
@@ -15,7 +15,7 @@ Description
 
 This driver provides support for the accelerometer found in various HP
 laptops sporting the feature officially called "HP Mobile Data
-Protection System 3D" or "HP 3D DriveGuard". It detect automatically
+Protection System 3D" or "HP 3D DriveGuard". It detects automatically
 laptops with this sensor. Known models (for now the HP 2133, nc6420,
 nc2510, nc8510, nc84x0, nw9440 and nx9420) will have their axis
 automatically oriented on standard way (eg: you can directly play
@@ -27,7 +27,7 @@ position - 3D position that the accelerometer reports. Format: "(x,y,z)"
 calibrate - read: values (x, y, z) that are used as the base for input
                  class device operation.
             write: forces the base to be recalibrated with the current
-                 position.
+                  position.
 rate - reports the sampling rate of the accelerometer device in HZ
 
 This driver also provides an absolute input class device, allowing
@@ -48,7 +48,7 @@ For better compatibility between the various laptops. The values reported by
 the accelerometer are converted into a "standard" organisation of the axes
 (aka "can play neverball out of the box"):
  * When the laptop is horizontal the position reported is about 0 for X and Y
-and a positive value for Z
+       and a positive value for Z
  * If the left side is elevated, X increases (becomes positive)
  * If the front side (where the touchpad is) is elevated, Y decreases
        (becomes negative)
@@ -59,3 +59,13 @@ email to the authors to add it to the database.  When reporting a new
 laptop, please include the output of "dmidecode" plus the value of
 /sys/devices/platform/lis3lv02d/position in these four cases.
 
+Q&A
+---
+
+Q: How do I safely simulate freefall? I have an HP "portable
+workstation" which has about 3.5kg and a plastic case, so letting it
+fall to the ground is out of question...
+
+A: The sensor is pretty sensitive, so your hands can do it. Lift it
+into free space, follow the fall with your hands for like 10
+centimeters. That should be enough to trigger the detection.
diff --git a/Documentation/hwmon/ltc4215 b/Documentation/hwmon/ltc4215
new file mode 100644 (file)
index 0000000..2e6a21e
--- /dev/null
@@ -0,0 +1,50 @@
+Kernel driver ltc4215
+=====================
+
+Supported chips:
+  * Linear Technology LTC4215
+    Prefix: 'ltc4215'
+    Addresses scanned: 0x44
+    Datasheet:
+        http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1163,P17572,D12697
+
+Author: Ira W. Snyder <iws@ovro.caltech.edu>
+
+
+Description
+-----------
+
+The LTC4215 controller allows a board to be safely inserted and removed
+from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4215 devices, due to the fact that some
+of the possible addresses are unfriendly to probing. You will need to use
+the "force" parameter to tell the driver where to find the device.
+
+Example: the following will load the driver for an LTC4215 at address 0x44
+on I2C bus #0:
+$ modprobe ltc4215 force=0,0x44
+
+
+Sysfs entries
+-------------
+
+The LTC4215 has built-in limits for overvoltage, undervoltage, and
+undercurrent warnings. This makes it very likely that the reference
+circuit will be used.
+
+in1_input              input voltage
+in2_input              output voltage
+
+in1_min_alarm          input undervoltage alarm
+in1_max_alarm          input overvoltage alarm
+
+curr1_input            current
+curr1_max_alarm                overcurrent alarm
+
+power1_input           power usage
+power1_alarm           power bad alarm
index 6dbfd5efd991de9f6a69eaa831d1a45634ba5979..2f10ce6a879f7276f635cd1ac51c03d8c004d8c1 100644 (file)
@@ -365,6 +365,7 @@ energy[1-*]_input           Cumulative energy use
                                Unit: microJoule
                                RO
 
+
 **********
 * Alarms *
 **********
@@ -453,6 +454,27 @@ beep_mask  Bitmask for beep.
                RW
 
 
+***********************
+* Intrusion detection *
+***********************
+
+intrusion[0-*]_alarm
+               Chassis intrusion detection
+               0: OK
+               1: intrusion detected
+               RW
+               Contrary to regular alarm flags which clear themselves
+               automatically when read, this one sticks until cleared by
+               the user. This is done by writing 0 to the file. Writing
+               other values is unsupported.
+
+intrusion[0-*]_beep
+               Chassis intrusion beep
+               0: disable
+               1: enable
+               RW
+
+
 sysfs attribute writes interpretation
 -------------------------------------
 
index d6e1ae30fa6e61f3da3e523befa708dcfbedb627..b6eb59384bb39c1b67d0c99a1ade601269a64d05 100644 (file)
@@ -2,30 +2,40 @@ Kernel driver w83627ehf
 =======================
 
 Supported chips:
-  * Winbond W83627EHF/EHG/DHG (ISA access ONLY)
+  * Winbond W83627EHF/EHG (ISA access ONLY)
     Prefix: 'w83627ehf'
     Addresses scanned: ISA address retrieved from Super I/O registers
     Datasheet:
-        http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
-        DHG datasheet confidential.
+        http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
+  * Winbond W83627DHG
+    Prefix: 'w83627dhg'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet:
+        http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
+  * Winbond W83667HG
+    Prefix: 'w83667hg'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: not available
 
 Authors:
         Jean Delvare <khali@linux-fr.org>
         Yuan Mu (Winbond)
         Rudolf Marek <r.marek@assembler.cz>
         David Hubbard <david.c.hubbard@gmail.com>
+        Gong Jun <JGong@nuvoton.com>
 
 Description
 -----------
 
-This driver implements support for the Winbond W83627EHF, W83627EHG, and
-W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
+This driver implements support for the Winbond W83627EHF, W83627EHG,
+W83627DHG and W83667HG super I/O chips. We will refer to them collectively
+as Winbond chips.
 
 The chips implement three temperature sensors, five fan rotation
 speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
-VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG), alarms with beep
-warnings (control unimplemented), and some automatic fan regulation
-strategies (plus manual fan control mode).
+VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
+with beep warnings (control unimplemented), and some automatic fan
+regulation strategies (plus manual fan control mode).
 
 Temperatures are measured in degrees Celsius and measurement resolution is 1
 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
@@ -54,7 +64,8 @@ follows:
 temp1 -> pwm1
 temp2 -> pwm2
 temp3 -> pwm3
-prog  -> pwm4 (the programmable setting is not supported by the driver)
+prog  -> pwm4 (not on 667HG; the programmable setting is not supported by
+              the driver)
 
 /sys files
 ----------
index 84f7cb3d5bec43499965cb683d966f22ee15f85b..ffb5c80bec3e1b39713357b799566193fce6e644 100644 (file)
@@ -42,7 +42,7 @@ Note: For step 2, please make sure that host page size == TARGET_PAGE_SIZE of qe
                hg clone http://xenbits.xensource.com/ext/efi-vfirmware.hg
            you can get the firmware's binary in the directory of efi-vfirmware.hg/binaries.
 
-       (3) Rename the firware you owned to Flash.fd, and copy it to /usr/local/share/qemu
+       (3) Rename the firmware you owned to Flash.fd, and copy it to /usr/local/share/qemu
 
 4. Boot up Linux or Windows guests:
        4.1 Create or install a image for guest boot. If you have xen experience, it should be easy.
index aeedb89a307ae2d8b1f6c9aa58399146e6c332b2..421920897a37bd4a1d3e4167b31bf0b94838d685 100644 (file)
@@ -1523,7 +1523,9 @@ and is between 256 and 4096 characters. It is defined in the file
 
        noclflush       [BUGS=X86] Don't use the CLFLUSH instruction
 
-       nohlt           [BUGS=ARM,SH]
+       nohlt           [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
+                       wfi(ARM) instruction doesn't work correctly and not to
+                       use it. This is also useful when using JTAG debugger.
 
        no-hlt          [BUGS=X86-32] Tells the kernel that the hlt
                        instruction doesn't work correctly and not to
@@ -1603,7 +1605,7 @@ and is between 256 and 4096 characters. It is defined in the file
        nosoftlockup    [KNL] Disable the soft-lockup detector.
 
        noswapaccount   [KNL] Disable accounting of swap in memory resource
-                       controller. (See Documentation/controllers/memory.txt)
+                       controller. (See Documentation/cgroups/memory.txt)
 
        nosync          [HW,M68K] Disables sync negotiation for all devices.
 
@@ -1695,6 +1697,8 @@ and is between 256 and 4096 characters. It is defined in the file
                        See also Documentation/blockdev/paride.txt.
 
        pci=option[,option...]  [PCI] various PCI subsystem options:
+               earlydump       [X86] dump PCI config space before the kernel
+                               changes anything
                off             [X86] don't probe for the PCI bus
                bios            [X86-32] force use of PCI BIOS, don't access
                                the hardware directly. Use this if your machine
@@ -1794,6 +1798,15 @@ and is between 256 and 4096 characters. It is defined in the file
                cbmemsize=nn[KMG]       The fixed amount of bus space which is
                                reserved for the CardBus bridge's memory
                                window. The default value is 64 megabytes.
+               resource_alignment=
+                               Format:
+                               [<order of align>@][<domain>:]<bus>:<slot>.<func>[; ...]
+                               Specifies alignment and device to reassign
+                               aligned memory resources.
+                               If <order of align> is not specified,
+                               PAGE_SIZE is used as alignment.
+                               PCI-PCI bridge can be specified, if resource
+                               windows need to be expanded.
 
        pcie_aspm=      [PCIE] Forcibly enable or disable PCIe Active State Power
                        Management.
@@ -1942,7 +1955,7 @@ and is between 256 and 4096 characters. It is defined in the file
 
        relax_domain_level=
                        [KNL, SMP] Set scheduler's default relax_domain_level.
-                       See Documentation/cpusets.txt.
+                       See Documentation/cgroups/cpusets.txt.
 
        reserve=        [KNL,BUGS] Force the kernel to ignore some iomem area
 
index f2dbbf3bdeaba7a5c6d58e1ccb3f8a686ade88ed..d36fcc0f2715c705d0f70d1aa9c13e20b8aaa917 100644 (file)
@@ -1630,6 +1630,13 @@ static bool service_io(struct device *dev)
                }
        }
 
+       /* OK, so we noted that it was pretty poor to use an fdatasync as a
+        * barrier.  But Christoph Hellwig points out that we need a sync
+        * *afterwards* as well: "Barriers specify no reordering to the front
+        * or the back."  And Jens Axboe confirmed it, so here we are: */
+       if (out->type & VIRTIO_BLK_T_BARRIER)
+               fdatasync(vblk->fd);
+
        /* We can't trigger an IRQ, because we're not the Launcher.  It does
         * that when we tell it we're done. */
        add_used(dev->vq, head, wlen);
index 488773018152056ea159685e732e42452a7ae142..938ea22f2cc096f6838a678217e463bf9ec0cd4d 100644 (file)
@@ -27,33 +27,37 @@ lock-class.
 State
 -----
 
-The validator tracks lock-class usage history into 5 separate state bits:
+The validator tracks lock-class usage history into 4n + 1 separate state bits:
 
-- 'ever held in hardirq context'                    [ == hardirq-safe   ]
-- 'ever held in softirq context'                    [ == softirq-safe   ]
-- 'ever held with hardirqs enabled'                 [ == hardirq-unsafe ]
-- 'ever held with softirqs and hardirqs enabled'    [ == softirq-unsafe ]
+- 'ever held in STATE context'
+- 'ever head as readlock in STATE context'
+- 'ever head with STATE enabled'
+- 'ever head as readlock with STATE enabled'
+
+Where STATE can be either one of (kernel/lockdep_states.h)
+ - hardirq
+ - softirq
+ - reclaim_fs
 
 - 'ever used'                                       [ == !unused        ]
 
-When locking rules are violated, these state bits are presented in the
-locking error messages, inside curlies.  A contrived example:
+When locking rules are violated, these state bits are presented in the
+locking error messages, inside curlies. A contrived example:
 
    modprobe/2287 is trying to acquire lock:
-    (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
+    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
 
    but task is already holding lock:
-    (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
+    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
 
 
-The bit position indicates hardirq, softirq, hardirq-read,
-softirq-read respectively, and the character displayed in each
-indicates:
+The bit position indicates STATE, STATE-read, for each of the states listed
+above, and the character displayed in each indicates:
 
    '.'  acquired while irqs disabled
    '+'  acquired in irq context
    '-'  acquired with irqs enabled
-   '?' read acquired in irq context with irqs enabled.
+   '?'  acquired in irq context with irqs enabled.
 
 Unused mutexes cannot be part of the cause of an error.
 
index 1da9d1b1793f3436b3561a48de7fbcd8c893e74e..4edd39ec7db91abcbcbac352fc3c5e6d3e3c3eca 100644 (file)
@@ -164,15 +164,19 @@ All md devices contain:
   raid_disks
      a text file with a simple number indicating the number of devices
      in a fully functional array.  If this is not yet known, the file
-     will be empty.  If an array is being resized (not currently
-     possible) this will contain the larger of the old and new sizes.
-     Some raid level (RAID1) allow this value to be set while the
-     array is active.  This will reconfigure the array.   Otherwise
-     it can only be set while assembling an array.
+     will be empty.  If an array is being resized this will contain
+     the new number of devices.
+     Some raid levels allow this value to be set while the array is
+     active.  This will reconfigure the array.   Otherwise it can only
+     be set while assembling an array.
+     A change to this attribute will not be permitted if it would
+     reduce the size of the array.  To reduce the number of drives
+     in an e.g. raid5, the array size must first be reduced by
+     setting the 'array_size' attribute.
 
   chunk_size
-     This is the size if bytes for 'chunks' and is only relevant to
-     raid levels that involve striping (1,4,5,6,10). The address space
+     This is the size in bytes for 'chunks' and is only relevant to
+     raid levels that involve striping (0,4,5,6,10). The address space
      of the array is conceptually divided into chunks and consecutive
      chunks are striped onto neighbouring devices.
      The size should be at least PAGE_SIZE (4k) and should be a power
@@ -183,6 +187,20 @@ All md devices contain:
      simply a number that is interpretted differently by different
      levels.  It can be written while assembling an array.
 
+  array_size
+     This can be used to artificially constrain the available space in
+     the array to be less than is actually available on the combined
+     devices.  Writing a number (in Kilobytes) which is less than
+     the available size will set the size.  Any reconfiguration of the
+     array (e.g. adding devices) will not cause the size to change.
+     Writing the word 'default' will cause the effective size of the
+     array to be whatever size is actually available based on
+     'level', 'chunk_size' and 'component_size'.
+
+     This can be used to reduce the size of the array before reducing
+     the number of devices in a raid4/5/6, or to support external
+     metadata formats which mandate such clipping.
+
   reshape_position
      This is either "none" or a sector number within the devices of
      the array where "reshape" is up to.  If this is set, the three
@@ -207,6 +225,11 @@ All md devices contain:
      about the array.  It can be 0.90 (traditional format), 1.0, 1.1,
      1.2 (newer format in varying locations) or "none" indicating that
      the kernel isn't managing metadata at all.
+     Alternately it can be "external:" followed by a string which
+     is set by user-space.  This indicates that metadata is managed
+     by a user-space program.  Any device failure or other event that
+     requires a metadata update will cause array activity to be
+     suspended until the event is acknowledged.
 
   resync_start
      The point at which resync should start.  If no resync is needed,
diff --git a/Documentation/misc-devices/isl29003 b/Documentation/misc-devices/isl29003
new file mode 100644 (file)
index 0000000..c4ff5f3
--- /dev/null
@@ -0,0 +1,62 @@
+Kernel driver isl29003
+=====================
+
+Supported chips:
+* Intersil ISL29003
+Prefix: 'isl29003'
+Addresses scanned: none
+Datasheet:
+http://www.intersil.com/data/fn/fn7464.pdf
+
+Author: Daniel Mack <daniel@caiaq.de>
+
+
+Description
+-----------
+The ISL29003 is an integrated light sensor with a 16-bit integrating type
+ADC, I2C user programmable lux range select for optimized counts/lux, and
+I2C multi-function control and monitoring capabilities. The internal ADC
+provides 16-bit resolution while rejecting 50Hz and 60Hz flicker caused by
+artificial light sources.
+
+The driver allows to set the lux range, the bit resolution, the operational
+mode (see below) and the power state of device and can read the current lux
+value, of course.
+
+
+Detection
+---------
+
+The ISL29003 does not have an ID register which could be used to identify
+it, so the detection routine will just try to read from the configured I2C
+addess and consider the device to be present as soon as it ACKs the
+transfer.
+
+
+Sysfs entries
+-------------
+
+range:
+       0: 0 lux to 1000 lux (default)
+       1: 0 lux to 4000 lux
+       2: 0 lux to 16,000 lux
+       3: 0 lux to 64,000 lux
+
+resolution:
+       0: 2^16 cycles (default)
+       1: 2^12 cycles
+       2: 2^8 cycles
+       3: 2^4 cycles
+
+mode:
+       0: diode1's current (unsigned 16bit) (default)
+       1: diode1's current (unsigned 16bit)
+       2: difference between diodes (l1 - l2, signed 15bit)
+
+power_state:
+       0: device is disabled (default)
+       1: device is enabled
+
+lux (read only):
+       returns the value from the last sensor reading
+
diff --git a/Documentation/networking/vxge.txt b/Documentation/networking/vxge.txt
new file mode 100644 (file)
index 0000000..d2e2997
--- /dev/null
@@ -0,0 +1,100 @@
+Neterion's (Formerly S2io) X3100 Series 10GbE PCIe Server Adapter Linux driver
+==============================================================================
+
+Contents
+--------
+
+1) Introduction
+2) Features supported
+3) Configurable driver parameters
+4) Troubleshooting
+
+1) Introduction:
+----------------
+This Linux driver supports all Neterion's X3100 series 10 GbE PCIe I/O
+Virtualized Server adapters.
+The X3100 series supports four modes of operation, configurable via
+firmware -
+       Single function mode
+       Multi function mode
+       SRIOV mode
+       MRIOV mode
+The functions share a 10GbE link and the pci-e bus, but hardly anything else
+inside the ASIC. Features like independent hw reset, statistics, bandwidth/
+priority allocation and guarantees, GRO, TSO, interrupt moderation etc are
+supported independently on each function.
+
+(See below for a complete list of features supported for both IPv4 and IPv6)
+
+2) Features supported:
+----------------------
+
+i)   Single function mode (up to 17 queues)
+
+ii)  Multi function mode (up to 17 functions)
+
+iii) PCI-SIG's I/O Virtualization
+       - Single Root mode: v1.0 (up to 17 functions)
+       - Multi-Root mode: v1.0 (up to 17 functions)
+
+iv)  Jumbo frames
+       X3100 Series supports MTU up to 9600 bytes, modifiable using
+       ifconfig command.
+
+v)   Offloads supported: (Enabled by default)
+       Checksum offload (TCP/UDP/IP) on transmit and receive paths
+       TCP Segmentation Offload (TSO) on transmit path
+       Generic Receive Offload (GRO) on receive path
+
+vi)  MSI-X: (Enabled by default)
+       Resulting in noticeable performance improvement (up to 7% on certain
+       platforms).
+
+vii) NAPI: (Enabled by default)
+       For better Rx interrupt moderation.
+
+viii)RTH (Receive Traffic Hash): (Enabled by default)
+       Receive side steering for better scaling.
+
+ix)  Statistics
+       Comprehensive MAC-level and software statistics displayed using
+       "ethtool -S" option.
+
+x)   Multiple hardware queues: (Enabled by default)
+       Up to 17 hardware based transmit and receive data channels, with
+       multiple steering options (transmit multiqueue enabled by default).
+
+3) Configurable driver parameters:
+----------------------------------
+
+i)  max_config_dev
+       Specifies maximum device functions to be enabled.
+       Valid range: 1-8
+
+ii) max_config_port
+       Specifies number of ports to be enabled.
+       Valid range: 1,2
+       Default: 1
+
+iii)max_config_vpath
+       Specifies maximum VPATH(s) configured for each device function.
+       Valid range: 1-17
+
+iv) vlan_tag_strip
+       Enables/disables vlan tag stripping from all received tagged frames that
+       are not replicated at the internal L2 switch.
+       Valid range: 0,1 (disabled, enabled respectively)
+       Default: 1
+
+v)  addr_learn_en
+       Enable learning the mac address of the guest OS interface in
+       virtualization environment.
+       Valid range: 0,1 (disabled, enabled respectively)
+       Default: 0
+
+4) Troubleshooting:
+-------------------
+
+To resolve an issue with the source code or X3100 series adapter, please collect
+the statistics, register dumps using ethool, relevant logs and email them to
+support@neterion.com.
index 6c238f59b2a94f589cc5c7e3d4d451e8714f825f..249db3a15d15c16c1ca105335bcc51d91b68b301 100644 (file)
@@ -1,6 +1,6 @@
 * Uploaded QE firmware
 
-      If a new firwmare has been uploaded to the QE (usually by the
+      If a new firmware has been uploaded to the QE (usually by the
       boot loader), then a 'firmware' child node should be added to the QE
       node.  This node provides information on the uploaded firmware that
       device drivers may need.
diff --git a/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt b/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt
new file mode 100644 (file)
index 0000000..c39ac28
--- /dev/null
@@ -0,0 +1,23 @@
+MMC/SD/SDIO slot directly connected to a SPI bus
+
+Required properties:
+- compatible : should be "mmc-spi-slot".
+- reg : should specify SPI address (chip-select number).
+- spi-max-frequency : maximum frequency for this device (Hz).
+- voltage-ranges : two cells are required, first cell specifies minimum
+  slot voltage (mV), second cell specifies maximum slot voltage (mV).
+  Several ranges could be specified.
+- gpios : (optional) may specify GPIOs in this order: Card-Detect GPIO,
+  Write-Protect GPIO.
+
+Example:
+
+       mmc-slot@0 {
+               compatible = "fsl,mpc8323rdb-mmc-slot",
+                            "mmc-spi-slot";
+               reg = <0>;
+               gpios = <&qe_pio_d 14 1
+                        &qe_pio_d 15 0>;
+               voltage-ranges = <3300 3300>;
+               spi-max-frequency = <50000000>;
+       };
index 3ef339f491e09058e37659f0bf96c52022b5dec7..5ba4d3fc625a424b341bfa5b5853473eaf80fe6a 100644 (file)
@@ -126,7 +126,7 @@ This uses the /cgroup virtual file system and "/cgroup/<cgroup>/cpu.rt_runtime_u
 to control the CPU time reserved for each control group instead.
 
 For more information on working with control groups, you should read
-Documentation/cgroups.txt as well.
+Documentation/cgroups/cgroups.txt as well.
 
 Group settings are checked against the following limits in order to keep the configuration
 schedulable:
diff --git a/Documentation/slow-work.txt b/Documentation/slow-work.txt
new file mode 100644 (file)
index 0000000..ebc50f8
--- /dev/null
@@ -0,0 +1,174 @@
+                    ====================================
+                    SLOW WORK ITEM EXECUTION THREAD POOL
+                    ====================================
+
+By: David Howells <dhowells@redhat.com>
+
+The slow work item execution thread pool is a pool of threads for performing
+things that take a relatively long time, such as making mkdir calls.
+Typically, when processing something, these items will spend a lot of time
+blocking a thread on I/O, thus making that thread unavailable for doing other
+work.
+
+The standard workqueue model is unsuitable for this class of work item as that
+limits the owner to a single thread or a single thread per CPU.  For some
+tasks, however, more threads - or fewer - are required.
+
+There is just one pool per system.  It contains no threads unless something
+wants to use it - and that something must register its interest first.  When
+the pool is active, the number of threads it contains is dynamic, varying
+between a maximum and minimum setting, depending on the load.
+
+
+====================
+CLASSES OF WORK ITEM
+====================
+
+This pool support two classes of work items:
+
+ (*) Slow work items.
+
+ (*) Very slow work items.
+
+The former are expected to finish much quicker than the latter.
+
+An operation of the very slow class may do a batch combination of several
+lookups, mkdirs, and a create for instance.
+
+An operation of the ordinarily slow class may, for example, write stuff or
+expand files, provided the time taken to do so isn't too long.
+
+Operations of both types may sleep during execution, thus tying up the thread
+loaned to it.
+
+
+THREAD-TO-CLASS ALLOCATION
+--------------------------
+
+Not all the threads in the pool are available to work on very slow work items.
+The number will be between one and one fewer than the number of active threads.
+This is configurable (see the "Pool Configuration" section).
+
+All the threads are available to work on ordinarily slow work items, but a
+percentage of the threads will prefer to work on very slow work items.
+
+The configuration ensures that at least one thread will be available to work on
+very slow work items, and at least one thread will be available that won't work
+on very slow work items at all.
+
+
+=====================
+USING SLOW WORK ITEMS
+=====================
+
+Firstly, a module or subsystem wanting to make use of slow work items must
+register its interest:
+
+        int ret = slow_work_register_user();
+
+This will return 0 if successful, or a -ve error upon failure.
+
+
+Slow work items may then be set up by:
+
+ (1) Declaring a slow_work struct type variable:
+
+       #include <linux/slow-work.h>
+
+       struct slow_work myitem;
+
+ (2) Declaring the operations to be used for this item:
+
+       struct slow_work_ops myitem_ops = {
+               .get_ref = myitem_get_ref,
+               .put_ref = myitem_put_ref,
+               .execute = myitem_execute,
+       };
+
+     [*] For a description of the ops, see section "Item Operations".
+
+ (3) Initialising the item:
+
+       slow_work_init(&myitem, &myitem_ops);
+
+     or:
+
+       vslow_work_init(&myitem, &myitem_ops);
+
+     depending on its class.
+
+A suitably set up work item can then be enqueued for processing:
+
+       int ret = slow_work_enqueue(&myitem);
+
+This will return a -ve error if the thread pool is unable to gain a reference
+on the item, 0 otherwise.
+
+
+The items are reference counted, so there ought to be no need for a flush
+operation.  When all a module's slow work items have been processed, and the
+module has no further interest in the facility, it should unregister its
+interest:
+
+       slow_work_unregister_user();
+
+
+===============
+ITEM OPERATIONS
+===============
+
+Each work item requires a table of operations of type struct slow_work_ops.
+All members are required:
+
+ (*) Get a reference on an item:
+
+       int (*get_ref)(struct slow_work *work);
+
+     This allows the thread pool to attempt to pin an item by getting a
+     reference on it.  This function should return 0 if the reference was
+     granted, or a -ve error otherwise.  If an error is returned,
+     slow_work_enqueue() will fail.
+
+     The reference is held whilst the item is queued and whilst it is being
+     executed.  The item may then be requeued with the same reference held, or
+     the reference will be released.
+
+ (*) Release a reference on an item:
+
+       void (*put_ref)(struct slow_work *work);
+
+     This allows the thread pool to unpin an item by releasing the reference on
+     it.  The thread pool will not touch the item again once this has been
+     called.
+
+ (*) Execute an item:
+
+       void (*execute)(struct slow_work *work);
+
+     This should perform the work required of the item.  It may sleep, it may
+     perform disk I/O and it may wait for locks.
+
+
+==================
+POOL CONFIGURATION
+==================
+
+The slow-work thread pool has a number of configurables:
+
+ (*) /proc/sys/kernel/slow-work/min-threads
+
+     The minimum number of threads that should be in the pool whilst it is in
+     use.  This may be anywhere between 2 and max-threads.
+
+ (*) /proc/sys/kernel/slow-work/max-threads
+
+     The maximum number of threads that should in the pool.  This may be
+     anywhere between min-threads and 255 or NR_CPUS * 2, whichever is greater.
+
+ (*) /proc/sys/kernel/slow-work/vslow-percentage
+
+     The percentage of active threads in the pool that may be used to execute
+     very slow work items.  This may be between 1 and 99.  The resultant number
+     is bounded to between 1 and one fewer than the number of active threads.
+     This ensures there is always at least one thread that can process very
+     slow work items, and always at least one thread that won't.
index a20a9066dc4c21af860c5dbbb06ef356af565ff7..1286f455992f195f2a0ae1511614d9617dbe22b3 100644 (file)
@@ -10,6 +10,8 @@ fs.txt
        - documentation for /proc/sys/fs/*.
 kernel.txt
        - documentation for /proc/sys/kernel/*.
+net.txt
+       - documentation for /proc/sys/net/*.
 sunrpc.txt
        - documentation for /proc/sys/sunrpc/*.
 vm.txt
index f99254327ae59b59971d979b38cc083d3ac096e5..1458448436cc4589bc329167ba945eb92719792b 100644 (file)
@@ -1,5 +1,6 @@
 Documentation for /proc/sys/fs/*       kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
+       (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
 
 For general info and legal blurb, please look in README.
 
@@ -14,7 +15,12 @@ kernel. Since some of the files _can_ be used to screw up your
 system, it is advisable to read both documentation and source
 before actually making adjustments.
 
+1. /proc/sys/fs
+----------------------------------------------------------
+
 Currently, these files are in /proc/sys/fs:
+- aio-max-nr
+- aio-nr
 - dentry-state
 - dquot-max
 - dquot-nr
@@ -30,8 +36,15 @@ Currently, these files are in /proc/sys/fs:
 - super-max
 - super-nr
 
-Documentation for the files in /proc/sys/fs/binfmt_misc is
-in Documentation/binfmt_misc.txt.
+==============================================================
+
+aio-nr & aio-max-nr:
+
+aio-nr is the running total of the number of events specified on the
+io_setup system call for all currently active aio contexts.  If aio-nr
+reaches aio-max-nr then io_setup will fail with EAGAIN.  Note that
+raising aio-max-nr does not result in the pre-allocation or re-sizing
+of any kernel data structures.
 
 ==============================================================
 
@@ -178,3 +191,60 @@ requests.  aio-max-nr allows you to change the maximum value
 aio-nr can grow to.
 
 ==============================================================
+
+
+2. /proc/sys/fs/binfmt_misc
+----------------------------------------------------------
+
+Documentation for the files in /proc/sys/fs/binfmt_misc is
+in Documentation/binfmt_misc.txt.
+
+
+3. /proc/sys/fs/mqueue - POSIX message queues filesystem
+----------------------------------------------------------
+
+The "mqueue"  filesystem provides  the necessary kernel features to enable the
+creation of a  user space  library that  implements  the  POSIX message queues
+API (as noted by the  MSG tag in the  POSIX 1003.1-2001 version  of the System
+Interfaces specification.)
+
+The "mqueue" filesystem contains values for determining/setting  the amount of
+resources used by the file system.
+
+/proc/sys/fs/mqueue/queues_max is a read/write  file for  setting/getting  the
+maximum number of message queues allowed on the system.
+
+/proc/sys/fs/mqueue/msg_max  is  a  read/write file  for  setting/getting  the
+maximum number of messages in a queue value.  In fact it is the limiting value
+for another (user) limit which is set in mq_open invocation. This attribute of
+a queue must be less or equal then msg_max.
+
+/proc/sys/fs/mqueue/msgsize_max is  a read/write  file for setting/getting the
+maximum  message size value (it is every  message queue's attribute set during
+its creation).
+
+
+4. /proc/sys/fs/epoll - Configuration options for the epoll interface
+--------------------------------------------------------
+
+This directory contains configuration options for the epoll(7) interface.
+
+max_user_instances
+------------------
+
+This is the maximum number of epoll file descriptors that a single user can
+have open at a given time. The default value is 128, and should be enough
+for normal users.
+
+max_user_watches
+----------------
+
+Every epoll file descriptor can store a number of files to be monitored
+for event readiness. Each one of these monitored files constitutes a "watch".
+This configuration option sets the maximum number of "watches" that are
+allowed for each user.
+Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
+on a 64bit one.
+The current default value for  max_user_watches  is the 1/32 of the available
+low memory, divided for the "watch" cost in bytes.
+
index a4ccdd1981cfbc9f45b8aaabf46017dd739ab5fa..f11ca7979fa67b5bbf08339cf473d110ecf92f7d 100644 (file)
@@ -1,5 +1,6 @@
 Documentation for /proc/sys/kernel/*   kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
+       (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
 
 For general info and legal blurb, please look in README.
 
@@ -18,6 +19,7 @@ Currently, these files might (depending on your configuration)
 show up in /proc/sys/kernel:
 - acpi_video_flags
 - acct
+- auto_msgmni
 - core_pattern
 - core_uses_pid
 - ctrl-alt-del
@@ -33,6 +35,7 @@ show up in /proc/sys/kernel:
 - msgmax
 - msgmnb
 - msgmni
+- nmi_watchdog
 - osrelease
 - ostype
 - overflowgid
@@ -40,6 +43,7 @@ show up in /proc/sys/kernel:
 - panic
 - pid_max
 - powersave-nap               [ PPC only ]
+- panic_on_unrecovered_nmi
 - printk
 - randomize_va_space
 - real-root-dev               ==> Documentation/initrd.txt
@@ -55,6 +59,7 @@ show up in /proc/sys/kernel:
 - sysrq                       ==> Documentation/sysrq.txt
 - tainted
 - threads-max
+- unknown_nmi_panic
 - version
 
 ==============================================================
@@ -381,3 +386,51 @@ can be ORed together:
  512 - A kernel warning has occurred.
 1024 - A module from drivers/staging was loaded.
 
+==============================================================
+
+auto_msgmni:
+
+Enables/Disables automatic recomputing of msgmni upon memory add/remove or
+upon ipc namespace creation/removal (see the msgmni description above).
+Echoing "1" into this file enables msgmni automatic recomputing.
+Echoing "0" turns it off.
+auto_msgmni default value is 1.
+
+==============================================================
+
+nmi_watchdog:
+
+Enables/Disables the NMI watchdog on x86 systems.  When the value is non-zero
+the NMI watchdog is enabled and will continuously test all online cpus to
+determine whether or not they are still functioning properly. Currently,
+passing "nmi_watchdog=" parameter at boot time is required for this function
+to work.
+
+If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the
+NMI watchdog shares registers with oprofile. By disabling the NMI watchdog,
+oprofile may have more registers to utilize.
+
+==============================================================
+
+unknown_nmi_panic:
+
+The value in this file affects behavior of handling NMI. When the value is
+non-zero, unknown NMI is trapped and then panic occurs. At that time, kernel
+debugging information is displayed on console.
+
+NMI switch that most IA32 servers have fires unknown NMI up, for example.
+If a system hangs up, try pressing the NMI switch.
+
+==============================================================
+
+panic_on_unrecovered_nmi:
+
+The default Linux behaviour on an NMI of either memory or unknown is to continue
+operation. For many environments such as scientific computing it is preferable
+that the box is taken out and the error dealt with than an uncorrected
+parity/ECC error get propogated.
+
+A small number of systems do generate NMI's for bizarre random reasons such as
+power management so the default is off. That sysctl works like the existing
+panic controls already in that directory.
+
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
new file mode 100644 (file)
index 0000000..a34d55b
--- /dev/null
@@ -0,0 +1,175 @@
+Documentation for /proc/sys/net/*      kernel version 2.4.0-test11-pre4
+       (c) 1999                Terrehon Bowden <terrehon@pacbell.net>
+                               Bodo Bauer <bb@ricochet.net>
+       (c) 2000                Jorge Nerin <comandante@zaralinux.com>
+       (c) 2009                Shen Feng <shen@cn.fujitsu.com>
+
+For general info and legal blurb, please look in README.
+
+==============================================================
+
+This file contains the documentation for the sysctl files in
+/proc/sys/net and is valid for Linux kernel version 2.4.0-test11-pre4.
+
+The interface  to  the  networking  parts  of  the  kernel  is  located  in
+/proc/sys/net. The following table shows all possible subdirectories.You may
+see only some of them, depending on your kernel's configuration.
+
+
+Table : Subdirectories in /proc/sys/net
+..............................................................................
+ Directory Content             Directory  Content
+ core      General parameter   appletalk  Appletalk protocol
+ unix      Unix domain sockets netrom     NET/ROM
+ 802       E802 protocol       ax25       AX25
+ ethernet  Ethernet protocol   rose       X.25 PLP layer
+ ipv4      IP version 4        x25        X.25 protocol
+ ipx       IPX                 token-ring IBM token ring
+ bridge    Bridging            decnet     DEC net
+ ipv6      IP version 6
+..............................................................................
+
+1. /proc/sys/net/core - Network core options
+-------------------------------------------------------
+
+rmem_default
+------------
+
+The default setting of the socket receive buffer in bytes.
+
+rmem_max
+--------
+
+The maximum receive socket buffer size in bytes.
+
+wmem_default
+------------
+
+The default setting (in bytes) of the socket send buffer.
+
+wmem_max
+--------
+
+The maximum send socket buffer size in bytes.
+
+message_burst and message_cost
+------------------------------
+
+These parameters  are used to limit the warning messages written to the kernel
+log from  the  networking  code.  They  enforce  a  rate  limit  to  make  a
+denial-of-service attack  impossible. A higher message_cost factor, results in
+fewer messages that will be written. Message_burst controls when messages will
+be dropped.  The  default  settings  limit  warning messages to one every five
+seconds.
+
+warnings
+--------
+
+This controls console messages from the networking stack that can occur because
+of problems on the network like duplicate address or bad checksums. Normally,
+this should be enabled, but if the problem persists the messages can be
+disabled.
+
+netdev_budget
+-------------
+
+Maximum number of packets taken from all interfaces in one polling cycle (NAPI
+poll). In one polling cycle interfaces which are registered to polling are
+probed in a round-robin manner. The limit of packets in one such probe can be
+set per-device via sysfs class/net/<device>/weight .
+
+netdev_max_backlog
+------------------
+
+Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
+receives packets faster than kernel can process them.
+
+optmem_max
+----------
+
+Maximum ancillary buffer size allowed per socket. Ancillary data is a sequence
+of struct cmsghdr structures with appended data.
+
+2. /proc/sys/net/unix - Parameters for Unix domain sockets
+-------------------------------------------------------
+
+There is only one file in this directory.
+unix_dgram_qlen limits the max number of datagrams queued in Unix domain
+socket's buffer. It will not take effect unless PF_UNIX flag is spicified.
+
+
+3. /proc/sys/net/ipv4 - IPV4 settings
+-------------------------------------------------------
+Please see: Documentation/networking/ip-sysctl.txt and ipvs-sysctl.txt for
+descriptions of these entries.
+
+
+4. Appletalk
+-------------------------------------------------------
+
+The /proc/sys/net/appletalk  directory  holds the Appletalk configuration data
+when Appletalk is loaded. The configurable parameters are:
+
+aarp-expiry-time
+----------------
+
+The amount  of  time  we keep an ARP entry before expiring it. Used to age out
+old hosts.
+
+aarp-resolve-time
+-----------------
+
+The amount of time we will spend trying to resolve an Appletalk address.
+
+aarp-retransmit-limit
+---------------------
+
+The number of times we will retransmit a query before giving up.
+
+aarp-tick-time
+--------------
+
+Controls the rate at which expires are checked.
+
+The directory  /proc/net/appletalk  holds the list of active Appletalk sockets
+on a machine.
+
+The fields  indicate  the DDP type, the local address (in network:node format)
+the remote  address,  the  size of the transmit pending queue, the size of the
+received queue  (bytes waiting for applications to read) the state and the uid
+owning the socket.
+
+/proc/net/atalk_iface lists  all  the  interfaces  configured for appletalk.It
+shows the  name  of the interface, its Appletalk address, the network range on
+that address  (or  network number for phase 1 networks), and the status of the
+interface.
+
+/proc/net/atalk_route lists  each  known  network  route.  It lists the target
+(network) that the route leads to, the router (may be directly connected), the
+route flags, and the device the route is using.
+
+
+5. IPX
+-------------------------------------------------------
+
+The IPX protocol has no tunable values in proc/sys/net.
+
+The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
+socket giving  the  local  and  remote  addresses  in  Novell  format (that is
+network:node:port). In  accordance  with  the  strange  Novell  tradition,
+everything but the port is in hex. Not_Connected is displayed for sockets that
+are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
+the number  of  bytes  pending  for  transmission  and  reception.  The  state
+indicates the  state  the  socket  is  in and the uid is the owning uid of the
+socket.
+
+The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
+it gives  the network number, the node number, and indicates if the network is
+the primary  network.  It  also  indicates  which  device  it  is bound to (or
+Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
+supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
+IPX.
+
+The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
+gives the  destination  network, the router node (or Directly) and the network
+address of the router (or Connected) for internal networks.
index 9e592c718afb4bb41737399b29ff088adca386da..afa2946892da0e8c785d6b1d2fe879751b397499 100644 (file)
@@ -81,6 +81,8 @@ On all -  write a character to /proc/sysrq-trigger.  e.g.:
 
 'i'     - Send a SIGKILL to all processes, except for init.
 
+'j'     - Forcibly "Just thaw it" - filesystems frozen by the FIFREEZE ioctl.
+
 'k'     - Secure Access Key (SAK) Kills all programs on the current virtual
           console. NOTE: See important comments below in SAK section.
 
@@ -160,6 +162,9 @@ t'E'rm and k'I'll are useful if you have some sort of runaway process you
 are unable to kill any other way, especially if it's spawning other
 processes.
 
+"'J'ust thaw it" is useful if your system becomes unresponsive due to a frozen
+(probably root) filesystem via the FIFREEZE ioctl.
+
 *  Sometimes SysRq seems to get 'stuck' after using it, what can I do?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 That happens to me, also. I've found that tapping shift, alt, and control
index 6aaaeb38730cf0ff1d5389cd73a6a8d2fb6bd413..be45dbb9d7f23ef17c472ef981f4a42512480229 100644 (file)
@@ -8,7 +8,8 @@ The current memory policy support was added to Linux 2.6 around May 2004.  This
 document attempts to describe the concepts and APIs of the 2.6 memory policy
 support.
 
-Memory policies should not be confused with cpusets (Documentation/cpusets.txt)
+Memory policies should not be confused with cpusets
+(Documentation/cgroups/cpusets.txt)
 which is an administrative mechanism for restricting the nodes from which
 memory may be allocated by a set of processes. Memory policies are a
 programming interface that a NUMA-aware application can take advantage of.  When
index d5fdfd34bbaf4835bd7381b93cdd09774f8b9b01..6513fe2d90b8084743bd66ebcb5a5bd73c64482b 100644 (file)
@@ -37,7 +37,8 @@ locations.
 
 Larger installations usually partition the system using cpusets into
 sections of nodes. Paul Jackson has equipped cpusets with the ability to
-move pages when a task is moved to another cpuset (See ../cpusets.txt).
+move pages when a task is moved to another cpuset (See
+Documentation/cgroups/cpusets.txt).
 Cpusets allows the automation of process locality. If a task is moved to
 a new cpuset then also all its pages are moved with it so that the
 performance of the process does not sink dramatically. Also the pages
index 33bb56655991421f8a5e7e24f695eab0ce73fe63..0f11d9becb0b4001657d6ca6b6391f473d3c524e 100644 (file)
@@ -7,7 +7,8 @@ you can create fake NUMA nodes that represent contiguous chunks of memory and
 assign them to cpusets and their attached tasks.  This is a way of limiting the
 amount of system memory that are available to a certain class of tasks.
 
-For more information on the features of cpusets, see Documentation/cpusets.txt.
+For more information on the features of cpusets, see
+Documentation/cgroups/cpusets.txt.
 There are a number of different configurations you can use for your needs.  For
 more information on the numa=fake command line option and its various ways of
 configuring fake nodes, see Documentation/x86/x86_64/boot-options.txt.
@@ -32,7 +33,7 @@ A machine may be split as follows with "numa=fake=4*512," as reported by dmesg:
        On node 3 totalpages: 131072
 
 Now following the instructions for mounting the cpusets filesystem from
-Documentation/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
+Documentation/cgroups/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
 address spaces) to individual cpusets:
 
        [root@xroads /]# mkdir exampleset
index c5f4e9d27b64a1fc323e87eeb8eab886150e96e2..6360b9b9bbbda557860ac202de5cb62cd244c43a 100644 (file)
@@ -357,6 +357,7 @@ S:  Odd Fixes for 2.4; Maintained for 2.6.
 P:     Ivan Kokshaysky
 M:     ink@jurassic.park.msu.ru
 S:     Maintained for 2.4; PCI support for 2.6.
+L:     linux-alpha@vger.kernel.org
 
 AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
 P:     Thomas Dahlmann
@@ -1762,6 +1763,12 @@ M:       viro@zeniv.linux.org.uk
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
 
+FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
+P:     Riku Voipio
+M:     riku.vipio@iki.fi
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
 P:     Kristian Hoegsberg, Stefan Richter
 M:     krh@redhat.com, stefanr@s5r6.in-berlin.de
@@ -1944,6 +1951,12 @@ L:       lm-sensors@lm-sensors.org
 W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 S:     Maintained
 
+HYPERVISOR VIRTUAL CONSOLE DRIVER
+L:     linuxppc-dev@ozlabs.org
+L:     linux-kernel@vger.kernel.org
+S:     Odd Fixes
+F:     drivers/char/hvc_*
+
 GSPCA FINEPIX SUBDRIVER
 P:     Frank Zago
 M:     frank@zago.net
@@ -2201,25 +2214,12 @@ L:      linux-ide@vger.kernel.org
 T:     quilt kernel.org/pub/linux/kernel/people/bart/pata-2.6/
 S:     Maintained
 
-IDE/ATAPI CDROM DRIVER
+IDE/ATAPI DRIVERS
 P:     Borislav Petkov
 M:     petkovbb@gmail.com
 L:     linux-ide@vger.kernel.org
 S:     Maintained
 
-IDE/ATAPI FLOPPY DRIVERS
-P:     Paul Bristow
-M:     Paul Bristow <paul@paulbristow.net>
-W:     http://paulbristow.net/linux/idefloppy.html
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-
-IDE/ATAPI TAPE DRIVERS
-P:     Gadi Oxman
-M:     Gadi Oxman <gadio@netvision.net.il>
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-
 IDLE-I7300
 P:     Andy Henroid
 M:     andrew.d.henroid@intel.com
@@ -3110,7 +3110,7 @@ M:        shemminger@linux-foundation.org
 L:     netem@lists.linux-foundation.org
 S:     Maintained
 
-NETERION (S2IO) Xframe 10GbE DRIVER
+NETERION (S2IO) 10GbE DRIVER (xframe/vxge)
 P:     Ramkrishna Vepa
 M:     ram.vepa@neterion.com
 P:     Rastapur Santosh
@@ -3119,8 +3119,11 @@ P:       Sivakumar Subramani
 M:     sivakumar.subramani@neterion.com
 P:     Sreenivasa Honnur
 M:     sreenivasa.honnur@neterion.com
+P:     Anil Murthy
+M:     anil.murthy@neterion.com
 L:     netdev@vger.kernel.org
-W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/TitleIndex?anonymous
+W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
+W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
 S:     Supported
 
 NETFILTER/IPTABLES/IPCHAINS
@@ -3411,6 +3414,11 @@ P:       Jim Cromie
 M:     jim.cromie@gmail.com
 S:     Maintained
 
+PCA9532 LED DRIVER
+P:     Riku Voipio
+M:     riku.voipio@iki.fi
+S:     Maintained
+
 PCI ERROR RECOVERY
 P:     Linas Vepstas
 M:     linas@austin.ibm.com
@@ -4850,7 +4858,7 @@ M:        lrg@slimlogic.co.uk
 P:     Mark Brown
 M:     broonie@opensource.wolfsonmicro.com
 W:     http://opensource.wolfsonmicro.com/node/15
-W:     http://www.slimlogic.co.uk/?page_id=5
+W:     http://www.slimlogic.co.uk/?p=48
 T:     git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
 S:     Supported
 
@@ -4972,7 +4980,8 @@ S:        Supported
 
 XFS FILESYSTEM
 P:     Silicon Graphics Inc
-P:     Bill O'Donnell
+P:     Felix Blyakher
+M:     felixb@sgi.com
 M:     xfs-masters@oss.sgi.com
 L:     xfs@oss.sgi.com
 W:     http://oss.sgi.com/projects/xfs
index fea4ea75b79d20d08cac71369968a5d95c4a104b..13cd42743810e916b1be719497ac511034ddef67 100644 (file)
@@ -80,7 +80,7 @@ struct alpha_machine_vector
        void (*update_irq_hw)(unsigned long, unsigned long, int);
        void (*ack_irq)(unsigned long);
        void (*device_interrupt)(unsigned long vector);
-       void (*machine_check)(u64 vector, u64 la);
+       void (*machine_check)(unsigned long vector, unsigned long la);
 
        void (*smp_callin)(void);
        void (*init_arch)(void);
index 2a14302c17a337194cf3df0a7d20ae4dfa28273d..cb04eaa6ba33d13fb7be187c2bcd67ea626a2bfa 100644 (file)
@@ -273,4 +273,18 @@ struct pci_dev *alpha_gendev_to_pci(struct device *dev);
 
 extern struct pci_dev *isa_bridge;
 
+extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
+                          size_t count);
+extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val,
+                           size_t count);
+extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
+                                     struct vm_area_struct *vma,
+                                     enum pci_mmap_state mmap_state);
+extern void pci_adjust_legacy_attr(struct pci_bus *bus,
+                                  enum pci_mmap_state mmap_type);
+#define HAVE_PCI_LEGACY        1
+
+extern int pci_create_resource_files(struct pci_dev *dev);
+extern void pci_remove_resource_files(struct pci_dev *dev);
+
 #endif /* __ALPHA_PCI_H */
index aeeb125f68513df03fe1d625de0cf1883b46c869..e38fb95cb3352fd15c5bf3e505459bc8f702500f 100644 (file)
@@ -166,6 +166,9 @@ static inline void __raw_write_unlock(raw_rwlock_t * lock)
        lock->lock = 0;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index afe20fa58c990927fd10c5e94d41fe4d8d9eee8a..5aa40cca4f2356ea12a62e8576d50303a2b704b5 100644 (file)
@@ -309,518 +309,71 @@ extern int __min_ipl;
 #define tbia()         __tbi(-2, /* no second argument */)
 
 /*
- * Atomic exchange.
- * Since it can be used to implement critical sections
- * it must clobber "memory" (also for interrupts in UP).
+ * Atomic exchange routines.
  */
 
-static inline unsigned long
-__xchg_u8(volatile char *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       insbl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extbl   %2,%4,%0\n"
-       "       mskbl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u16(volatile short *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       inswl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extwl   %2,%4,%0\n"
-       "       mskwl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u32(volatile int *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
-
-       return val;
-}
-
-static inline unsigned long
-__xchg_u64(volatile long *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,2f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
+#define __ASM__MB
+#define ____xchg(type, args...)                __xchg ## type ## _local(args)
+#define ____cmpxchg(type, args...)     __cmpxchg ## type ## _local(args)
+#include <asm/xchg.h>
 
-       return val;
-}
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid xchg().  */
-extern void __xchg_called_with_bad_pointer(void);
-
-#define __xchg(ptr, x, size) \
-({ \
-       unsigned long __xchg__res; \
-       volatile void *__xchg__ptr = (ptr); \
-       switch (size) { \
-               case 1: __xchg__res = __xchg_u8(__xchg__ptr, x); break; \
-               case 2: __xchg__res = __xchg_u16(__xchg__ptr, x); break; \
-               case 4: __xchg__res = __xchg_u32(__xchg__ptr, x); break; \
-               case 8: __xchg__res = __xchg_u64(__xchg__ptr, x); break; \
-               default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
-       } \
-       __xchg__res; \
-})
-
-#define xchg(ptr,x)                                                         \
-  ({                                                                        \
-     __typeof__(*(ptr)) _x_ = (x);                                          \
-     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
+#define xchg_local(ptr,x)                                              \
+  ({                                                                   \
+     __typeof__(*(ptr)) _x_ = (x);                                     \
+     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,      \
+                                      sizeof(*(ptr)));                 \
   })
 
-static inline unsigned long
-__xchg_u8_local(volatile char *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       insbl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extbl   %2,%4,%0\n"
-       "       mskbl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u16_local(volatile short *m, unsigned long val)
-{
-       unsigned long ret, tmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %4,7,%3\n"
-       "       inswl   %1,%4,%1\n"
-       "1:     ldq_l   %2,0(%3)\n"
-       "       extwl   %2,%4,%0\n"
-       "       mskwl   %2,%4,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%3)\n"
-       "       beq     %2,2f\n"
-       ".subsection 2\n"
-       "2:     br      1b\n"
-       ".previous"
-       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
-       : "r" ((long)m), "1" (val) : "memory");
-
-       return ret;
-}
-
-static inline unsigned long
-__xchg_u32_local(volatile int *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
-
-       return val;
-}
-
-static inline unsigned long
-__xchg_u64_local(volatile long *m, unsigned long val)
-{
-       unsigned long dummy;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%4\n"
-       "       bis $31,%3,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "rI" (val), "m" (*m) : "memory");
-
-       return val;
-}
-
-#define __xchg_local(ptr, x, size) \
-({ \
-       unsigned long __xchg__res; \
-       volatile void *__xchg__ptr = (ptr); \
-       switch (size) { \
-               case 1: __xchg__res = __xchg_u8_local(__xchg__ptr, x); break; \
-               case 2: __xchg__res = __xchg_u16_local(__xchg__ptr, x); break; \
-               case 4: __xchg__res = __xchg_u32_local(__xchg__ptr, x); break; \
-               case 8: __xchg__res = __xchg_u64_local(__xchg__ptr, x); break; \
-               default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
-       } \
-       __xchg__res; \
-})
-
-#define xchg_local(ptr,x)                                                   \
-  ({                                                                        \
-     __typeof__(*(ptr)) _x_ = (x);                                          \
-     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,           \
-               sizeof(*(ptr))); \
+#define cmpxchg_local(ptr, o, n)                                       \
+  ({                                                                   \
+     __typeof__(*(ptr)) _o_ = (o);                                     \
+     __typeof__(*(ptr)) _n_ = (n);                                     \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,   \
+                                         (unsigned long)_n_,           \
+                                         sizeof(*(ptr)));              \
   })
 
-/* 
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- *
- * The memory barrier should be placed in SMP only when we actually
- * make the change. If we don't change anything (so if the returned
- * prev is equal to old) then we aren't acquiring anything new and
- * we don't need any memory barrier as far I can tell.
- */
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long
-__cmpxchg_u8(volatile char *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       insbl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extbl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskbl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u16(volatile short *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       inswl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extwl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskwl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u32(volatile int *m, int old, int new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,3f\n"
-#ifdef CONFIG_SMP
-       "       mb\n"
-#endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
 
-static inline unsigned long
-__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,3f\n"
 #ifdef CONFIG_SMP
-       "       mb\n"
+#undef __ASM__MB
+#define __ASM__MB      "\tmb\n"
 #endif
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid cmpxchg().  */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static __always_inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
-{
-       switch (size) {
-               case 1:
-                       return __cmpxchg_u8(ptr, old, new);
-               case 2:
-                       return __cmpxchg_u16(ptr, old, new);
-               case 4:
-                       return __cmpxchg_u32(ptr, old, new);
-               case 8:
-                       return __cmpxchg_u64(ptr, old, new);
-       }
-       __cmpxchg_called_with_bad_pointer();
-       return old;
-}
-
-#define cmpxchg(ptr, o, n)                                              \
-  ({                                                                    \
-     __typeof__(*(ptr)) _o_ = (o);                                      \
-     __typeof__(*(ptr)) _n_ = (n);                                      \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,          \
-                                   (unsigned long)_n_, sizeof(*(ptr))); \
+#undef ____xchg
+#undef ____cmpxchg
+#define ____xchg(type, args...)                __xchg ##type(args)
+#define ____cmpxchg(type, args...)     __cmpxchg ##type(args)
+#include <asm/xchg.h>
+
+#define xchg(ptr,x)                                                    \
+  ({                                                                   \
+     __typeof__(*(ptr)) _x_ = (x);                                     \
+     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_,            \
+                                sizeof(*(ptr)));                       \
   })
-#define cmpxchg64(ptr, o, n)                                            \
-  ({                                                                    \
-       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                               \
-       cmpxchg((ptr), (o), (n));                                        \
-  })
-
-static inline unsigned long
-__cmpxchg_u8_local(volatile char *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       insbl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extbl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskbl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u16_local(volatile short *m, long old, long new)
-{
-       unsigned long prev, tmp, cmp, addr64;
-
-       __asm__ __volatile__(
-       "       andnot  %5,7,%4\n"
-       "       inswl   %1,%5,%1\n"
-       "1:     ldq_l   %2,0(%4)\n"
-       "       extwl   %2,%5,%0\n"
-       "       cmpeq   %0,%6,%3\n"
-       "       beq     %3,2f\n"
-       "       mskwl   %2,%5,%2\n"
-       "       or      %1,%2,%2\n"
-       "       stq_c   %2,0(%4)\n"
-       "       beq     %2,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br      1b\n"
-       ".previous"
-       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
-       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u32_local(volatile int *m, int old, int new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stl_c %1,%2\n"
-       "       beq %1,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
-
-static inline unsigned long
-__cmpxchg_u64_local(volatile long *m, unsigned long old, unsigned long new)
-{
-       unsigned long prev, cmp;
-
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%5\n"
-       "       cmpeq %0,%3,%1\n"
-       "       beq %1,2f\n"
-       "       mov %4,%1\n"
-       "       stq_c %1,%2\n"
-       "       beq %1,3f\n"
-       "2:\n"
-       ".subsection 2\n"
-       "3:     br 1b\n"
-       ".previous"
-       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
-       : "r"((long) old), "r"(new), "m"(*m) : "memory");
-
-       return prev;
-}
-
-static __always_inline unsigned long
-__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
-               int size)
-{
-       switch (size) {
-               case 1:
-                       return __cmpxchg_u8_local(ptr, old, new);
-               case 2:
-                       return __cmpxchg_u16_local(ptr, old, new);
-               case 4:
-                       return __cmpxchg_u32_local(ptr, old, new);
-               case 8:
-                       return __cmpxchg_u64_local(ptr, old, new);
-       }
-       __cmpxchg_called_with_bad_pointer();
-       return old;
-}
 
-#define cmpxchg_local(ptr, o, n)                                        \
-  ({                                                                    \
-     __typeof__(*(ptr)) _o_ = (o);                                      \
-     __typeof__(*(ptr)) _n_ = (n);                                      \
-     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,    \
-                                   (unsigned long)_n_, sizeof(*(ptr))); \
+#define cmpxchg(ptr, o, n)                                             \
+  ({                                                                   \
+     __typeof__(*(ptr)) _o_ = (o);                                     \
+     __typeof__(*(ptr)) _n_ = (n);                                     \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,         \
+                                   (unsigned long)_n_, sizeof(*(ptr)));\
   })
-#define cmpxchg64_local(ptr, o, n)                                      \
-  ({                                                                    \
-       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                               \
-       cmpxchg_local((ptr), (o), (n));                                  \
+
+#define cmpxchg64(ptr, o, n)                                           \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg((ptr), (o), (n));                                       \
   })
 
+#undef __ASM__MB
+#undef ____cmpxchg
+
+#define __HAVE_ARCH_CMPXCHG 1
 
 #endif /* __ASSEMBLY__ */
 
index c1541353ccefe04e67fe183ecb2013f7cb491642..f072f344497e7adba62719db66324bb11144c5ae 100644 (file)
@@ -8,7 +8,12 @@
  * not a major issue.  However, for interoperability, libraries still
  * need to be careful to avoid a name clashes.
  */
+
+#ifdef __KERNEL__
+#include <asm-generic/int-ll64.h>
+#else
 #include <asm-generic/int-l64.h>
+#endif
 
 #ifndef __ASSEMBLY__
 
index 22de3b434a22a59d7f16bce6520787efab1fc8f9..163f3053001c82e4976c082d1798ab656615088a 100644 (file)
@@ -498,13 +498,13 @@ struct exception_table_entry
 };
 
 /* Returns the new pc */
-#define fixup_exception(map_reg, fixup, pc)                    \
+#define fixup_exception(map_reg, _fixup, pc)                   \
 ({                                                             \
-       if ((fixup)->fixup.bits.valreg != 31)                   \
-               map_reg((fixup)->fixup.bits.valreg) = 0;        \
-       if ((fixup)->fixup.bits.errreg != 31)                   \
-               map_reg((fixup)->fixup.bits.errreg) = -EFAULT;  \
-       (pc) + (fixup)->fixup.bits.nextinsn;                    \
+       if ((_fixup)->fixup.bits.valreg != 31)                  \
+               map_reg((_fixup)->fixup.bits.valreg) = 0;       \
+       if ((_fixup)->fixup.bits.errreg != 31)                  \
+               map_reg((_fixup)->fixup.bits.errreg) = -EFAULT; \
+       (pc) + (_fixup)->fixup.bits.nextinsn;                   \
 })
 
 
diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h
new file mode 100644 (file)
index 0000000..beba1b8
--- /dev/null
@@ -0,0 +1,258 @@
+#ifndef __ALPHA_SYSTEM_H
+#error Do not include xchg.h directly!
+#else
+/*
+ * xchg/xchg_local and cmpxchg/cmpxchg_local share the same code
+ * except that local version do not have the expensive memory barrier.
+ * So this file is included twice from asm/system.h.
+ */
+
+/*
+ * Atomic exchange.
+ * Since it can be used to implement critical sections
+ * it must clobber "memory" (also for interrupts in UP).
+ */
+
+static inline unsigned long
+____xchg(_u8, volatile char *m, unsigned long val)
+{
+       unsigned long ret, tmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %4,7,%3\n"
+       "       insbl   %1,%4,%1\n"
+       "1:     ldq_l   %2,0(%3)\n"
+       "       extbl   %2,%4,%0\n"
+       "       mskbl   %2,%4,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%3)\n"
+       "       beq     %2,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br      1b\n"
+       ".previous"
+       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+       : "r" ((long)m), "1" (val) : "memory");
+
+       return ret;
+}
+
+static inline unsigned long
+____xchg(_u16, volatile short *m, unsigned long val)
+{
+       unsigned long ret, tmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %4,7,%3\n"
+       "       inswl   %1,%4,%1\n"
+       "1:     ldq_l   %2,0(%3)\n"
+       "       extwl   %2,%4,%0\n"
+       "       mskwl   %2,%4,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%3)\n"
+       "       beq     %2,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br      1b\n"
+       ".previous"
+       : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+       : "r" ((long)m), "1" (val) : "memory");
+
+       return ret;
+}
+
+static inline unsigned long
+____xchg(_u32, volatile int *m, unsigned long val)
+{
+       unsigned long dummy;
+
+       __asm__ __volatile__(
+       "1:     ldl_l %0,%4\n"
+       "       bis $31,%3,%1\n"
+       "       stl_c %1,%2\n"
+       "       beq %1,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br 1b\n"
+       ".previous"
+       : "=&r" (val), "=&r" (dummy), "=m" (*m)
+       : "rI" (val), "m" (*m) : "memory");
+
+       return val;
+}
+
+static inline unsigned long
+____xchg(_u64, volatile long *m, unsigned long val)
+{
+       unsigned long dummy;
+
+       __asm__ __volatile__(
+       "1:     ldq_l %0,%4\n"
+       "       bis $31,%3,%1\n"
+       "       stq_c %1,%2\n"
+       "       beq %1,2f\n"
+               __ASM__MB
+       ".subsection 2\n"
+       "2:     br 1b\n"
+       ".previous"
+       : "=&r" (val), "=&r" (dummy), "=m" (*m)
+       : "rI" (val), "m" (*m) : "memory");
+
+       return val;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid xchg().  */
+extern void __xchg_called_with_bad_pointer(void);
+
+static __always_inline unsigned long
+____xchg(, volatile void *ptr, unsigned long x, int size)
+{
+       switch (size) {
+               case 1:
+                       return ____xchg(_u8, ptr, x);
+               case 2:
+                       return ____xchg(_u16, ptr, x);
+               case 4:
+                       return ____xchg(_u32, ptr, x);
+               case 8:
+                       return ____xchg(_u64, ptr, x);
+       }
+       __xchg_called_with_bad_pointer();
+       return x;
+}
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ *
+ * The memory barrier should be placed in SMP only when we actually
+ * make the change. If we don't change anything (so if the returned
+ * prev is equal to old) then we aren't acquiring anything new and
+ * we don't need any memory barrier as far I can tell.
+ */
+
+static inline unsigned long
+____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new)
+{
+       unsigned long prev, tmp, cmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %5,7,%4\n"
+       "       insbl   %1,%5,%1\n"
+       "1:     ldq_l   %2,0(%4)\n"
+       "       extbl   %2,%5,%0\n"
+       "       cmpeq   %0,%6,%3\n"
+       "       beq     %3,2f\n"
+       "       mskbl   %2,%5,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%4)\n"
+       "       beq     %2,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br      1b\n"
+       ".previous"
+       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+       return prev;
+}
+
+static inline unsigned long
+____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new)
+{
+       unsigned long prev, tmp, cmp, addr64;
+
+       __asm__ __volatile__(
+       "       andnot  %5,7,%4\n"
+       "       inswl   %1,%5,%1\n"
+       "1:     ldq_l   %2,0(%4)\n"
+       "       extwl   %2,%5,%0\n"
+       "       cmpeq   %0,%6,%3\n"
+       "       beq     %3,2f\n"
+       "       mskwl   %2,%5,%2\n"
+       "       or      %1,%2,%2\n"
+       "       stq_c   %2,0(%4)\n"
+       "       beq     %2,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br      1b\n"
+       ".previous"
+       : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+       : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+       return prev;
+}
+
+static inline unsigned long
+____cmpxchg(_u32, volatile int *m, int old, int new)
+{
+       unsigned long prev, cmp;
+
+       __asm__ __volatile__(
+       "1:     ldl_l %0,%5\n"
+       "       cmpeq %0,%3,%1\n"
+       "       beq %1,2f\n"
+       "       mov %4,%1\n"
+       "       stl_c %1,%2\n"
+       "       beq %1,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br 1b\n"
+       ".previous"
+       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+       : "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+       return prev;
+}
+
+static inline unsigned long
+____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new)
+{
+       unsigned long prev, cmp;
+
+       __asm__ __volatile__(
+       "1:     ldq_l %0,%5\n"
+       "       cmpeq %0,%3,%1\n"
+       "       beq %1,2f\n"
+       "       mov %4,%1\n"
+       "       stq_c %1,%2\n"
+       "       beq %1,3f\n"
+               __ASM__MB
+       "2:\n"
+       ".subsection 2\n"
+       "3:     br 1b\n"
+       ".previous"
+       : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+       : "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+       return prev;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __always_inline unsigned long
+____cmpxchg(, volatile void *ptr, unsigned long old, unsigned long new,
+             int size)
+{
+       switch (size) {
+               case 1:
+                       return ____cmpxchg(_u8, ptr, old, new);
+               case 2:
+                       return ____cmpxchg(_u16, ptr, old, new);
+               case 4:
+                       return ____cmpxchg(_u32, ptr, old, new);
+               case 8:
+                       return ____cmpxchg(_u64, ptr, old, new);
+       }
+       __cmpxchg_called_with_bad_pointer();
+       return old;
+}
+
+#endif
index b4697759a1235ad60ce5458fcd6b896fb4f24e1d..a427538252f878aa664520e5c3f6f6d7ee844513 100644 (file)
@@ -12,7 +12,7 @@ obj-y    := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
 
 obj-$(CONFIG_VGA_HOSE) += console.o
 obj-$(CONFIG_SMP)      += smp.o
-obj-$(CONFIG_PCI)      += pci.o pci_iommu.o
+obj-$(CONFIG_PCI)      += pci.o pci_iommu.o pci-sysfs.o
 obj-$(CONFIG_SRM_ENV)  += srm_env.o
 obj-$(CONFIG_MODULES)  += module.o
 
index 11aee012a8aed0986b7e744c7a43a0f7ac275814..985e5c1681ace50d0ef11c1bfdf29c485bcfbdda 100644 (file)
@@ -157,8 +157,8 @@ ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn,
                       err_print_prefix,
                       streamname[stream], bitsname[bits], sourcename[source]);
 
-       printk("%s    Address: 0x%016lx\n"
-                "    Syndrome[upper.lower]: %02lx.%02lx\n", 
+       printk("%s    Address: 0x%016llx\n"
+                "    Syndrome[upper.lower]: %02llx.%02llx\n",
               err_print_prefix,
               c_addr,
               c2_syn, c1_syn);
index 68cd493f54c5fd93b5fddec8eb2323a65e124924..73770c6ca01321457d0430133525d4668dcc97e0 100644 (file)
@@ -246,13 +246,13 @@ ev7_process_pal_subpacket(struct el_subpacket *header)
 
        switch(header->type) {
        case EL_TYPE__PAL__LOGOUT_FRAME:
-               printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n",
+               printk("%s*** MCHK occurred on LPID %ld (RBOX %llx)\n",
                       err_print_prefix,
                       packet->by_type.logout.whami, 
                       packet->by_type.logout.rbox_whami);
                el_print_timestamp(&packet->by_type.logout.timestamp);
-               printk("%s  EXC_ADDR: %016lx\n"
-                        "  HALT_CODE: %lx\n", 
+               printk("%s  EXC_ADDR: %016llx\n"
+                        "  HALT_CODE: %llx\n",
                       err_print_prefix,
                       packet->by_type.logout.exc_addr,
                       packet->by_type.logout.halt_code);
index 413bf37eb094057b0e38e03b965764056cb11c5a..6bfd243efba342200a36a51b4be1033921c0b3c0 100644 (file)
@@ -129,7 +129,7 @@ marvel_print_po7_crrct_sym(u64 crrct_sym)
 
 
        printk("%s      Correctable Error Symptoms:\n"
-              "%s        Syndrome: 0x%lx\n",
+              "%s        Syndrome: 0x%llx\n",
               err_print_prefix,
               err_print_prefix, EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__SYN));
        marvel_print_err_cyc(EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__ERR_CYC));
@@ -186,7 +186,7 @@ marvel_print_po7_uncrr_sym(u64 uncrr_sym, u64 valid_mask)
        uncrr_sym &= valid_mask;
 
        if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__SYN))
-               printk("%s        Syndrome: 0x%lx\n",
+               printk("%s        Syndrome: 0x%llx\n",
                       err_print_prefix, 
                       EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__SYN));
 
@@ -307,7 +307,7 @@ marvel_print_po7_ugbge_sym(u64 ugbge_sym)
                sprintf(opcode_str, "BlkIO");
                break;
        default:
-               sprintf(opcode_str, "0x%lx\n", 
+               sprintf(opcode_str, "0x%llx\n",
                        EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE));
                break;
        }
@@ -321,7 +321,7 @@ marvel_print_po7_ugbge_sym(u64 ugbge_sym)
               opcode_str);
 
        if (0xC5 != EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE))
-               printk("%s        Packet Offset 0x%08lx\n",
+               printk("%s        Packet Offset 0x%08llx\n",
                       err_print_prefix,
                       EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_PKT_OFF));
 }
@@ -480,8 +480,8 @@ marvel_print_po7_err_sum(struct ev7_pal_io_subpacket *io)
                printk("%s    Lost Error\n", err_print_prefix);
 
        printk("%s    Failing Packet:\n"
-              "%s      Cycle 1: %016lx\n"
-              "%s      Cycle 2: %016lx\n",
+              "%s      Cycle 1: %016llx\n"
+              "%s      Cycle 2: %016llx\n",
               err_print_prefix,
               err_print_prefix, io->po7_err_pkt0,
               err_print_prefix, io->po7_err_pkt1);
@@ -515,9 +515,9 @@ marvel_print_pox_tlb_err(u64 tlb_err)
        if (!(tlb_err & IO7__POX_TLBERR__ERR_VALID))
                return;
 
-       printk("%s      TLB Error on index 0x%lx:\n"
+       printk("%s      TLB Error on index 0x%llx:\n"
               "%s        - %s\n"
-              "%s        - Addr: 0x%016lx\n",
+              "%s        - Addr: 0x%016llx\n",
               err_print_prefix,
               EXTRACT(tlb_err, IO7__POX_TLBERR__ERR_TLB_PTR),
               err_print_prefix,
@@ -579,7 +579,7 @@ marvel_print_pox_spl_cmplt(u64 spl_cmplt)
                sprintf(message, "Uncorrectable Split Write Data Error");
                break;
        default:
-               sprintf(message, "%08lx\n", 
+               sprintf(message, "%08llx\n",
                        EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__MESSAGE));
                break;
        }
@@ -620,9 +620,9 @@ marvel_print_pox_trans_sum(u64 trans_sum)
                return;
 
        printk("%s      Transaction Summary:\n"
-              "%s        Command: 0x%lx - %s\n"
-              "%s        Address: 0x%016lx%s\n"
-              "%s        PCI-X Master Slot: 0x%lx\n",
+              "%s        Command: 0x%llx - %s\n"
+              "%s        Address: 0x%016llx%s\n"
+              "%s        PCI-X Master Slot: 0x%llx\n",
               err_print_prefix, 
               err_print_prefix, 
               EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_CMD),
@@ -964,12 +964,12 @@ marvel_process_io_error(struct ev7_lf_subpackets *lf_subpackets, int print)
 
 #if 0
                printk("%s  PORT 7 ERROR:\n"
-                      "%s    PO7_ERROR_SUM: %016lx\n"
-                      "%s    PO7_UNCRR_SYM: %016lx\n"
-                      "%s    PO7_CRRCT_SYM: %016lx\n"
-                      "%s    PO7_UGBGE_SYM: %016lx\n"
-                      "%s    PO7_ERR_PKT0:  %016lx\n"
-                      "%s    PO7_ERR_PKT1:  %016lx\n",
+                      "%s    PO7_ERROR_SUM: %016llx\n"
+                      "%s    PO7_UNCRR_SYM: %016llx\n"
+                      "%s    PO7_CRRCT_SYM: %016llx\n"
+                      "%s    PO7_UGBGE_SYM: %016llx\n"
+                      "%s    PO7_ERR_PKT0:  %016llx\n"
+                      "%s    PO7_ERR_PKT1:  %016llx\n",
                       err_print_prefix,
                       err_print_prefix, io->po7_error_sum,
                       err_print_prefix, io->po7_uncrr_sym,
@@ -987,12 +987,12 @@ marvel_process_io_error(struct ev7_lf_subpackets *lf_subpackets, int print)
                if (!MARVEL_IO_ERR_VALID(io->ports[i].pox_err_sum))
                        continue;
 
-               printk("%s  PID %u PORT %d POx_ERR_SUM: %016lx\n", 
+               printk("%s  PID %u PORT %d POx_ERR_SUM: %016llx\n",
                       err_print_prefix, 
                       lf_subpackets->io_pid, i, io->ports[i].pox_err_sum);
                marvel_print_pox_err(io->ports[i].pox_err_sum, &io->ports[i]);
 
-               printk("%s  [ POx_FIRST_ERR: %016lx ]\n", 
+               printk("%s  [ POx_FIRST_ERR: %016llx ]\n",
                       err_print_prefix, io->ports[i].pox_first_err);
                marvel_print_pox_err(io->ports[i].pox_first_err, 
                                     &io->ports[i]);
index 257449ed15efca1ac97d46e999acb0e223e62408..c7e28a88d6e31b2869ab45488d7e5f9092127ffb 100644 (file)
@@ -107,12 +107,12 @@ titan_parse_p_serror(int which, u64 serror, int print)
        if (!print)
                return status;
 
-       printk("%s  PChip %d SERROR: %016lx\n", 
+       printk("%s  PChip %d SERROR: %016llx\n",
               err_print_prefix, which, serror);
        if (serror & TITAN__PCHIP_SERROR__ECCMASK) {
                printk("%s    %sorrectable ECC Error:\n"
                       "      Source: %-6s  Command: %-8s  Syndrome: 0x%08x\n"
-                      "      Address: 0x%lx\n", 
+                      "      Address: 0x%llx\n",
                       err_print_prefix,
                       (serror & TITAN__PCHIP_SERROR__UECC) ? "Unc" : "C",
                       serror_src[EXTRACT(serror, TITAN__PCHIP_SERROR__SRC)],
@@ -223,7 +223,7 @@ titan_parse_p_perror(int which, int port, u64 perror, int print)
        if (!print) 
                return status;
 
-       printk("%s  PChip %d %cPERROR: %016lx\n", 
+       printk("%s  PChip %d %cPERROR: %016llx\n",
               err_print_prefix, which, 
               port ? 'A' : 'G', perror);
        if (perror & TITAN__PCHIP_PERROR__IPTPW)
@@ -316,7 +316,7 @@ titan_parse_p_agperror(int which, u64 agperror, int print)
        addr = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__ADDR) << 3;
        len = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__LEN);
 
-       printk("%s  PChip %d AGPERROR: %016lx\n", err_print_prefix,
+       printk("%s  PChip %d AGPERROR: %016llx\n", err_print_prefix,
               which, agperror);
        if (agperror & TITAN__PCHIP_AGPERROR__NOWINDOW)
                printk("%s    No Window\n", err_print_prefix);
@@ -597,16 +597,16 @@ privateer_process_680_frame(struct el_common *mchk_header, int print)
                return status;
 
        /* TODO - decode instead of just dumping... */
-       printk("%s  Summary Flags:         %016lx\n"
-                "  CChip DIRx:            %016lx\n"
-                "  System Management IR:  %016lx\n"
-                "  CPU IR:                %016lx\n"
-                "  Power Supply IR:       %016lx\n"
-                "  LM78 Fault Status:     %016lx\n"
-                "  System Doors:          %016lx\n"
-                "  Temperature Warning:   %016lx\n"
-                "  Fan Control:           %016lx\n"
-                "  Fatal Power Down Code: %016lx\n",
+       printk("%s  Summary Flags:         %016llx\n"
+                "  CChip DIRx:            %016llx\n"
+                "  System Management IR:  %016llx\n"
+                "  CPU IR:                %016llx\n"
+                "  Power Supply IR:       %016llx\n"
+                "  LM78 Fault Status:     %016llx\n"
+                "  System Doors:          %016llx\n"
+                "  Temperature Warning:   %016llx\n"
+                "  Fan Control:           %016llx\n"
+                "  Fatal Power Down Code: %016llx\n",
               err_print_prefix,
               emchk->summary,
               emchk->c_dirx,
diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c
new file mode 100644 (file)
index 0000000..6ea822e
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * arch/alpha/kernel/pci-sysfs.c
+ *
+ * Copyright (C) 2009 Ivan Kokshaysky
+ *
+ * Alpha PCI resource files.
+ *
+ * Loosely based on generic HAVE_PCI_MMAP implementation in
+ * drivers/pci/pci-sysfs.c
+ */
+
+#include <linux/sched.h>
+#include <linux/pci.h>
+
+static int hose_mmap_page_range(struct pci_controller *hose,
+                               struct vm_area_struct *vma,
+                               enum pci_mmap_state mmap_type, int sparse)
+{
+       unsigned long base;
+
+       if (mmap_type == pci_mmap_mem)
+               base = sparse ? hose->sparse_mem_base : hose->dense_mem_base;
+       else
+               base = sparse ? hose->sparse_io_base : hose->dense_io_base;
+
+       vma->vm_pgoff += base >> PAGE_SHIFT;
+       vma->vm_flags |= (VM_IO | VM_RESERVED);
+
+       return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                                 vma->vm_end - vma->vm_start,
+                                 vma->vm_page_prot);
+}
+
+static int __pci_mmap_fits(struct pci_dev *pdev, int num,
+                          struct vm_area_struct *vma, int sparse)
+{
+       unsigned long nr, start, size;
+       int shift = sparse ? 5 : 0;
+
+       nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       start = vma->vm_pgoff;
+       size = ((pci_resource_len(pdev, num) - 1) >> (PAGE_SHIFT - shift)) + 1;
+
+       if (start < size && size - start >= nr)
+               return 1;
+       WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on %s BAR %d "
+               "(size 0x%08lx)\n",
+               current->comm, sparse ? " sparse" : "", start, start + nr,
+               pci_name(pdev), num, size);
+       return 0;
+}
+
+/**
+ * pci_mmap_resource - map a PCI resource into user memory space
+ * @kobj: kobject for mapping
+ * @attr: struct bin_attribute for the file being mapped
+ * @vma: struct vm_area_struct passed into the mmap
+ * @sparse: address space type
+ *
+ * Use the bus mapping routines to map a PCI resource into userspace.
+ */
+static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
+                            struct vm_area_struct *vma, int sparse)
+{
+       struct pci_dev *pdev = to_pci_dev(container_of(kobj,
+                                                      struct device, kobj));
+       struct resource *res = (struct resource *)attr->private;
+       enum pci_mmap_state mmap_type;
+       struct pci_bus_region bar;
+       int i;
+
+       for (i = 0; i < PCI_ROM_RESOURCE; i++)
+               if (res == &pdev->resource[i])
+                       break;
+       if (i >= PCI_ROM_RESOURCE)
+               return -ENODEV;
+
+       if (!__pci_mmap_fits(pdev, i, vma, sparse))
+               return -EINVAL;
+
+       if (iomem_is_exclusive(res->start))
+               return -EINVAL;
+
+       pcibios_resource_to_bus(pdev, &bar, res);
+       vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
+       mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
+
+       return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
+}
+
+static int pci_mmap_resource_sparse(struct kobject *kobj,
+                                   struct bin_attribute *attr,
+                                   struct vm_area_struct *vma)
+{
+       return pci_mmap_resource(kobj, attr, vma, 1);
+}
+
+static int pci_mmap_resource_dense(struct kobject *kobj,
+                                  struct bin_attribute *attr,
+                                  struct vm_area_struct *vma)
+{
+       return pci_mmap_resource(kobj, attr, vma, 0);
+}
+
+/**
+ * pci_remove_resource_files - cleanup resource files
+ * @dev: dev to cleanup
+ *
+ * If we created resource files for @dev, remove them from sysfs and
+ * free their resources.
+ */
+void pci_remove_resource_files(struct pci_dev *pdev)
+{
+       int i;
+
+       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+               struct bin_attribute *res_attr;
+
+               res_attr = pdev->res_attr[i];
+               if (res_attr) {
+                       sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+                       kfree(res_attr);
+               }
+
+               res_attr = pdev->res_attr_wc[i];
+               if (res_attr) {
+                       sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+                       kfree(res_attr);
+               }
+       }
+}
+
+static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
+{
+       struct pci_bus_region bar;
+       struct pci_controller *hose = pdev->sysdata;
+       long dense_offset;
+       unsigned long sparse_size;
+
+       pcibios_resource_to_bus(pdev, &bar, &pdev->resource[num]);
+
+       /* All core logic chips have 4G sparse address space, except
+          CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM
+          definitions in asm/core_xxx.h files). This corresponds
+          to 128M or 512M of the bus space. */
+       dense_offset = (long)(hose->dense_mem_base - hose->sparse_mem_base);
+       sparse_size = dense_offset >= 0x400000000UL ? 0x20000000 : 0x8000000;
+
+       return bar.end < sparse_size;
+}
+
+static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
+                              char *suffix, struct bin_attribute *res_attr,
+                              unsigned long sparse)
+{
+       size_t size = pci_resource_len(pdev, num);
+
+       sprintf(name, "resource%d%s", num, suffix);
+       res_attr->mmap = sparse ? pci_mmap_resource_sparse :
+                                 pci_mmap_resource_dense;
+       res_attr->attr.name = name;
+       res_attr->attr.mode = S_IRUSR | S_IWUSR;
+       res_attr->size = sparse ? size << 5 : size;
+       res_attr->private = &pdev->resource[num];
+       return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+}
+
+static int pci_create_attr(struct pci_dev *pdev, int num)
+{
+       /* allocate attribute structure, piggyback attribute name */
+       int retval, nlen1, nlen2 = 0, res_count = 1;
+       unsigned long sparse_base, dense_base;
+       struct bin_attribute *attr;
+       struct pci_controller *hose = pdev->sysdata;
+       char *suffix, *attr_name;
+
+       suffix = "";    /* Assume bwx machine, normal resourceN files. */
+       nlen1 = 10;
+
+       if (pdev->resource[num].flags & IORESOURCE_MEM) {
+               sparse_base = hose->sparse_mem_base;
+               dense_base = hose->dense_mem_base;
+               if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
+                       sparse_base = 0;
+                       suffix = "_dense";
+                       nlen1 = 16;     /* resourceN_dense */
+               }
+       } else {
+               sparse_base = hose->sparse_io_base;
+               dense_base = hose->dense_io_base;
+       }
+
+       if (sparse_base) {
+               suffix = "_sparse";
+               nlen1 = 17;
+               if (dense_base) {
+                       nlen2 = 16;     /* resourceN_dense */
+                       res_count = 2;
+               }
+       }
+
+       attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
+       if (!attr)
+               return -ENOMEM;
+
+       /* Create bwx, sparse or single dense file */
+       attr_name = (char *)(attr + res_count);
+       pdev->res_attr[num] = attr;
+       retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
+                                    sparse_base);
+       if (retval || res_count == 1)
+               return retval;
+
+       /* Create dense file */
+       attr_name += nlen1;
+       attr++;
+       pdev->res_attr_wc[num] = attr;
+       return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
+}
+
+/**
+ * pci_create_resource_files - create resource files in sysfs for @dev
+ * @dev: dev in question
+ *
+ * Walk the resources in @dev creating files for each resource available.
+ */
+int pci_create_resource_files(struct pci_dev *pdev)
+{
+       int i;
+       int retval;
+
+       /* Expose the PCI resources from this device as files */
+       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+
+               /* skip empty resources */
+               if (!pci_resource_len(pdev, i))
+                       continue;
+
+               retval = pci_create_attr(pdev, i);
+               if (retval) {
+                       pci_remove_resource_files(pdev);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+/* Legacy I/O bus mapping stuff. */
+
+static int __legacy_mmap_fits(struct pci_controller *hose,
+                             struct vm_area_struct *vma,
+                             unsigned long res_size, int sparse)
+{
+       unsigned long nr, start, size;
+
+       nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       start = vma->vm_pgoff;
+       size = ((res_size - 1) >> PAGE_SHIFT) + 1;
+
+       if (start < size && size - start >= nr)
+               return 1;
+       WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on hose %d "
+               "(size 0x%08lx)\n",
+               current->comm, sparse ? " sparse" : "", start, start + nr,
+               hose->index, size);
+       return 0;
+}
+
+static inline int has_sparse(struct pci_controller *hose,
+                            enum pci_mmap_state mmap_type)
+{
+       unsigned long base;
+
+       base = (mmap_type == pci_mmap_mem) ? hose->sparse_mem_base :
+                                            hose->sparse_io_base;
+
+       return base != 0;
+}
+
+int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
+                              enum pci_mmap_state mmap_type)
+{
+       struct pci_controller *hose = bus->sysdata;
+       int sparse = has_sparse(hose, mmap_type);
+       unsigned long res_size;
+
+       res_size = (mmap_type == pci_mmap_mem) ? bus->legacy_mem->size :
+                                                bus->legacy_io->size;
+       if (!__legacy_mmap_fits(hose, vma, res_size, sparse))
+               return -EINVAL;
+
+       return hose_mmap_page_range(hose, vma, mmap_type, sparse);
+}
+
+/**
+ * pci_adjust_legacy_attr - adjustment of legacy file attributes
+ * @b: bus to create files under
+ * @mmap_type: I/O port or memory
+ *
+ * Adjust file name and size for sparse mappings.
+ */
+void pci_adjust_legacy_attr(struct pci_bus *bus, enum pci_mmap_state mmap_type)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       if (!has_sparse(hose, mmap_type))
+               return;
+
+       if (mmap_type == pci_mmap_mem) {
+               bus->legacy_mem->attr.name = "legacy_mem_sparse";
+               bus->legacy_mem->size <<= 5;
+       } else {
+               bus->legacy_io->attr.name = "legacy_io_sparse";
+               bus->legacy_io->size <<= 5;
+       }
+       return;
+}
+
+/* Legacy I/O bus read/write functions */
+int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       port += hose->io_space->start;
+
+       switch(size) {
+       case 1:
+               *((u8 *)val) = inb(port);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               *((u16 *)val) = inw(port);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               *((u32 *)val) = inl(port);
+               return 4;
+       }
+       return -EINVAL;
+}
+
+int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       port += hose->io_space->start;
+
+       switch(size) {
+       case 1:
+               outb(port, val);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               outw(port, val);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               outl(port, val);
+               return 4;
+       }
+       return -EINVAL;
+}
index a3b938811400f70c82ec960082f6bdeaab935e0f..a91ba28999b57a03d34036f105fd1070fa8fe2d3 100644 (file)
@@ -168,7 +168,7 @@ pcibios_align_resource(void *data, struct resource *res,
                 */
 
                /* Align to multiple of size of minimum base.  */
-               alignto = max(0x1000UL, align);
+               alignto = max_t(resource_size_t, 0x1000, align);
                start = ALIGN(start, alignto);
                if (hose->sparse_mem_base && size <= 7 * 16*MB) {
                        if (((start / (16*MB)) & 0x7) == 0) {
index b9094da05d7a136a5dff6bf7a6a0751e25af5316..bfb880af959d4d39c4ed335cc4afb3326fcc989a 100644 (file)
@@ -247,7 +247,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
            && paddr + size <= __direct_map_size) {
                ret = paddr + __direct_map_base;
 
-               DBGA2("pci_map_single: [%p,%lx] -> direct %lx from %p\n",
+               DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %p\n",
                      cpu_addr, size, ret, __builtin_return_address(0));
 
                return ret;
@@ -258,7 +258,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
        if (dac_allowed) {
                ret = paddr + alpha_mv.pci_dac_offset;
 
-               DBGA2("pci_map_single: [%p,%lx] -> DAC %lx from %p\n",
+               DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %p\n",
                      cpu_addr, size, ret, __builtin_return_address(0));
 
                return ret;
@@ -299,7 +299,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
        ret = arena->dma_base + dma_ofs * PAGE_SIZE;
        ret += (unsigned long)cpu_addr & ~PAGE_MASK;
 
-       DBGA2("pci_map_single: [%p,%lx] np %ld -> sg %lx from %p\n",
+       DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %p\n",
              cpu_addr, size, npages, ret, __builtin_return_address(0));
 
        return ret;
@@ -355,14 +355,14 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
            && dma_addr < __direct_map_base + __direct_map_size) {
                /* Nothing to do.  */
 
-               DBGA2("pci_unmap_single: direct [%lx,%lx] from %p\n",
+               DBGA2("pci_unmap_single: direct [%llx,%zx] from %p\n",
                      dma_addr, size, __builtin_return_address(0));
 
                return;
        }
 
        if (dma_addr > 0xffffffff) {
-               DBGA2("pci64_unmap_single: DAC [%lx,%lx] from %p\n",
+               DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %p\n",
                      dma_addr, size, __builtin_return_address(0));
                return;
        }
@@ -373,9 +373,9 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
 
        dma_ofs = (dma_addr - arena->dma_base) >> PAGE_SHIFT;
        if (dma_ofs * PAGE_SIZE >= arena->size) {
-               printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %lx "
-                      " base %lx size %x\n", dma_addr, arena->dma_base,
-                      arena->size);
+               printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %llx "
+                      " base %llx size %x\n",
+                      dma_addr, arena->dma_base, arena->size);
                return;
                BUG();
        }
@@ -394,7 +394,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
 
        spin_unlock_irqrestore(&arena->lock, flags);
 
-       DBGA2("pci_unmap_single: sg [%lx,%lx] np %ld from %p\n",
+       DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %p\n",
              dma_addr, size, npages, __builtin_return_address(0));
 }
 EXPORT_SYMBOL(pci_unmap_single);
@@ -444,7 +444,7 @@ try_again:
                goto try_again;
        }
                
-       DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n",
+       DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %p\n",
              size, cpu_addr, *dma_addrp, __builtin_return_address(0));
 
        return cpu_addr;
@@ -464,7 +464,7 @@ pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
        pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
        free_pages((unsigned long)cpu_addr, get_order(size));
 
-       DBGA2("pci_free_consistent: [%x,%lx] from %p\n",
+       DBGA2("pci_free_consistent: [%llx,%zx] from %p\n",
              dma_addr, size, __builtin_return_address(0));
 }
 EXPORT_SYMBOL(pci_free_consistent);
@@ -551,7 +551,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
                out->dma_address = paddr + __direct_map_base;
                out->dma_length = size;
 
-               DBGA("    sg_fill: [%p,%lx] -> direct %lx\n",
+               DBGA("    sg_fill: [%p,%lx] -> direct %llx\n",
                     __va(paddr), size, out->dma_address);
 
                return 0;
@@ -563,7 +563,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
                out->dma_address = paddr + alpha_mv.pci_dac_offset;
                out->dma_length = size;
 
-               DBGA("    sg_fill: [%p,%lx] -> DAC %lx\n",
+               DBGA("    sg_fill: [%p,%lx] -> DAC %llx\n",
                     __va(paddr), size, out->dma_address);
 
                return 0;
@@ -589,7 +589,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
        out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr;
        out->dma_length = size;
 
-       DBGA("    sg_fill: [%p,%lx] -> sg %lx np %ld\n",
+       DBGA("    sg_fill: [%p,%lx] -> sg %llx np %ld\n",
             __va(paddr), size, out->dma_address, npages);
 
        /* All virtually contiguous.  We need to find the length of each
@@ -752,7 +752,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
 
                if (addr > 0xffffffff) {
                        /* It's a DAC address -- nothing to do.  */
-                       DBGA("    (%ld) DAC [%lx,%lx]\n",
+                       DBGA("    (%ld) DAC [%llx,%zx]\n",
                              sg - end + nents, addr, size);
                        continue;
                }
@@ -760,12 +760,12 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
                if (addr >= __direct_map_base
                    && addr < __direct_map_base + __direct_map_size) {
                        /* Nothing to do.  */
-                       DBGA("    (%ld) direct [%lx,%lx]\n",
+                       DBGA("    (%ld) direct [%llx,%zx]\n",
                              sg - end + nents, addr, size);
                        continue;
                }
 
-               DBGA("    (%ld) sg [%lx,%lx]\n",
+               DBGA("    (%ld) sg [%llx,%zx]\n",
                     sg - end + nents, addr, size);
 
                npages = iommu_num_pages(addr, size, PAGE_SIZE);
index 8d0097f10208dad922760de0a72756a55272c722..3a2fb7a02db402a75b8eaaea3dfe8a51d02eddd9 100644 (file)
@@ -272,7 +272,7 @@ alpha_vfork(struct pt_regs *regs)
  */
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+copy_thread(unsigned long clone_flags, unsigned long usp,
            unsigned long unused,
            struct task_struct * p, struct pt_regs * regs)
 {
index fe14c6747cd651d56e07d10d6094f5671eb532c6..567f2598d090a331f89a1444ab42b82763ab1297 100644 (file)
@@ -20,7 +20,7 @@ struct pci_controller;
 extern struct pci_ops apecs_pci_ops;
 extern void apecs_init_arch(void);
 extern void apecs_pci_clr_err(void);
-extern void apecs_machine_check(u64, u64);
+extern void apecs_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_cia.c */
@@ -29,7 +29,7 @@ extern void cia_init_pci(void);
 extern void cia_init_arch(void);
 extern void pyxis_init_arch(void);
 extern void cia_kill_arch(int);
-extern void cia_machine_check(u64, u64);
+extern void cia_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_irongate.c */
@@ -42,7 +42,7 @@ extern void irongate_machine_check(u64, u64);
 /* core_lca.c */
 extern struct pci_ops lca_pci_ops;
 extern void lca_init_arch(void);
-extern void lca_machine_check(u64, u64);
+extern void lca_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_marvel.c */
@@ -64,7 +64,7 @@ void io7_clear_errors(struct io7 *io7);
 extern struct pci_ops mcpcia_pci_ops;
 extern void mcpcia_init_arch(void);
 extern void mcpcia_init_hoses(void);
-extern void mcpcia_machine_check(u64, u64);
+extern void mcpcia_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void mcpcia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_polaris.c */
@@ -72,14 +72,14 @@ extern struct pci_ops polaris_pci_ops;
 extern int polaris_read_config_dword(struct pci_dev *, int, u32 *);
 extern int polaris_write_config_dword(struct pci_dev *, int, u32);
 extern void polaris_init_arch(void);
-extern void polaris_machine_check(u64, u64);
+extern void polaris_machine_check(unsigned long vector, unsigned long la_ptr);
 #define polaris_pci_tbi ((void *)0)
 
 /* core_t2.c */
 extern struct pci_ops t2_pci_ops;
 extern void t2_init_arch(void);
 extern void t2_kill_arch(int);
-extern void t2_machine_check(u64, u64);
+extern void t2_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_titan.c */
@@ -94,14 +94,14 @@ extern struct _alpha_agp_info *titan_agp_info(void);
 extern struct pci_ops tsunami_pci_ops;
 extern void tsunami_init_arch(void);
 extern void tsunami_kill_arch(int);
-extern void tsunami_machine_check(u64, u64);
+extern void tsunami_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_wildfire.c */
 extern struct pci_ops wildfire_pci_ops;
 extern void wildfire_init_arch(void);
 extern void wildfire_kill_arch(int);
-extern void wildfire_machine_check(u64, u64);
+extern void wildfire_machine_check(unsigned long vector, unsigned long la_ptr);
 extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 extern int wildfire_pa_to_nid(unsigned long);
 extern int wildfire_cpuid_to_nid(int);
index 02bee6983ce2e7f9a91cd57a264ec189671c073e..80df86cd746bd2e8ca81ef82f338f7b337c229d5 100644 (file)
@@ -1255,7 +1255,7 @@ show_cpuinfo(struct seq_file *f, void *slot)
                       platform_string(), nr_processors);
 
 #ifdef CONFIG_SMP
-       seq_printf(f, "cpus active\t\t: %d\n"
+       seq_printf(f, "cpus active\t\t: %u\n"
                      "cpu active mask\t\t: %016lx\n",
                       num_online_cpus(), cpus_addr(cpu_possible_map)[0]);
 #endif
index fd467b207f0f9527cfb18596bc5d79747462c597..bca5bda90cde75407940f0f238d3099c29ca0567 100644 (file)
@@ -2542,8 +2542,8 @@ void __init SMC669_Init ( int index )
         SMC37c669_display_device_info( );
 #endif
        local_irq_restore(flags);
-        printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n",
-               (unsigned long) SMC_base );
+        printk( "SMC37c669 Super I/O Controller found @ 0x%p\n",
+               SMC_base );
     }
     else {
        local_irq_restore(flags);
index 78ad7cd1bbd60326d38bee8f00c8beb6a55f03eb..d12af472e1c0ec4aa380e8bdc73aab15627d7a2c 100644 (file)
@@ -218,7 +218,6 @@ srm_env_init(void)
                                BASE_DIR);
                goto cleanup;
        }
-       base_dir->owner = THIS_MODULE;
 
        /*
         * Create per-name subdirectory
@@ -229,7 +228,6 @@ srm_env_init(void)
                                BASE_DIR, NAMED_DIR);
                goto cleanup;
        }
-       named_dir->owner = THIS_MODULE;
 
        /*
         * Create per-number subdirectory
@@ -241,7 +239,6 @@ srm_env_init(void)
                goto cleanup;
 
        }
-       numbered_dir->owner = THIS_MODULE;
 
        /*
         * Create all named nodes
@@ -254,7 +251,6 @@ srm_env_init(void)
                        goto cleanup;
 
                entry->proc_entry->data         = (void *) entry;
-               entry->proc_entry->owner        = THIS_MODULE;
                entry->proc_entry->read_proc    = srm_env_read;
                entry->proc_entry->write_proc   = srm_env_write;
 
@@ -275,7 +271,6 @@ srm_env_init(void)
 
                entry->id                       = var_num;
                entry->proc_entry->data         = (void *) entry;
-               entry->proc_entry->owner        = THIS_MODULE;
                entry->proc_entry->read_proc    = srm_env_read;
                entry->proc_entry->write_proc   = srm_env_write;
        }
index e2516f9a8967e45aa8c4df23f3de48cae1cdd67e..2b5caf3d9b1526678506fef65bc0e746b61edc9f 100644 (file)
@@ -244,12 +244,11 @@ jensen_init_arch(void)
 }
 
 static void
-jensen_machine_check (u64 vector, u64 la)
+jensen_machine_check(unsigned long vector, unsigned long la)
 {
        printk(KERN_CRIT "Machine check\n");
 }
 
-
 /*
  * The System Vector
  */
index d232e42be018ba13cf61522377785c4e5947ec28..9e263256a42d551c386c345147d77817f8d221a7 100644 (file)
@@ -453,7 +453,7 @@ sable_lynx_enable_irq(unsigned int irq)
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
        spin_unlock(&sable_lynx_irq_lock);
 #if 0
-       printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
+       printk("%s: mask 0x%lx bit 0x%lx irq 0x%x\n",
               __func__, mask, bit, irq);
 #endif
 }
@@ -469,7 +469,7 @@ sable_lynx_disable_irq(unsigned int irq)
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
        spin_unlock(&sable_lynx_irq_lock);
 #if 0
-       printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
+       printk("%s: mask 0x%lx bit 0x%lx irq 0x%x\n",
               __func__, mask, bit, irq);
 #endif
 }
index cefc5a355ef9645233bfec5535e71e1d96e47e54..6ee7655b7568bf36719f2447e389831244721f01 100644 (file)
@@ -623,7 +623,7 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
        }
 
        lock_kernel();
-       printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
+       printk("Bad unaligned kernel access at %016lx: %p %lx %lu\n",
                pc, va, opcode, reg);
        do_exit(SIGSEGV);
 
index aa9d34feddc666b1dea00bab8445a51673cf88d6..679a4a3e265e8222f91c67a17ab58d838a1dddb0 100644 (file)
@@ -474,14 +474,34 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
index 62747458647027e15bfa956587adb693d2ce25ba..6e37c77c47605f06a08e1876d80fe64c0981cc50 100644 (file)
@@ -465,12 +465,33 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
index cd29824d791c7bf55457608912b3ca51716a2bd2..21db4b3ec8ff104c8b95e9c9eb1d3854536c2d25 100644 (file)
@@ -496,13 +496,33 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
-CONFIG_SMC911X=y
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
index 7e253f58ed18a34af0e5997a5ab497cc07ef3fdb..9a75c30b910d4564a5dc78b55cfb7a378dcf21d6 100644 (file)
@@ -490,13 +490,33 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
-CONFIG_SMC911X=y
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
index 2b41ebbfa7ffe261841d8bd17835f24abe8750ea..c13681ac1ede0cada819fb8c577b2e0e7c82ae5c 100644 (file)
@@ -217,6 +217,9 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
 /* read_can_lock - would read_trylock() succeed? */
 #define __raw_read_can_lock(x)         ((x)->lock < 0x80000000)
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 2de14e2afdc5df8d3295f0aca4e3e6f7963980ba..c3265a2e7cd43278686b1d2e4168bb84554d9d6a 100644 (file)
@@ -301,7 +301,7 @@ void release_thread(struct task_struct *dead_task)
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start,
+copy_thread(unsigned long clone_flags, unsigned long stack_start,
            unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *thread = task_thread_info(p);
index 7ac812dc055a792476ffdc5a93e6568ae75e069a..e26c4fe61faeaa6180c0735cff5c94c18d33073b 100644 (file)
@@ -198,17 +198,17 @@ static int at91_pm_verify_clocks(void)
        /* USB must not be using PLLB */
        if (cpu_is_at91rm9200()) {
                if ((scsr & (AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP)) != 0) {
-                       pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
+                       pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
                        return 0;
                }
        } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
                if ((scsr & (AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP)) != 0) {
-                       pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
+                       pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
                        return 0;
                }
        } else if (cpu_is_at91cap9()) {
                if ((scsr & AT91CAP9_PMC_UHP) != 0) {
-                       pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
+                       pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
                        return 0;
                }
        }
@@ -223,7 +223,7 @@ static int at91_pm_verify_clocks(void)
 
                css = at91_sys_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
                if (css != AT91_PMC_CSS_SLOW) {
-                       pr_debug("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
+                       pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
                        return 0;
                }
        }
index bbbd72767a02eadeea8752f3670d79e6c39b4cff..4d9c1f872472a8e89abf73e8f1633990598d95ee 100644 (file)
@@ -28,7 +28,7 @@ static inline void arch_idle(void)
        cpu_do_idle();
 }
 
-static inline void arch_reset(char mode)
+static inline void arch_reset(char mode, const char *cmd)
 {
        __raw_writel(RESET_GLOBAL | RESET_CPU1,
                     IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_RESET);
index 001edfefec195e37752f7f26fd24d8a3c97723f2..4f5b0e0ce6cf8f87e0e843b82ce2f8b0b4cbc34c 100644 (file)
@@ -14,7 +14,7 @@ static inline void arch_idle(void)
        cpu_do_idle();
 }
 
-static inline void arch_reset(char mode)
+static inline void arch_reset(char mode, const char *cmd)
 {
        cpu_reset(0);
 }
index 5fce022114dece491665a5774945e45645030c69..c3648eff51371fe6382e3a1a75b82fb8b5e32071 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/mtd/plat-ram.h>
 #include <linux/memory.h>
 #include <linux/gpio.h>
-#include <linux/smc911x.h>
+#include <linux/smsc911x.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/i2c/at24.h>
@@ -70,7 +70,7 @@ static struct imxuart_platform_data uart_pdata = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct resource smc911x_resources[] = {
+static struct resource smsc911x_resources[] = {
        [0] = {
                .start          = CS1_BASE_ADDR + 0x300,
                .end            = CS1_BASE_ADDR + 0x300 + SZ_64K - 1,
@@ -79,22 +79,25 @@ static struct resource smc911x_resources[] = {
        [1] = {
                .start          = IOMUX_TO_IRQ(MX31_PIN_GPIO3_1),
                .end            = IOMUX_TO_IRQ(MX31_PIN_GPIO3_1),
-               .flags          = IORESOURCE_IRQ,
+               .flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
        },
 };
 
-static struct smc911x_platdata smc911x_info = {
-       .flags          = SMC911X_USE_32BIT,
-       .irq_flags      = IRQF_SHARED | IRQF_TRIGGER_LOW,
+static struct smsc911x_platform_config smsc911x_info = {
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY |
+                         SMSC911X_SAVE_MAC_ADDRESS,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
 };
 
 static struct platform_device pcm037_eth = {
-       .name           = "smc911x",
+       .name           = "smsc911x",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(smc911x_resources),
-       .resource       = smc911x_resources,
+       .num_resources  = ARRAY_SIZE(smsc911x_resources),
+       .resource       = smsc911x_resources,
        .dev            = {
-               .platform_data = &smc911x_info,
+               .platform_data = &smsc911x_info,
        },
 };
 
index 08c60ff227befbfb8832e3afbf7a39e64ec31148..5a03e7ccb01a65e64e9f9cf0e2c337a635100738 100644 (file)
@@ -80,7 +80,7 @@
 #define NETX_PA_XPEC(no) (NETX_IO_PHYS + NETX_OFS_XPEC(no))
 #define NETX_PA_VIC      (NETX_IO_PHYS + NETX_OFS_VIC)
 
-/* virual addresses */
+/* virtual addresses */
 #define NETX_VA_SYSTEM   (NETX_IO_VIRT + NETX_OFS_SYSTEM)
 #define NETX_VA_MEMCR    (NETX_IO_VIRT + NETX_OFS_MEMCR)
 #define NETX_VA_DPMAS    (NETX_IO_VIRT + NETX_OFS_DPMAS)
index 3f325d3718a9909a1e4c8edce9b34d4b115ce4fe..cd8de89c5fadca3f92e8a95099bd38272a025cf5 100644 (file)
@@ -109,7 +109,7 @@ config MACH_OMAP_PALMZ71
        help
         Support for the Palm Zire71 PDA. To boot the kernel,
         you'll need a PalmOS compatible bootloader; check out
-        http://hackndev.com/palm/z71 for more informations.
+        http://hackndev.com/palm/z71 for more information.
         Say Y here if you have such a PDA, say N otherwise.
 
 config MACH_OMAP_PALMTT
index a2c3fcc27a22990e4d1a2f3220b3d6a079100148..c49d9bfa3abde7694e261115e40424f586f1152f 100644 (file)
@@ -47,6 +47,8 @@ obj-$(CONFIG_MACH_OMAP_3430SDP)               += board-3430sdp.o \
 
 obj-$(CONFIG_MACH_NOKIA_RX51)          += board-rx51.o \
                                           board-rx51-peripherals.o \
+                                          mmc-twl4030.o
+
 # Platform specific device init code
 ifeq ($(CONFIG_USB_MUSB_SOC),y)
 obj-y                                  += usb-musb.o
index e096f776f996cf51df6aeb5271764cc88d7368be..da57b0fcda14c5c2ca0ac92e1da076f7176763ee 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/spi/ads7846.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/io.h>
+#include <linux/smsc911x.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
 #include "mmc-twl4030.h"
 
-#define LDP_SMC911X_CS         1
-#define LDP_SMC911X_GPIO       152
+#define LDP_SMSC911X_CS                1
+#define LDP_SMSC911X_GPIO      152
 #define DEBUG_BASE             0x08000000
 #define LDP_ETHR_START         DEBUG_BASE
 
-static struct resource ldp_smc911x_resources[] = {
+static struct resource ldp_smsc911x_resources[] = {
        [0] = {
                .start  = LDP_ETHR_START,
                .end    = LDP_ETHR_START + SZ_4K,
@@ -59,40 +60,50 @@ static struct resource ldp_smc911x_resources[] = {
        },
 };
 
-static struct platform_device ldp_smc911x_device = {
-       .name           = "smc911x",
+static struct smsc911x_platform_config ldp_smsc911x_config = {
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = SMSC911X_USE_32BIT,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device ldp_smsc911x_device = {
+       .name           = "smsc911x",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(ldp_smc911x_resources),
-       .resource       = ldp_smc911x_resources,
+       .num_resources  = ARRAY_SIZE(ldp_smsc911x_resources),
+       .resource       = ldp_smsc911x_resources,
+       .dev            = {
+               .platform_data = &ldp_smsc911x_config,
+       },
 };
 
 static struct platform_device *ldp_devices[] __initdata = {
-       &ldp_smc911x_device,
+       &ldp_smsc911x_device,
 };
 
-static inline void __init ldp_init_smc911x(void)
+static inline void __init ldp_init_smsc911x(void)
 {
        int eth_cs;
        unsigned long cs_mem_base;
        int eth_gpio = 0;
 
-       eth_cs = LDP_SMC911X_CS;
+       eth_cs = LDP_SMSC911X_CS;
 
        if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smc911x\n");
+               printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
                return;
        }
 
-       ldp_smc911x_resources[0].start = cs_mem_base + 0x0;
-       ldp_smc911x_resources[0].end   = cs_mem_base + 0xff;
+       ldp_smsc911x_resources[0].start = cs_mem_base + 0x0;
+       ldp_smsc911x_resources[0].end   = cs_mem_base + 0xff;
        udelay(100);
 
-       eth_gpio = LDP_SMC911X_GPIO;
+       eth_gpio = LDP_SMSC911X_GPIO;
 
-       ldp_smc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+       ldp_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
 
-       if (gpio_request(eth_gpio, "smc911x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+       if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
                                eth_gpio);
                return;
        }
@@ -104,7 +115,7 @@ static void __init omap_ldp_init_irq(void)
        omap2_init_common_hw(NULL);
        omap_init_irq();
        omap_gpio_init();
-       ldp_init_smc911x();
+       ldp_init_smsc911x();
 }
 
 static struct omap_uart_config ldp_uart_config __initdata = {
index b3f6e9d81807c9197c4b9d63ef52891f82c90844..b1f23bea863fec71ff972b5c9aec8952222f9fc4 100644 (file)
@@ -57,6 +57,9 @@
 #define GPMC_CS0_BASE  0x60
 #define GPMC_CS_SIZE   0x30
 
+#define OVERO_SMSC911X_CS      5
+#define OVERO_SMSC911X_GPIO    176
+
 #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
        defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 
@@ -116,6 +119,67 @@ static void __init overo_ads7846_init(void)
 static inline void __init overo_ads7846_init(void) { return; }
 #endif
 
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+
+#include <linux/smsc911x.h>
+
+static struct resource overo_smsc911x_resources[] = {
+       {
+               .name   = "smsc911x-memory",
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       },
+};
+
+static struct smsc911x_platform_config overo_smsc911x_config = {
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = SMSC911X_USE_32BIT ,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device overo_smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(overo_smsc911x_resources),
+       .resource       = &overo_smsc911x_resources,
+       .dev            = {
+               .platform_data = &overo_smsc911x_config,
+       },
+};
+
+static inline void __init overo_init_smsc911x(void)
+{
+       unsigned long cs_mem_base;
+
+       if (gpmc_cs_request(OVERO_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed request for GPMC mem for smsc911x\n");
+               return;
+       }
+
+       overo_smsc911x_resources[0].start = cs_mem_base + 0x0;
+       overo_smsc911x_resources[0].end   = cs_mem_base + 0xff;
+
+       if ((gpio_request(OVERO_SMSC911X_GPIO, "SMSC911X IRQ") == 0) &&
+           (gpio_direction_input(OVERO_SMSC911X_GPIO) == 0)) {
+               gpio_export(OVERO_SMSC911X_GPIO, 0);
+       } else {
+               printk(KERN_ERR "could not obtain gpio for SMSC911X IRQ\n");
+               return;
+       }
+
+       overo_smsc911x_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X_GPIO);
+       overo_smsc911x_resources[1].end   = 0;
+
+       platform_device_register(&overo_smsc911x_device);
+}
+
+#else
+static inline void __init overo_init_smsc911x(void) { return; }
+#endif
+
 static struct mtd_partition overo_nand_partitions[] = {
        {
                .name           = "xloader",
@@ -290,6 +354,7 @@ static void __init overo_init(void)
        overo_flash_init();
        usb_musb_init();
        overo_ads7846_init();
+       overo_init_smsc911x();
 
        if ((gpio_request(OVERO_GPIO_W2W_NRESET,
                          "OVERO_GPIO_W2W_NRESET") == 0) &&
index d6766685cfc7d1b9e1c2eb95d94cdfbbc9798aca..9ab947c14f260c4be91dbc988d30e64954bf4e46 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/io.h>
-#include <linux/smc911x.h>
+#include <linux/smsc911x.h>
 #include <linux/ata_platform.h>
 
 #include <asm/clkdev.h>
@@ -128,14 +128,15 @@ int realview_flash_register(struct resource *res, u32 num)
        return platform_device_register(&realview_flash_device);
 }
 
-static struct smc911x_platdata realview_smc911x_platdata = {
-       .flags          = SMC911X_USE_32BIT,
-       .irq_flags      = IRQF_SHARED,
-       .irq_polarity   = 1,
+static struct smsc911x_platform_config smsc911x_config = {
+       .flags          = SMSC911X_USE_32BIT,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
 };
 
 static struct platform_device realview_eth_device = {
-       .name           = "smc911x",
+       .name           = "smsc911x",
        .id             = 0,
        .num_resources  = 2,
 };
@@ -145,8 +146,8 @@ int realview_eth_register(const char *name, struct resource *res)
        if (name)
                realview_eth_device.name = name;
        realview_eth_device.resource = res;
-       if (strcmp(realview_eth_device.name, "smc911x") == 0)
-               realview_eth_device.dev.platform_data = &realview_smc911x_platdata;
+       if (strcmp(realview_eth_device.name, "smsc911x") == 0)
+               realview_eth_device.dev.platform_data = &smsc911x_config;
 
        return platform_device_register(&realview_eth_device);
 }
index 67d6d9cc68b2a693b5edc2a89aa8d78125e294d3..d0d39adf640777c9f56222fbe9be9028f0926243 100644 (file)
@@ -191,6 +191,7 @@ void __cpuinit local_timer_setup(void)
        clk->name               = "dummy_timer";
        clk->features           = CLOCK_EVT_FEAT_DUMMY;
        clk->rating             = 200;
+       clk->mult               = 1;
        clk->set_mode           = dummy_timer_set_mode;
        clk->broadcast          = smp_timer_broadcast;
        clk->cpumask            = cpumask_of(cpu);
index 94077fbd96b7691850275d71114eb2b9d328f5d3..6f7e70907e443c708b6cd67e59df07ba86f56302 100644 (file)
@@ -29,10 +29,10 @@ ENTRY(v6_early_abort)
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
 /*
- * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR.
+ * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR (erratum 326103).
  * The test below covers all the write situations, including Java bytecodes
  */
-       bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
+       bic     r1, r1, #1 << 11                @ clear bit 11 of FSR
        tst     r3, #PSR_J_BIT                  @ Java?
        movne   pc, lr
        do_thumb_abort
index d6dd83826f8af0baffd833ad11807d18377d5cfb..6e77c042d8e9417ad5b9141c6eab37767693e3ed 100644 (file)
@@ -115,6 +115,10 @@ static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
        raw_local_irq_restore(flags);
 }
 
+static inline void l2_inv_all(void)
+{
+       __asm__("mcr p15, 1, %0, c15, c11, 0" : : "r" (0));
+}
 
 /*
  * Linux primitives.
@@ -254,9 +258,7 @@ static void __init enable_dcache(void)
 
 static void __init __invalidate_icache(void)
 {
-       int dummy;
-
-       __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 0" : "=r" (dummy));
+       __asm__("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
 }
 
 static int __init invalidate_and_disable_icache(void)
@@ -321,6 +323,7 @@ static void __init enable_l2(void)
 
                d = flush_and_disable_dcache();
                i = invalidate_and_disable_icache();
+               l2_inv_all();
                write_extra_features(u | 0x00400000);
                if (i)
                        enable_icache();
index ba592a9e6fb36cfa868c2b4a8ade37248c0743b8..a2bed62aec21900ba3b023c7a9c39a359ea123f1 100644 (file)
  *  r10 = thread_info structure
  *  lr  = failure return
  */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-#include <asm/assembler.h>
+#include <asm/thread_info.h>
 #include <asm/vfpmacros.h>
+#include "../kernel/entry-header.S"
 
 ENTRY(do_vfp)
+#ifdef CONFIG_PREEMPT
+       ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
+       add     r11, r4, #1             @ increment it
+       str     r11, [r10, #TI_PREEMPT]
+#endif
        enable_irq
        ldr     r4, .LCvfp
        ldr     r11, [r10, #TI_CPU]     @ CPU number
@@ -30,6 +33,12 @@ ENTRY(do_vfp)
 ENDPROC(do_vfp)
 
 ENTRY(vfp_null_entry)
+#ifdef CONFIG_PREEMPT
+       get_thread_info r10
+       ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
+       sub     r11, r4, #1             @ decrement it
+       str     r11, [r10, #TI_PREEMPT]
+#endif
        mov     pc, lr
 ENDPROC(vfp_null_entry)
 
@@ -41,6 +50,12 @@ ENDPROC(vfp_null_entry)
 
        __INIT
 ENTRY(vfp_testing_entry)
+#ifdef CONFIG_PREEMPT
+       get_thread_info r10
+       ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
+       sub     r11, r4, #1             @ decrement it
+       str     r11, [r10, #TI_PREEMPT]
+#endif
        ldr     r0, VFP_arch_address
        str     r5, [r0]                @ known non-zero value
        mov     pc, r9                  @ we have handled the fault
index a5a4e57763c391598bc089102c90af94e89def6a..83c4e384b16d07efa738e293ae05ef79ea61be1f 100644 (file)
@@ -137,6 +137,12 @@ check_for_exception:
        VFPFMXR FPEXC, r1               @ restore FPEXC last
        sub     r2, r2, #4
        str     r2, [sp, #S_PC]         @ retry the instruction
+#ifdef CONFIG_PREEMPT
+       get_thread_info r10
+       ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
+       sub     r11, r4, #1             @ decrement it
+       str     r11, [r10, #TI_PREEMPT]
+#endif
        mov     pc, r9                  @ we think we have handled things
 
 
@@ -155,6 +161,12 @@ look_for_VFP_exceptions:
        @ not recognised by VFP
 
        DBGSTR  "not VFP"
+#ifdef CONFIG_PREEMPT
+       get_thread_info r10
+       ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
+       sub     r11, r4, #1             @ decrement it
+       str     r11, [r10, #TI_PREEMPT]
+#endif
        mov     pc, lr
 
 process_exception:
index 75457b30d813c1d3a359e346e418bbc4725dbea2..01599c4ef7266f9f3eb27b56bbe0cdd3f3931121 100644 (file)
@@ -266,7 +266,7 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
                 * on VFP subarch 1.
                 */
                 vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
-                return;
+               goto exit;
        }
 
        /*
@@ -297,7 +297,7 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
         * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
         */
        if (fpexc ^ (FPEXC_EX | FPEXC_FP2V))
-               return;
+               goto exit;
 
        /*
         * The barrier() here prevents fpinst2 being read
@@ -310,6 +310,8 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
        exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
        if (exceptions)
                vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
+ exit:
+       preempt_enable();
 }
 
 static void vfp_enable(void *unused)
index 05fe3053dcaec7f725059d78e7a6988788c557ff..414a8ad97f5245fc142ef878997ca469ad076c6b 100644 (file)
@@ -127,13 +127,13 @@ config BOARD_HAMMERHEAD
        select CPU_AT32AP7000
        select USB_ARCH_HAS_HCD
        help
-         The Hammerhead platform is built around a AVR32 32-bit microcontroller from Atmel.
+         The Hammerhead platform is built around an AVR32 32-bit microcontroller from Atmel.
          It offers versatile peripherals, such as ethernet, usb device, usb host etc.
 
-         The board also incooperates a power supply and is a Power over Ethernet (PoE) Powered
+         The board also incorporates a power supply and is a Power over Ethernet (PoE) Powered
          Device (PD).
 
-         Additonally, a Cyclone III FPGA from Altera is integrated on the board. The FPGA is
+         Additionally, a Cyclone III FPGA from Altera is integrated on the board. The FPGA is
          mapped into the 32-bit AVR memory bus. The FPGA offers two DDR2 SDRAM interfaces, which
          will cover even the most exceptional need of memory bandwidth. Together with the onboard
          video decoder the board is ready for video processing.
index 43ae555ecb33995e906d3b4f5567197893b08ce9..1bbe1da54869bd2192f6a9f4638bdf20e468b983 100644 (file)
@@ -332,7 +332,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index ce4e4296b95467f3e0b715a9ec953398917be8f7..62d4abbaa65431185993ee249722dcb2d3cfdc44 100644 (file)
@@ -250,21 +250,3 @@ asmlinkage void do_bus_error(unsigned long addr, int write_access,
        dump_dtlb();
        die("Bus Error", regs, SIGKILL);
 }
-
-/*
- * This functionality is currently not possible to implement because
- * we're using segmentation to ensure a fixed mapping of the kernel
- * virtual address space.
- *
- * It would be possible to implement this, but it would require us to
- * disable segmentation at startup and load the kernel mappings into
- * the TLB like any other pages. There will be lots of trickery to
- * avoid recursive invocation of the TLB miss handler, though...
- */
-#ifdef CONFIG_DEBUG_PAGEALLOC
-void kernel_map_pages(struct page *page, int numpages, int enable)
-{
-
-}
-EXPORT_SYMBOL(kernel_map_pages);
-#endif
index 0c1f86e3e44a0bfa99700609e69dfe82551e3f3e..3640cdc38aace3db670bbd703eb31959bd76cf05 100644 (file)
@@ -777,7 +777,7 @@ config CACHELINE_ALIGNED_L1
        default n if BF54x
        depends on !BF531
        help
-         If enabled, cacheline_anligned data is linked
+         If enabled, cacheline_aligned data is linked
          into L1 data memory. (less latency)
 
 config SYSCALL_TAB_L1
@@ -957,7 +957,7 @@ config MPU
          memory they do not own.  This comes at a performance penalty
          and is recommended only for debugging.
 
-comment "Asynchonous Memory Configuration"
+comment "Asynchronous Memory Configuration"
 
 menu "EBIU_AMGCTL Global Control"
 config C_AMCKEN
@@ -989,7 +989,7 @@ config C_B3PEN
        default n
 
 choice
-       prompt"Enable Asynchonous Memory Banks"
+       prompt "Enable Asynchronous Memory Banks"
        default C_AMBEN_ALL
 
 config C_AMBEN
index 33e2e8993f7f967739c8539f932ea6b1d46725da..f49427293ca1c48e688e1f95a92504d2d8fa0b0a 100644 (file)
@@ -193,7 +193,7 @@ asmlinkage int bfin_clone(struct pt_regs *regs)
 }
 
 int
-copy_thread(int nr, unsigned long clone_flags,
+copy_thread(unsigned long clone_flags,
            unsigned long usp, unsigned long topstk,
            struct task_struct *p, struct pt_regs *regs)
 {
index 834cab7438a8fa3293f2c8e1ef4269c6740d8e13..530d1393a23226926c80ef833dd6b32230405214 100644 (file)
@@ -854,7 +854,6 @@ static int __init sram_proc_init(void)
                printk(KERN_WARNING "unable to create /proc/sram\n");
                return -1;
        }
-       ptr->owner = THIS_MODULE;
        ptr->read_proc = sram_proc_read;
        return 0;
 }
index 3462245fe9fbf1e72ba496c81b76b754cd6f050a..7adac388a77142b2cb7e5d5db4b5483f473c9476 100644 (file)
@@ -438,7 +438,7 @@ config ETRAX_SERIAL_PORT0_DMA1_IN
        help
          Enables the DMA1 input channel for ser0 (ttyS0).
          If you do not enable DMA, an interrupt for each character will be
-         used when receiveing data.
+         used when receiving data.
          Normally you want to use DMA, unless you use the DMA channel for
          something else.
 
@@ -565,7 +565,7 @@ config ETRAX_SERIAL_PORT2_DMA7_IN
        help
          Enables the DMA7 input channel for ser2 (ttyS2).
          If you do not enable DMA, an interrupt for each character will be
-         used when receiveing data.
+         used when receiving data.
          Normally you want to use DMA, unless you use the DMA channel for
          something else.
 
@@ -604,7 +604,7 @@ config ETRAX_SERIAL_PORT3_DMA3_IN
        help
          Enables the DMA3 input channel for ser3 (ttyS3).
          If you do not enable DMA, an interrupt for each character will be
-         used when receiveing data.
+         used when receiving data.
          Normally you want to use DMA, unless you use the DMA channel for
          something else.
 
index bd9b3ff63f6c7b772ce89b8bd1df0e9934b75d06..c4c69cf721e5155141f8261ed536ede9570c3e35 100644 (file)
@@ -115,7 +115,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
  */
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index c685ba4c33875c978abb599ce82c132ed3527f1e..2b73c7a5b6499a195a66badd8ef97b4d0c84b413 100644 (file)
@@ -261,7 +261,6 @@ timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq2  = {
        .handler = timer_interrupt,
        .flags = IRQF_SHARED | IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer",
 };
 
index 005ed2b3f7f4337472844240de1f9be3bccf4c0a..21bbd93be34f3732986d228d5139df43182058cb 100644 (file)
@@ -28,7 +28,7 @@ config        ETRAX_NBR_LED_GRP_ONE
        help
          Select this if you want one Ethernet LED group. This LED group
          can be used for one or more Ethernet interfaces. However, it is
-         recomended that each Ethernet interface use a dedicated LED group.
+         recommended that each Ethernet interface use a dedicated LED group.
 
 config ETRAX_NBR_LED_GRP_TWO
        bool "Use two LED groups"
index 7a64fcef9d07edc354721d70f30af651c2ff7738..b9e328e688be8d70837d895698c4d87ee71e696f 100644 (file)
@@ -342,7 +342,7 @@ config ETRAX_SERIAL_PORT4_DMA9_IN
        help
          Enables the DMA9 input channel for ser4 (ttyS4).
          If you do not enable DMA, an interrupt for each character will be
-         used when receiveing data.
+         used when receiving data.
          Normally you want to use DMA, unless you use the DMA channel for
          something else.
 
index ced5b725d9bd0a1ec2d5da7495877c30e3dbf95d..120e7f796fea9707f009af5bffbc15aad6fbdd0f 100644 (file)
@@ -131,7 +131,7 @@ kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 extern asmlinkage void ret_from_fork(void);
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+copy_thread(unsigned long clone_flags, unsigned long usp,
        unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
 {
index 9dac17334640a9cf3eda77c0c0a22b53e817f0a1..f59a973c97ee31893595b2a6c6e2e7778ce15e10 100644 (file)
@@ -65,7 +65,6 @@ static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
 static struct irqaction irq_ipi  = {
        .handler = crisv32_ipi_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "ipi",
 };
 
index 3a13dd6e0a9a0d7e7eb40aaaff2ada62a2033239..65633d0dab860847b1367455b275a535448b6ee3 100644 (file)
@@ -267,7 +267,6 @@ timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq_timer = {
        .handler = timer_interrupt,
        .flags = IRQF_SHARED | IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer"
 };
 
index f6d74475f1c6744e74bdab893d94cfd536b0c5a9..774de82abef6a5453ccc6abcf5a47b83805da5e8 100644 (file)
@@ -59,7 +59,7 @@ config ETRAX_SDRAM_GRP1_CONFIG
        depends on ETRAX_ARCH_V32
        default "0"
        help
-         SDRAM configuration for group 1. The defult value is 0
+         SDRAM configuration for group 1. The default value is 0
          because group 1 is not used in the default configuration,
          described in the help for SDRAM_GRP0_CONFIG.
 
index 0d5709b983a103038fae9de47d557e407086c2d4..129756b96661257945d768bfe3f5eecee2b4e282 100644 (file)
@@ -121,6 +121,8 @@ static  inline int __raw_write_trylock(raw_rwlock_t *rw)
        return 1;
 }
 
+#define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock)
+#define _raw_write_lock_flags(lock, flags) _raw_write_lock(lock)
 
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
index 60816e876455112047e21d6191a1a2380aa27dd0..4df0b320d524e351847e9f2b270237731b2b1607 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/system.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/fs_struct.h>
 #include <linux/init_task.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
index 9e38f99bbab89c7e0677e5da0f38f09d9d6590ea..4dd9adaf115a4de8083ce7bfde075e5f3ac82123 100644 (file)
@@ -109,28 +109,24 @@ static struct irqaction fpga_irq[4]  = {
        [0] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.0",
                .dev_id         = (void *) 0x0028UL,
        },
        [1] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.1",
                .dev_id         = (void *) 0x0050UL,
        },
        [2] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.2",
                .dev_id         = (void *) 0x1c00UL,
        },
        [3] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.3",
                .dev_id         = (void *) 0x6386UL,
        }
index 3c2752ca97754eb881d5fef6ceeeb576ee679df1..e45209031873e63de6e0202bbd3e831a29ff27bb 100644 (file)
@@ -108,7 +108,6 @@ static struct irqaction fpga_irq[1]  = {
        [0] = {
                .handler        = fpga_interrupt,
                .flags          = IRQF_DISABLED,
-               .mask           = CPU_MASK_NONE,
                .name           = "fpga.0",
                .dev_id         = (void *) 0x0700UL,
        }
index 7754c7338e4b42cfaeb4c3a76158665f3b05d275..ba55ecdfb245a5c201bf34583bcad836677ea26e 100644 (file)
@@ -120,14 +120,12 @@ static struct irqaction mb93493_irq[2]  = {
        [0] = {
                .handler        = mb93493_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "mb93493.0",
                .dev_id         = (void *) __addr_MB93493_IQSR(0),
        },
        [1] = {
                .handler        = mb93493_interrupt,
                .flags          = IRQF_DISABLED | IRQF_SHARED,
-               .mask           = CPU_MASK_NONE,
                .name           = "mb93493.1",
                .dev_id         = (void *) __addr_MB93493_IQSR(1),
        }
index 9583a338e9d6022b7529dcffa34201917502151d..0de50df7497036e52602c2bcfc5a0a0753f6b534 100644 (file)
@@ -204,7 +204,7 @@ void prepare_to_copy(struct task_struct *tsk)
 /*
  * set up the kernel stack and exception frames for a new process
  */
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                unsigned long usp, unsigned long topstk,
                struct task_struct *p, struct pt_regs *regs)
 {
index 69f6a4ef5d61b35c67323a85485e1cebedff7a43..fb0ce75772256568bc2195ba08cbfb9a652def94 100644 (file)
@@ -45,7 +45,6 @@ static irqreturn_t timer_interrupt(int irq, void *dummy);
 static struct irqaction timer_irq  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer",
 };
 
index a8ef654a5a0b8403af3a52c709478956140d2690..e2f33d0f99698ceb03212a5f46fa1e61ccd72cc1 100644 (file)
@@ -191,7 +191,7 @@ asmlinkage int h8300_clone(struct pt_regs *regs)
 
 }
 
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                 unsigned long usp, unsigned long topstk,
                 struct task_struct * p, struct pt_regs * regs)
 {
index d1c926596b087ace1359ac7504303296e31f9b9b..4883ba7103a84d8b391a290fc64198949f2c3ca9 100644 (file)
@@ -60,7 +60,6 @@ static struct irqaction itu_irq = {
        .name           = "itu",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
 static const int __initdata divide_rate[] = {1, 2, 4, 8};
index e14271b7211943b183b23dc7076c78cdd280ba9c..042dbb53f3fb372707ab7a533a884e7ccb6b8dd3 100644 (file)
@@ -55,7 +55,6 @@ static struct irqaction timer16_irq = {
        .name           = "timer-16",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
 static const int __initdata divide_rate[] = {1, 2, 4, 8};
index 0556d7c7bea62c620377b82ca3b35f92d46f5712..38be0cabef0da0c4433d9d52924eef8f199e5b0b 100644 (file)
@@ -75,7 +75,6 @@ static struct irqaction timer8_irq = {
        .name           = "timer-8",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
 static const int __initdata divide_rate[] = {8, 64, 8192};
index df7f453a9673c6cdddd0e4f5b24d6cca49be7ceb..e7c6e614a758b6ea05380d393476a49b82ea8bc0 100644 (file)
@@ -65,10 +65,9 @@ static struct irqaction tpu_irq = {
        .name           = "tpu",
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
 };
 
-const static int __initdata divide_rate[] = {
+static const int __initdata divide_rate[] = {
 #if CONFIG_H8300_TPU_CH == 0
        1,4,16,64,0,0,0,0,
 #elif (CONFIG_H8300_TPU_CH == 1) || (CONFIG_H8300_TPU_CH == 5)
index a109db30ce55e0ade28e542f475cd0b479d45639..75645495c2ddc491605ca29e9405b71edf8081f4 100644 (file)
@@ -193,7 +193,6 @@ CONFIG_BOUNCE=y
 CONFIG_NR_QUICK=1
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
-CONFIG_MMU_NOTIFIER=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -416,8 +415,6 @@ CONFIG_SGI_IOC4=y
 # CONFIG_ENCLOSURE_SERVICES is not set
 CONFIG_SGI_XP=m
 # CONFIG_HP_ILO is not set
-CONFIG_SGI_GRU=m
-# CONFIG_SGI_GRU_DEBUG is not set
 # CONFIG_C2PORT is not set
 CONFIG_HAVE_IDE=y
 CONFIG_IDE=y
index 24b1ad5334cb7bda3bb35b8c6d14616fb956a504..2bef5261d96dce13c983758a68f0e280041bdaa5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/major.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/capability.h>
 #include <linux/console.h>
@@ -848,38 +849,36 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct serial_state *state)
+static inline void line_info(struct seq_file *m, struct serial_state *state)
 {
-       return sprintf(buf, "%d: uart:%s port:%lX irq:%d\n",
+       seq_printf(m, "%d: uart:%s port:%lX irq:%d\n",
                       state->line, uart_config[state->type].name,
                       state->port, state->irq);
 }
 
-static int rs_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
+static int rs_proc_show(struct seq_file *m, void *v)
 {
-       int i, len = 0, l;
-       off_t   begin = 0;
-
-       len += sprintf(page, "simserinfo:1.0 driver:%s\n", serial_version);
-       for (i = 0; i < NR_PORTS && len < 4000; i++) {
-               l = line_info(page + len, &rs_table[i]);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
-       }
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (begin-off);
-       return ((count < begin+len-off) ? count : begin+len-off);
+       int i;
+
+       seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version);
+       for (i = 0; i < NR_PORTS; i++)
+               line_info(m, &rs_table[i]);
+       return 0;
 }
 
+static int rs_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rs_proc_show, NULL);
+}
+
+static const struct file_operations rs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rs_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * ---------------------------------------------------------------------
  * rs_init() and friends
@@ -917,7 +916,7 @@ static const struct tty_operations hp_ops = {
        .start = rs_start,
        .hangup = rs_hangup,
        .wait_until_sent = rs_wait_until_sent,
-       .read_proc = rs_read_proc,
+       .proc_fops = &rs_proc_fops,
 };
 
 /*
index c47830e26cb7dd310af374b9b8ccd60194bef129..111ed52228921cac226a8994e404e3100defb73c 100644 (file)
@@ -202,7 +202,11 @@ extern long ia64_cmpxchg_called_with_bad_pointer (void);
 
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_PARAVIRT) && defined(__KERNEL__)
-#define IA64_INTRINSIC_API(name)       pv_cpu_ops.name
+#ifdef ASM_SUPPORTED
+# define IA64_INTRINSIC_API(name)      paravirt_ ## name
+#else
+# define IA64_INTRINSIC_API(name)      pv_cpu_ops.name
+#endif
 #define IA64_INTRINSIC_MACRO(name)     paravirt_ ## name
 #else
 #define IA64_INTRINSIC_API(name)       ia64_native_ ## name
index 040bc87db9304766b5379abefcd563c25aa3c01c..7f2a456603cbf52d8d9af527b67e459c1e4eb740 100644 (file)
@@ -87,7 +87,7 @@ get_mmu_context (struct mm_struct *mm)
        /* re-check, now that we've got the lock: */
        context = mm->context;
        if (context == 0) {
-               cpus_clear(mm->cpu_vm_mask);
+               cpumask_clear(mm_cpumask(mm));
                if (ia64_ctx.next >= ia64_ctx.limit) {
                        ia64_ctx.next = find_next_zero_bit(ia64_ctx.bitmap,
                                        ia64_ctx.max_ctx, ia64_ctx.next);
@@ -166,8 +166,8 @@ activate_context (struct mm_struct *mm)
 
        do {
                context = get_mmu_context(mm);
-               if (!cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
-                       cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+               if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
+                       cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
                reload_context(context);
                /*
                 * in the unlikely event of a TLB-flush by another thread,
index d2da61e4c49bb690021e332f38bace45d3a1e4b7..908eaef42a08d1dfd9451b55cf9852f61faaab80 100644 (file)
@@ -16,6 +16,12 @@ struct mod_arch_specific {
        struct elf64_shdr *got;         /* global offset table */
        struct elf64_shdr *opd;         /* official procedure descriptors */
        struct elf64_shdr *unwind;      /* unwind-table section */
+#ifdef CONFIG_PARAVIRT
+       struct elf64_shdr *paravirt_bundles;
+                                       /* paravirt_alt_bundle_patch table */
+       struct elf64_shdr *paravirt_insts;
+                                       /* paravirt_alt_inst_patch table */
+#endif
        unsigned long gp;               /* global-pointer for module */
 
        void *core_unw_table;           /* core unwind-table cookie returned by unwinder */
index 0a1026cca4fab0bd68d4ca1158dfb3466c580729..d2d46efb3e6e83888e4f53910439b15794076785 100644 (file)
@@ -30,6 +30,9 @@
 #define __paravirt_work_processed_syscall_target \
                                                ia64_work_processed_syscall
 
+#define paravirt_fsyscall_table                        ia64_native_fsyscall_table
+#define paravirt_fsys_bubble_down              ia64_native_fsys_bubble_down
+
 #ifdef CONFIG_PARAVIRT_GUEST_ASM_CLOBBER_CHECK
 # define PARAVIRT_POISON       0xdeadbeefbaadf00d
 # define CLOBBER(clob)                         \
 (pred) mov reg = psr                   \
        CLOBBER(clob)
 
+#define MOV_FROM_ITC(pred, pred_clob, reg, clob)       \
+(pred) mov reg = ar.itc                                \
+       CLOBBER(clob)                                   \
+       CLOBBER_PRED(pred_clob)
+
 #define MOV_TO_IFA(reg, clob)  \
        mov cr.ifa = reg        \
        CLOBBER(clob)
 #define RSM_PSR_DT             \
        rsm psr.dt
 
+#define RSM_PSR_BE_I(clob0, clob1)     \
+       rsm psr.be | psr.i              \
+       CLOBBER(clob0)                  \
+       CLOBBER(clob1)
+
 #define SSM_PSR_DT_AND_SRLZ_I  \
        ssm psr.dt              \
        ;;                      \
diff --git a/arch/ia64/include/asm/native/patchlist.h b/arch/ia64/include/asm/native/patchlist.h
new file mode 100644 (file)
index 0000000..be16ca9
--- /dev/null
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * arch/ia64/include/asm/native/inst.h
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#define __paravirt_start_gate_fsyscall_patchlist               \
+       __ia64_native_start_gate_fsyscall_patchlist
+#define __paravirt_end_gate_fsyscall_patchlist                 \
+       __ia64_native_end_gate_fsyscall_patchlist
+#define __paravirt_start_gate_brl_fsys_bubble_down_patchlist   \
+       __ia64_native_start_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_end_gate_brl_fsys_bubble_down_patchlist     \
+       __ia64_native_end_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_start_gate_vtop_patchlist                   \
+       __ia64_native_start_gate_vtop_patchlist
+#define __paravirt_end_gate_vtop_patchlist                     \
+       __ia64_native_end_gate_vtop_patchlist
+#define __paravirt_start_gate_mckinley_e9_patchlist            \
+       __ia64_native_start_gate_mckinley_e9_patchlist
+#define __paravirt_end_gate_mckinley_e9_patchlist              \
+       __ia64_native_end_gate_mckinley_e9_patchlist
index b8e6eb1090d77f2f62be6463da22f3db4d5dba57..8d72962ec8383b8d77ba65c4cbdaa4aec271518c 100644 (file)
        IS_PRED_IN(pred)                        \
        IS_RREG_OUT(reg)                        \
        IS_RREG_CLOB(clob)
+#define MOV_FROM_ITC(pred, pred_clob, reg, clob)       \
+       IS_PRED_IN(pred)                                \
+       IS_PRED_CLOB(pred_clob)                         \
+       IS_RREG_OUT(reg)                                \
+       IS_RREG_CLOB(clob)
 #define MOV_TO_IFA(reg, clob)                  \
        IS_RREG_IN(reg)                         \
        IS_RREG_CLOB(clob)
        IS_RREG_CLOB(clob2)
 #define RSM_PSR_DT                             \
        nop 0
+#define RSM_PSR_BE_I(clob0, clob1)             \
+       IS_RREG_CLOB(clob0)                     \
+       IS_RREG_CLOB(clob1)
 #define SSM_PSR_DT_AND_SRLZ_I                  \
        nop 0
 #define BSW_0(clob0, clob1, clob2)             \
index 2bf3636473fe9c5b826b53488f00ff4aa5a1f33b..2eb0a981a09a8adcbf1302915f085ad08c721b91 100644 (file)
 #ifndef __ASM_PARAVIRT_H
 #define __ASM_PARAVIRT_H
 
+#ifndef __ASSEMBLY__
+/******************************************************************************
+ * fsys related addresses
+ */
+struct pv_fsys_data {
+       unsigned long *fsyscall_table;
+       void *fsys_bubble_down;
+};
+
+extern struct pv_fsys_data pv_fsys_data;
+
+unsigned long *paravirt_get_fsyscall_table(void);
+char *paravirt_get_fsys_bubble_down(void);
+
+/******************************************************************************
+ * patchlist addresses for gate page
+ */
+enum pv_gate_patchlist {
+       PV_GATE_START_FSYSCALL,
+       PV_GATE_END_FSYSCALL,
+
+       PV_GATE_START_BRL_FSYS_BUBBLE_DOWN,
+       PV_GATE_END_BRL_FSYS_BUBBLE_DOWN,
+
+       PV_GATE_START_VTOP,
+       PV_GATE_END_VTOP,
+
+       PV_GATE_START_MCKINLEY_E9,
+       PV_GATE_END_MCKINLEY_E9,
+};
+
+struct pv_patchdata {
+       unsigned long start_fsyscall_patchlist;
+       unsigned long end_fsyscall_patchlist;
+       unsigned long start_brl_fsys_bubble_down_patchlist;
+       unsigned long end_brl_fsys_bubble_down_patchlist;
+       unsigned long start_vtop_patchlist;
+       unsigned long end_vtop_patchlist;
+       unsigned long start_mckinley_e9_patchlist;
+       unsigned long end_mckinley_e9_patchlist;
+
+       void *gate_section;
+};
+
+extern struct pv_patchdata pv_patchdata;
+
+unsigned long paravirt_get_gate_patchlist(enum pv_gate_patchlist type);
+void *paravirt_get_gate_section(void);
+#endif
+
 #ifdef CONFIG_PARAVIRT_GUEST
 
 #define PARAVIRT_HYPERVISOR_TYPE_DEFAULT       0
@@ -68,6 +118,14 @@ struct pv_init_ops {
        int (*arch_setup_nomca)(void);
 
        void (*post_smp_prepare_boot_cpu)(void);
+
+#ifdef ASM_SUPPORTED
+       unsigned long (*patch_bundle)(void *sbundle, void *ebundle,
+                                     unsigned long type);
+       unsigned long (*patch_inst)(unsigned long stag, unsigned long etag,
+                                   unsigned long type);
+#endif
+       void (*patch_branch)(unsigned long tag, unsigned long type);
 };
 
 extern struct pv_init_ops pv_init_ops;
@@ -210,6 +268,8 @@ struct pv_time_ops {
        int (*do_steal_accounting)(unsigned long *new_itm);
 
        void (*clocksource_resume)(void);
+
+       unsigned long long (*sched_clock)(void);
 };
 
 extern struct pv_time_ops pv_time_ops;
@@ -227,6 +287,11 @@ paravirt_do_steal_accounting(unsigned long *new_itm)
        return pv_time_ops.do_steal_accounting(new_itm);
 }
 
+static inline unsigned long long paravirt_sched_clock(void)
+{
+       return pv_time_ops.sched_clock();
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #else
diff --git a/arch/ia64/include/asm/paravirt_patch.h b/arch/ia64/include/asm/paravirt_patch.h
new file mode 100644 (file)
index 0000000..128ff5d
--- /dev/null
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_PARAVIRT_PATCH_H
+#define __ASM_PARAVIRT_PATCH_H
+
+#ifdef __ASSEMBLY__
+
+       .section .paravirt_branches, "a"
+       .previous
+#define PARAVIRT_PATCH_SITE_BR(type)           \
+       {                                       \
+       [1:] ;                                  \
+       br.cond.sptk.many 2f ;                  \
+       nop.b 0 ;                               \
+       nop.b 0;; ;                             \
+       } ;                                     \
+       2:                                      \
+       .xdata8 ".paravirt_branches", 1b, type
+
+#else
+
+#include <linux/stringify.h>
+#include <asm/intrinsics.h>
+
+/* for binary patch */
+struct paravirt_patch_site_bundle {
+       void            *sbundle;
+       void            *ebundle;
+       unsigned long   type;
+};
+
+/* label means the beginning of new bundle */
+#define paravirt_alt_bundle(instr, privop)                             \
+       "\t998:\n"                                                      \
+       "\t" instr "\n"                                                 \
+       "\t999:\n"                                                      \
+       "\t.pushsection .paravirt_bundles, \"a\"\n"                     \
+       "\t.popsection\n"                                               \
+       "\t.xdata8 \".paravirt_bundles\", 998b, 999b, "                 \
+       __stringify(privop) "\n"
+
+
+struct paravirt_patch_bundle_elem {
+       const void      *sbundle;
+       const void      *ebundle;
+       unsigned long   type;
+};
+
+
+struct paravirt_patch_site_inst {
+       unsigned long   stag;
+       unsigned long   etag;
+       unsigned long   type;
+};
+
+#define paravirt_alt_inst(instr, privop)                               \
+       "\t[998:]\n"                                                    \
+       "\t" instr "\n"                                                 \
+       "\t[999:]\n"                                                    \
+       "\t.pushsection .paravirt_insts, \"a\"\n"                       \
+       "\t.popsection\n"                                               \
+       "\t.xdata8 \".paravirt_insts\", 998b, 999b, "                   \
+       __stringify(privop) "\n"
+
+struct paravirt_patch_site_branch {
+       unsigned long   tag;
+       unsigned long   type;
+};
+
+struct paravirt_patch_branch_target {
+       const void      *entry;
+       unsigned long   type;
+};
+
+void
+__paravirt_patch_apply_branch(
+       unsigned long tag, unsigned long type,
+       const struct paravirt_patch_branch_target *entries,
+       unsigned int nr_entries);
+
+void
+paravirt_patch_reloc_br(unsigned long tag, const void *target);
+
+void
+paravirt_patch_reloc_brl(unsigned long tag, const void *target);
+
+
+#if defined(ASM_SUPPORTED) && defined(CONFIG_PARAVIRT)
+unsigned long
+ia64_native_patch_bundle(void *sbundle, void *ebundle, unsigned long type);
+
+unsigned long
+__paravirt_patch_apply_bundle(void *sbundle, void *ebundle, unsigned long type,
+                             const struct paravirt_patch_bundle_elem *elems,
+                             unsigned long nelems,
+                             const struct paravirt_patch_bundle_elem **found);
+
+void
+paravirt_patch_apply_bundle(const struct paravirt_patch_site_bundle *start,
+                           const struct paravirt_patch_site_bundle *end);
+
+void
+paravirt_patch_apply_inst(const struct paravirt_patch_site_inst *start,
+                         const struct paravirt_patch_site_inst *end);
+
+void paravirt_patch_apply(void);
+#else
+#define paravirt_patch_apply_bundle(start, end)        do { } while (0)
+#define paravirt_patch_apply_inst(start, end)  do { } while (0)
+#define paravirt_patch_apply()                 do { } while (0)
+#endif
+
+#endif /* !__ASSEMBLEY__ */
+
+#endif /* __ASM_PARAVIRT_PATCH_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "linux"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ */
index 33c8e55f5775f7e12330ffe8e37e61568f937f00..3d2951130b5ff94ca3d05e434100e1b0918bbb95 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 struct pv_cpu_ops {
-       void (*fc)(unsigned long addr);
+       void (*fc)(void *addr);
        unsigned long (*thash)(unsigned long addr);
        unsigned long (*get_cpuid)(int index);
        unsigned long (*get_pmd)(int index);
@@ -60,12 +60,18 @@ extern unsigned long ia64_native_getreg_func(int regnum);
 /* Instructions paravirtualized for performance */
 /************************************************/
 
+#ifndef ASM_SUPPORTED
+#define paravirt_ssm_i()       pv_cpu_ops.ssm_i()
+#define paravirt_rsm_i()       pv_cpu_ops.rsm_i()
+#define __paravirt_getreg()    pv_cpu_ops.getreg()
+#endif
+
 /* mask for ia64_native_ssm/rsm() must be constant.("i" constraing).
  * static inline function doesn't satisfy it. */
 #define paravirt_ssm(mask)                     \
        do {                                    \
                if ((mask) == IA64_PSR_I)       \
-                       pv_cpu_ops.ssm_i();     \
+                       paravirt_ssm_i();       \
                else                            \
                        ia64_native_ssm(mask);  \
        } while (0)
@@ -73,7 +79,7 @@ extern unsigned long ia64_native_getreg_func(int regnum);
 #define paravirt_rsm(mask)                     \
        do {                                    \
                if ((mask) == IA64_PSR_I)       \
-                       pv_cpu_ops.rsm_i();     \
+                       paravirt_rsm_i();       \
                else                            \
                        ia64_native_rsm(mask);  \
        } while (0)
@@ -86,7 +92,7 @@ extern unsigned long ia64_native_getreg_func(int regnum);
                if ((reg) == _IA64_REG_IP)                      \
                        res = ia64_native_getreg(_IA64_REG_IP); \
                else                                            \
-                       res = pv_cpu_ops.getreg(reg);           \
+                       res = __paravirt_getreg(reg);           \
                res;                                            \
        })
 
@@ -112,6 +118,12 @@ void paravirt_cpu_asm_init(const struct pv_cpu_asm_switch *cpu_asm_switch);
 
 #endif /* CONFIG_PARAVIRT */
 
+#if defined(CONFIG_PARAVIRT) && defined(ASM_SUPPORTED)
+#define paravirt_dv_serialize_data()   ia64_dv_serialize_data()
+#else
+#define paravirt_dv_serialize_data()   /* nothing */
+#endif
+
 /* these routines utilize privilege-sensitive or performance-sensitive
  * privileged instructions so the code must be replaced with
  * paravirtualized versions */
@@ -121,4 +133,349 @@ void paravirt_cpu_asm_init(const struct pv_cpu_asm_switch *cpu_asm_switch);
        IA64_PARAVIRT_ASM_FUNC(work_processed_syscall)
 #define ia64_leave_kernel              IA64_PARAVIRT_ASM_FUNC(leave_kernel)
 
+
+#if defined(CONFIG_PARAVIRT)
+/******************************************************************************
+ * binary patching infrastructure
+ */
+#define PARAVIRT_PATCH_TYPE_FC                         1
+#define PARAVIRT_PATCH_TYPE_THASH                      2
+#define PARAVIRT_PATCH_TYPE_GET_CPUID                  3
+#define PARAVIRT_PATCH_TYPE_GET_PMD                    4
+#define PARAVIRT_PATCH_TYPE_PTCGA                      5
+#define PARAVIRT_PATCH_TYPE_GET_RR                     6
+#define PARAVIRT_PATCH_TYPE_SET_RR                     7
+#define PARAVIRT_PATCH_TYPE_SET_RR0_TO_RR4             8
+#define PARAVIRT_PATCH_TYPE_SSM_I                      9
+#define PARAVIRT_PATCH_TYPE_RSM_I                      10
+#define PARAVIRT_PATCH_TYPE_GET_PSR_I                  11
+#define PARAVIRT_PATCH_TYPE_INTRIN_LOCAL_IRQ_RESTORE   12
+
+/* PARAVIRT_PATY_TYPE_[GS]ETREG + _IA64_REG_xxx */
+#define PARAVIRT_PATCH_TYPE_GETREG                     0x10000000
+#define PARAVIRT_PATCH_TYPE_SETREG                     0x20000000
+
+/*
+ * struct task_struct* (*ia64_switch_to)(void* next_task);
+ * void *ia64_leave_syscall;
+ * void *ia64_work_processed_syscall
+ * void *ia64_leave_kernel;
+ */
+
+#define PARAVIRT_PATCH_TYPE_BR_START                   0x30000000
+#define PARAVIRT_PATCH_TYPE_BR_SWITCH_TO               \
+       (PARAVIRT_PATCH_TYPE_BR_START + 0)
+#define PARAVIRT_PATCH_TYPE_BR_LEAVE_SYSCALL           \
+       (PARAVIRT_PATCH_TYPE_BR_START + 1)
+#define PARAVIRT_PATCH_TYPE_BR_WORK_PROCESSED_SYSCALL  \
+       (PARAVIRT_PATCH_TYPE_BR_START + 2)
+#define PARAVIRT_PATCH_TYPE_BR_LEAVE_KERNEL            \
+       (PARAVIRT_PATCH_TYPE_BR_START + 3)
+
+#ifdef ASM_SUPPORTED
+#include <asm/paravirt_patch.h>
+
+/*
+ * pv_cpu_ops calling stub.
+ * normal function call convension can't be written by gcc
+ * inline assembly.
+ *
+ * from the caller's point of view,
+ * the following registers will be clobbered.
+ * r2, r3
+ * r8-r15
+ * r16, r17
+ * b6, b7
+ * p6-p15
+ * ar.ccv
+ *
+ * from the callee's point of view ,
+ * the following registers can be used.
+ * r2, r3: scratch
+ * r8: scratch, input argument0 and return value
+ * r0-r15: scratch, input argument1-5
+ * b6: return pointer
+ * b7: scratch
+ * p6-p15: scratch
+ * ar.ccv: scratch
+ *
+ * other registers must not be changed. especially
+ * b0: rp: preserved. gcc ignores b0 in clobbered register.
+ * r16: saved gp
+ */
+/* 5 bundles */
+#define __PARAVIRT_BR                                                  \
+       ";;\n"                                                          \
+       "{ .mlx\n"                                                      \
+       "nop 0\n"                                                       \
+       "movl r2 = %[op_addr]\n"/* get function pointer address */      \
+       ";;\n"                                                          \
+       "}\n"                                                           \
+       "1:\n"                                                          \
+       "{ .mii\n"                                                      \
+       "ld8 r2 = [r2]\n"       /* load function descriptor address */  \
+       "mov r17 = ip\n"        /* get ip to calc return address */     \
+       "mov r16 = gp\n"        /* save gp */                           \
+       ";;\n"                                                          \
+       "}\n"                                                           \
+       "{ .mii\n"                                                      \
+       "ld8 r3 = [r2], 8\n"    /* load entry address */                \
+       "adds r17 =  1f - 1b, r17\n"    /* calculate return address */  \
+       ";;\n"                                                          \
+       "mov b7 = r3\n"         /* set entry address */                 \
+       "}\n"                                                           \
+       "{ .mib\n"                                                      \
+       "ld8 gp = [r2]\n"       /* load gp value */                     \
+       "mov b6 = r17\n"        /* set return address */                \
+       "br.cond.sptk.few b7\n" /* intrinsics are very short isns */    \
+       "}\n"                                                           \
+       "1:\n"                                                          \
+       "{ .mii\n"                                                      \
+       "mov gp = r16\n"        /* restore gp value */                  \
+       "nop 0\n"                                                       \
+       "nop 0\n"                                                       \
+       ";;\n"                                                          \
+       "}\n"
+
+#define PARAVIRT_OP(op)                                \
+       [op_addr] "i"(&pv_cpu_ops.op)
+
+#define PARAVIRT_TYPE(type)                    \
+       PARAVIRT_PATCH_TYPE_ ## type
+
+#define PARAVIRT_REG_CLOBBERS0                                 \
+       "r2", "r3", /*"r8",*/ "r9", "r10", "r11", "r14",        \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_REG_CLOBBERS1                                 \
+       "r2","r3", /*"r8",*/ "r9", "r10", "r11", "r14",         \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_REG_CLOBBERS2                                 \
+       "r2", "r3", /*"r8", "r9",*/ "r10", "r11", "r14",        \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_REG_CLOBBERS5                                 \
+       "r2", "r3", /*"r8", "r9", "r10", "r11", "r14",*/        \
+               "r15", "r16", "r17"
+
+#define PARAVIRT_BR_CLOBBERS                   \
+       "b6", "b7"
+
+#define PARAVIRT_PR_CLOBBERS                                           \
+       "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15"
+
+#define PARAVIRT_AR_CLOBBERS                   \
+       "ar.ccv"
+
+#define PARAVIRT_CLOBBERS0                     \
+               PARAVIRT_REG_CLOBBERS0,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_CLOBBERS1                     \
+               PARAVIRT_REG_CLOBBERS1,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_CLOBBERS2                     \
+               PARAVIRT_REG_CLOBBERS2,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_CLOBBERS5                     \
+               PARAVIRT_REG_CLOBBERS5,         \
+               PARAVIRT_BR_CLOBBERS,           \
+               PARAVIRT_PR_CLOBBERS,           \
+               PARAVIRT_AR_CLOBBERS,           \
+               "memory"
+
+#define PARAVIRT_BR0(op, type)                                 \
+       register unsigned long ia64_clobber asm ("r8");         \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_clobber)                      \
+                     : PARAVIRT_OP(op)                         \
+                     : PARAVIRT_CLOBBERS0)
+
+#define PARAVIRT_BR0_RET(op, type)                             \
+       register unsigned long ia64_intri_res asm ("r8");       \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_intri_res)                    \
+                     : PARAVIRT_OP(op)                         \
+                     : PARAVIRT_CLOBBERS0)
+
+#define PARAVIRT_BR1(op, type, arg1)                           \
+       register unsigned long __##arg1 asm ("r8") = arg1;      \
+       register unsigned long ia64_clobber asm ("r8");         \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_clobber)                      \
+                     : PARAVIRT_OP(op), "0"(__##arg1)          \
+                     : PARAVIRT_CLOBBERS1)
+
+#define PARAVIRT_BR1_RET(op, type, arg1)                       \
+       register unsigned long ia64_intri_res asm ("r8");       \
+       register unsigned long __##arg1 asm ("r8") = arg1;      \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_intri_res)                    \
+                     : PARAVIRT_OP(op), "0"(__##arg1)          \
+                     : PARAVIRT_CLOBBERS1)
+
+#define PARAVIRT_BR1_VOID(op, type, arg1)                      \
+       register void *__##arg1 asm ("r8") = arg1;              \
+       register unsigned long ia64_clobber asm ("r8");         \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                         PARAVIRT_TYPE(type))  \
+                     : "=r"(ia64_clobber)                      \
+                     : PARAVIRT_OP(op), "0"(__##arg1)          \
+                     : PARAVIRT_CLOBBERS1)
+
+#define PARAVIRT_BR2(op, type, arg1, arg2)                             \
+       register unsigned long __##arg1 asm ("r8") = arg1;              \
+       register unsigned long __##arg2 asm ("r9") = arg2;              \
+       register unsigned long ia64_clobber1 asm ("r8");                \
+       register unsigned long ia64_clobber2 asm ("r9");                \
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,                \
+                                         PARAVIRT_TYPE(type))          \
+                     : "=r"(ia64_clobber1), "=r"(ia64_clobber2)        \
+                     : PARAVIRT_OP(op), "0"(__##arg1), "1"(__##arg2)   \
+                     : PARAVIRT_CLOBBERS2)
+
+
+#define PARAVIRT_DEFINE_CPU_OP0(op, type)              \
+       static inline void                              \
+       paravirt_ ## op (void)                          \
+       {                                               \
+               PARAVIRT_BR0(op, type);                 \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP0_RET(op, type)          \
+       static inline unsigned long                     \
+       paravirt_ ## op (void)                          \
+       {                                               \
+               PARAVIRT_BR0_RET(op, type);             \
+               return ia64_intri_res;                  \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP1_VOID(op, type)         \
+       static inline void                              \
+       paravirt_ ## op (void *arg1)                    \
+       {                                               \
+               PARAVIRT_BR1_VOID(op, type, arg1);      \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP1(op, type)              \
+       static inline void                              \
+       paravirt_ ## op (unsigned long arg1)            \
+       {                                               \
+               PARAVIRT_BR1(op, type, arg1);           \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP1_RET(op, type)          \
+       static inline unsigned long                     \
+       paravirt_ ## op (unsigned long arg1)            \
+       {                                               \
+               PARAVIRT_BR1_RET(op, type, arg1);       \
+               return ia64_intri_res;                  \
+       }
+
+#define PARAVIRT_DEFINE_CPU_OP2(op, type)              \
+       static inline void                              \
+       paravirt_ ## op (unsigned long arg1,            \
+                        unsigned long arg2)            \
+       {                                               \
+               PARAVIRT_BR2(op, type, arg1, arg2);     \
+       }
+
+
+PARAVIRT_DEFINE_CPU_OP1_VOID(fc, FC);
+PARAVIRT_DEFINE_CPU_OP1_RET(thash, THASH)
+PARAVIRT_DEFINE_CPU_OP1_RET(get_cpuid, GET_CPUID)
+PARAVIRT_DEFINE_CPU_OP1_RET(get_pmd, GET_PMD)
+PARAVIRT_DEFINE_CPU_OP2(ptcga, PTCGA)
+PARAVIRT_DEFINE_CPU_OP1_RET(get_rr, GET_RR)
+PARAVIRT_DEFINE_CPU_OP2(set_rr, SET_RR)
+PARAVIRT_DEFINE_CPU_OP0(ssm_i, SSM_I)
+PARAVIRT_DEFINE_CPU_OP0(rsm_i, RSM_I)
+PARAVIRT_DEFINE_CPU_OP0_RET(get_psr_i, GET_PSR_I)
+PARAVIRT_DEFINE_CPU_OP1(intrin_local_irq_restore, INTRIN_LOCAL_IRQ_RESTORE)
+
+static inline void
+paravirt_set_rr0_to_rr4(unsigned long val0, unsigned long val1,
+                       unsigned long val2, unsigned long val3,
+                       unsigned long val4)
+{
+       register unsigned long __val0 asm ("r8") = val0;
+       register unsigned long __val1 asm ("r9") = val1;
+       register unsigned long __val2 asm ("r10") = val2;
+       register unsigned long __val3 asm ("r11") = val3;
+       register unsigned long __val4 asm ("r14") = val4;
+
+       register unsigned long ia64_clobber0 asm ("r8");
+       register unsigned long ia64_clobber1 asm ("r9");
+       register unsigned long ia64_clobber2 asm ("r10");
+       register unsigned long ia64_clobber3 asm ("r11");
+       register unsigned long ia64_clobber4 asm ("r14");
+
+       asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,
+                                         PARAVIRT_TYPE(SET_RR0_TO_RR4))
+                     : "=r"(ia64_clobber0),
+                       "=r"(ia64_clobber1),
+                       "=r"(ia64_clobber2),
+                       "=r"(ia64_clobber3),
+                       "=r"(ia64_clobber4)
+                     : PARAVIRT_OP(set_rr0_to_rr4),
+                       "0"(__val0), "1"(__val1), "2"(__val2),
+                       "3"(__val3), "4"(__val4)
+                     : PARAVIRT_CLOBBERS5);
+}
+
+/* unsigned long paravirt_getreg(int reg) */
+#define __paravirt_getreg(reg)                                         \
+       ({                                                              \
+               register unsigned long ia64_intri_res asm ("r8");       \
+               register unsigned long __reg asm ("r8") = (reg);        \
+                                                                       \
+               BUILD_BUG_ON(!__builtin_constant_p(reg));               \
+               asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                                 PARAVIRT_TYPE(GETREG) \
+                                                 + (reg))              \
+                             : "=r"(ia64_intri_res)                    \
+                             : PARAVIRT_OP(getreg), "0"(__reg)         \
+                             : PARAVIRT_CLOBBERS1);                    \
+                                                                       \
+               ia64_intri_res;                                         \
+       })
+
+/* void paravirt_setreg(int reg, unsigned long val) */
+#define paravirt_setreg(reg, val)                                      \
+       do {                                                            \
+               register unsigned long __val asm ("r8") = val;          \
+               register unsigned long __reg asm ("r9") = reg;          \
+               register unsigned long ia64_clobber1 asm ("r8");        \
+               register unsigned long ia64_clobber2 asm ("r9");        \
+                                                                       \
+               BUILD_BUG_ON(!__builtin_constant_p(reg));               \
+               asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,        \
+                                                 PARAVIRT_TYPE(SETREG) \
+                                                 + (reg))              \
+                             : "=r"(ia64_clobber1),                    \
+                               "=r"(ia64_clobber2)                     \
+                             : PARAVIRT_OP(setreg),                    \
+                               "1"(__reg), "0"(__val)                  \
+                             : PARAVIRT_CLOBBERS2);                    \
+       } while (0)
+
+#endif /* ASM_SUPPORTED */
+#endif /* CONFIG_PARAVIRT && ASM_SUPPOTED */
+
 #endif /* _ASM_IA64_PARAVIRT_PRIVOP_H */
index 21c402365d0ea7f86bf63cbf0009bb7c7e266642..59840833625165fc72c75b40c24e94a1ba7db5ae 100644 (file)
@@ -126,7 +126,8 @@ extern void identify_siblings (struct cpuinfo_ia64 *);
 extern int is_multithreading_enabled(void);
 
 extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
 #else /* CONFIG_SMP */
 
index 0229fb95fb3824f657452dc4adbd1bd4e52c48e1..13ab71576bc7a42e698508a92a04b2ed87ee7fd7 100644 (file)
@@ -120,6 +120,38 @@ do {                                                                                       \
 #define __raw_read_can_lock(rw)                (*(volatile int *)(rw) >= 0)
 #define __raw_write_can_lock(rw)       (*(volatile int *)(rw) == 0)
 
+#ifdef ASM_SUPPORTED
+
+static __always_inline void
+__raw_read_lock_flags(raw_rwlock_t *lock, unsigned long flags)
+{
+       __asm__ __volatile__ (
+               "tbit.nz p6, p0 = %1,%2\n"
+               "br.few 3f\n"
+               "1:\n"
+               "fetchadd4.rel r2 = [%0], -1;;\n"
+               "(p6) ssm psr.i\n"
+               "2:\n"
+               "hint @pause\n"
+               "ld4 r2 = [%0];;\n"
+               "cmp4.lt p7,p0 = r2, r0\n"
+               "(p7) br.cond.spnt.few 2b\n"
+               "(p6) rsm psr.i\n"
+               ";;\n"
+               "3:\n"
+               "fetchadd4.acq r2 = [%0], 1;;\n"
+               "cmp4.lt p7,p0 = r2, r0\n"
+               "(p7) br.cond.spnt.few 1b\n"
+               : : "r"(lock), "r"(flags), "i"(IA64_PSR_I_BIT)
+               : "p6", "p7", "r2", "memory");
+}
+
+#define __raw_read_lock(lock) __raw_read_lock_flags(lock, 0)
+
+#else /* !ASM_SUPPORTED */
+
+#define __raw_read_lock_flags(rw, flags) __raw_read_lock(rw)
+
 #define __raw_read_lock(rw)                                                            \
 do {                                                                                   \
        raw_rwlock_t *__read_lock_ptr = (rw);                                           \
@@ -131,6 +163,8 @@ do {                                                                                        \
        }                                                                               \
 } while (0)
 
+#endif /* !ASM_SUPPORTED */
+
 #define __raw_read_unlock(rw)                                  \
 do {                                                           \
        raw_rwlock_t *__read_lock_ptr = (rw);                   \
@@ -138,20 +172,33 @@ do {                                                              \
 } while (0)
 
 #ifdef ASM_SUPPORTED
-#define __raw_write_lock(rw)                                                   \
-do {                                                                           \
-       __asm__ __volatile__ (                                                  \
-               "mov ar.ccv = r0\n"                                             \
-               "dep r29 = -1, r0, 31, 1;;\n"                                   \
-               "1:\n"                                                          \
-               "ld4 r2 = [%0];;\n"                                             \
-               "cmp4.eq p0,p7 = r0,r2\n"                                       \
-               "(p7) br.cond.spnt.few 1b \n"                                   \
-               "cmpxchg4.acq r2 = [%0], r29, ar.ccv;;\n"                       \
-               "cmp4.eq p0,p7 = r0, r2\n"                                      \
-               "(p7) br.cond.spnt.few 1b;;\n"                                  \
-               :: "r"(rw) : "ar.ccv", "p7", "r2", "r29", "memory");            \
-} while(0)
+
+static __always_inline void
+__raw_write_lock_flags(raw_rwlock_t *lock, unsigned long flags)
+{
+       __asm__ __volatile__ (
+               "tbit.nz p6, p0 = %1, %2\n"
+               "mov ar.ccv = r0\n"
+               "dep r29 = -1, r0, 31, 1\n"
+               "br.few 3f;;\n"
+               "1:\n"
+               "(p6) ssm psr.i\n"
+               "2:\n"
+               "hint @pause\n"
+               "ld4 r2 = [%0];;\n"
+               "cmp4.eq p0,p7 = r0, r2\n"
+               "(p7) br.cond.spnt.few 2b\n"
+               "(p6) rsm psr.i\n"
+               ";;\n"
+               "3:\n"
+               "cmpxchg4.acq r2 = [%0], r29, ar.ccv;;\n"
+               "cmp4.eq p0,p7 = r0, r2\n"
+               "(p7) br.cond.spnt.few 1b;;\n"
+               : : "r"(lock), "r"(flags), "i"(IA64_PSR_I_BIT)
+               : "ar.ccv", "p6", "p7", "r2", "r29", "memory");
+}
+
+#define __raw_write_lock(rw) __raw_write_lock_flags(rw, 0)
 
 #define __raw_write_trylock(rw)                                                        \
 ({                                                                             \
@@ -174,6 +221,8 @@ static inline void __raw_write_unlock(raw_rwlock_t *x)
 
 #else /* !ASM_SUPPORTED */
 
+#define __raw_write_lock_flags(l, flags) __raw_write_lock(l)
+
 #define __raw_write_lock(l)                                                            \
 ({                                                                                     \
        __u64 ia64_val, ia64_set_val = ia64_dep_mi(-1, 0, 31, 1);                       \
index 4e03cfe74a0c40712c7ff328c0436eca46946e95..86c7db86118034bcc8ed60162112786afd30c4f5 100644 (file)
@@ -40,5 +40,6 @@ get_cycles (void)
 }
 
 extern void ia64_cpu_local_tick (void);
+extern unsigned long long ia64_native_sched_clock (void);
 
 #endif /* _ASM_IA64_TIMEX_H */
index 3193f4417e16c8ea919016f05aa904215f6eeae9..7b4c8c70b2d18f7949372899ab056f41d913ed6b 100644 (file)
  */
 #define parent_node(nid) (nid)
 
-/*
- * Returns the number of the first CPU on Node 'node'.
- */
-#define node_to_first_cpu(node) (cpumask_first(cpumask_of_node(node)))
-
 /*
  * Determines the node for a given pci bus
  */
@@ -117,11 +112,6 @@ void build_cpu_to_node_map(void);
 
 extern void arch_fix_phys_package_id(int num, u32 slot);
 
-#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
-                                       CPU_MASK_ALL : \
-                                       node_to_cpumask(pcibus_to_node(bus)) \
-                               )
-
 #define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ?            \
                                 cpu_all_mask :                         \
                                 cpumask_of_node(pcibus_to_node(bus)))
index f607018af4a19397691212e7074a55455a2f3cd2..53e9dfacd07393a57b9ae9ab114c2e4b5596f4dc 100644 (file)
@@ -305,5 +305,11 @@ static inline int uv_num_possible_blades(void)
        return 1;
 }
 
+static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
+{
+       /* not currently needed on ia64 */
+}
+
+
 #endif /* __ASM_IA64_UV_HUB__ */
 
index c149ef085437f22cc46b2ad6db09c1ec0520d45f..fe0b8f05e1a8719c39b91babcd4afe06b80eefed 100644 (file)
@@ -8,8 +8,8 @@
  * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
  */
 
-#ifndef __ASM_IA64_UV_MMRS__
-#define __ASM_IA64_UV_MMRS__
+#ifndef _ASM_IA64_UV_UV_MMRS_H
+#define _ASM_IA64_UV_UV_MMRS_H
 
 #define UV_MMR_ENABLE          (1UL << 63)
 
@@ -242,6 +242,158 @@ union uvh_event_occurred0_u {
 #define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL
 #define UVH_EVENT_OCCURRED0_ALIAS_32 0x005f0
 
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
+
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
+
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL
+
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL
+
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
 /* ========================================================================= */
 /*                               UVH_INT_CMPB                                */
 /* ========================================================================= */
@@ -670,4 +822,4 @@ union uvh_si_alias2_overlay_config_u {
 };
 
 
-#endif /* __ASM_IA64_UV_MMRS__ */
+#endif /* _ASM_IA64_UV_UV_MMRS_H */
index 7a804e80fc67d0c0aee90d0cbe13e365512d0570..e425227a418e9b15a40a0dce0d8f09be3061ec90 100644 (file)
@@ -33,9 +33,6 @@
 #ifndef _ASM_IA64_XEN_HYPERVISOR_H
 #define _ASM_IA64_XEN_HYPERVISOR_H
 
-#ifdef CONFIG_XEN
-
-#include <linux/init.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/version.h>     /* to compile feature.c */
 #include <xen/features.h>              /* to comiple xen-netfront.c */
 
 /* xen_domain_type is set before executing any C code by early_xen_setup */
 enum xen_domain_type {
-       XEN_NATIVE,
-       XEN_PV_DOMAIN,
-       XEN_HVM_DOMAIN,
+       XEN_NATIVE,     /* running on bare hardware */
+       XEN_PV_DOMAIN,  /* running in a PV domain */
+       XEN_HVM_DOMAIN, /* running in a Xen hvm domain*/
 };
 
+#ifdef CONFIG_XEN
 extern enum xen_domain_type xen_domain_type;
+#else
+#define xen_domain_type                XEN_NATIVE
+#endif
 
 #define xen_domain()           (xen_domain_type != XEN_NATIVE)
-#define xen_pv_domain()                (xen_domain_type == XEN_PV_DOMAIN)
-#define xen_initial_domain()   (xen_pv_domain() && \
+#define xen_pv_domain()                (xen_domain() &&                        \
+                                xen_domain_type == XEN_PV_DOMAIN)
+#define xen_hvm_domain()       (xen_domain() &&                        \
+                                xen_domain_type == XEN_HVM_DOMAIN)
+
+#ifdef CONFIG_XEN_DOM0
+#define xen_initial_domain()   (xen_pv_domain() &&                     \
                                 (xen_start_info->flags & SIF_INITDOMAIN))
-#define xen_hvm_domain()       (xen_domain_type == XEN_HVM_DOMAIN)
+#else
+#define xen_initial_domain()   (0)
+#endif
 
-/* deprecated. remove this */
-#define is_running_on_xen()    (xen_domain_type == XEN_PV_DOMAIN)
 
+#ifdef CONFIG_XEN
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
@@ -74,16 +81,6 @@ void force_evtchn_callback(void);
 
 /* For setup_arch() in arch/ia64/kernel/setup.c */
 void xen_ia64_enable_opt_feature(void);
-
-#else /* CONFIG_XEN */
-
-#define xen_domain()           (0)
-#define xen_pv_domain()                (0)
-#define xen_initial_domain()   (0)
-#define xen_hvm_domain()       (0)
-#define is_running_on_xen()    (0)     /* deprecated. remove this */
 #endif
 
-#define is_initial_xendomain() (0)     /* deprecated. remove this */
-
 #endif /* _ASM_IA64_XEN_HYPERVISOR_H */
index 19c2ae1d878a0473278b35a198114b860ba52d74..c53a476112082328ac403943fa784629b7ca1f4f 100644 (file)
@@ -33,6 +33,9 @@
 #define __paravirt_work_processed_syscall_target \
                                                xen_work_processed_syscall
 
+#define paravirt_fsyscall_table                        xen_fsyscall_table
+#define paravirt_fsys_bubble_down              xen_fsys_bubble_down
+
 #define MOV_FROM_IFA(reg)      \
        movl reg = XSI_IFA;     \
        ;;                      \
 .endm
 #define MOV_FROM_PSR(pred, reg, clob)  __MOV_FROM_PSR pred, reg, clob
 
+/* assuming ar.itc is read with interrupt disabled. */
+#define MOV_FROM_ITC(pred, pred_clob, reg, clob)               \
+(pred) movl clob = XSI_ITC_OFFSET;                             \
+       ;;                                                      \
+(pred) ld8 clob = [clob];                                      \
+(pred) mov reg = ar.itc;                                       \
+       ;;                                                      \
+(pred) add reg = reg, clob;                                    \
+       ;;                                                      \
+(pred) movl clob = XSI_ITC_LAST;                               \
+       ;;                                                      \
+(pred) ld8 clob = [clob];                                      \
+       ;;                                                      \
+(pred) cmp.geu.unc pred_clob, p0 = clob, reg;                  \
+       ;;                                                      \
+(pred_clob)    add reg = 1, clob;                              \
+       ;;                                                      \
+(pred) movl clob = XSI_ITC_LAST;                               \
+       ;;                                                      \
+(pred) st8 [clob] = reg
+
 
 #define MOV_TO_IFA(reg, clob)  \
        movl clob = XSI_IFA;    \
 #define RSM_PSR_DT             \
        XEN_HYPER_RSM_PSR_DT
 
+#define RSM_PSR_BE_I(clob0, clob1)     \
+       RSM_PSR_I(p0, clob0, clob1);    \
+       rum psr.be
+
 #define SSM_PSR_DT_AND_SRLZ_I  \
        XEN_HYPER_SSM_PSR_DT
 
index f00fab40854d1951b473b88ec201adee9b03a41a..e951e740bdf21514c8622f9b8ba875ada702e450 100644 (file)
@@ -209,6 +209,15 @@ struct mapped_regs {
                        unsigned long krs[8];   /* kernel registers */
                        unsigned long tmp[16];  /* temp registers
                                                   (e.g. for hyperprivops) */
+
+                       /* itc paravirtualization
+                        * vAR.ITC = mAR.ITC + itc_offset
+                        * itc_last is one which was lastly passed to
+                        * the guest OS in order to prevent it from
+                        * going backwords.
+                        */
+                       unsigned long itc_offset;
+                       unsigned long itc_last;
                };
        };
 };
index 4d92d9bbda7be19dd419107a34c08f344edfbff1..c57fa910f2c937e7473a9ea63e5ac9a7be74c86c 100644 (file)
@@ -1,3 +1,12 @@
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+/* read ar.itc in advance, and use it before leaving bank 0 */
+#define XEN_ACCOUNT_GET_STAMP          \
+       MOV_FROM_ITC(pUStk, p6, r20, r2);
+#else
+#define XEN_ACCOUNT_GET_STAMP
+#endif
+
 /*
  * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
  * the minimum state necessary that allows us to turn psr.ic back
        ;;                                                                                      \
 .mem.offset 0,0; st8.spill [r16]=r2,16;                                                                \
 .mem.offset 8,0; st8.spill [r17]=r3,16;                                                                \
-       ACCOUNT_GET_STAMP                                                                       \
+       XEN_ACCOUNT_GET_STAMP                                                                   \
        adds r2=IA64_PT_REGS_R16_OFFSET,r1;                                                     \
        ;;                                                                                      \
        EXTRA;                                                                                  \
diff --git a/arch/ia64/include/asm/xen/patchlist.h b/arch/ia64/include/asm/xen/patchlist.h
new file mode 100644 (file)
index 0000000..eae944e
--- /dev/null
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * arch/ia64/include/asm/xen/patchlist.h
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#define __paravirt_start_gate_fsyscall_patchlist               \
+       __xen_start_gate_fsyscall_patchlist
+#define __paravirt_end_gate_fsyscall_patchlist                 \
+       __xen_end_gate_fsyscall_patchlist
+#define __paravirt_start_gate_brl_fsys_bubble_down_patchlist   \
+       __xen_start_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_end_gate_brl_fsys_bubble_down_patchlist     \
+       __xen_end_gate_brl_fsys_bubble_down_patchlist
+#define __paravirt_start_gate_vtop_patchlist                   \
+       __xen_start_gate_vtop_patchlist
+#define __paravirt_end_gate_vtop_patchlist                     \
+       __xen_end_gate_vtop_patchlist
+#define __paravirt_start_gate_mckinley_e9_patchlist            \
+       __xen_start_gate_mckinley_e9_patchlist
+#define __paravirt_end_gate_mckinley_e9_patchlist              \
+       __xen_end_gate_mckinley_e9_patchlist
index 71ec7546e100d5a5f549874057caead44c4809e5..fb4ec5e0b066b81741078f9f00374417b3c9de60 100644 (file)
@@ -55,6 +55,8 @@
 #define XSI_BANK1_R16                  (XSI_BASE + XSI_BANK1_R16_OFS)
 #define XSI_BANKNUM                    (XSI_BASE + XSI_BANKNUM_OFS)
 #define XSI_IHA                                (XSI_BASE + XSI_IHA_OFS)
+#define XSI_ITC_OFFSET                 (XSI_BASE + XSI_ITC_OFFSET_OFS)
+#define XSI_ITC_LAST                   (XSI_BASE + XSI_ITC_LAST_OFS)
 #endif
 
 #ifndef __ASSEMBLY__
@@ -67,7 +69,7 @@
  *  may have different semantics depending on whether they are executed
  *  at PL0 vs PL!=0.  When paravirtualized, these instructions mustn't
  *  be allowed to execute directly, lest incorrect semantics result. */
-extern void xen_fc(unsigned long addr);
+extern void xen_fc(void *addr);
 extern unsigned long xen_thash(unsigned long addr);
 
 /* Note that "ttag" and "cover" are also privilege-sensitive; "ttag"
@@ -80,8 +82,10 @@ extern unsigned long xen_thash(unsigned long addr);
 extern unsigned long xen_get_cpuid(int index);
 extern unsigned long xen_get_pmd(int index);
 
+#ifndef ASM_SUPPORTED
 extern unsigned long xen_get_eflag(void);      /* see xen_ia64_getreg */
 extern void xen_set_eflag(unsigned long);      /* see xen_ia64_setreg */
+#endif
 
 /************************************************/
 /* Instructions paravirtualized for performance */
@@ -106,6 +110,7 @@ extern void xen_set_eflag(unsigned long);   /* see xen_ia64_setreg */
 #define xen_get_virtual_pend()         \
        (*(((uint8_t *)XEN_MAPPEDREGS->interrupt_mask_addr) - 1))
 
+#ifndef ASM_SUPPORTED
 /* Although all privileged operations can be left to trap and will
  * be properly handled by Xen, some are frequent enough that we use
  * hyperprivops for performance. */
@@ -123,6 +128,7 @@ extern void xen_set_rr0_to_rr4(unsigned long val0, unsigned long val1,
                               unsigned long val4);
 extern void xen_set_kr(unsigned long index, unsigned long val);
 extern void xen_ptcga(unsigned long addr, unsigned long size);
+#endif /* !ASM_SUPPORTED */
 
 #endif /* !__ASSEMBLY__ */
 
index f2778f2c4fd9307f75c989fc8553364efe1b9253..5628e9a990a61225196c5de205ebdceeaf800aee 100644 (file)
@@ -5,7 +5,7 @@
 extra-y        := head.o init_task.o vmlinux.lds
 
 obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o      \
-        irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o          \
+        irq_lsapic.o ivt.o machvec.o pal.o paravirt_patchlist.o patch.o process.o perfmon.o ptrace.o sal.o             \
         salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
         unwind.o mca.o mca_asm.o topology.o dma-mapping.o
 
@@ -36,7 +36,8 @@ obj-$(CONFIG_PCI_MSI)         += msi_ia64.o
 mca_recovery-y                 += mca_drv.o mca_drv_asm.o
 obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
 
-obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirtentry.o
+obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirtentry.o \
+                                  paravirt_patch.o
 
 obj-$(CONFIG_IA64_ESI)         += esi.o
 ifneq ($(CONFIG_IA64_ESI),)
@@ -45,35 +46,13 @@ endif
 obj-$(CONFIG_DMAR)             += pci-dma.o
 obj-$(CONFIG_SWIOTLB)          += pci-swiotlb.o
 
-# The gate DSO image is built using a special linker script.
-targets += gate.so gate-syms.o
-
-extra-y += gate.so gate-syms.o gate.lds gate.o
-
 # fp_emulate() expects f2-f5,f16-f31 to contain the user-level state.
 CFLAGS_traps.o  += -mfixed-range=f2-f5,f16-f31
 
-CPPFLAGS_gate.lds := -P -C -U$(ARCH)
-
-quiet_cmd_gate = GATE $@
-      cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
-
-GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
-                    $(call ld-option, -Wl$(comma)--hash-style=sysv)
-$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE
-       $(call if_changed,gate)
-
-$(obj)/built-in.o: $(obj)/gate-syms.o
-$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o
-
-GATECFLAGS_gate-syms.o = -r
-$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
-       $(call if_changed,gate)
-
-# gate-data.o contains the gate DSO image as data in section .data.gate.
-# We must build gate.so before we can assemble it.
-# Note: kbuild does not track this dependency due to usage of .incbin
-$(obj)/gate-data.o: $(obj)/gate.so
+# The gate DSO image is built using a special linker script.
+include $(srctree)/arch/ia64/kernel/Makefile.gate
+# tell compiled for native
+CPPFLAGS_gate.lds += -D__IA64_GATE_PARAVIRTUALIZED_NATIVE
 
 # Calculate NR_IRQ = max(IA64_NATIVE_NR_IRQS, XEN_NR_IRQS, ...) based on config
 define sed-y
@@ -109,9 +88,9 @@ include/asm-ia64/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
 clean-files += $(objtree)/include/asm-ia64/nr-irqs.h
 
 #
-# native ivt.S and entry.S
+# native ivt.S, entry.S and fsys.S
 #
-ASM_PARAVIRT_OBJS = ivt.o entry.o
+ASM_PARAVIRT_OBJS = ivt.o entry.o fsys.o
 define paravirtualized_native
 AFLAGS_$(1) += -D__IA64_ASM_PARAVIRTUALIZED_NATIVE
 AFLAGS_pvchk-sed-$(1) += -D__IA64_ASM_PARAVIRTUALIZED_PVCHECK
diff --git a/arch/ia64/kernel/Makefile.gate b/arch/ia64/kernel/Makefile.gate
new file mode 100644 (file)
index 0000000..1d87f84
--- /dev/null
@@ -0,0 +1,27 @@
+# The gate DSO image is built using a special linker script.
+
+targets += gate.so gate-syms.o
+
+extra-y += gate.so gate-syms.o gate.lds gate.o
+
+CPPFLAGS_gate.lds := -P -C -U$(ARCH)
+
+quiet_cmd_gate = GATE $@
+      cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
+                    $(call ld-option, -Wl$(comma)--hash-style=sysv)
+$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE
+       $(call if_changed,gate)
+
+$(obj)/built-in.o: $(obj)/gate-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o
+
+GATECFLAGS_gate-syms.o = -r
+$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
+       $(call if_changed,gate)
+
+# gate-data.o contains the gate DSO image as data in section .data.gate.
+# We must build gate.so before we can assemble it.
+# Note: kbuild does not track this dependency due to usage of .incbin
+$(obj)/gate-data.o: $(obj)/gate.so
index bdef2ce38c8b45c3227b7d70673db1bce4deb46f..5510317db37b2a439711bb3fa97d6af0c7cd00bf 100644 (file)
@@ -890,7 +890,7 @@ __init void prefill_possible_map(void)
                possible, max((possible - available_cpus), 0));
 
        for (i = 0; i < possible; i++)
-               cpu_set(i, cpu_possible_map);
+               set_cpu_possible(i, true);
 }
 
 int acpi_map_lsapic(acpi_handle handle, int *pcpu)
@@ -928,9 +928,9 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
        buffer.length = ACPI_ALLOCATE_BUFFER;
        buffer.pointer = NULL;
 
-       cpus_complement(tmp_map, cpu_present_map);
-       cpu = first_cpu(tmp_map);
-       if (cpu >= NR_CPUS)
+       cpumask_complement(&tmp_map, cpu_present_mask);
+       cpu = cpumask_first(&tmp_map);
+       if (cpu >= nr_cpu_ids)
                return -EINVAL;
 
        acpi_map_cpu2node(handle, cpu, physid);
index 742dbb1d5a4fb06cd8cfd3a2f63358b48e20535e..af56501690432110a1f27847bea9dffd60737b81 100644 (file)
@@ -316,5 +316,7 @@ void foo(void)
        DEFINE_MAPPED_REG_OFS(XSI_BANK1_R16_OFS, bank1_regs[0]);
        DEFINE_MAPPED_REG_OFS(XSI_B0NATS_OFS, vbnat);
        DEFINE_MAPPED_REG_OFS(XSI_B1NATS_OFS, vnat);
+       DEFINE_MAPPED_REG_OFS(XSI_ITC_OFFSET_OFS, itc_offset);
+       DEFINE_MAPPED_REG_OFS(XSI_ITC_LAST_OFS, itc_last);
 #endif /* CONFIG_XEN */
 }
index efaff15d8cf1dc9cad35a767a53b3865d51037b4..7ef80e8161ce3dbad06d522ef5634e9e8520be3e 100644 (file)
@@ -456,6 +456,7 @@ efi_map_pal_code (void)
                 GRANULEROUNDDOWN((unsigned long) pal_vaddr),
                 pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)),
                 IA64_GRANULE_SHIFT);
+       paravirt_dv_serialize_data();
        ia64_set_psr(psr);              /* restore psr */
 }
 
index e5341e2c1175c6f0b5e16f88bd831f90422fbf03..ccfdeee9d89f7c291306b7bdfa08caa689ecc14f 100644 (file)
@@ -735,7 +735,7 @@ GLOBAL_ENTRY(__paravirt_leave_syscall)
 __paravirt_work_processed_syscall:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        adds r2=PT(LOADRS)+16,r12
-(pUStk)        mov.m r22=ar.itc                        // fetch time at leave
+       MOV_FROM_ITC(pUStk, p9, r22, r19)       // fetch time at leave
        adds r18=TI_FLAGS+IA64_TASK_SIZE,r13
        ;;
 (p6)   ld4 r31=[r18]                           // load current_thread_info()->flags
@@ -984,7 +984,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        .pred.rel.mutex pUStk,pKStk
        MOV_FROM_PSR(pKStk, r22, r29)   // M2 read PSR now that interrupts are disabled
-(pUStk)        mov.m r22=ar.itc        // M  fetch time at leave
+       MOV_FROM_ITC(pUStk, p9, r22, r29)       // M  fetch time at leave
        nop.i 0
        ;;
 #else
index c1625c7e17795b093acd281eb7d2a56fd1a6be47..3567d54f8cee7533ecba41847c5f9957d9481296 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/unistd.h>
 
 #include "entry.h"
+#include "paravirt_inst.h"
 
 /*
  * See Documentation/ia64/fsys.txt for details on fsyscalls.
@@ -279,7 +280,7 @@ ENTRY(fsys_gettimeofday)
 (p9)   cmp.eq p13,p0 = 0,r30   // if mmio_ptr, clear p13 jitter control
        ;;
        .pred.rel.mutex p8,p9
-(p8)   mov r2 = ar.itc         // CPU_TIMER. 36 clocks latency!!!
+       MOV_FROM_ITC(p8, p6, r2, r10)   // CPU_TIMER. 36 clocks latency!!!
 (p9)   ld8 r2 = [r30]          // MMIO_TIMER. Could also have latency issues..
 (p13)  ld8 r25 = [r19]         // get itc_lastcycle value
        ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET     // tv_sec
@@ -418,7 +419,7 @@ EX(.fail_efault, ld8 r14=[r33])                     // r14 <- *set
        mov r17=(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1))
        ;;
 
-       rsm psr.i                               // mask interrupt delivery
+       RSM_PSR_I(p0, r18, r19)                 // mask interrupt delivery
        mov ar.ccv=0
        andcm r14=r14,r17                       // filter out SIGKILL & SIGSTOP
 
@@ -491,7 +492,7 @@ EX(.fail_efault, ld8 r14=[r33])                     // r14 <- *set
 #ifdef CONFIG_SMP
        st4.rel [r31]=r0                        // release the lock
 #endif
-       ssm psr.i
+       SSM_PSR_I(p0, p9, r31)
        ;;
 
        srlz.d                                  // ensure psr.i is set again
@@ -513,7 +514,7 @@ EX(.fail_efault, (p15) st8 [r34]=r3)
 #ifdef CONFIG_SMP
        st4.rel [r31]=r0                        // release the lock
 #endif
-       ssm psr.i
+       SSM_PSR_I(p0, p9, r17)
        ;;
        srlz.d
        br.sptk.many fsys_fallback_syscall      // with signal pending, do the heavy-weight syscall
@@ -521,7 +522,7 @@ EX(.fail_efault, (p15) st8 [r34]=r3)
 #ifdef CONFIG_SMP
 .lock_contention:
        /* Rather than spinning here, fall back on doing a heavy-weight syscall.  */
-       ssm psr.i
+       SSM_PSR_I(p0, p9, r17)
        ;;
        srlz.d
        br.sptk.many fsys_fallback_syscall
@@ -592,17 +593,17 @@ ENTRY(fsys_fallback_syscall)
        adds r17=-1024,r15
        movl r14=sys_call_table
        ;;
-       rsm psr.i
+       RSM_PSR_I(p0, r26, r27)
        shladd r18=r17,3,r14
        ;;
        ld8 r18=[r18]                           // load normal (heavy-weight) syscall entry-point
-       mov r29=psr                             // read psr (12 cyc load latency)
+       MOV_FROM_PSR(p0, r29, r26)              // read psr (12 cyc load latency)
        mov r27=ar.rsc
        mov r21=ar.fpsr
        mov r26=ar.pfs
 END(fsys_fallback_syscall)
        /* FALL THROUGH */
-GLOBAL_ENTRY(fsys_bubble_down)
+GLOBAL_ENTRY(paravirt_fsys_bubble_down)
        .prologue
        .altrp b6
        .body
@@ -640,7 +641,7 @@ GLOBAL_ENTRY(fsys_bubble_down)
         *
         * PSR.BE : already is turned off in __kernel_syscall_via_epc()
         * PSR.AC : don't care (kernel normally turns PSR.AC on)
-        * PSR.I  : already turned off by the time fsys_bubble_down gets
+        * PSR.I  : already turned off by the time paravirt_fsys_bubble_down gets
         *          invoked
         * PSR.DFL: always 0 (kernel never turns it on)
         * PSR.DFH: don't care --- kernel never touches f32-f127 on its own
@@ -650,7 +651,7 @@ GLOBAL_ENTRY(fsys_bubble_down)
         * PSR.DB : don't care --- kernel never enables kernel-level
         *          breakpoints
         * PSR.TB : must be 0 already; if it wasn't zero on entry to
-        *          __kernel_syscall_via_epc, the branch to fsys_bubble_down
+        *          __kernel_syscall_via_epc, the branch to paravirt_fsys_bubble_down
         *          will trigger a taken branch; the taken-trap-handler then
         *          converts the syscall into a break-based system-call.
         */
@@ -683,7 +684,7 @@ GLOBAL_ENTRY(fsys_bubble_down)
        ;;
        mov ar.rsc=0                            // M2   set enforced lazy mode, pl 0, LE, loadrs=0
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mov.m r30=ar.itc                        // M    get cycle for accounting
+       MOV_FROM_ITC(p0, p6, r30, r23)          // M    get cycle for accounting
 #else
        nop.m 0
 #endif
@@ -734,21 +735,21 @@ GLOBAL_ENTRY(fsys_bubble_down)
        mov rp=r14                              // I0   set the real return addr
        and r3=_TIF_SYSCALL_TRACEAUDIT,r3       // A
        ;;
-       ssm psr.i                               // M2   we're on kernel stacks now, reenable irqs
+       SSM_PSR_I(p0, p6, r22)                  // M2   we're on kernel stacks now, reenable irqs
        cmp.eq p8,p0=r3,r0                      // A
 (p10)  br.cond.spnt.many ia64_ret_from_syscall // B    return if bad call-frame or r15 is a NaT
 
        nop.m 0
 (p8)   br.call.sptk.many b6=b6                 // B    (ignore return address)
        br.cond.spnt ia64_trace_syscall         // B
-END(fsys_bubble_down)
+END(paravirt_fsys_bubble_down)
 
        .rodata
        .align 8
-       .globl fsyscall_table
+       .globl paravirt_fsyscall_table
 
-       data8 fsys_bubble_down
-fsyscall_table:
+       data8 paravirt_fsys_bubble_down
+paravirt_fsyscall_table:
        data8 fsys_ni_syscall
        data8 0                         // exit                 // 1025
        data8 0                         // read
@@ -1033,4 +1034,4 @@ fsyscall_table:
 
        // fill in zeros for the remaining entries
        .zero:
-       .space fsyscall_table + 8*NR_syscalls - .zero, 0
+       .space paravirt_fsyscall_table + 8*NR_syscalls - .zero, 0
index 74b1ccce4e848187f59df741e944d3edf054f444..cf5e0a105e16521cf20f1fc6aa1957cf5af2e97f 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/sigcontext.h>
 #include <asm/system.h>
 #include <asm/unistd.h>
+#include "paravirt_inst.h"
 
 /*
  * We can't easily refer to symbols inside the kernel.  To avoid full runtime relocation,
@@ -48,87 +49,6 @@ GLOBAL_ENTRY(__kernel_syscall_via_break)
 }
 END(__kernel_syscall_via_break)
 
-/*
- * On entry:
- *     r11 = saved ar.pfs
- *     r15 = system call #
- *     b0  = saved return address
- *     b6  = return address
- * On exit:
- *     r11 = saved ar.pfs
- *     r15 = system call #
- *     b0  = saved return address
- *     all other "scratch" registers:  undefined
- *     all "preserved" registers:      same as on entry
- */
-
-GLOBAL_ENTRY(__kernel_syscall_via_epc)
-       .prologue
-       .altrp b6
-       .body
-{
-       /*
-        * Note: the kernel cannot assume that the first two instructions in this
-        * bundle get executed.  The remaining code must be safe even if
-        * they do not get executed.
-        */
-       adds r17=-1024,r15                      // A
-       mov r10=0                               // A    default to successful syscall execution
-       epc                                     // B    causes split-issue
-}
-       ;;
-       rsm psr.be | psr.i                      // M2 (5 cyc to srlz.d)
-       LOAD_FSYSCALL_TABLE(r14)                // X
-       ;;
-       mov r16=IA64_KR(CURRENT)                // M2 (12 cyc)
-       shladd r18=r17,3,r14                    // A
-       mov r19=NR_syscalls-1                   // A
-       ;;
-       lfetch [r18]                            // M0|1
-       mov r29=psr                             // M2 (12 cyc)
-       // If r17 is a NaT, p6 will be zero
-       cmp.geu p6,p7=r19,r17                   // A    (sysnr > 0 && sysnr < 1024+NR_syscalls)?
-       ;;
-       mov r21=ar.fpsr                         // M2 (12 cyc)
-       tnat.nz p10,p9=r15                      // I0
-       mov.i r26=ar.pfs                        // I0 (would stall anyhow due to srlz.d...)
-       ;;
-       srlz.d                                  // M0 (forces split-issue) ensure PSR.BE==0
-(p6)   ld8 r18=[r18]                           // M0|1
-       nop.i 0
-       ;;
-       nop.m 0
-(p6)   tbit.z.unc p8,p0=r18,0                  // I0 (dual-issues with "mov b7=r18"!)
-       nop.i 0
-       ;;
-(p8)   ssm psr.i
-(p6)   mov b7=r18                              // I0
-(p8)   br.dptk.many b7                         // B
-
-       mov r27=ar.rsc                          // M2 (12 cyc)
-/*
- * brl.cond doesn't work as intended because the linker would convert this branch
- * into a branch to a PLT.  Perhaps there will be a way to avoid this with some
- * future version of the linker.  In the meantime, we just use an indirect branch
- * instead.
- */
-#ifdef CONFIG_ITANIUM
-(p6)   add r14=-8,r14                          // r14 <- addr of fsys_bubble_down entry
-       ;;
-(p6)   ld8 r14=[r14]                           // r14 <- fsys_bubble_down
-       ;;
-(p6)   mov b7=r14
-(p6)   br.sptk.many b7
-#else
-       BRL_COND_FSYS_BUBBLE_DOWN(p6)
-#endif
-       ssm psr.i
-       mov r10=-1
-(p10)  mov r8=EINVAL
-(p9)   mov r8=ENOSYS
-       FSYS_RETURN
-END(__kernel_syscall_via_epc)
-
 #      define ARG0_OFF         (16 + IA64_SIGFRAME_ARG0_OFFSET)
 #      define ARG1_OFF         (16 + IA64_SIGFRAME_ARG1_OFFSET)
 #      define ARG2_OFF         (16 + IA64_SIGFRAME_ARG2_OFFSET)
@@ -374,3 +294,92 @@ restore_rbs:
        // invala not necessary as that will happen when returning to user-mode
        br.cond.sptk back_from_restore_rbs
 END(__kernel_sigtramp)
+
+/*
+ * On entry:
+ *     r11 = saved ar.pfs
+ *     r15 = system call #
+ *     b0  = saved return address
+ *     b6  = return address
+ * On exit:
+ *     r11 = saved ar.pfs
+ *     r15 = system call #
+ *     b0  = saved return address
+ *     all other "scratch" registers:  undefined
+ *     all "preserved" registers:      same as on entry
+ */
+
+GLOBAL_ENTRY(__kernel_syscall_via_epc)
+       .prologue
+       .altrp b6
+       .body
+{
+       /*
+        * Note: the kernel cannot assume that the first two instructions in this
+        * bundle get executed.  The remaining code must be safe even if
+        * they do not get executed.
+        */
+       adds r17=-1024,r15                      // A
+       mov r10=0                               // A    default to successful syscall execution
+       epc                                     // B    causes split-issue
+}
+       ;;
+       RSM_PSR_BE_I(r20, r22)                  // M2 (5 cyc to srlz.d)
+       LOAD_FSYSCALL_TABLE(r14)                // X
+       ;;
+       mov r16=IA64_KR(CURRENT)                // M2 (12 cyc)
+       shladd r18=r17,3,r14                    // A
+       mov r19=NR_syscalls-1                   // A
+       ;;
+       lfetch [r18]                            // M0|1
+       MOV_FROM_PSR(p0, r29, r8)               // M2 (12 cyc)
+       // If r17 is a NaT, p6 will be zero
+       cmp.geu p6,p7=r19,r17                   // A    (sysnr > 0 && sysnr < 1024+NR_syscalls)?
+       ;;
+       mov r21=ar.fpsr                         // M2 (12 cyc)
+       tnat.nz p10,p9=r15                      // I0
+       mov.i r26=ar.pfs                        // I0 (would stall anyhow due to srlz.d...)
+       ;;
+       srlz.d                                  // M0 (forces split-issue) ensure PSR.BE==0
+(p6)   ld8 r18=[r18]                           // M0|1
+       nop.i 0
+       ;;
+       nop.m 0
+(p6)   tbit.z.unc p8,p0=r18,0                  // I0 (dual-issues with "mov b7=r18"!)
+       nop.i 0
+       ;;
+       SSM_PSR_I(p8, p14, r25)
+(p6)   mov b7=r18                              // I0
+(p8)   br.dptk.many b7                         // B
+
+       mov r27=ar.rsc                          // M2 (12 cyc)
+/*
+ * brl.cond doesn't work as intended because the linker would convert this branch
+ * into a branch to a PLT.  Perhaps there will be a way to avoid this with some
+ * future version of the linker.  In the meantime, we just use an indirect branch
+ * instead.
+ */
+#ifdef CONFIG_ITANIUM
+(p6)   add r14=-8,r14                          // r14 <- addr of fsys_bubble_down entry
+       ;;
+(p6)   ld8 r14=[r14]                           // r14 <- fsys_bubble_down
+       ;;
+(p6)   mov b7=r14
+(p6)   br.sptk.many b7
+#else
+       BRL_COND_FSYS_BUBBLE_DOWN(p6)
+#endif
+       SSM_PSR_I(p0, p14, r10)
+       mov r10=-1
+(p10)  mov r8=EINVAL
+(p9)   mov r8=ENOSYS
+       FSYS_RETURN
+
+#ifdef CONFIG_PARAVIRT
+       /*
+        * padd to make the size of this symbol constant
+        * independent of paravirtualization.
+        */
+       .align PAGE_SIZE / 8
+#endif
+END(__kernel_syscall_via_epc)
index 3cb1abc00e24f585119def5e51cc72da0d47ea37..88c64ed47c36bb8d20e9166775bd14cc55f166ed 100644 (file)
@@ -7,6 +7,7 @@
 
 
 #include <asm/system.h>
+#include "paravirt_patchlist.h"
 
 SECTIONS
 {
@@ -33,21 +34,21 @@ SECTIONS
        . = GATE_ADDR + 0x600;
 
        .data.patch             : {
-               __start_gate_mckinley_e9_patchlist = .;
+               __paravirt_start_gate_mckinley_e9_patchlist = .;
                *(.data.patch.mckinley_e9)
-               __end_gate_mckinley_e9_patchlist = .;
+               __paravirt_end_gate_mckinley_e9_patchlist = .;
 
-               __start_gate_vtop_patchlist = .;
+               __paravirt_start_gate_vtop_patchlist = .;
                *(.data.patch.vtop)
-               __end_gate_vtop_patchlist = .;
+               __paravirt_end_gate_vtop_patchlist = .;
 
-               __start_gate_fsyscall_patchlist = .;
+               __paravirt_start_gate_fsyscall_patchlist = .;
                *(.data.patch.fsyscall_table)
-               __end_gate_fsyscall_patchlist = .;
+               __paravirt_end_gate_fsyscall_patchlist = .;
 
-               __start_gate_brl_fsys_bubble_down_patchlist = .;
+               __paravirt_start_gate_brl_fsys_bubble_down_patchlist = .;
                *(.data.patch.brl_fsys_bubble_down)
-               __end_gate_brl_fsys_bubble_down_patchlist = .;
+               __paravirt_end_gate_brl_fsys_bubble_down_patchlist = .;
        }                                               :readable
 
        .IA_64.unwind_info      : { *(.IA_64.unwind_info*) }
index 59301c4728009ecb410516fb0e737107eda42d67..23f846de62d58ae6e60a9c445911419daa4ff17f 100644 (file)
@@ -1050,7 +1050,7 @@ END(ia64_delay_loop)
  * except that the multiplication and the shift are done with 128-bit
  * intermediate precision so that we can produce a full 64-bit result.
  */
-GLOBAL_ENTRY(sched_clock)
+GLOBAL_ENTRY(ia64_native_sched_clock)
        addl r8=THIS_CPU(cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
        mov.m r9=ar.itc         // fetch cycle-counter                          (35 cyc)
        ;;
@@ -1066,7 +1066,13 @@ GLOBAL_ENTRY(sched_clock)
        ;;
        shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT
        br.ret.sptk.many rp
-END(sched_clock)
+END(ia64_native_sched_clock)
+#ifndef CONFIG_PARAVIRT
+       //unsigned long long
+       //sched_clock(void) __attribute__((alias("ia64_native_sched_clock")));
+       .global sched_clock
+sched_clock = ia64_native_sched_clock
+#endif
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 GLOBAL_ENTRY(cycle_to_cputime)
index f675d8e338533c5f2b47ce416a56624915835aa3..ec9a5fdfa1b9dc6e899fe690503bc8a4604cf4db 100644 (file)
@@ -804,7 +804,7 @@ ENTRY(break_fault)
 ///////////////////////////////////////////////////////////////////////
        st1 [r16]=r0                            // M2|3 clear current->thread.on_ustack flag
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mov.m r30=ar.itc                        // M    get cycle for accounting
+       MOV_FROM_ITC(p0, p14, r30, r18)         // M    get cycle for accounting
 #else
        mov b6=r30                              // I0   setup syscall handler branch reg early
 #endif
index bab1de2d2f6a0920f40c76a5c36359d56ed2af87..8f33a8840422ce96bc1a6df85f4876e0f5180b1d 100644 (file)
@@ -1456,9 +1456,9 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg)
 
        ia64_mca_cmc_int_handler(cmc_irq, arg);
 
-       for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
+       cpuid = cpumask_next(cpuid+1, cpu_online_mask);
 
-       if (cpuid < NR_CPUS) {
+       if (cpuid < nr_cpu_ids) {
                platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
        } else {
                /* If no log record, switch out of polling mode */
@@ -1525,7 +1525,7 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg)
 
        ia64_mca_cpe_int_handler(cpe_irq, arg);
 
-       for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
+       cpuid = cpumask_next(cpuid+1, cpu_online_mask);
 
        if (cpuid < NR_CPUS) {
                platform_send_ipi(cpuid, IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
index aaa7d901521fd7590e3132a68b65ffd995197551..da3b0cf495a36a27d80c5befab84f7a7f2f84e94 100644 (file)
@@ -446,6 +446,14 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
                        mod->arch.opd = s;
                else if (strcmp(".IA_64.unwind", secstrings + s->sh_name) == 0)
                        mod->arch.unwind = s;
+#ifdef CONFIG_PARAVIRT
+               else if (strcmp(".paravirt_bundles",
+                               secstrings + s->sh_name) == 0)
+                       mod->arch.paravirt_bundles = s;
+               else if (strcmp(".paravirt_insts",
+                               secstrings + s->sh_name) == 0)
+                       mod->arch.paravirt_insts = s;
+#endif
 
        if (!mod->arch.core_plt || !mod->arch.init_plt || !mod->arch.got || !mod->arch.opd) {
                printk(KERN_ERR "%s: sections missing\n", mod->name);
@@ -525,8 +533,7 @@ get_ltoff (struct module *mod, uint64_t value, int *okp)
                        goto found;
 
        /* Not enough GOT entries? */
-       if (e >= (struct got_entry *) (mod->arch.got->sh_addr + mod->arch.got->sh_size))
-               BUG();
+       BUG_ON(e >= (struct got_entry *) (mod->arch.got->sh_addr + mod->arch.got->sh_size));
 
        e->val = value;
        ++mod->arch.next_got_entry;
@@ -921,6 +928,30 @@ module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mo
        DEBUGP("%s: init: entry=%p\n", __func__, mod->init);
        if (mod->arch.unwind)
                register_unwind_table(mod);
+#ifdef CONFIG_PARAVIRT
+        if (mod->arch.paravirt_bundles) {
+                struct paravirt_patch_site_bundle *start =
+                        (struct paravirt_patch_site_bundle *)
+                        mod->arch.paravirt_bundles->sh_addr;
+                struct paravirt_patch_site_bundle *end =
+                        (struct paravirt_patch_site_bundle *)
+                        (mod->arch.paravirt_bundles->sh_addr +
+                         mod->arch.paravirt_bundles->sh_size);
+
+                paravirt_patch_apply_bundle(start, end);
+        }
+        if (mod->arch.paravirt_insts) {
+                struct paravirt_patch_site_inst *start =
+                        (struct paravirt_patch_site_inst *)
+                        mod->arch.paravirt_insts->sh_addr;
+                struct paravirt_patch_site_inst *end =
+                        (struct paravirt_patch_site_inst *)
+                        (mod->arch.paravirt_insts->sh_addr +
+                         mod->arch.paravirt_insts->sh_size);
+
+                paravirt_patch_apply_inst(start, end);
+        }
+#endif
        return 0;
 }
 
index e5c57f413ca27b197ef0edeb2166efde99d113cb..a4f19c70aadd39d95878740ecc92905c94d4270e 100644 (file)
@@ -1002,8 +1002,6 @@ create_palinfo_proc_entries(unsigned int cpu)
                *pdir = create_proc_read_entry(
                                palinfo_entries[j].name, 0, cpu_dir,
                                palinfo_read_entry, (void *)f.value);
-               if (*pdir)
-                       (*pdir)->owner = THIS_MODULE;
                pdir++;
        }
 }
index 9f14c16f63693794445645753ff6d61443151b61..a21d7bb9c69c8f11eaddabf62df77ee672cbf426 100644 (file)
@@ -46,13 +46,23 @@ struct pv_info pv_info = {
  * initialization hooks.
  */
 
-struct pv_init_ops pv_init_ops;
+static void __init
+ia64_native_patch_branch(unsigned long tag, unsigned long type);
+
+struct pv_init_ops pv_init_ops =
+{
+#ifdef ASM_SUPPORTED
+       .patch_bundle = ia64_native_patch_bundle,
+#endif
+       .patch_branch = ia64_native_patch_branch,
+};
 
 /***************************************************************************
  * pv_cpu_ops
  * intrinsics hooks.
  */
 
+#ifndef ASM_SUPPORTED
 /* ia64_native_xxx are macros so that we have to make them real functions */
 
 #define DEFINE_VOID_FUNC1(name)                                        \
@@ -60,7 +70,14 @@ struct pv_init_ops pv_init_ops;
        ia64_native_ ## name ## _func(unsigned long arg)        \
        {                                                       \
                ia64_native_ ## name(arg);                      \
-       }                                                       \
+       }
+
+#define DEFINE_VOID_FUNC1_VOID(name)                           \
+       static void                                             \
+       ia64_native_ ## name ## _func(void *arg)                \
+       {                                                       \
+               ia64_native_ ## name(arg);                      \
+       }
 
 #define DEFINE_VOID_FUNC2(name)                                        \
        static void                                             \
@@ -68,7 +85,7 @@ struct pv_init_ops pv_init_ops;
                                      unsigned long arg1)       \
        {                                                       \
                ia64_native_ ## name(arg0, arg1);               \
-       }                                                       \
+       }
 
 #define DEFINE_FUNC0(name)                     \
        static unsigned long                    \
@@ -84,7 +101,7 @@ struct pv_init_ops pv_init_ops;
                return ia64_native_ ## name(arg);       \
        }                                               \
 
-DEFINE_VOID_FUNC1(fc);
+DEFINE_VOID_FUNC1_VOID(fc);
 DEFINE_VOID_FUNC1(intrin_local_irq_restore);
 
 DEFINE_VOID_FUNC2(ptcga);
@@ -274,6 +291,266 @@ ia64_native_setreg_func(int regnum, unsigned long val)
                break;
        }
 }
+#else
+
+#define __DEFINE_FUNC(name, code)                                      \
+       extern const char ia64_native_ ## name ## _direct_start[];      \
+       extern const char ia64_native_ ## name ## _direct_end[];        \
+       asm (".align 32\n"                                              \
+            ".proc ia64_native_" #name "_func\n"                       \
+            "ia64_native_" #name "_func:\n"                            \
+            "ia64_native_" #name "_direct_start:\n"                    \
+            code                                                       \
+            "ia64_native_" #name "_direct_end:\n"                      \
+            "br.cond.sptk.many b6\n"                                   \
+            ".endp ia64_native_" #name "_func\n")
+
+#define DEFINE_VOID_FUNC0(name, code)                          \
+       extern void                                             \
+       ia64_native_ ## name ## _func(void);                    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1(name, code)                          \
+       extern void                                             \
+       ia64_native_ ## name ## _func(unsigned long arg);       \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1_VOID(name, code)                     \
+       extern void                                             \
+       ia64_native_ ## name ## _func(void *arg);               \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC2(name, code)                          \
+       extern void                                             \
+       ia64_native_ ## name ## _func(unsigned long arg0,       \
+                                     unsigned long arg1);      \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_FUNC0(name, code)               \
+       extern unsigned long                    \
+       ia64_native_ ## name ## _func(void);    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_FUNC1(name, type, code)                 \
+       extern unsigned long                            \
+       ia64_native_ ## name ## _func(type arg);        \
+       __DEFINE_FUNC(name, code)
+
+DEFINE_VOID_FUNC1_VOID(fc,
+                      "fc r8\n");
+DEFINE_VOID_FUNC1(intrin_local_irq_restore,
+                 ";;\n"
+                 "     cmp.ne p6, p7 = r8, r0\n"
+                 ";;\n"
+                 "(p6) ssm psr.i\n"
+                 "(p7) rsm psr.i\n"
+                 ";;\n"
+                 "(p6) srlz.d\n");
+
+DEFINE_VOID_FUNC2(ptcga,
+                 "ptc.ga r8, r9\n");
+DEFINE_VOID_FUNC2(set_rr,
+                 "mov rr[r8] = r9\n");
+
+/* ia64_native_getreg(_IA64_REG_PSR) & IA64_PSR_I */
+DEFINE_FUNC0(get_psr_i,
+            "mov r2 = " __stringify(1 << IA64_PSR_I_BIT) "\n"
+            "mov r8 = psr\n"
+            ";;\n"
+            "and r8 = r2, r8\n");
+
+DEFINE_FUNC1(thash, unsigned long,
+            "thash r8 = r8\n");
+DEFINE_FUNC1(get_cpuid, int,
+            "mov r8 = cpuid[r8]\n");
+DEFINE_FUNC1(get_pmd, int,
+            "mov r8 = pmd[r8]\n");
+DEFINE_FUNC1(get_rr, unsigned long,
+            "mov r8 = rr[r8]\n");
+
+DEFINE_VOID_FUNC0(ssm_i,
+                 "ssm psr.i\n");
+DEFINE_VOID_FUNC0(rsm_i,
+                 "rsm psr.i\n");
+
+extern void
+ia64_native_set_rr0_to_rr4_func(unsigned long val0, unsigned long val1,
+                               unsigned long val2, unsigned long val3,
+                               unsigned long val4);
+__DEFINE_FUNC(set_rr0_to_rr4,
+             "mov rr[r0] = r8\n"
+             "movl r2 = 0x2000000000000000\n"
+             ";;\n"
+             "mov rr[r2] = r9\n"
+             "shl r3 = r2, 1\n"        /* movl r3 = 0x4000000000000000 */
+             ";;\n"
+             "add r2 = r2, r3\n"       /* movl r2 = 0x6000000000000000 */
+             "mov rr[r3] = r10\n"
+             ";;\n"
+             "mov rr[r2] = r11\n"
+             "shl r3 = r3, 1\n"        /* movl r3 = 0x8000000000000000 */
+             ";;\n"
+             "mov rr[r3] = r14\n");
+
+extern unsigned long ia64_native_getreg_func(int regnum);
+asm(".global ia64_native_getreg_func\n");
+#define __DEFINE_GET_REG(id, reg)                      \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"  \
+       ";;\n"                                          \
+       "cmp.eq p6, p0 = r2, r8\n"                      \
+       ";;\n"                                          \
+       "(p6) mov r8 = " #reg "\n"                      \
+       "(p6) br.cond.sptk.many b6\n"                   \
+       ";;\n"
+#define __DEFINE_GET_AR(id, reg)       __DEFINE_GET_REG(AR_ ## id, ar.reg)
+#define __DEFINE_GET_CR(id, reg)       __DEFINE_GET_REG(CR_ ## id, cr.reg)
+
+__DEFINE_FUNC(getreg,
+             __DEFINE_GET_REG(GP, gp)
+             /*__DEFINE_GET_REG(IP, ip)*/ /* returned ip value shouldn't be constant */
+             __DEFINE_GET_REG(PSR, psr)
+             __DEFINE_GET_REG(TP, tp)
+             __DEFINE_GET_REG(SP, sp)
+
+             __DEFINE_GET_REG(AR_KR0, ar0)
+             __DEFINE_GET_REG(AR_KR1, ar1)
+             __DEFINE_GET_REG(AR_KR2, ar2)
+             __DEFINE_GET_REG(AR_KR3, ar3)
+             __DEFINE_GET_REG(AR_KR4, ar4)
+             __DEFINE_GET_REG(AR_KR5, ar5)
+             __DEFINE_GET_REG(AR_KR6, ar6)
+             __DEFINE_GET_REG(AR_KR7, ar7)
+             __DEFINE_GET_AR(RSC, rsc)
+             __DEFINE_GET_AR(BSP, bsp)
+             __DEFINE_GET_AR(BSPSTORE, bspstore)
+             __DEFINE_GET_AR(RNAT, rnat)
+             __DEFINE_GET_AR(FCR, fcr)
+             __DEFINE_GET_AR(EFLAG, eflag)
+             __DEFINE_GET_AR(CSD, csd)
+             __DEFINE_GET_AR(SSD, ssd)
+             __DEFINE_GET_REG(AR_CFLAG, ar27)
+             __DEFINE_GET_AR(FSR, fsr)
+             __DEFINE_GET_AR(FIR, fir)
+             __DEFINE_GET_AR(FDR, fdr)
+             __DEFINE_GET_AR(CCV, ccv)
+             __DEFINE_GET_AR(UNAT, unat)
+             __DEFINE_GET_AR(FPSR, fpsr)
+             __DEFINE_GET_AR(ITC, itc)
+             __DEFINE_GET_AR(PFS, pfs)
+             __DEFINE_GET_AR(LC, lc)
+             __DEFINE_GET_AR(EC, ec)
+
+             __DEFINE_GET_CR(DCR, dcr)
+             __DEFINE_GET_CR(ITM, itm)
+             __DEFINE_GET_CR(IVA, iva)
+             __DEFINE_GET_CR(PTA, pta)
+             __DEFINE_GET_CR(IPSR, ipsr)
+             __DEFINE_GET_CR(ISR, isr)
+             __DEFINE_GET_CR(IIP, iip)
+             __DEFINE_GET_CR(IFA, ifa)
+             __DEFINE_GET_CR(ITIR, itir)
+             __DEFINE_GET_CR(IIPA, iipa)
+             __DEFINE_GET_CR(IFS, ifs)
+             __DEFINE_GET_CR(IIM, iim)
+             __DEFINE_GET_CR(IHA, iha)
+             __DEFINE_GET_CR(LID, lid)
+             __DEFINE_GET_CR(IVR, ivr)
+             __DEFINE_GET_CR(TPR, tpr)
+             __DEFINE_GET_CR(EOI, eoi)
+             __DEFINE_GET_CR(IRR0, irr0)
+             __DEFINE_GET_CR(IRR1, irr1)
+             __DEFINE_GET_CR(IRR2, irr2)
+             __DEFINE_GET_CR(IRR3, irr3)
+             __DEFINE_GET_CR(ITV, itv)
+             __DEFINE_GET_CR(PMV, pmv)
+             __DEFINE_GET_CR(CMCV, cmcv)
+             __DEFINE_GET_CR(LRR0, lrr0)
+             __DEFINE_GET_CR(LRR1, lrr1)
+
+             "mov r8 = -1\n"   /* unsupported case */
+       );
+
+extern void ia64_native_setreg_func(int regnum, unsigned long val);
+asm(".global ia64_native_setreg_func\n");
+#define __DEFINE_SET_REG(id, reg)                      \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"  \
+       ";;\n"                                          \
+       "cmp.eq p6, p0 = r2, r9\n"                      \
+       ";;\n"                                          \
+       "(p6) mov " #reg " = r8\n"                      \
+       "(p6) br.cond.sptk.many b6\n"                   \
+       ";;\n"
+#define __DEFINE_SET_AR(id, reg)       __DEFINE_SET_REG(AR_ ## id, ar.reg)
+#define __DEFINE_SET_CR(id, reg)       __DEFINE_SET_REG(CR_ ## id, cr.reg)
+__DEFINE_FUNC(setreg,
+             "mov r2 = " __stringify(_IA64_REG_PSR_L) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r9\n"
+             ";;\n"
+             "(p6) mov psr.l = r8\n"
+#ifdef HAVE_SERIALIZE_DIRECTIVE
+             ".serialize.data\n"
+#endif
+             "(p6) br.cond.sptk.many b6\n"
+             __DEFINE_SET_REG(GP, gp)
+             __DEFINE_SET_REG(SP, sp)
+
+             __DEFINE_SET_REG(AR_KR0, ar0)
+             __DEFINE_SET_REG(AR_KR1, ar1)
+             __DEFINE_SET_REG(AR_KR2, ar2)
+             __DEFINE_SET_REG(AR_KR3, ar3)
+             __DEFINE_SET_REG(AR_KR4, ar4)
+             __DEFINE_SET_REG(AR_KR5, ar5)
+             __DEFINE_SET_REG(AR_KR6, ar6)
+             __DEFINE_SET_REG(AR_KR7, ar7)
+             __DEFINE_SET_AR(RSC, rsc)
+             __DEFINE_SET_AR(BSP, bsp)
+             __DEFINE_SET_AR(BSPSTORE, bspstore)
+             __DEFINE_SET_AR(RNAT, rnat)
+             __DEFINE_SET_AR(FCR, fcr)
+             __DEFINE_SET_AR(EFLAG, eflag)
+             __DEFINE_SET_AR(CSD, csd)
+             __DEFINE_SET_AR(SSD, ssd)
+             __DEFINE_SET_REG(AR_CFLAG, ar27)
+             __DEFINE_SET_AR(FSR, fsr)
+             __DEFINE_SET_AR(FIR, fir)
+             __DEFINE_SET_AR(FDR, fdr)
+             __DEFINE_SET_AR(CCV, ccv)
+             __DEFINE_SET_AR(UNAT, unat)
+             __DEFINE_SET_AR(FPSR, fpsr)
+             __DEFINE_SET_AR(ITC, itc)
+             __DEFINE_SET_AR(PFS, pfs)
+             __DEFINE_SET_AR(LC, lc)
+             __DEFINE_SET_AR(EC, ec)
+
+             __DEFINE_SET_CR(DCR, dcr)
+             __DEFINE_SET_CR(ITM, itm)
+             __DEFINE_SET_CR(IVA, iva)
+             __DEFINE_SET_CR(PTA, pta)
+             __DEFINE_SET_CR(IPSR, ipsr)
+             __DEFINE_SET_CR(ISR, isr)
+             __DEFINE_SET_CR(IIP, iip)
+             __DEFINE_SET_CR(IFA, ifa)
+             __DEFINE_SET_CR(ITIR, itir)
+             __DEFINE_SET_CR(IIPA, iipa)
+             __DEFINE_SET_CR(IFS, ifs)
+             __DEFINE_SET_CR(IIM, iim)
+             __DEFINE_SET_CR(IHA, iha)
+             __DEFINE_SET_CR(LID, lid)
+             __DEFINE_SET_CR(IVR, ivr)
+             __DEFINE_SET_CR(TPR, tpr)
+             __DEFINE_SET_CR(EOI, eoi)
+             __DEFINE_SET_CR(IRR0, irr0)
+             __DEFINE_SET_CR(IRR1, irr1)
+             __DEFINE_SET_CR(IRR2, irr2)
+             __DEFINE_SET_CR(IRR3, irr3)
+             __DEFINE_SET_CR(ITV, itv)
+             __DEFINE_SET_CR(PMV, pmv)
+             __DEFINE_SET_CR(CMCV, cmcv)
+             __DEFINE_SET_CR(LRR0, lrr0)
+             __DEFINE_SET_CR(LRR1, lrr1)
+       );
+#endif
 
 struct pv_cpu_ops pv_cpu_ops = {
        .fc             = ia64_native_fc_func,
@@ -366,4 +643,258 @@ ia64_native_do_steal_accounting(unsigned long *new_itm)
 
 struct pv_time_ops pv_time_ops = {
        .do_steal_accounting = ia64_native_do_steal_accounting,
+       .sched_clock = ia64_native_sched_clock,
+};
+
+/***************************************************************************
+ * binary pacthing
+ * pv_init_ops.patch_bundle
+ */
+
+#ifdef ASM_SUPPORTED
+#define IA64_NATIVE_PATCH_DEFINE_GET_REG(name, reg)    \
+       __DEFINE_FUNC(get_ ## name,                     \
+                     ";;\n"                            \
+                     "mov r8 = " #reg "\n"             \
+                     ";;\n")
+
+#define IA64_NATIVE_PATCH_DEFINE_SET_REG(name, reg)    \
+       __DEFINE_FUNC(set_ ## name,                     \
+                     ";;\n"                            \
+                     "mov " #reg " = r8\n"             \
+                     ";;\n")
+
+#define IA64_NATIVE_PATCH_DEFINE_REG(name, reg)                \
+       IA64_NATIVE_PATCH_DEFINE_GET_REG(name, reg);    \
+       IA64_NATIVE_PATCH_DEFINE_SET_REG(name, reg)     \
+
+#define IA64_NATIVE_PATCH_DEFINE_AR(name, reg)                 \
+       IA64_NATIVE_PATCH_DEFINE_REG(ar_ ## name, ar.reg)
+
+#define IA64_NATIVE_PATCH_DEFINE_CR(name, reg)                 \
+       IA64_NATIVE_PATCH_DEFINE_REG(cr_ ## name, cr.reg)
+
+
+IA64_NATIVE_PATCH_DEFINE_GET_REG(psr, psr);
+IA64_NATIVE_PATCH_DEFINE_GET_REG(tp, tp);
+
+/* IA64_NATIVE_PATCH_DEFINE_SET_REG(psr_l, psr.l); */
+__DEFINE_FUNC(set_psr_l,
+             ";;\n"
+             "mov psr.l = r8\n"
+#ifdef HAVE_SERIALIZE_DIRECTIVE
+             ".serialize.data\n"
+#endif
+             ";;\n");
+
+IA64_NATIVE_PATCH_DEFINE_REG(gp, gp);
+IA64_NATIVE_PATCH_DEFINE_REG(sp, sp);
+
+IA64_NATIVE_PATCH_DEFINE_REG(kr0, ar0);
+IA64_NATIVE_PATCH_DEFINE_REG(kr1, ar1);
+IA64_NATIVE_PATCH_DEFINE_REG(kr2, ar2);
+IA64_NATIVE_PATCH_DEFINE_REG(kr3, ar3);
+IA64_NATIVE_PATCH_DEFINE_REG(kr4, ar4);
+IA64_NATIVE_PATCH_DEFINE_REG(kr5, ar5);
+IA64_NATIVE_PATCH_DEFINE_REG(kr6, ar6);
+IA64_NATIVE_PATCH_DEFINE_REG(kr7, ar7);
+
+IA64_NATIVE_PATCH_DEFINE_AR(rsc, rsc);
+IA64_NATIVE_PATCH_DEFINE_AR(bsp, bsp);
+IA64_NATIVE_PATCH_DEFINE_AR(bspstore, bspstore);
+IA64_NATIVE_PATCH_DEFINE_AR(rnat, rnat);
+IA64_NATIVE_PATCH_DEFINE_AR(fcr, fcr);
+IA64_NATIVE_PATCH_DEFINE_AR(eflag, eflag);
+IA64_NATIVE_PATCH_DEFINE_AR(csd, csd);
+IA64_NATIVE_PATCH_DEFINE_AR(ssd, ssd);
+IA64_NATIVE_PATCH_DEFINE_REG(ar27, ar27);
+IA64_NATIVE_PATCH_DEFINE_AR(fsr, fsr);
+IA64_NATIVE_PATCH_DEFINE_AR(fir, fir);
+IA64_NATIVE_PATCH_DEFINE_AR(fdr, fdr);
+IA64_NATIVE_PATCH_DEFINE_AR(ccv, ccv);
+IA64_NATIVE_PATCH_DEFINE_AR(unat, unat);
+IA64_NATIVE_PATCH_DEFINE_AR(fpsr, fpsr);
+IA64_NATIVE_PATCH_DEFINE_AR(itc, itc);
+IA64_NATIVE_PATCH_DEFINE_AR(pfs, pfs);
+IA64_NATIVE_PATCH_DEFINE_AR(lc, lc);
+IA64_NATIVE_PATCH_DEFINE_AR(ec, ec);
+
+IA64_NATIVE_PATCH_DEFINE_CR(dcr, dcr);
+IA64_NATIVE_PATCH_DEFINE_CR(itm, itm);
+IA64_NATIVE_PATCH_DEFINE_CR(iva, iva);
+IA64_NATIVE_PATCH_DEFINE_CR(pta, pta);
+IA64_NATIVE_PATCH_DEFINE_CR(ipsr, ipsr);
+IA64_NATIVE_PATCH_DEFINE_CR(isr, isr);
+IA64_NATIVE_PATCH_DEFINE_CR(iip, iip);
+IA64_NATIVE_PATCH_DEFINE_CR(ifa, ifa);
+IA64_NATIVE_PATCH_DEFINE_CR(itir, itir);
+IA64_NATIVE_PATCH_DEFINE_CR(iipa, iipa);
+IA64_NATIVE_PATCH_DEFINE_CR(ifs, ifs);
+IA64_NATIVE_PATCH_DEFINE_CR(iim, iim);
+IA64_NATIVE_PATCH_DEFINE_CR(iha, iha);
+IA64_NATIVE_PATCH_DEFINE_CR(lid, lid);
+IA64_NATIVE_PATCH_DEFINE_CR(ivr, ivr);
+IA64_NATIVE_PATCH_DEFINE_CR(tpr, tpr);
+IA64_NATIVE_PATCH_DEFINE_CR(eoi, eoi);
+IA64_NATIVE_PATCH_DEFINE_CR(irr0, irr0);
+IA64_NATIVE_PATCH_DEFINE_CR(irr1, irr1);
+IA64_NATIVE_PATCH_DEFINE_CR(irr2, irr2);
+IA64_NATIVE_PATCH_DEFINE_CR(irr3, irr3);
+IA64_NATIVE_PATCH_DEFINE_CR(itv, itv);
+IA64_NATIVE_PATCH_DEFINE_CR(pmv, pmv);
+IA64_NATIVE_PATCH_DEFINE_CR(cmcv, cmcv);
+IA64_NATIVE_PATCH_DEFINE_CR(lrr0, lrr0);
+IA64_NATIVE_PATCH_DEFINE_CR(lrr1, lrr1);
+
+static const struct paravirt_patch_bundle_elem ia64_native_patch_bundle_elems[]
+__initdata_or_module =
+{
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM(name, type)              \
+       {                                                       \
+               (void*)ia64_native_ ## name ## _direct_start,   \
+               (void*)ia64_native_ ## name ## _direct_end,     \
+               PARAVIRT_PATCH_TYPE_ ## type,                   \
+       }
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(fc, FC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(thash, THASH),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_cpuid, GET_CPUID),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_pmd, GET_PMD),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(ptcga, PTCGA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_rr, GET_RR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(set_rr, SET_RR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(set_rr0_to_rr4, SET_RR0_TO_RR4),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(ssm_i, SSM_I),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(rsm_i, RSM_I),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(get_psr_i, GET_PSR_I),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM(intrin_local_irq_restore,
+                                     INTRIN_LOCAL_IRQ_RESTORE),
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(name, reg)                        \
+       {                                                               \
+               (void*)ia64_native_get_ ## name ## _direct_start,       \
+               (void*)ia64_native_get_ ## name ## _direct_end,         \
+               PARAVIRT_PATCH_TYPE_GETREG + _IA64_REG_ ## reg,         \
+       }
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(name, reg)                        \
+       {                                                               \
+               (void*)ia64_native_set_ ## name ## _direct_start,       \
+               (void*)ia64_native_set_ ## name ## _direct_end,         \
+               PARAVIRT_PATCH_TYPE_SETREG + _IA64_REG_ ## reg,         \
+       }
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(name, reg)           \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(name, reg),        \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(name, reg)         \
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(name, reg)            \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(ar_ ## name, AR_ ## reg)
+
+#define IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(name, reg)            \
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(cr_ ## name, CR_ ## reg)
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(psr, PSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(tp, TP),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(psr_l, PSR_L),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(gp, GP),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(sp, SP),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr0, AR_KR0),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr1, AR_KR1),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr2, AR_KR2),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr3, AR_KR3),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr4, AR_KR4),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr5, AR_KR5),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr6, AR_KR6),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr7, AR_KR7),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(rsc, RSC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(bsp, BSP),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(bspstore, BSPSTORE),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(rnat, RNAT),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fcr, FCR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(eflag, EFLAG),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(csd, CSD),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ssd, SSD),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(ar27, AR_CFLAG),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fsr, FSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fir, FIR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fdr, FDR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ccv, CCV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(unat, UNAT),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fpsr, FPSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(itc, ITC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(pfs, PFS),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(lc, LC),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ec, EC),
+
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(dcr, DCR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itm, ITM),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iva, IVA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(pta, PTA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ipsr, IPSR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(isr, ISR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iip, IIP),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ifa, IFA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itir, ITIR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iipa, IIPA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ifs, IFS),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iim, IIM),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iha, IHA),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lid, LID),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ivr, IVR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(tpr, TPR),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(eoi, EOI),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr0, IRR0),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr1, IRR1),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr2, IRR2),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr3, IRR3),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itv, ITV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(pmv, PMV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(cmcv, CMCV),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lrr0, LRR0),
+       IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lrr1, LRR1),
 };
+
+unsigned long __init_or_module
+ia64_native_patch_bundle(void *sbundle, void *ebundle, unsigned long type)
+{
+       const unsigned long nelems = sizeof(ia64_native_patch_bundle_elems) /
+               sizeof(ia64_native_patch_bundle_elems[0]);
+
+       return __paravirt_patch_apply_bundle(sbundle, ebundle, type,
+                                             ia64_native_patch_bundle_elems,
+                                             nelems, NULL);
+}
+#endif /* ASM_SUPPOTED */
+
+extern const char ia64_native_switch_to[];
+extern const char ia64_native_leave_syscall[];
+extern const char ia64_native_work_processed_syscall[];
+extern const char ia64_native_leave_kernel[];
+
+const struct paravirt_patch_branch_target ia64_native_branch_target[]
+__initconst = {
+#define PARAVIRT_BR_TARGET(name, type)                 \
+       {                                               \
+               ia64_native_ ## name,                   \
+               PARAVIRT_PATCH_TYPE_BR_ ## type,        \
+       }
+       PARAVIRT_BR_TARGET(switch_to, SWITCH_TO),
+       PARAVIRT_BR_TARGET(leave_syscall, LEAVE_SYSCALL),
+       PARAVIRT_BR_TARGET(work_processed_syscall, WORK_PROCESSED_SYSCALL),
+       PARAVIRT_BR_TARGET(leave_kernel, LEAVE_KERNEL),
+};
+
+static void __init
+ia64_native_patch_branch(unsigned long tag, unsigned long type)
+{
+       const unsigned long nelem =
+               sizeof(ia64_native_branch_target) /
+               sizeof(ia64_native_branch_target[0]);
+       __paravirt_patch_apply_branch(tag, type,
+                                     ia64_native_branch_target, nelem);
+}
diff --git a/arch/ia64/kernel/paravirt_patch.c b/arch/ia64/kernel/paravirt_patch.c
new file mode 100644 (file)
index 0000000..bfdfef1
--- /dev/null
@@ -0,0 +1,514 @@
+/******************************************************************************
+ * linux/arch/ia64/xen/paravirt_patch.c
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#include <linux/init.h>
+#include <asm/intrinsics.h>
+#include <asm/kprobes.h>
+#include <asm/paravirt.h>
+#include <asm/paravirt_patch.h>
+
+typedef union ia64_inst {
+        struct {
+               unsigned long long qp : 6;
+               unsigned long long : 31;
+               unsigned long long opcode : 4;
+               unsigned long long reserved : 23;
+        } generic;
+        unsigned long long l;
+} ia64_inst_t;
+
+/*
+ * flush_icache_range() can't be used here.
+ * we are here before cpu_init() which initializes
+ * ia64_i_cache_stride_shift. flush_icache_range() uses it.
+ */
+void __init_or_module
+paravirt_flush_i_cache_range(const void *instr, unsigned long size)
+{
+       extern void paravirt_fc_i(const void *addr);
+       unsigned long i;
+
+       for (i = 0; i < size; i += sizeof(bundle_t))
+               paravirt_fc_i(instr + i);
+}
+
+bundle_t* __init_or_module
+paravirt_get_bundle(unsigned long tag)
+{
+       return (bundle_t *)(tag & ~3UL);
+}
+
+unsigned long __init_or_module
+paravirt_get_slot(unsigned long tag)
+{
+       return tag & 3UL;
+}
+
+unsigned long __init_or_module
+paravirt_get_num_inst(unsigned long stag, unsigned long etag)
+{
+       bundle_t *sbundle = paravirt_get_bundle(stag);
+       unsigned long sslot = paravirt_get_slot(stag);
+       bundle_t *ebundle = paravirt_get_bundle(etag);
+       unsigned long eslot = paravirt_get_slot(etag);
+
+       return (ebundle - sbundle) * 3 + eslot - sslot + 1;
+}
+
+unsigned long __init_or_module
+paravirt_get_next_tag(unsigned long tag)
+{
+       unsigned long slot = paravirt_get_slot(tag);
+
+       switch (slot) {
+       case 0:
+       case 1:
+               return tag + 1;
+       case 2: {
+               bundle_t *bundle = paravirt_get_bundle(tag);
+               return (unsigned long)(bundle + 1);
+       }
+       default:
+               BUG();
+       }
+       /* NOTREACHED */
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_slot0(const bundle_t *bundle)
+{
+       ia64_inst_t inst;
+       inst.l = bundle->quad0.slot0;
+       return inst;
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_slot1(const bundle_t *bundle)
+{
+       ia64_inst_t inst;
+       inst.l = bundle->quad0.slot1_p0 |
+               ((unsigned long long)bundle->quad1.slot1_p1 << 18UL);
+       return inst;
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_slot2(const bundle_t *bundle)
+{
+       ia64_inst_t inst;
+       inst.l = bundle->quad1.slot2;
+       return inst;
+}
+
+ia64_inst_t __init_or_module
+paravirt_read_inst(unsigned long tag)
+{
+       bundle_t *bundle = paravirt_get_bundle(tag);
+       unsigned long slot = paravirt_get_slot(tag);
+
+       switch (slot) {
+       case 0:
+               return paravirt_read_slot0(bundle);
+       case 1:
+               return paravirt_read_slot1(bundle);
+       case 2:
+               return paravirt_read_slot2(bundle);
+       default:
+               BUG();
+       }
+       /* NOTREACHED */
+}
+
+void __init_or_module
+paravirt_write_slot0(bundle_t *bundle, ia64_inst_t inst)
+{
+       bundle->quad0.slot0 = inst.l;
+}
+
+void __init_or_module
+paravirt_write_slot1(bundle_t *bundle, ia64_inst_t inst)
+{
+       bundle->quad0.slot1_p0 = inst.l;
+       bundle->quad1.slot1_p1 = inst.l >> 18UL;
+}
+
+void __init_or_module
+paravirt_write_slot2(bundle_t *bundle, ia64_inst_t inst)
+{
+       bundle->quad1.slot2 = inst.l;
+}
+
+void __init_or_module
+paravirt_write_inst(unsigned long tag, ia64_inst_t inst)
+{
+       bundle_t *bundle = paravirt_get_bundle(tag);
+       unsigned long slot = paravirt_get_slot(tag);
+
+       switch (slot) {
+       case 0:
+               paravirt_write_slot0(bundle, inst);
+               break;
+       case 1:
+               paravirt_write_slot1(bundle, inst);
+               break;
+       case 2:
+               paravirt_write_slot2(bundle, inst);
+               break;
+       default:
+               BUG();
+               break;
+       }
+       paravirt_flush_i_cache_range(bundle, sizeof(*bundle));
+}
+
+/* for debug */
+void
+paravirt_print_bundle(const bundle_t *bundle)
+{
+       const unsigned long *quad = (const unsigned long *)bundle;
+       ia64_inst_t slot0 = paravirt_read_slot0(bundle);
+       ia64_inst_t slot1 = paravirt_read_slot1(bundle);
+       ia64_inst_t slot2 = paravirt_read_slot2(bundle);
+
+       printk(KERN_DEBUG
+              "bundle 0x%p 0x%016lx 0x%016lx\n", bundle, quad[0], quad[1]);
+       printk(KERN_DEBUG
+              "bundle template 0x%x\n",
+              bundle->quad0.template);
+       printk(KERN_DEBUG
+              "slot0 0x%lx slot1_p0 0x%lx slot1_p1 0x%lx slot2 0x%lx\n",
+              (unsigned long)bundle->quad0.slot0,
+              (unsigned long)bundle->quad0.slot1_p0,
+              (unsigned long)bundle->quad1.slot1_p1,
+              (unsigned long)bundle->quad1.slot2);
+       printk(KERN_DEBUG
+              "slot0 0x%016llx slot1 0x%016llx slot2 0x%016llx\n",
+              slot0.l, slot1.l, slot2.l);
+}
+
+static int noreplace_paravirt __init_or_module = 0;
+
+static int __init setup_noreplace_paravirt(char *str)
+{
+       noreplace_paravirt = 1;
+       return 1;
+}
+__setup("noreplace-paravirt", setup_noreplace_paravirt);
+
+#ifdef ASM_SUPPORTED
+static void __init_or_module
+fill_nop_bundle(void *sbundle, void *ebundle)
+{
+       extern const char paravirt_nop_bundle[];
+       extern const unsigned long paravirt_nop_bundle_size;
+
+       void *bundle = sbundle;
+
+       BUG_ON((((unsigned long)sbundle) % sizeof(bundle_t)) != 0);
+       BUG_ON((((unsigned long)ebundle) % sizeof(bundle_t)) != 0);
+
+       while (bundle < ebundle) {
+               memcpy(bundle, paravirt_nop_bundle, paravirt_nop_bundle_size);
+
+               bundle += paravirt_nop_bundle_size;
+       }
+}
+
+/* helper function */
+unsigned long __init_or_module
+__paravirt_patch_apply_bundle(void *sbundle, void *ebundle, unsigned long type,
+                             const struct paravirt_patch_bundle_elem *elems,
+                             unsigned long nelems,
+                             const struct paravirt_patch_bundle_elem **found)
+{
+       unsigned long used = 0;
+       unsigned long i;
+
+       BUG_ON((((unsigned long)sbundle) % sizeof(bundle_t)) != 0);
+       BUG_ON((((unsigned long)ebundle) % sizeof(bundle_t)) != 0);
+
+       found = NULL;
+       for (i = 0; i < nelems; i++) {
+               const struct paravirt_patch_bundle_elem *p = &elems[i];
+               if (p->type == type) {
+                       unsigned long need = p->ebundle - p->sbundle;
+                       unsigned long room = ebundle - sbundle;
+
+                       if (found != NULL)
+                               *found = p;
+
+                       if (room < need) {
+                               /* no room to replace. skip it */
+                               printk(KERN_DEBUG
+                                      "the space is too small to put "
+                                      "bundles. type %ld need %ld room %ld\n",
+                                      type, need, room);
+                               break;
+                       }
+
+                       used = need;
+                       memcpy(sbundle, p->sbundle, used);
+                       break;
+               }
+       }
+
+       return used;
+}
+
+void __init_or_module
+paravirt_patch_apply_bundle(const struct paravirt_patch_site_bundle *start,
+                           const struct paravirt_patch_site_bundle *end)
+{
+       const struct paravirt_patch_site_bundle *p;
+
+       if (noreplace_paravirt)
+               return;
+       if (pv_init_ops.patch_bundle == NULL)
+               return;
+
+       for (p = start; p < end; p++) {
+               unsigned long used;
+
+               used = (*pv_init_ops.patch_bundle)(p->sbundle, p->ebundle,
+                                                  p->type);
+               if (used == 0)
+                       continue;
+
+               fill_nop_bundle(p->sbundle + used, p->ebundle);
+               paravirt_flush_i_cache_range(p->sbundle,
+                                            p->ebundle - p->sbundle);
+       }
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+
+/*
+ * nop.i, nop.m, nop.f instruction are same format.
+ * but nop.b has differennt format.
+ * This doesn't support nop.b for now.
+ */
+static void __init_or_module
+fill_nop_inst(unsigned long stag, unsigned long etag)
+{
+       extern const bundle_t paravirt_nop_mfi_inst_bundle[];
+       unsigned long tag;
+       const ia64_inst_t nop_inst =
+               paravirt_read_slot0(paravirt_nop_mfi_inst_bundle);
+
+       for (tag = stag; tag < etag; tag = paravirt_get_next_tag(tag))
+               paravirt_write_inst(tag, nop_inst);
+}
+
+void __init_or_module
+paravirt_patch_apply_inst(const struct paravirt_patch_site_inst *start,
+                         const struct paravirt_patch_site_inst *end)
+{
+       const struct paravirt_patch_site_inst *p;
+
+       if (noreplace_paravirt)
+               return;
+       if (pv_init_ops.patch_inst == NULL)
+               return;
+
+       for (p = start; p < end; p++) {
+               unsigned long tag;
+               bundle_t *sbundle;
+               bundle_t *ebundle;
+
+               tag = (*pv_init_ops.patch_inst)(p->stag, p->etag, p->type);
+               if (tag == p->stag)
+                       continue;
+
+               fill_nop_inst(tag, p->etag);
+               sbundle = paravirt_get_bundle(p->stag);
+               ebundle = paravirt_get_bundle(p->etag) + 1;
+               paravirt_flush_i_cache_range(sbundle, (ebundle - sbundle) *
+                                            sizeof(bundle_t));
+       }
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+#endif /* ASM_SUPPOTED */
+
+/* brl.cond.sptk.many <target64> X3 */
+typedef union inst_x3_op {
+       ia64_inst_t inst;
+       struct {
+               unsigned long qp: 6;
+               unsigned long btyp: 3;
+               unsigned long unused: 3;
+               unsigned long p: 1;
+               unsigned long imm20b: 20;
+               unsigned long wh: 2;
+               unsigned long d: 1;
+               unsigned long i: 1;
+               unsigned long opcode: 4;
+       };
+       unsigned long l;
+} inst_x3_op_t;
+
+typedef union inst_x3_imm {
+       ia64_inst_t inst;
+       struct {
+               unsigned long unused: 2;
+               unsigned long imm39: 39;
+       };
+       unsigned long l;
+} inst_x3_imm_t;
+
+void __init_or_module
+paravirt_patch_reloc_brl(unsigned long tag, const void *target)
+{
+       unsigned long tag_op = paravirt_get_next_tag(tag);
+       unsigned long tag_imm = tag;
+       bundle_t *bundle = paravirt_get_bundle(tag);
+
+       ia64_inst_t inst_op = paravirt_read_inst(tag_op);
+       ia64_inst_t inst_imm = paravirt_read_inst(tag_imm);
+
+       inst_x3_op_t inst_x3_op = { .l = inst_op.l };
+       inst_x3_imm_t inst_x3_imm = { .l = inst_imm.l };
+
+       unsigned long imm60 =
+               ((unsigned long)target - (unsigned long)bundle) >> 4;
+
+       BUG_ON(paravirt_get_slot(tag) != 1); /* MLX */
+       BUG_ON(((unsigned long)target & (sizeof(bundle_t) - 1)) != 0);
+
+       /* imm60[59] 1bit */
+       inst_x3_op.i = (imm60 >> 59) & 1;
+       /* imm60[19:0] 20bit */
+       inst_x3_op.imm20b = imm60 & ((1UL << 20) - 1);
+       /* imm60[58:20] 39bit */
+       inst_x3_imm.imm39 = (imm60 >> 20) & ((1UL << 39) - 1);
+
+       inst_op.l = inst_x3_op.l;
+       inst_imm.l = inst_x3_imm.l;
+
+       paravirt_write_inst(tag_op, inst_op);
+       paravirt_write_inst(tag_imm, inst_imm);
+}
+
+/* br.cond.sptk.many <target25>        B1 */
+typedef union inst_b1 {
+       ia64_inst_t inst;
+       struct {
+               unsigned long qp: 6;
+               unsigned long btype: 3;
+               unsigned long unused: 3;
+               unsigned long p: 1;
+               unsigned long imm20b: 20;
+               unsigned long wh: 2;
+               unsigned long d: 1;
+               unsigned long s: 1;
+               unsigned long opcode: 4;
+       };
+       unsigned long l;
+} inst_b1_t;
+
+void __init
+paravirt_patch_reloc_br(unsigned long tag, const void *target)
+{
+       bundle_t *bundle = paravirt_get_bundle(tag);
+       ia64_inst_t inst = paravirt_read_inst(tag);
+       unsigned long target25 = (unsigned long)target - (unsigned long)bundle;
+       inst_b1_t inst_b1;
+
+       BUG_ON(((unsigned long)target & (sizeof(bundle_t) - 1)) != 0);
+
+       inst_b1.l = inst.l;
+       if (target25 & (1UL << 63))
+               inst_b1.s = 1;
+       else
+               inst_b1.s = 0;
+
+       inst_b1.imm20b = target25 >> 4;
+       inst.l = inst_b1.l;
+
+       paravirt_write_inst(tag, inst);
+}
+
+void __init
+__paravirt_patch_apply_branch(
+       unsigned long tag, unsigned long type,
+       const struct paravirt_patch_branch_target *entries,
+       unsigned int nr_entries)
+{
+       unsigned int i;
+       for (i = 0; i < nr_entries; i++) {
+               if (entries[i].type == type) {
+                       paravirt_patch_reloc_br(tag, entries[i].entry);
+                       break;
+               }
+       }
+}
+
+static void __init
+paravirt_patch_apply_branch(const struct paravirt_patch_site_branch *start,
+                           const struct paravirt_patch_site_branch *end)
+{
+       const struct paravirt_patch_site_branch *p;
+
+       if (noreplace_paravirt)
+               return;
+       if (pv_init_ops.patch_branch == NULL)
+               return;
+
+       for (p = start; p < end; p++)
+               (*pv_init_ops.patch_branch)(p->tag, p->type);
+
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+
+void __init
+paravirt_patch_apply(void)
+{
+       extern const char __start_paravirt_bundles[];
+       extern const char __stop_paravirt_bundles[];
+       extern const char __start_paravirt_insts[];
+       extern const char __stop_paravirt_insts[];
+       extern const char __start_paravirt_branches[];
+       extern const char __stop_paravirt_branches[];
+
+       paravirt_patch_apply_bundle((const struct paravirt_patch_site_bundle *)
+                                   __start_paravirt_bundles,
+                                   (const struct paravirt_patch_site_bundle *)
+                                   __stop_paravirt_bundles);
+       paravirt_patch_apply_inst((const struct paravirt_patch_site_inst *)
+                                 __start_paravirt_insts,
+                                 (const struct paravirt_patch_site_inst *)
+                                 __stop_paravirt_insts);
+       paravirt_patch_apply_branch((const struct paravirt_patch_site_branch *)
+                                   __start_paravirt_branches,
+                                   (const struct paravirt_patch_site_branch *)
+                                   __stop_paravirt_branches);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "linux"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/arch/ia64/kernel/paravirt_patchlist.c b/arch/ia64/kernel/paravirt_patchlist.c
new file mode 100644 (file)
index 0000000..b28082a
--- /dev/null
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#include <linux/bug.h>
+#include <asm/paravirt.h>
+
+#define DECLARE(name)                                          \
+       extern unsigned long                                    \
+               __ia64_native_start_gate_##name##_patchlist[];  \
+       extern unsigned long                                    \
+               __ia64_native_end_gate_##name##_patchlist[]
+
+DECLARE(fsyscall);
+DECLARE(brl_fsys_bubble_down);
+DECLARE(vtop);
+DECLARE(mckinley_e9);
+
+extern unsigned long __start_gate_section[];
+
+#define ASSIGN(name)                                                       \
+       .start_##name##_patchlist =                                         \
+               (unsigned long)__ia64_native_start_gate_##name##_patchlist, \
+       .end_##name##_patchlist =                                           \
+               (unsigned long)__ia64_native_end_gate_##name##_patchlist
+
+struct pv_patchdata pv_patchdata __initdata = {
+       ASSIGN(fsyscall),
+       ASSIGN(brl_fsys_bubble_down),
+       ASSIGN(vtop),
+       ASSIGN(mckinley_e9),
+
+       .gate_section = (void*)__start_gate_section,
+};
+
+
+unsigned long __init
+paravirt_get_gate_patchlist(enum pv_gate_patchlist type)
+{
+
+#define CASE(NAME, name)                                       \
+       case PV_GATE_START_##NAME:                              \
+               return pv_patchdata.start_##name##_patchlist;   \
+       case PV_GATE_END_##NAME:                                \
+               return pv_patchdata.end_##name##_patchlist;     \
+
+       switch (type) {
+               CASE(FSYSCALL, fsyscall);
+               CASE(BRL_FSYS_BUBBLE_DOWN, brl_fsys_bubble_down);
+               CASE(VTOP, vtop);
+               CASE(MCKINLEY_E9, mckinley_e9);
+       default:
+               BUG();
+               break;
+       }
+       return 0;
+}
+
+void * __init
+paravirt_get_gate_section(void)
+{
+       return pv_patchdata.gate_section;
+}
diff --git a/arch/ia64/kernel/paravirt_patchlist.h b/arch/ia64/kernel/paravirt_patchlist.h
new file mode 100644 (file)
index 0000000..0684aa6
--- /dev/null
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * linux/arch/ia64/xen/paravirt_patchlist.h
+ *
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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
+ *
+ */
+
+#if defined(__IA64_GATE_PARAVIRTUALIZED_XEN)
+#include <asm/xen/patchlist.h>
+#else
+#include <asm/native/patchlist.h>
+#endif
+
index 2f42fcb9776a1c9752465317a8efcaa393d47ec4..6158560d7f1738993ee4fa00437cd809c8854661 100644 (file)
  *
  */
 
+#include <linux/init.h>
 #include <asm/asmmacro.h>
 #include <asm/asm-offsets.h>
+#include <asm/paravirt_privop.h>
+#include <asm/paravirt_patch.h>
 #include "entry.h"
 
 #define DATA8(sym, init_value)                 \
        data8 init_value ;                      \
        .popsection
 
-#define BRANCH(targ, reg, breg)                \
-       movl reg=targ ;                 \
-       ;;                              \
-       ld8 reg=[reg] ;                 \
-       ;;                              \
-       mov breg=reg ;                  \
+#define BRANCH(targ, reg, breg, type)                                  \
+       PARAVIRT_PATCH_SITE_BR(PARAVIRT_PATCH_TYPE_BR_ ## type) ;       \
+       ;;                                                              \
+       movl reg=targ ;                                                 \
+       ;;                                                              \
+       ld8 reg=[reg] ;                                                 \
+       ;;                                                              \
+       mov breg=reg ;                                                  \
        br.cond.sptk.many breg
 
-#define BRANCH_PROC(sym, reg, breg)                            \
-       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ; \
-       GLOBAL_ENTRY(paravirt_ ## sym) ;                        \
-               BRANCH(paravirt_ ## sym ## _targ, reg, breg) ;  \
+#define BRANCH_PROC(sym, reg, breg, type)                              \
+       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ;         \
+       GLOBAL_ENTRY(paravirt_ ## sym) ;                                \
+               BRANCH(paravirt_ ## sym ## _targ, reg, breg, type) ;    \
        END(paravirt_ ## sym)
 
-#define BRANCH_PROC_UNWINFO(sym, reg, breg)                    \
-       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ; \
-       GLOBAL_ENTRY(paravirt_ ## sym) ;                        \
-               PT_REGS_UNWIND_INFO(0) ;                        \
-               BRANCH(paravirt_ ## sym ## _targ, reg, breg) ;  \
+#define BRANCH_PROC_UNWINFO(sym, reg, breg, type)                      \
+       DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ;         \
+       GLOBAL_ENTRY(paravirt_ ## sym) ;                                \
+               PT_REGS_UNWIND_INFO(0) ;                                \
+               BRANCH(paravirt_ ## sym ## _targ, reg, breg, type) ;    \
        END(paravirt_ ## sym)
 
 
-BRANCH_PROC(switch_to, r22, b7)
-BRANCH_PROC_UNWINFO(leave_syscall, r22, b7)
-BRANCH_PROC(work_processed_syscall, r2, b7)
-BRANCH_PROC_UNWINFO(leave_kernel, r22, b7)
+BRANCH_PROC(switch_to, r22, b7, SWITCH_TO)
+BRANCH_PROC_UNWINFO(leave_syscall, r22, b7, LEAVE_SYSCALL)
+BRANCH_PROC(work_processed_syscall, r2, b7, WORK_PROCESSED_SYSCALL)
+BRANCH_PROC_UNWINFO(leave_kernel, r22, b7, LEAVE_KERNEL)
+
+
+#ifdef CONFIG_MODULES
+#define __INIT_OR_MODULE       .text
+#define __INITDATA_OR_MODULE   .data
+#else
+#define __INIT_OR_MODULE       __INIT
+#define __INITDATA_OR_MODULE   __INITDATA
+#endif /* CONFIG_MODULES */
+
+       __INIT_OR_MODULE
+       GLOBAL_ENTRY(paravirt_fc_i)
+       fc.i r32
+       br.ret.sptk.many rp
+       END(paravirt_fc_i)
+       __FINIT
+
+       __INIT_OR_MODULE
+       .align 32
+       GLOBAL_ENTRY(paravirt_nop_b_inst_bundle)
+       {
+               nop.b 0
+               nop.b 0
+               nop.b 0
+       }
+       END(paravirt_nop_b_inst_bundle)
+       __FINIT
+
+       /* NOTE: nop.[mfi] has same format */
+       __INIT_OR_MODULE
+       GLOBAL_ENTRY(paravirt_nop_mfi_inst_bundle)
+       {
+               nop.m 0
+               nop.f 0
+               nop.i 0
+       }
+       END(paravirt_nop_mfi_inst_bundle)
+       __FINIT
+
+       __INIT_OR_MODULE
+       GLOBAL_ENTRY(paravirt_nop_bundle)
+paravirt_nop_bundle_start:
+       {
+               nop 0
+               nop 0
+               nop 0
+       }
+paravirt_nop_bundle_end:
+       END(paravirt_nop_bundle)
+       __FINIT
+
+       __INITDATA_OR_MODULE
+       .align 8
+       .global paravirt_nop_bundle_size
+paravirt_nop_bundle_size:
+       data8   paravirt_nop_bundle_end - paravirt_nop_bundle_start
index b83b2c516008d4cdac5db340a53c74dfa8f4444a..68a1311db806b49a918c76ecea4af5ca75a55da0 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 
+#include <asm/paravirt.h>
 #include <asm/patch.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
@@ -169,16 +170,35 @@ ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
        ia64_srlz_i();
 }
 
+extern unsigned long ia64_native_fsyscall_table[NR_syscalls];
+extern char ia64_native_fsys_bubble_down[];
+struct pv_fsys_data pv_fsys_data __initdata = {
+       .fsyscall_table = (unsigned long *)ia64_native_fsyscall_table,
+       .fsys_bubble_down = (void *)ia64_native_fsys_bubble_down,
+};
+
+unsigned long * __init
+paravirt_get_fsyscall_table(void)
+{
+       return pv_fsys_data.fsyscall_table;
+}
+
+char * __init
+paravirt_get_fsys_bubble_down(void)
+{
+       return pv_fsys_data.fsys_bubble_down;
+}
+
 static void __init
 patch_fsyscall_table (unsigned long start, unsigned long end)
 {
-       extern unsigned long fsyscall_table[NR_syscalls];
+       u64 fsyscall_table = (u64)paravirt_get_fsyscall_table();
        s32 *offp = (s32 *) start;
        u64 ip;
 
        while (offp < (s32 *) end) {
                ip = (u64) ia64_imva((char *) offp + *offp);
-               ia64_patch_imm64(ip, (u64) fsyscall_table);
+               ia64_patch_imm64(ip, fsyscall_table);
                ia64_fc((void *) ip);
                ++offp;
        }
@@ -189,7 +209,7 @@ patch_fsyscall_table (unsigned long start, unsigned long end)
 static void __init
 patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
 {
-       extern char fsys_bubble_down[];
+       u64 fsys_bubble_down = (u64)paravirt_get_fsys_bubble_down();
        s32 *offp = (s32 *) start;
        u64 ip;
 
@@ -207,13 +227,13 @@ patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
 void __init
 ia64_patch_gate (void)
 {
-#      define START(name)      ((unsigned long) __start_gate_##name##_patchlist)
-#      define END(name)        ((unsigned long)__end_gate_##name##_patchlist)
+#      define START(name)      paravirt_get_gate_patchlist(PV_GATE_START_##name)
+#      define END(name)        paravirt_get_gate_patchlist(PV_GATE_END_##name)
 
-       patch_fsyscall_table(START(fsyscall), END(fsyscall));
-       patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down));
-       ia64_patch_vtop(START(vtop), END(vtop));
-       ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
+       patch_fsyscall_table(START(FSYSCALL), END(FSYSCALL));
+       patch_brl_fsys_bubble_down(START(BRL_FSYS_BUBBLE_DOWN), END(BRL_FSYS_BUBBLE_DOWN));
+       ia64_patch_vtop(START(VTOP), END(VTOP));
+       ia64_patch_mckinley_e9(START(MCKINLEY_E9), END(MCKINLEY_E9));
 }
 
 void ia64_patch_phys_stack_reg(unsigned long val)
@@ -229,7 +249,7 @@ void ia64_patch_phys_stack_reg(unsigned long val)
        while (offp < end) {
                ip = (u64) offp + *offp;
                ia64_patch(ip, mask, imm);
-               ia64_fc(ip);
+               ia64_fc((void *)ip);
                ++offp;
        }
        ia64_sync_i();
index 5c0f408cfd719f02ded2c58dc6ebf2b3c181c7b5..8a06dc480594c0d3e93636eccad9ea9316944127 100644 (file)
@@ -5603,7 +5603,7 @@ pfm_interrupt_handler(int irq, void *arg)
  * /proc/perfmon interface, for debug only
  */
 
-#define PFM_PROC_SHOW_HEADER   ((void *)NR_CPUS+1)
+#define PFM_PROC_SHOW_HEADER   ((void *)nr_cpu_ids+1)
 
 static void *
 pfm_proc_start(struct seq_file *m, loff_t *pos)
@@ -5612,7 +5612,7 @@ pfm_proc_start(struct seq_file *m, loff_t *pos)
                return PFM_PROC_SHOW_HEADER;
        }
 
-       while (*pos <= NR_CPUS) {
+       while (*pos <= nr_cpu_ids) {
                if (cpu_online(*pos - 1)) {
                        return (void *)*pos;
                }
index c57162705147e500981235cbec79bd416c5ec136..5d7c0e5b9e76f150b20269cb9ba9e2497062209a 100644 (file)
@@ -413,7 +413,7 @@ ia64_load_extra (struct task_struct *task)
  * so there is nothing to worry about.
  */
 int
-copy_thread (int nr, unsigned long clone_flags,
+copy_thread(unsigned long clone_flags,
             unsigned long user_stack_base, unsigned long user_stack_size,
             struct task_struct *p, struct pt_regs *regs)
 {
index ecb9eb78d6877685de4d677d52e4b21292de4ddc..7053c55b7649337c19f5495c205a0d1584f33caa 100644 (file)
@@ -317,7 +317,7 @@ retry:
        }
 
        n = data->cpu_check;
-       for (i = 0; i < NR_CPUS; i++) {
+       for (i = 0; i < nr_cpu_ids; i++) {
                if (cpu_isset(n, data->cpu_event)) {
                        if (!cpu_online(n)) {
                                cpu_clear(n, data->cpu_event);
@@ -326,7 +326,7 @@ retry:
                        cpu = n;
                        break;
                }
-               if (++n == NR_CPUS)
+               if (++n == nr_cpu_ids)
                        n = 0;
        }
 
@@ -337,7 +337,7 @@ retry:
 
        /* for next read, start checking at next CPU */
        data->cpu_check = cpu;
-       if (++data->cpu_check == NR_CPUS)
+       if (++data->cpu_check == nr_cpu_ids)
                data->cpu_check = 0;
 
        snprintf(cmd, sizeof(cmd), "read %d\n", cpu);
index 865af27c7737c1596dde7762e3ab65555fc990db..714066aeda7f6f758ecd080ec52bd4ae8a17be89 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/meminit.h>
 #include <asm/page.h>
 #include <asm/paravirt.h>
+#include <asm/paravirt_patch.h>
 #include <asm/patch.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -537,6 +538,7 @@ setup_arch (char **cmdline_p)
        paravirt_arch_setup_early();
 
        ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
+       paravirt_patch_apply();
 
        *cmdline_p = __va(ia64_boot_param->command_line);
        strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
@@ -730,10 +732,10 @@ static void *
 c_start (struct seq_file *m, loff_t *pos)
 {
 #ifdef CONFIG_SMP
-       while (*pos < NR_CPUS && !cpu_isset(*pos, cpu_online_map))
+       while (*pos < nr_cpu_ids && !cpu_online(*pos))
                ++*pos;
 #endif
-       return *pos < NR_CPUS ? cpu_data(*pos) : NULL;
+       return *pos < nr_cpu_ids ? cpu_data(*pos) : NULL;
 }
 
 static void *
@@ -1016,8 +1018,7 @@ cpu_init (void)
                                        | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC));
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
-       if (current->mm)
-               BUG();
+       BUG_ON(current->mm);
 
        ia64_mmu_init(ia64_imva(cpu_data));
        ia64_mca_cpu_init(ia64_imva(cpu_data));
index da8f020d82c1f5acb7e20fc2dd6ef4a1b8d86333..2ea4199d9c57895a7814282212033267895f28e6 100644 (file)
@@ -166,11 +166,11 @@ send_IPI_allbutself (int op)
  * Called with preemption disabled.
  */
 static inline void
-send_IPI_mask(cpumask_t mask, int op)
+send_IPI_mask(const struct cpumask *mask, int op)
 {
        unsigned int cpu;
 
-       for_each_cpu_mask(cpu, mask) {
+       for_each_cpu(cpu, mask) {
                        send_IPI_single(cpu, op);
        }
 }
@@ -316,7 +316,7 @@ void arch_send_call_function_single_ipi(int cpu)
        send_IPI_single(cpu, IPI_CALL_FUNC_SINGLE);
 }
 
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
        send_IPI_mask(mask, IPI_CALL_FUNC);
 }
index 52290547c85ba89edd5ba3fa1a98985891803361..7700e23034bb4ba94ceb1d236fb632cb9b8bf924 100644 (file)
@@ -581,14 +581,14 @@ smp_build_cpu_map (void)
 
        ia64_cpu_to_sapicid[0] = boot_cpu_id;
        cpus_clear(cpu_present_map);
-       cpu_set(0, cpu_present_map);
-       cpu_set(0, cpu_possible_map);
+       set_cpu_present(0, true);
+       set_cpu_possible(0, true);
        for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
                sapicid = smp_boot_data.cpu_phys_id[i];
                if (sapicid == boot_cpu_id)
                        continue;
-               cpu_set(cpu, cpu_present_map);
-               cpu_set(cpu, cpu_possible_map);
+               set_cpu_present(cpu, true);
+               set_cpu_possible(cpu, true);
                ia64_cpu_to_sapicid[cpu] = sapicid;
                cpu++;
        }
@@ -626,12 +626,9 @@ smp_prepare_cpus (unsigned int max_cpus)
         */
        if (!max_cpus) {
                printk(KERN_INFO "SMP mode deactivated.\n");
-               cpus_clear(cpu_online_map);
-               cpus_clear(cpu_present_map);
-               cpus_clear(cpu_possible_map);
-               cpu_set(0, cpu_online_map);
-               cpu_set(0, cpu_present_map);
-               cpu_set(0, cpu_possible_map);
+               init_cpu_online(cpumask_of(0));
+               init_cpu_present(cpumask_of(0));
+               init_cpu_possible(cpumask_of(0));
                return;
        }
 }
index f0ebb342409d0b4ab3cd5d9ba470aa3284ef2667..641c8b61c4f167200adf0e52646d5d823a509096 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/efi.h>
 #include <linux/timex.h>
 #include <linux/clocksource.h>
+#include <linux/platform_device.h>
 
 #include <asm/machvec.h>
 #include <asm/delay.h>
@@ -49,6 +50,15 @@ EXPORT_SYMBOL(last_cli_ip);
 
 #endif
 
+#ifdef CONFIG_PARAVIRT
+/* We need to define a real function for sched_clock, to override the
+   weak default version */
+unsigned long long sched_clock(void)
+{
+        return paravirt_sched_clock();
+}
+#endif
+
 #ifdef CONFIG_PARAVIRT
 static void
 paravirt_clocksource_resume(void)
@@ -405,6 +415,21 @@ static struct irqaction timer_irqaction = {
        .name =         "timer"
 };
 
+static struct platform_device rtc_efi_dev = {
+       .name = "rtc-efi",
+       .id = -1,
+};
+
+static int __init rtc_init(void)
+{
+       if (platform_device_register(&rtc_efi_dev) < 0)
+               printk(KERN_ERR "unable to register rtc device...\n");
+
+       /* not necessarily an error */
+       return 0;
+}
+module_init(rtc_init);
+
 void __init
 time_init (void)
 {
index 3765efc5f96333d3a40df579c075f5e6e95a77eb..4a95e86b9ac200bafd30ddca8b1d50be6aec5081 100644 (file)
@@ -169,6 +169,30 @@ SECTIONS
          __end___mckinley_e9_bundles = .;
        }
 
+#if defined(CONFIG_PARAVIRT)
+  . = ALIGN(16);
+  .paravirt_bundles : AT(ADDR(.paravirt_bundles) - LOAD_OFFSET)
+       {
+         __start_paravirt_bundles = .;
+          *(.paravirt_bundles)
+         __stop_paravirt_bundles = .;
+       }
+  . = ALIGN(16);
+  .paravirt_insts : AT(ADDR(.paravirt_insts) - LOAD_OFFSET)
+       {
+         __start_paravirt_insts = .;
+          *(.paravirt_insts)
+         __stop_paravirt_insts = .;
+       }
+  . = ALIGN(16);
+  .paravirt_branches : AT(ADDR(.paravirt_branches) - LOAD_OFFSET)
+       {
+         __start_paravirt_branches = .;
+         *(.paravirt_branches)
+         __stop_paravirt_branches = .;
+       }
+#endif
+
 #if defined(CONFIG_IA64_GENERIC)
   /* Machine Vector */
   . = ALIGN(16);
@@ -201,6 +225,12 @@ SECTIONS
          __start_gate_section = .;
          *(.data.gate)
          __stop_gate_section = .;
+#ifdef CONFIG_XEN
+         . = ALIGN(PAGE_SIZE);
+         __xen_start_gate_section = .;
+         *(.data.gate.xen)
+         __xen_stop_gate_section = .;
+#endif
        }
   . = ALIGN(PAGE_SIZE);                /* make sure the gate page doesn't expose
                                 * kernel data
index 076b00d1dbffe3696eecb5662726faa204478bad..28af6a731bb8a26361a60650263a3c943ff7bb9f 100644 (file)
@@ -70,7 +70,7 @@ static void kvm_flush_icache(unsigned long start, unsigned long len)
        int l;
 
        for (l = 0; l < (len + 32); l += 32)
-               ia64_fc(start + l);
+               ia64_fc((void *)(start + l));
 
        ia64_sync_i();
        ia64_srlz_i();
index d4d28050587883e0f708fb5f46ed9cdb4a7ae3da..a18ee17b9192e01f3c3f1683817be3ae775e1ca7 100644 (file)
@@ -386,7 +386,7 @@ void set_rse_reg(struct kvm_pt_regs *regs, unsigned long r1,
                else
                        *rnat_addr = (*rnat_addr) & (~nat_mask);
 
-               ia64_setreg(_IA64_REG_AR_BSPSTORE, bspstore);
+               ia64_setreg(_IA64_REG_AR_BSPSTORE, (unsigned long)bspstore);
                ia64_setreg(_IA64_REG_AR_RNAT, rnat);
        }
        local_irq_restore(psr);
index 38232b37668b3be87e8c8404aac2caea282bcc67..2c2501f131597c6389e82e6c4e3e62eb6ecf7f80 100644 (file)
@@ -210,6 +210,7 @@ void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte, u64 itir, u64 va, int type)
                phy_pte  &= ~PAGE_FLAGS_RV_MASK;
                psr = ia64_clear_ic();
                ia64_itc(type, va, phy_pte, itir_ps(itir));
+               paravirt_dv_serialize_data();
                ia64_set_psr(psr);
        }
 
@@ -456,6 +457,7 @@ void  thash_purge_and_insert(struct kvm_vcpu *v, u64 pte, u64 itir,
                phy_pte  &= ~PAGE_FLAGS_RV_MASK;
                psr = ia64_clear_ic();
                ia64_itc(type, ifa, phy_pte, ps);
+               paravirt_dv_serialize_data();
                ia64_set_psr(psr);
        }
        if (!(pte&VTLB_PTE_IO))
index 56e12903973cc6456d9e2d7f48a7ec45e6301edd..c0f3bee690424da0ed3f7489fd57b832b8d622cc 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/mca.h>
+#include <asm/paravirt.h>
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
@@ -259,6 +260,7 @@ put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot)
 static void __init
 setup_gate (void)
 {
+       void *gate_section;
        struct page *page;
 
        /*
@@ -266,10 +268,11 @@ setup_gate (void)
         * headers etc. and once execute-only page to enable
         * privilege-promotion via "epc":
         */
-       page = virt_to_page(ia64_imva(__start_gate_section));
+       gate_section = paravirt_get_gate_section();
+       page = virt_to_page(ia64_imva(gate_section));
        put_kernel_page(page, GATE_ADDR, PAGE_READONLY);
 #ifdef HAVE_BUGGY_SEGREL
-       page = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE));
+       page = virt_to_page(ia64_imva(gate_section + PAGE_SIZE));
        put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
 #else
        put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE);
@@ -633,8 +636,7 @@ mem_init (void)
 #endif
 
 #ifdef CONFIG_FLATMEM
-       if (!mem_map)
-               BUG();
+       BUG_ON(!mem_map);
        max_mapnr = max_low_pfn;
 #endif
 
@@ -667,8 +669,8 @@ mem_init (void)
         * code can tell them apart.
         */
        for (i = 0; i < NR_syscalls; ++i) {
-               extern unsigned long fsyscall_table[NR_syscalls];
                extern unsigned long sys_call_table[NR_syscalls];
+               unsigned long *fsyscall_table = paravirt_get_fsyscall_table();
 
                if (!fsyscall_table[i] || nolwsys)
                        fsyscall_table[i] = sys_call_table[i] | 1;
index bd9818a36b4769e9aa961ea82206bdfb8ff21fb9..b9f3d7bbb3384d97b01a48be9db4683dab10340a 100644 (file)
@@ -309,7 +309,7 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start,
 
        preempt_disable();
 #ifdef CONFIG_SMP
-       if (mm != current->active_mm || cpus_weight(mm->cpu_vm_mask) != 1) {
+       if (mm != current->active_mm || cpumask_weight(mm_cpumask(mm)) != 1) {
                platform_global_tlb_purge(mm, start, end, nbits);
                preempt_enable();
                return;
index ba66ac2e4c60f07241ed80203fe5741631327866..e59809a3fc01e1d7d502aa8e3e10d2a36f3f042b 100644 (file)
@@ -17,6 +17,7 @@ s/mov.*=.*cr\.iip/.warning \"cr.iip should not used directly\"/g
 s/mov.*=.*cr\.ivr/.warning \"cr.ivr should not used directly\"/g
 s/mov.*=[^\.]*psr/.warning \"psr should not used directly\"/g  # avoid ar.fpsr
 s/mov.*=.*ar\.eflags/.warning \"ar.eflags should not used directly\"/g
+s/mov.*=.*ar\.itc.*/.warning \"ar.itc should not used directly\"/g
 s/mov.*cr\.ifa.*=.*/.warning \"cr.ifa should not used directly\"/g
 s/mov.*cr\.itir.*=.*/.warning \"cr.itir should not used directly\"/g
 s/mov.*cr\.iha.*=.*/.warning \"cr.iha should not used directly\"/g
index 0d4ffa4da1da755361b5506c945333a246d6a694..57f280dd9defe70d6320ce22b7c51c76e31f5710 100644 (file)
@@ -135,8 +135,7 @@ static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device,
        }
 
        war_list = kzalloc(DEV_PER_WIDGET * sizeof(*war_list), GFP_KERNEL);
-       if (!war_list)
-               BUG();
+       BUG_ON(!war_list);
 
        SAL_CALL_NOLOCK(isrv, SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
                        nasid, widget, __pa(war_list), 0, 0, 0 ,0);
@@ -180,23 +179,20 @@ sn_common_hubdev_init(struct hubdev_info *hubdev)
                sizeof(struct sn_flush_device_kernel *);
        hubdev->hdi_flush_nasid_list.widget_p =
                kzalloc(size, GFP_KERNEL);
-       if (!hubdev->hdi_flush_nasid_list.widget_p)
-               BUG();
+       BUG_ON(!hubdev->hdi_flush_nasid_list.widget_p);
 
        for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
                size = DEV_PER_WIDGET *
                        sizeof(struct sn_flush_device_kernel);
                sn_flush_device_kernel = kzalloc(size, GFP_KERNEL);
-               if (!sn_flush_device_kernel)
-                       BUG();
+               BUG_ON(!sn_flush_device_kernel);
 
                dev_entry = sn_flush_device_kernel;
                for (device = 0; device < DEV_PER_WIDGET;
                     device++, dev_entry++) {
                        size = sizeof(struct sn_flush_device_common);
                        dev_entry->common = kzalloc(size, GFP_KERNEL);
-                       if (!dev_entry->common)
-                               BUG();
+                       BUG_ON(!dev_entry->common);
                        if (sn_prom_feature_available(PRF_DEVICE_FLUSH_LIST))
                                status = sal_get_device_dmaflush_list(
                                             hubdev->hdi_nasid, widget, device,
@@ -326,8 +322,7 @@ sn_common_bus_fixup(struct pci_bus *bus,
         */
        controller->platform_data = kzalloc(sizeof(struct sn_platform_data),
                                            GFP_KERNEL);
-       if (controller->platform_data == NULL)
-               BUG();
+       BUG_ON(controller->platform_data == NULL);
        sn_platform_data =
                        (struct sn_platform_data *) controller->platform_data;
        sn_platform_data->provider_soft = provider_soft;
index e2eb2da60f963ee3aa7e62c727ef408026b4cd13..ee774c366a06c82840a89c80dfb46b3086ead611 100644 (file)
@@ -128,8 +128,7 @@ sn_legacy_pci_window_fixup(struct pci_controller *controller,
 {
                controller->window = kcalloc(2, sizeof(struct pci_window),
                                             GFP_KERNEL);
-               if (controller->window == NULL)
-                       BUG();
+               BUG_ON(controller->window == NULL);
                controller->window[0].offset = legacy_io;
                controller->window[0].resource.name = "legacy_io";
                controller->window[0].resource.flags = IORESOURCE_IO;
@@ -168,8 +167,7 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
        idx = controller->windows;
        new_count = controller->windows + count;
        new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
-       if (new_window == NULL)
-               BUG();
+       BUG_ON(new_window == NULL);
        if (controller->window) {
                memcpy(new_window, controller->window,
                       sizeof(struct pci_window) * controller->windows);
@@ -222,8 +220,7 @@ sn_io_slot_fixup(struct pci_dev *dev)
                (u64) __pa(pcidev_info),
                (u64) __pa(sn_irq_info));
 
-       if (status)
-               BUG(); /* Cannot get platform pci device information */
+       BUG_ON(status); /* Cannot get platform pci device information */
 
 
        /* Copy over PIO Mapped Addresses */
@@ -307,8 +304,7 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        prom_bussoft_ptr = __va(prom_bussoft_ptr);
 
        controller = kzalloc(sizeof(*controller), GFP_KERNEL);
-       if (!controller)
-               BUG();
+       BUG_ON(!controller);
        controller->segment = segment;
 
        /*
index 02c5b8a9fb6061037e8c35551a4881198cf1d4fc..e456f062f2419deb5f2bfd9d0e968d88b1c79ac5 100644 (file)
@@ -732,8 +732,7 @@ void __init build_cnode_tables(void)
                kl_config_hdr_t *klgraph_header;
                nasid = cnodeid_to_nasid(node);
                klgraph_header = ia64_sn_get_klconfig_addr(nasid);
-               if (klgraph_header == NULL)
-                       BUG();
+               BUG_ON(klgraph_header == NULL);
                brd = NODE_OFFSET_TO_LBOARD(nasid, klgraph_header->ch_board_info);
                while (brd) {
                        if (board_needs_cnode(brd->brd_type) && physical_node_map[brd->brd_nasid] < 0) {
@@ -750,7 +749,7 @@ nasid_slice_to_cpuid(int nasid, int slice)
 {
        long cpu;
 
-       for (cpu = 0; cpu < NR_CPUS; cpu++)
+       for (cpu = 0; cpu < nr_cpu_ids; cpu++)
                if (cpuid_to_nasid(cpu) == nasid &&
                                        cpuid_to_slice(cpu) == slice)
                        return cpu;
index 4dcce3d0e04ca1c9bc0e10d10cf4d7fcab6f7723..e6332881864374111440c339a0da72e55130ff40 100644 (file)
@@ -225,7 +225,6 @@ static struct proc_dir_entry *sgi_prominfo_entry;
 int __init prominfo_init(void)
 {
        struct proc_dir_entry **entp;
-       struct proc_dir_entry *p;
        cnodeid_t cnodeid;
        unsigned long nasid;
        int size;
@@ -246,14 +245,10 @@ int __init prominfo_init(void)
                sprintf(name, "node%d", cnodeid);
                *entp = proc_mkdir(name, sgi_prominfo_entry);
                nasid = cnodeid_to_nasid(cnodeid);
-               p = create_proc_read_entry("fit", 0, *entp, read_fit_entry,
+               create_proc_read_entry("fit", 0, *entp, read_fit_entry,
                                           (void *)nasid);
-               if (p)
-                       p->owner = THIS_MODULE;
-               p = create_proc_read_entry("version", 0, *entp,
+               create_proc_read_entry("version", 0, *entp,
                                           read_version_entry, (void *)nasid);
-               if (p)
-                       p->owner = THIS_MODULE;
                entp++;
        }
 
index e585f9a2afb936c74f9ec0ceea13beb1ef7271c4..1176506b2baeb780e5cad3ba08cb533c54a801d8 100644 (file)
@@ -133,7 +133,7 @@ sn2_ipi_flush_all_tlb(struct mm_struct *mm)
        unsigned long itc;
 
        itc = ia64_get_itc();
-       smp_flush_tlb_cpumask(mm->cpu_vm_mask);
+       smp_flush_tlb_cpumask(*mm_cpumask(mm));
        itc = ia64_get_itc() - itc;
        __get_cpu_var(ptcstats).shub_ipi_flushes_itc_clocks += itc;
        __get_cpu_var(ptcstats).shub_ipi_flushes++;
@@ -182,7 +182,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
        nodes_clear(nodes_flushed);
        i = 0;
 
-       for_each_cpu_mask(cpu, mm->cpu_vm_mask) {
+       for_each_cpu(cpu, mm_cpumask(mm)) {
                cnode = cpu_to_node(cpu);
                node_set(cnode, nodes_flushed);
                lcpu = cpu;
@@ -461,7 +461,7 @@ bool sn_cpu_disable_allowed(int cpu)
 
 static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
 {
-       if (*offset < NR_CPUS)
+       if (*offset < nr_cpu_ids)
                return offset;
        return NULL;
 }
@@ -469,7 +469,7 @@ static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
 static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset)
 {
        (*offset)++;
-       if (*offset < NR_CPUS)
+       if (*offset < nr_cpu_ids)
                return offset;
        return NULL;
 }
@@ -491,7 +491,7 @@ static int sn2_ptc_seq_show(struct seq_file *file, void *data)
                seq_printf(file, "# ptctest %d, flushopt %d\n", sn2_ptctest, sn2_flush_opt);
        }
 
-       if (cpu < NR_CPUS && cpu_online(cpu)) {
+       if (cpu < nr_cpu_ids && cpu_online(cpu)) {
                stat = &per_cpu(ptcstats, cpu);
                seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
                                stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
@@ -554,7 +554,7 @@ static int __init sn2_ptc_init(void)
 
        proc_sn2_ptc = proc_create(PTC_BASENAME, 0444,
                                   NULL, &proc_sn2_ptc_operations);
-       if (!&proc_sn2_ptc_operations) {
+       if (!proc_sn2_ptc) {
                printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME);
                return -EINVAL;
        }
index be339477f90603f8a5186dc5a634165dcd3b5e3e..9e6491cf72bd4f1d1246b826e4fa878b4fce7394 100644 (file)
@@ -275,8 +275,7 @@ static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objb
 
        /* get it's interconnect topology */
        sz = op->ports * sizeof(struct sn_hwperf_port_info);
-       if (sz > sizeof(ptdata))
-               BUG();
+       BUG_ON(sz > sizeof(ptdata));
        e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
                              SN_HWPERF_ENUM_PORTS, nodeobj->id, sz,
                              (u64)&ptdata, 0, 0, NULL);
@@ -310,8 +309,7 @@ static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objb
        if (router && (!found_cpu || !found_mem)) {
                /* search for a node connected to the same router */
                sz = router->ports * sizeof(struct sn_hwperf_port_info);
-               if (sz > sizeof(ptdata))
-                       BUG();
+               BUG_ON(sz > sizeof(ptdata));
                e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
                                      SN_HWPERF_ENUM_PORTS, router->id, sz,
                                      (u64)&ptdata, 0, 0, NULL);
@@ -612,7 +610,7 @@ static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info)
        op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
 
        if (cpu != SN_HWPERF_ARG_ANY_CPU) {
-               if (cpu >= NR_CPUS || !cpu_online(cpu)) {
+               if (cpu >= nr_cpu_ids || !cpu_online(cpu)) {
                        r = -EINVAL;
                        goto out;
                }
index 060df4aa9916853297a0be09d4221c5a95e37654..c659ad5613a009f1fea4922275c5d83d286e3b71 100644 (file)
@@ -256,9 +256,7 @@ void sn_dma_flush(u64 addr)
 
        hubinfo = (NODEPDA(nasid_to_cnodeid(nasid)))->pdinfo;
 
-       if (!hubinfo) {
-               BUG();
-       }
+       BUG_ON(!hubinfo);
 
        flush_nasid_list = &hubinfo->hdi_flush_nasid_list;
        if (flush_nasid_list->widget_p == NULL)
index 0ad0224693d99b75bca4724459c454cb5f7f000a..e6f4a0a74228adcafd9628fec7215afd4bc8044b 100644 (file)
@@ -3,14 +3,29 @@
 #
 
 obj-y := hypercall.o xenivt.o xensetup.o xen_pv_ops.o irq_xen.o \
-        hypervisor.o xencomm.o xcom_hcall.o grant-table.o time.o suspend.o
+        hypervisor.o xencomm.o xcom_hcall.o grant-table.o time.o suspend.o \
+        gate-data.o
 
 obj-$(CONFIG_IA64_GENERIC) += machvec.o
 
+# The gate DSO image is built using a special linker script.
+include $(srctree)/arch/ia64/kernel/Makefile.gate
+
+# tell compiled for xen
+CPPFLAGS_gate.lds += -D__IA64_GATE_PARAVIRTUALIZED_XEN
+AFLAGS_gate.o += -D__IA64_ASM_PARAVIRTUALIZED_XEN -D__IA64_GATE_PARAVIRTUALIZED_XEN
+
+# use same file of native.
+$(obj)/gate.o: $(src)/../kernel/gate.S FORCE
+       $(call if_changed_dep,as_o_S)
+$(obj)/gate.lds: $(src)/../kernel/gate.lds.S FORCE
+       $(call if_changed_dep,cpp_lds_S)
+
+
 AFLAGS_xenivt.o += -D__IA64_ASM_PARAVIRTUALIZED_XEN
 
 # xen multi compile
-ASM_PARAVIRT_MULTI_COMPILE_SRCS = ivt.S entry.S
+ASM_PARAVIRT_MULTI_COMPILE_SRCS = ivt.S entry.S fsys.S
 ASM_PARAVIRT_OBJS = $(addprefix xen-,$(ASM_PARAVIRT_MULTI_COMPILE_SRCS:.S=.o))
 obj-y += $(ASM_PARAVIRT_OBJS)
 define paravirtualized_xen
diff --git a/arch/ia64/xen/gate-data.S b/arch/ia64/xen/gate-data.S
new file mode 100644 (file)
index 0000000..7d4830a
--- /dev/null
@@ -0,0 +1,3 @@
+       .section .data.gate.xen, "aw"
+
+       .incbin "arch/ia64/xen/gate.so"
index 45e02bb64a92353137b484cd1d9d1d364f60ca63..e32dae444dd6ec077f0f1ae259927aac723d5ec7 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/intrinsics.h>
 #include <asm/xen/privop.h>
 
+#ifdef __INTEL_COMPILER
 /*
  * Hypercalls without parameter.
  */
@@ -72,6 +73,7 @@ GLOBAL_ENTRY(xen_set_rr0_to_rr4)
        br.ret.sptk.many rp
        ;;
 END(xen_set_rr0_to_rr4)
+#endif
 
 GLOBAL_ENTRY(xen_send_ipi)
        mov r14=r32
index 68d6204c3f1627d0bd76cb04b1aeef2cf885218f..fb8332690179062dafee85ab92075b8fb8d4a3cc 100644 (file)
@@ -175,10 +175,58 @@ static void xen_itc_jitter_data_reset(void)
        } while (unlikely(ret != lcycle));
 }
 
+/* based on xen_sched_clock() in arch/x86/xen/time.c. */
+/*
+ * This relies on HAVE_UNSTABLE_SCHED_CLOCK. If it can't be defined,
+ * something similar logic should be implemented here.
+ */
+/*
+ * Xen sched_clock implementation.  Returns the number of unstolen
+ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
+ * states.
+ */
+static unsigned long long xen_sched_clock(void)
+{
+       struct vcpu_runstate_info runstate;
+
+       unsigned long long now;
+       unsigned long long offset;
+       unsigned long long ret;
+
+       /*
+        * Ideally sched_clock should be called on a per-cpu basis
+        * anyway, so preempt should already be disabled, but that's
+        * not current practice at the moment.
+        */
+       preempt_disable();
+
+       /*
+        * both ia64_native_sched_clock() and xen's runstate are
+        * based on mAR.ITC. So difference of them makes sense.
+        */
+       now = ia64_native_sched_clock();
+
+       get_runstate_snapshot(&runstate);
+
+       WARN_ON(runstate.state != RUNSTATE_running);
+
+       offset = 0;
+       if (now > runstate.state_entry_time)
+               offset = now - runstate.state_entry_time;
+       ret = runstate.time[RUNSTATE_blocked] +
+               runstate.time[RUNSTATE_running] +
+               offset;
+
+       preempt_enable();
+
+       return ret;
+}
+
 struct pv_time_ops xen_time_ops __initdata = {
        .init_missing_ticks_accounting  = xen_init_missing_ticks_accounting,
        .do_steal_accounting            = xen_do_steal_accounting,
        .clocksource_resume             = xen_itc_jitter_data_reset,
+       .sched_clock                    = xen_sched_clock,
 };
 
 /* Called after suspend, to resume time.  */
index 936cff3c96e0215f413054d038950fc8ecc22973..5e2270a999fa58f410093c50cd30f92510c7a780 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/pm.h>
+#include <linux/unistd.h>
 
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/xencomm.h>
@@ -153,6 +154,13 @@ xen_post_smp_prepare_boot_cpu(void)
        xen_setup_vcpu_info_placement();
 }
 
+#ifdef ASM_SUPPORTED
+static unsigned long __init_or_module
+xen_patch_bundle(void *sbundle, void *ebundle, unsigned long type);
+#endif
+static void __init
+xen_patch_branch(unsigned long tag, unsigned long type);
+
 static const struct pv_init_ops xen_init_ops __initconst = {
        .banner = xen_banner,
 
@@ -163,6 +171,53 @@ static const struct pv_init_ops xen_init_ops __initconst = {
        .arch_setup_nomca = xen_arch_setup_nomca,
 
        .post_smp_prepare_boot_cpu = xen_post_smp_prepare_boot_cpu,
+#ifdef ASM_SUPPORTED
+       .patch_bundle = xen_patch_bundle,
+#endif
+       .patch_branch = xen_patch_branch,
+};
+
+/***************************************************************************
+ * pv_fsys_data
+ * addresses for fsys
+ */
+
+extern unsigned long xen_fsyscall_table[NR_syscalls];
+extern char xen_fsys_bubble_down[];
+struct pv_fsys_data xen_fsys_data __initdata = {
+       .fsyscall_table = (unsigned long *)xen_fsyscall_table,
+       .fsys_bubble_down = (void *)xen_fsys_bubble_down,
+};
+
+/***************************************************************************
+ * pv_patchdata
+ * patchdata addresses
+ */
+
+#define DECLARE(name)                                                  \
+       extern unsigned long __xen_start_gate_##name##_patchlist[];     \
+       extern unsigned long __xen_end_gate_##name##_patchlist[]
+
+DECLARE(fsyscall);
+DECLARE(brl_fsys_bubble_down);
+DECLARE(vtop);
+DECLARE(mckinley_e9);
+
+extern unsigned long __xen_start_gate_section[];
+
+#define ASSIGN(name)                                                   \
+       .start_##name##_patchlist =                                     \
+               (unsigned long)__xen_start_gate_##name##_patchlist,     \
+       .end_##name##_patchlist =                                       \
+               (unsigned long)__xen_end_gate_##name##_patchlist
+
+static struct pv_patchdata xen_patchdata __initdata = {
+       ASSIGN(fsyscall),
+       ASSIGN(brl_fsys_bubble_down),
+       ASSIGN(vtop),
+       ASSIGN(mckinley_e9),
+
+       .gate_section = (void*)__xen_start_gate_section,
 };
 
 /***************************************************************************
@@ -170,6 +225,76 @@ static const struct pv_init_ops xen_init_ops __initconst = {
  * intrinsics hooks.
  */
 
+#ifndef ASM_SUPPORTED
+static void
+xen_set_itm_with_offset(unsigned long val)
+{
+       /* ia64_cpu_local_tick() calls this with interrupt enabled. */
+       /* WARN_ON(!irqs_disabled()); */
+       xen_set_itm(val - XEN_MAPPEDREGS->itc_offset);
+}
+
+static unsigned long
+xen_get_itm_with_offset(void)
+{
+       /* unused at this moment */
+       printk(KERN_DEBUG "%s is called.\n", __func__);
+
+       WARN_ON(!irqs_disabled());
+       return ia64_native_getreg(_IA64_REG_CR_ITM) +
+               XEN_MAPPEDREGS->itc_offset;
+}
+
+/* ia64_set_itc() is only called by
+ * cpu_init() with ia64_set_itc(0) and ia64_sync_itc().
+ * So XEN_MAPPEDRESG->itc_offset cal be considered as almost constant.
+ */
+static void
+xen_set_itc(unsigned long val)
+{
+       unsigned long mitc;
+
+       WARN_ON(!irqs_disabled());
+       mitc = ia64_native_getreg(_IA64_REG_AR_ITC);
+       XEN_MAPPEDREGS->itc_offset = val - mitc;
+       XEN_MAPPEDREGS->itc_last = val;
+}
+
+static unsigned long
+xen_get_itc(void)
+{
+       unsigned long res;
+       unsigned long itc_offset;
+       unsigned long itc_last;
+       unsigned long ret_itc_last;
+
+       itc_offset = XEN_MAPPEDREGS->itc_offset;
+       do {
+               itc_last = XEN_MAPPEDREGS->itc_last;
+               res = ia64_native_getreg(_IA64_REG_AR_ITC);
+               res += itc_offset;
+               if (itc_last >= res)
+                       res = itc_last + 1;
+               ret_itc_last = cmpxchg(&XEN_MAPPEDREGS->itc_last,
+                                      itc_last, res);
+       } while (unlikely(ret_itc_last != itc_last));
+       return res;
+
+#if 0
+       /* ia64_itc_udelay() calls ia64_get_itc() with interrupt enabled.
+          Should it be paravirtualized instead? */
+       WARN_ON(!irqs_disabled());
+       itc_offset = XEN_MAPPEDREGS->itc_offset;
+       itc_last = XEN_MAPPEDREGS->itc_last;
+       res = ia64_native_getreg(_IA64_REG_AR_ITC);
+       res += itc_offset;
+       if (itc_last >= res)
+               res = itc_last + 1;
+       XEN_MAPPEDREGS->itc_last = res;
+       return res;
+#endif
+}
+
 static void xen_setreg(int regnum, unsigned long val)
 {
        switch (regnum) {
@@ -181,11 +306,14 @@ static void xen_setreg(int regnum, unsigned long val)
                xen_set_eflag(val);
                break;
 #endif
+       case _IA64_REG_AR_ITC:
+               xen_set_itc(val);
+               break;
        case _IA64_REG_CR_TPR:
                xen_set_tpr(val);
                break;
        case _IA64_REG_CR_ITM:
-               xen_set_itm(val);
+               xen_set_itm_with_offset(val);
                break;
        case _IA64_REG_CR_EOI:
                xen_eoi(val);
@@ -209,6 +337,12 @@ static unsigned long xen_getreg(int regnum)
                res = xen_get_eflag();
                break;
 #endif
+       case _IA64_REG_AR_ITC:
+               res = xen_get_itc();
+               break;
+       case _IA64_REG_CR_ITM:
+               res = xen_get_itm_with_offset();
+               break;
        case _IA64_REG_CR_IVR:
                res = xen_get_ivr();
                break;
@@ -259,8 +393,417 @@ xen_intrin_local_irq_restore(unsigned long mask)
        else
                xen_rsm_i();
 }
+#else
+#define __DEFINE_FUNC(name, code)                                      \
+       extern const char xen_ ## name ## _direct_start[];              \
+       extern const char xen_ ## name ## _direct_end[];                \
+       asm (".align 32\n"                                              \
+            ".proc xen_" #name "\n"                                    \
+            "xen_" #name ":\n"                                         \
+            "xen_" #name "_direct_start:\n"                            \
+            code                                                       \
+            "xen_" #name "_direct_end:\n"                              \
+            "br.cond.sptk.many b6\n"                                   \
+            ".endp xen_" #name "\n")
+
+#define DEFINE_VOID_FUNC0(name, code)          \
+       extern void                             \
+       xen_ ## name (void);                    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1(name, code)          \
+       extern void                             \
+       xen_ ## name (unsigned long arg);       \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC1_VOID(name, code)     \
+       extern void                             \
+       xen_ ## name (void *arg);               \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_VOID_FUNC2(name, code)          \
+       extern void                             \
+       xen_ ## name (unsigned long arg0,       \
+                     unsigned long arg1);      \
+       __DEFINE_FUNC(name, code)
 
-static const struct pv_cpu_ops xen_cpu_ops __initdata = {
+#define DEFINE_FUNC0(name, code)               \
+       extern unsigned long                    \
+       xen_ ## name (void);                    \
+       __DEFINE_FUNC(name, code)
+
+#define DEFINE_FUNC1(name, type, code)         \
+       extern unsigned long                    \
+       xen_ ## name (type arg);                \
+       __DEFINE_FUNC(name, code)
+
+#define XEN_PSR_I_ADDR_ADDR     (XSI_BASE + XSI_PSR_I_ADDR_OFS)
+
+/*
+ * static void xen_set_itm_with_offset(unsigned long val)
+ *        xen_set_itm(val - XEN_MAPPEDREGS->itc_offset);
+ */
+/* 2 bundles */
+DEFINE_VOID_FUNC1(set_itm_with_offset,
+                 "mov r2 = " __stringify(XSI_BASE) " + "
+                 __stringify(XSI_ITC_OFFSET_OFS) "\n"
+                 ";;\n"
+                 "ld8 r3 = [r2]\n"
+                 ";;\n"
+                 "sub r8 = r8, r3\n"
+                 "break " __stringify(HYPERPRIVOP_SET_ITM) "\n");
+
+/*
+ * static unsigned long xen_get_itm_with_offset(void)
+ *    return ia64_native_getreg(_IA64_REG_CR_ITM) + XEN_MAPPEDREGS->itc_offset;
+ */
+/* 2 bundles */
+DEFINE_FUNC0(get_itm_with_offset,
+            "mov r2 = " __stringify(XSI_BASE) " + "
+            __stringify(XSI_ITC_OFFSET_OFS) "\n"
+            ";;\n"
+            "ld8 r3 = [r2]\n"
+            "mov r8 = cr.itm\n"
+            ";;\n"
+            "add r8 = r8, r2\n");
+
+/*
+ * static void xen_set_itc(unsigned long val)
+ *     unsigned long mitc;
+ *
+ *     WARN_ON(!irqs_disabled());
+ *     mitc = ia64_native_getreg(_IA64_REG_AR_ITC);
+ *     XEN_MAPPEDREGS->itc_offset = val - mitc;
+ *     XEN_MAPPEDREGS->itc_last = val;
+ */
+/* 2 bundles */
+DEFINE_VOID_FUNC1(set_itc,
+                 "mov r2 = " __stringify(XSI_BASE) " + "
+                 __stringify(XSI_ITC_LAST_OFS) "\n"
+                 "mov r3 = ar.itc\n"
+                 ";;\n"
+                 "sub r3 = r8, r3\n"
+                 "st8 [r2] = r8, "
+                 __stringify(XSI_ITC_LAST_OFS) " - "
+                 __stringify(XSI_ITC_OFFSET_OFS) "\n"
+                 ";;\n"
+                 "st8 [r2] = r3\n");
+
+/*
+ * static unsigned long xen_get_itc(void)
+ *     unsigned long res;
+ *     unsigned long itc_offset;
+ *     unsigned long itc_last;
+ *     unsigned long ret_itc_last;
+ *
+ *     itc_offset = XEN_MAPPEDREGS->itc_offset;
+ *     do {
+ *             itc_last = XEN_MAPPEDREGS->itc_last;
+ *             res = ia64_native_getreg(_IA64_REG_AR_ITC);
+ *             res += itc_offset;
+ *             if (itc_last >= res)
+ *                     res = itc_last + 1;
+ *             ret_itc_last = cmpxchg(&XEN_MAPPEDREGS->itc_last,
+ *                                    itc_last, res);
+ *     } while (unlikely(ret_itc_last != itc_last));
+ *     return res;
+ */
+/* 5 bundles */
+DEFINE_FUNC0(get_itc,
+            "mov r2 = " __stringify(XSI_BASE) " + "
+            __stringify(XSI_ITC_OFFSET_OFS) "\n"
+            ";;\n"
+            "ld8 r9 = [r2], " __stringify(XSI_ITC_LAST_OFS) " - "
+            __stringify(XSI_ITC_OFFSET_OFS) "\n"
+                                       /* r9 = itc_offset */
+                                       /* r2 = XSI_ITC_OFFSET */
+            "888:\n"
+            "mov r8 = ar.itc\n"        /* res = ar.itc */
+            ";;\n"
+            "ld8 r3 = [r2]\n"          /* r3 = itc_last */
+            "add r8 = r8, r9\n"        /* res = ar.itc + itc_offset */
+            ";;\n"
+            "cmp.gtu p6, p0 = r3, r8\n"
+            ";;\n"
+            "(p6) add r8 = 1, r3\n"    /* if (itc_last > res) itc_last + 1 */
+            ";;\n"
+            "mov ar.ccv = r8\n"
+            ";;\n"
+            "cmpxchg8.acq r10 = [r2], r8, ar.ccv\n"
+            ";;\n"
+            "cmp.ne p6, p0 = r10, r3\n"
+            "(p6) hint @pause\n"
+            "(p6) br.cond.spnt 888b\n");
+
+DEFINE_VOID_FUNC1_VOID(fc,
+                      "break " __stringify(HYPERPRIVOP_FC) "\n");
+
+/*
+ * psr_i_addr_addr = XEN_PSR_I_ADDR_ADDR
+ * masked_addr = *psr_i_addr_addr
+ * pending_intr_addr = masked_addr - 1
+ * if (val & IA64_PSR_I) {
+ *   masked = *masked_addr
+ *   *masked_addr = 0:xen_set_virtual_psr_i(1)
+ *   compiler barrier
+ *   if (masked) {
+ *      uint8_t pending = *pending_intr_addr;
+ *      if (pending)
+ *              XEN_HYPER_SSM_I
+ *   }
+ * } else {
+ *   *masked_addr = 1:xen_set_virtual_psr_i(0)
+ * }
+ */
+/* 6 bundles */
+DEFINE_VOID_FUNC1(intrin_local_irq_restore,
+                 /* r8 = input value: 0 or IA64_PSR_I
+                  * p6 =  (flags & IA64_PSR_I)
+                  *    = if clause
+                  * p7 = !(flags & IA64_PSR_I)
+                  *    = else clause
+                  */
+                 "cmp.ne p6, p7 = r8, r0\n"
+                 "mov r9 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+                 ";;\n"
+                 /* r9 = XEN_PSR_I_ADDR */
+                 "ld8 r9 = [r9]\n"
+                 ";;\n"
+
+                 /* r10 = masked previous value */
+                 "(p6) ld1.acq r10 = [r9]\n"
+                 ";;\n"
+
+                 /* p8 = !masked interrupt masked previously? */
+                 "(p6) cmp.ne.unc p8, p0 = r10, r0\n"
+
+                 /* p7 = else clause */
+                 "(p7) mov r11 = 1\n"
+                 ";;\n"
+                 /* masked = 1 */
+                 "(p7) st1.rel [r9] = r11\n"
+
+                 /* p6 = if clause */
+                 /* masked = 0
+                  * r9 = masked_addr - 1
+                  *    = pending_intr_addr
+                  */
+                 "(p8) st1.rel [r9] = r0, -1\n"
+                 ";;\n"
+                 /* r8 = pending_intr */
+                 "(p8) ld1.acq r11 = [r9]\n"
+                 ";;\n"
+                 /* p9 = interrupt pending? */
+                 "(p8) cmp.ne.unc p9, p10 = r11, r0\n"
+                 ";;\n"
+                 "(p10) mf\n"
+                 /* issue hypercall to trigger interrupt */
+                 "(p9) break " __stringify(HYPERPRIVOP_SSM_I) "\n");
+
+DEFINE_VOID_FUNC2(ptcga,
+                 "break " __stringify(HYPERPRIVOP_PTC_GA) "\n");
+DEFINE_VOID_FUNC2(set_rr,
+                 "break " __stringify(HYPERPRIVOP_SET_RR) "\n");
+
+/*
+ * tmp = XEN_MAPPEDREGS->interrupt_mask_addr = XEN_PSR_I_ADDR_ADDR;
+ * tmp = *tmp
+ * tmp = *tmp;
+ * psr_i = tmp? 0: IA64_PSR_I;
+ */
+/* 4 bundles */
+DEFINE_FUNC0(get_psr_i,
+            "mov r9 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+            ";;\n"
+            "ld8 r9 = [r9]\n"                  /* r9 = XEN_PSR_I_ADDR */
+            "mov r8 = 0\n"                     /* psr_i = 0 */
+            ";;\n"
+            "ld1.acq r9 = [r9]\n"              /* r9 = XEN_PSR_I */
+            ";;\n"
+            "cmp.eq.unc p6, p0 = r9, r0\n"     /* p6 = (XEN_PSR_I != 0) */
+            ";;\n"
+            "(p6) mov r8 = " __stringify(1 << IA64_PSR_I_BIT) "\n");
+
+DEFINE_FUNC1(thash, unsigned long,
+            "break " __stringify(HYPERPRIVOP_THASH) "\n");
+DEFINE_FUNC1(get_cpuid, int,
+            "break " __stringify(HYPERPRIVOP_GET_CPUID) "\n");
+DEFINE_FUNC1(get_pmd, int,
+            "break " __stringify(HYPERPRIVOP_GET_PMD) "\n");
+DEFINE_FUNC1(get_rr, unsigned long,
+            "break " __stringify(HYPERPRIVOP_GET_RR) "\n");
+
+/*
+ * void xen_privop_ssm_i(void)
+ *
+ * int masked = !xen_get_virtual_psr_i();
+ *     // masked = *(*XEN_MAPPEDREGS->interrupt_mask_addr)
+ * xen_set_virtual_psr_i(1)
+ *     // *(*XEN_MAPPEDREGS->interrupt_mask_addr) = 0
+ * // compiler barrier
+ * if (masked) {
+ *     uint8_t* pend_int_addr =
+ *             (uint8_t*)(*XEN_MAPPEDREGS->interrupt_mask_addr) - 1;
+ *     uint8_t pending = *pend_int_addr;
+ *     if (pending)
+ *             XEN_HYPER_SSM_I
+ * }
+ */
+/* 4 bundles */
+DEFINE_VOID_FUNC0(ssm_i,
+                 "mov r8 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+                 ";;\n"
+                 "ld8 r8 = [r8]\n"             /* r8 = XEN_PSR_I_ADDR */
+                 ";;\n"
+                 "ld1.acq r9 = [r8]\n"         /* r9 = XEN_PSR_I */
+                 ";;\n"
+                 "st1.rel [r8] = r0, -1\n"     /* psr_i = 0. enable interrupt
+                                                * r8 = XEN_PSR_I_ADDR - 1
+                                                *    = pend_int_addr
+                                                */
+                 "cmp.eq.unc p0, p6 = r9, r0\n"/* p6 = !XEN_PSR_I
+                                                * previously interrupt
+                                                * masked?
+                                                */
+                 ";;\n"
+                 "(p6) ld1.acq r8 = [r8]\n"    /* r8 = xen_pend_int */
+                 ";;\n"
+                 "(p6) cmp.eq.unc p6, p7 = r8, r0\n"   /*interrupt pending?*/
+                 ";;\n"
+                 /* issue hypercall to get interrupt */
+                 "(p7) break " __stringify(HYPERPRIVOP_SSM_I) "\n"
+                 ";;\n");
+
+/*
+ * psr_i_addr_addr = XEN_MAPPEDREGS->interrupt_mask_addr
+ *                = XEN_PSR_I_ADDR_ADDR;
+ * psr_i_addr = *psr_i_addr_addr;
+ * *psr_i_addr = 1;
+ */
+/* 2 bundles */
+DEFINE_VOID_FUNC0(rsm_i,
+                 "mov r8 = " __stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+                                               /* r8 = XEN_PSR_I_ADDR */
+                 "mov r9 = 1\n"
+                 ";;\n"
+                 "ld8 r8 = [r8]\n"             /* r8 = XEN_PSR_I */
+                 ";;\n"
+                 "st1.rel [r8] = r9\n");       /* XEN_PSR_I = 1 */
+
+extern void
+xen_set_rr0_to_rr4(unsigned long val0, unsigned long val1,
+                  unsigned long val2, unsigned long val3,
+                  unsigned long val4);
+__DEFINE_FUNC(set_rr0_to_rr4,
+             "break " __stringify(HYPERPRIVOP_SET_RR0_TO_RR4) "\n");
+
+
+extern unsigned long xen_getreg(int regnum);
+#define __DEFINE_GET_REG(id, privop)                                   \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"                  \
+       ";;\n"                                                          \
+       "cmp.eq p6, p0 = r2, r8\n"                                      \
+       ";;\n"                                                          \
+       "(p6) break " __stringify(HYPERPRIVOP_GET_ ## privop) "\n"      \
+       "(p6) br.cond.sptk.many b6\n"                                   \
+       ";;\n"
+
+__DEFINE_FUNC(getreg,
+             __DEFINE_GET_REG(PSR, PSR)
+#ifdef CONFIG_IA32_SUPPORT
+             __DEFINE_GET_REG(AR_EFLAG, EFLAG)
+#endif
+
+             /* get_itc */
+             "mov r2 = " __stringify(_IA64_REG_AR_ITC) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_get_itc\n"
+             ";;\n"
+
+             /* get itm */
+             "mov r2 = " __stringify(_IA64_REG_CR_ITM) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_get_itm_with_offset\n"
+             ";;\n"
+
+             __DEFINE_GET_REG(CR_IVR, IVR)
+             __DEFINE_GET_REG(CR_TPR, TPR)
+
+             /* fall back */
+             "movl r2 = ia64_native_getreg_func\n"
+             ";;\n"
+             "mov b7 = r2\n"
+             ";;\n"
+             "br.cond.sptk.many b7\n");
+
+extern void xen_setreg(int regnum, unsigned long val);
+#define __DEFINE_SET_REG(id, privop)                                   \
+       "mov r2 = " __stringify(_IA64_REG_ ## id) "\n"                  \
+       ";;\n"                                                          \
+       "cmp.eq p6, p0 = r2, r9\n"                                      \
+       ";;\n"                                                          \
+       "(p6) break " __stringify(HYPERPRIVOP_ ## privop) "\n"          \
+       "(p6) br.cond.sptk.many b6\n"                                   \
+       ";;\n"
+
+__DEFINE_FUNC(setreg,
+             /* kr0 .. kr 7*/
+             /*
+              * if (_IA64_REG_AR_KR0 <= regnum &&
+              *     regnum <= _IA64_REG_AR_KR7) {
+              *     register __index asm ("r8") = regnum - _IA64_REG_AR_KR0
+              *     register __val asm ("r9") = val
+              *    "break HYPERPRIVOP_SET_KR"
+              * }
+              */
+             "mov r17 = r9\n"
+             "mov r2 = " __stringify(_IA64_REG_AR_KR0) "\n"
+             ";;\n"
+             "cmp.ge p6, p0 = r9, r2\n"
+             "sub r17 = r17, r2\n"
+             ";;\n"
+             "(p6) cmp.ge.unc p7, p0 = "
+             __stringify(_IA64_REG_AR_KR7) " - " __stringify(_IA64_REG_AR_KR0)
+             ", r17\n"
+             ";;\n"
+             "(p7) mov r9 = r8\n"
+             ";;\n"
+             "(p7) mov r8 = r17\n"
+             "(p7) break " __stringify(HYPERPRIVOP_SET_KR) "\n"
+
+             /* set itm */
+             "mov r2 = " __stringify(_IA64_REG_CR_ITM) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_set_itm_with_offset\n"
+
+             /* set itc */
+             "mov r2 = " __stringify(_IA64_REG_AR_ITC) "\n"
+             ";;\n"
+             "cmp.eq p6, p0 = r2, r8\n"
+             ";;\n"
+             "(p6) br.cond.spnt xen_set_itc\n"
+
+#ifdef CONFIG_IA32_SUPPORT
+             __DEFINE_SET_REG(AR_EFLAG, SET_EFLAG)
+#endif
+             __DEFINE_SET_REG(CR_TPR, SET_TPR)
+             __DEFINE_SET_REG(CR_EOI, EOI)
+
+             /* fall back */
+             "movl r2 = ia64_native_setreg_func\n"
+             ";;\n"
+             "mov b7 = r2\n"
+             ";;\n"
+             "br.cond.sptk.many b7\n");
+#endif
+
+static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .fc             = xen_fc,
        .thash          = xen_thash,
        .get_cpuid      = xen_get_cpuid,
@@ -337,7 +880,7 @@ xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
        HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
 }
 
-static const struct pv_iosapic_ops xen_iosapic_ops __initconst = {
+static struct pv_iosapic_ops xen_iosapic_ops __initdata = {
        .pcat_compat_init = xen_pcat_compat_init,
        .__get_irq_chip = xen_iosapic_get_irq_chip,
 
@@ -355,6 +898,8 @@ xen_setup_pv_ops(void)
        xen_info_init();
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
+       pv_fsys_data = xen_fsys_data;
+       pv_patchdata = xen_patchdata;
        pv_cpu_ops = xen_cpu_ops;
        pv_iosapic_ops = xen_iosapic_ops;
        pv_irq_ops = xen_irq_ops;
@@ -362,3 +907,252 @@ xen_setup_pv_ops(void)
 
        paravirt_cpu_asm_init(&xen_cpu_asm_switch);
 }
+
+#ifdef ASM_SUPPORTED
+/***************************************************************************
+ * binary pacthing
+ * pv_init_ops.patch_bundle
+ */
+
+#define DEFINE_FUNC_GETREG(name, privop)                               \
+       DEFINE_FUNC0(get_ ## name,                                      \
+                    "break "__stringify(HYPERPRIVOP_GET_ ## privop) "\n")
+
+DEFINE_FUNC_GETREG(psr, PSR);
+DEFINE_FUNC_GETREG(eflag, EFLAG);
+DEFINE_FUNC_GETREG(ivr, IVR);
+DEFINE_FUNC_GETREG(tpr, TPR);
+
+#define DEFINE_FUNC_SET_KR(n)                                          \
+       DEFINE_VOID_FUNC0(set_kr ## n,                                  \
+                         ";;\n"                                        \
+                         "mov r9 = r8\n"                               \
+                         "mov r8 = " #n "\n"                           \
+                         "break " __stringify(HYPERPRIVOP_SET_KR) "\n")
+
+DEFINE_FUNC_SET_KR(0);
+DEFINE_FUNC_SET_KR(1);
+DEFINE_FUNC_SET_KR(2);
+DEFINE_FUNC_SET_KR(3);
+DEFINE_FUNC_SET_KR(4);
+DEFINE_FUNC_SET_KR(5);
+DEFINE_FUNC_SET_KR(6);
+DEFINE_FUNC_SET_KR(7);
+
+#define __DEFINE_FUNC_SETREG(name, privop)                             \
+       DEFINE_VOID_FUNC0(name,                                         \
+                         "break "__stringify(HYPERPRIVOP_ ## privop) "\n")
+
+#define DEFINE_FUNC_SETREG(name, privop)                       \
+       __DEFINE_FUNC_SETREG(set_ ## name, SET_ ## privop)
+
+DEFINE_FUNC_SETREG(eflag, EFLAG);
+DEFINE_FUNC_SETREG(tpr, TPR);
+__DEFINE_FUNC_SETREG(eoi, EOI);
+
+extern const char xen_check_events[];
+extern const char __xen_intrin_local_irq_restore_direct_start[];
+extern const char __xen_intrin_local_irq_restore_direct_end[];
+extern const unsigned long __xen_intrin_local_irq_restore_direct_reloc;
+
+asm (
+       ".align 32\n"
+       ".proc xen_check_events\n"
+       "xen_check_events:\n"
+       /* masked = 0
+        * r9 = masked_addr - 1
+        *    = pending_intr_addr
+        */
+       "st1.rel [r9] = r0, -1\n"
+       ";;\n"
+       /* r8 = pending_intr */
+       "ld1.acq r11 = [r9]\n"
+       ";;\n"
+       /* p9 = interrupt pending? */
+       "cmp.ne p9, p10 = r11, r0\n"
+       ";;\n"
+       "(p10) mf\n"
+       /* issue hypercall to trigger interrupt */
+       "(p9) break " __stringify(HYPERPRIVOP_SSM_I) "\n"
+       "br.cond.sptk.many b6\n"
+       ".endp xen_check_events\n"
+       "\n"
+       ".align 32\n"
+       ".proc __xen_intrin_local_irq_restore_direct\n"
+       "__xen_intrin_local_irq_restore_direct:\n"
+       "__xen_intrin_local_irq_restore_direct_start:\n"
+       "1:\n"
+       "{\n"
+       "cmp.ne p6, p7 = r8, r0\n"
+       "mov r17 = ip\n" /* get ip to calc return address */
+       "mov r9 = "__stringify(XEN_PSR_I_ADDR_ADDR) "\n"
+       ";;\n"
+       "}\n"
+       "{\n"
+       /* r9 = XEN_PSR_I_ADDR */
+       "ld8 r9 = [r9]\n"
+       ";;\n"
+       /* r10 = masked previous value */
+       "(p6) ld1.acq r10 = [r9]\n"
+       "adds r17 =  1f - 1b, r17\n" /* calculate return address */
+       ";;\n"
+       "}\n"
+       "{\n"
+       /* p8 = !masked interrupt masked previously? */
+       "(p6) cmp.ne.unc p8, p0 = r10, r0\n"
+       "\n"
+       /* p7 = else clause */
+       "(p7) mov r11 = 1\n"
+       ";;\n"
+       "(p8) mov b6 = r17\n" /* set return address */
+       "}\n"
+       "{\n"
+       /* masked = 1 */
+       "(p7) st1.rel [r9] = r11\n"
+       "\n"
+       "[99:]\n"
+       "(p8) brl.cond.dptk.few xen_check_events\n"
+       "}\n"
+       /* pv calling stub is 5 bundles. fill nop to adjust return address */
+       "{\n"
+       "nop 0\n"
+       "nop 0\n"
+       "nop 0\n"
+       "}\n"
+       "1:\n"
+       "__xen_intrin_local_irq_restore_direct_end:\n"
+       ".endp __xen_intrin_local_irq_restore_direct\n"
+       "\n"
+       ".align 8\n"
+       "__xen_intrin_local_irq_restore_direct_reloc:\n"
+       "data8 99b\n"
+);
+
+static struct paravirt_patch_bundle_elem xen_patch_bundle_elems[]
+__initdata_or_module =
+{
+#define XEN_PATCH_BUNDLE_ELEM(name, type)              \
+       {                                               \
+               (void*)xen_ ## name ## _direct_start,   \
+               (void*)xen_ ## name ## _direct_end,     \
+               PARAVIRT_PATCH_TYPE_ ## type,           \
+       }
+
+       XEN_PATCH_BUNDLE_ELEM(fc, FC),
+       XEN_PATCH_BUNDLE_ELEM(thash, THASH),
+       XEN_PATCH_BUNDLE_ELEM(get_cpuid, GET_CPUID),
+       XEN_PATCH_BUNDLE_ELEM(get_pmd, GET_PMD),
+       XEN_PATCH_BUNDLE_ELEM(ptcga, PTCGA),
+       XEN_PATCH_BUNDLE_ELEM(get_rr, GET_RR),
+       XEN_PATCH_BUNDLE_ELEM(set_rr, SET_RR),
+       XEN_PATCH_BUNDLE_ELEM(set_rr0_to_rr4, SET_RR0_TO_RR4),
+       XEN_PATCH_BUNDLE_ELEM(ssm_i, SSM_I),
+       XEN_PATCH_BUNDLE_ELEM(rsm_i, RSM_I),
+       XEN_PATCH_BUNDLE_ELEM(get_psr_i, GET_PSR_I),
+       {
+               (void*)__xen_intrin_local_irq_restore_direct_start,
+               (void*)__xen_intrin_local_irq_restore_direct_end,
+               PARAVIRT_PATCH_TYPE_INTRIN_LOCAL_IRQ_RESTORE,
+       },
+
+#define XEN_PATCH_BUNDLE_ELEM_GETREG(name, reg)                        \
+       {                                                       \
+               xen_get_ ## name ## _direct_start,              \
+               xen_get_ ## name ## _direct_end,                \
+               PARAVIRT_PATCH_TYPE_GETREG + _IA64_REG_ ## reg, \
+       }
+
+       XEN_PATCH_BUNDLE_ELEM_GETREG(psr, PSR),
+       XEN_PATCH_BUNDLE_ELEM_GETREG(eflag, AR_EFLAG),
+
+       XEN_PATCH_BUNDLE_ELEM_GETREG(ivr, CR_IVR),
+       XEN_PATCH_BUNDLE_ELEM_GETREG(tpr, CR_TPR),
+
+       XEN_PATCH_BUNDLE_ELEM_GETREG(itc, AR_ITC),
+       XEN_PATCH_BUNDLE_ELEM_GETREG(itm_with_offset, CR_ITM),
+
+
+#define __XEN_PATCH_BUNDLE_ELEM_SETREG(name, reg)              \
+       {                                                       \
+               xen_ ## name ## _direct_start,                  \
+               xen_ ## name ## _direct_end,                    \
+               PARAVIRT_PATCH_TYPE_SETREG + _IA64_REG_ ## reg, \
+       }
+
+#define XEN_PATCH_BUNDLE_ELEM_SETREG(name, reg)                        \
+       __XEN_PATCH_BUNDLE_ELEM_SETREG(set_ ## name, reg)
+
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr0, AR_KR0),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr1, AR_KR1),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr2, AR_KR2),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr3, AR_KR3),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr4, AR_KR4),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr5, AR_KR5),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr6, AR_KR6),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(kr7, AR_KR7),
+
+       XEN_PATCH_BUNDLE_ELEM_SETREG(eflag, AR_EFLAG),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(tpr, CR_TPR),
+       __XEN_PATCH_BUNDLE_ELEM_SETREG(eoi, CR_EOI),
+
+       XEN_PATCH_BUNDLE_ELEM_SETREG(itc, AR_ITC),
+       XEN_PATCH_BUNDLE_ELEM_SETREG(itm_with_offset, CR_ITM),
+};
+
+static unsigned long __init_or_module
+xen_patch_bundle(void *sbundle, void *ebundle, unsigned long type)
+{
+       const unsigned long nelems = sizeof(xen_patch_bundle_elems) /
+               sizeof(xen_patch_bundle_elems[0]);
+       unsigned long used;
+       const struct paravirt_patch_bundle_elem *found;
+
+       used = __paravirt_patch_apply_bundle(sbundle, ebundle, type,
+                                            xen_patch_bundle_elems, nelems,
+                                            &found);
+
+       if (found == NULL)
+               /* fallback */
+               return ia64_native_patch_bundle(sbundle, ebundle, type);
+       if (used == 0)
+               return used;
+
+       /* relocation */
+       switch (type) {
+       case PARAVIRT_PATCH_TYPE_INTRIN_LOCAL_IRQ_RESTORE: {
+               unsigned long reloc =
+                       __xen_intrin_local_irq_restore_direct_reloc;
+               unsigned long reloc_offset = reloc - (unsigned long)
+                       __xen_intrin_local_irq_restore_direct_start;
+               unsigned long tag = (unsigned long)sbundle + reloc_offset;
+               paravirt_patch_reloc_brl(tag, xen_check_events);
+               break;
+       }
+       default:
+               /* nothing */
+               break;
+       }
+       return used;
+}
+#endif /* ASM_SUPPOTED */
+
+const struct paravirt_patch_branch_target xen_branch_target[]
+__initconst = {
+#define PARAVIRT_BR_TARGET(name, type)                 \
+       {                                               \
+               &xen_ ## name,                          \
+               PARAVIRT_PATCH_TYPE_BR_ ## type,        \
+       }
+       PARAVIRT_BR_TARGET(switch_to, SWITCH_TO),
+       PARAVIRT_BR_TARGET(leave_syscall, LEAVE_SYSCALL),
+       PARAVIRT_BR_TARGET(work_processed_syscall, WORK_PROCESSED_SYSCALL),
+       PARAVIRT_BR_TARGET(leave_kernel, LEAVE_KERNEL),
+};
+
+static void __init
+xen_patch_branch(unsigned long tag, unsigned long type)
+{
+       const unsigned long nelem =
+               sizeof(xen_branch_target) / sizeof(xen_branch_target[0]);
+       __paravirt_patch_apply_branch(tag, type, xen_branch_target, nelem);
+}
index 7103d91e1a2f92ee3db9a4d060336ee29c08d347..3e876f0baebca2e6ef344dc94a07feb0cbcf6298 100644 (file)
@@ -225,7 +225,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
        return 0; /* Task didn't use the fpu at all. */
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long spu,
+int copy_thread(unsigned long clone_flags, unsigned long spu,
        unsigned long unused, struct task_struct *tsk, struct pt_regs *regs)
 {
        struct pt_regs *childregs = task_pt_regs(tsk);
index 6ea017727cced935c638a876dc193e7ef4e3288e..cada3ba4b9902f23bb13620e726a2625897e5d8a 100644 (file)
@@ -230,7 +230,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq0 = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "MFT2",
 };
 
index fedf3e326121cc6e61b3459b552c2cd993bcfe0b..fb8a06b9ab6a6dd39fc385956983d7c3b8d14339 100644 (file)
@@ -1,5 +1,378 @@
-#ifdef __uClinux__
-#include "bootinfo_no.h"
-#else
-#include "bootinfo_mm.h"
+/*
+** asm/bootinfo.h -- Definition of the Linux/m68k boot information structure
+**
+** Copyright 1992 by Greg Harp
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file COPYING in the main directory of this archive
+** for more details.
+**
+** Created 09/29/92 by Greg Harp
+**
+** 5/2/94 Roman Hodek:
+**   Added bi_atari part of the machine dependent union bi_un; for now it
+**   contains just a model field to distinguish between TT and Falcon.
+** 26/7/96 Roman Zippel:
+**   Renamed to setup.h; added some useful macros to allow gcc some
+**   optimizations if possible.
+** 5/10/96 Geert Uytterhoeven:
+**   Redesign of the boot information structure; renamed to bootinfo.h again
+** 27/11/96 Geert Uytterhoeven:
+**   Backwards compatibility with bootinfo interface version 1.0
+*/
+
+#ifndef _M68K_BOOTINFO_H
+#define _M68K_BOOTINFO_H
+
+
+    /*
+     *  Bootinfo definitions
+     *
+     *  This is an easily parsable and extendable structure containing all
+     *  information to be passed from the bootstrap to the kernel.
+     *
+     *  This way I hope to keep all future changes back/forewards compatible.
+     *  Thus, keep your fingers crossed...
+     *
+     *  This structure is copied right after the kernel bss by the bootstrap
+     *  routine.
+     */
+
+#ifndef __ASSEMBLY__
+
+struct bi_record {
+    unsigned short tag;                        /* tag ID */
+    unsigned short size;               /* size of record (in bytes) */
+    unsigned long data[0];             /* data */
+};
+
+#endif /* __ASSEMBLY__ */
+
+
+    /*
+     *  Tag Definitions
+     *
+     *  Machine independent tags start counting from 0x0000
+     *  Machine dependent tags start counting from 0x8000
+     */
+
+#define BI_LAST                        0x0000  /* last record (sentinel) */
+#define BI_MACHTYPE            0x0001  /* machine type (u_long) */
+#define BI_CPUTYPE             0x0002  /* cpu type (u_long) */
+#define BI_FPUTYPE             0x0003  /* fpu type (u_long) */
+#define BI_MMUTYPE             0x0004  /* mmu type (u_long) */
+#define BI_MEMCHUNK            0x0005  /* memory chunk address and size */
+                                       /* (struct mem_info) */
+#define BI_RAMDISK             0x0006  /* ramdisk address and size */
+                                       /* (struct mem_info) */
+#define BI_COMMAND_LINE                0x0007  /* kernel command line parameters */
+                                       /* (string) */
+
+    /*
+     *  Amiga-specific tags
+     */
+
+#define BI_AMIGA_MODEL         0x8000  /* model (u_long) */
+#define BI_AMIGA_AUTOCON       0x8001  /* AutoConfig device */
+                                       /* (struct ConfigDev) */
+#define BI_AMIGA_CHIP_SIZE     0x8002  /* size of Chip RAM (u_long) */
+#define BI_AMIGA_VBLANK                0x8003  /* VBLANK frequency (u_char) */
+#define BI_AMIGA_PSFREQ                0x8004  /* power supply frequency (u_char) */
+#define BI_AMIGA_ECLOCK                0x8005  /* EClock frequency (u_long) */
+#define BI_AMIGA_CHIPSET       0x8006  /* native chipset present (u_long) */
+#define BI_AMIGA_SERPER                0x8007  /* serial port period (u_short) */
+
+    /*
+     *  Atari-specific tags
+     */
+
+#define BI_ATARI_MCH_COOKIE    0x8000  /* _MCH cookie from TOS (u_long) */
+#define BI_ATARI_MCH_TYPE      0x8001  /* special machine type (u_long) */
+                                       /* (values are ATARI_MACH_* defines */
+
+/* mch_cookie values (upper word) */
+#define ATARI_MCH_ST           0
+#define ATARI_MCH_STE          1
+#define ATARI_MCH_TT           2
+#define ATARI_MCH_FALCON       3
+
+/* mch_type values */
+#define ATARI_MACH_NORMAL      0       /* no special machine type */
+#define ATARI_MACH_MEDUSA      1       /* Medusa 040 */
+#define ATARI_MACH_HADES       2       /* Hades 040 or 060 */
+#define ATARI_MACH_AB40                3       /* Afterburner040 on Falcon */
+
+    /*
+     *  VME-specific tags
+     */
+
+#define BI_VME_TYPE            0x8000  /* VME sub-architecture (u_long) */
+#define BI_VME_BRDINFO         0x8001  /* VME board information (struct) */
+
+/* BI_VME_TYPE codes */
+#define        VME_TYPE_TP34V          0x0034  /* Tadpole TP34V */
+#define VME_TYPE_MVME147       0x0147  /* Motorola MVME147 */
+#define VME_TYPE_MVME162       0x0162  /* Motorola MVME162 */
+#define VME_TYPE_MVME166       0x0166  /* Motorola MVME166 */
+#define VME_TYPE_MVME167       0x0167  /* Motorola MVME167 */
+#define VME_TYPE_MVME172       0x0172  /* Motorola MVME172 */
+#define VME_TYPE_MVME177       0x0177  /* Motorola MVME177 */
+#define VME_TYPE_BVME4000      0x4000  /* BVM Ltd. BVME4000 */
+#define VME_TYPE_BVME6000      0x6000  /* BVM Ltd. BVME6000 */
+
+/* BI_VME_BRDINFO is a 32 byte struct as returned by the Bug code on
+ * Motorola VME boards.  Contains board number, Bug version, board
+ * configuration options, etc.  See include/asm/mvme16xhw.h for details.
+ */
+
+
+    /*
+     *  Macintosh-specific tags (all u_long)
+     */
+
+#define BI_MAC_MODEL           0x8000  /* Mac Gestalt ID (model type) */
+#define BI_MAC_VADDR           0x8001  /* Mac video base address */
+#define BI_MAC_VDEPTH          0x8002  /* Mac video depth */
+#define BI_MAC_VROW            0x8003  /* Mac video rowbytes */
+#define BI_MAC_VDIM            0x8004  /* Mac video dimensions */
+#define BI_MAC_VLOGICAL                0x8005  /* Mac video logical base */
+#define BI_MAC_SCCBASE         0x8006  /* Mac SCC base address */
+#define BI_MAC_BTIME           0x8007  /* Mac boot time */
+#define BI_MAC_GMTBIAS         0x8008  /* Mac GMT timezone offset */
+#define BI_MAC_MEMSIZE         0x8009  /* Mac RAM size (sanity check) */
+#define BI_MAC_CPUID           0x800a  /* Mac CPU type (sanity check) */
+#define BI_MAC_ROMBASE         0x800b  /* Mac system ROM base address */
+
+    /*
+     *  Macintosh hardware profile data - unused, see macintosh.h for
+     *  resonable type values
+     */
+
+#define BI_MAC_VIA1BASE                0x8010  /* Mac VIA1 base address (always present) */
+#define BI_MAC_VIA2BASE                0x8011  /* Mac VIA2 base address (type varies) */
+#define BI_MAC_VIA2TYPE                0x8012  /* Mac VIA2 type (VIA, RBV, OSS) */
+#define BI_MAC_ADBTYPE         0x8013  /* Mac ADB interface type */
+#define BI_MAC_ASCBASE         0x8014  /* Mac Apple Sound Chip base address */
+#define BI_MAC_SCSI5380                0x8015  /* Mac NCR 5380 SCSI (base address, multi) */
+#define BI_MAC_SCSIDMA         0x8016  /* Mac SCSI DMA (base address) */
+#define BI_MAC_SCSI5396                0x8017  /* Mac NCR 53C96 SCSI (base address, multi) */
+#define BI_MAC_IDETYPE         0x8018  /* Mac IDE interface type */
+#define BI_MAC_IDEBASE         0x8019  /* Mac IDE interface base address */
+#define BI_MAC_NUBUS           0x801a  /* Mac Nubus type (none, regular, pseudo) */
+#define BI_MAC_SLOTMASK                0x801b  /* Mac Nubus slots present */
+#define BI_MAC_SCCTYPE         0x801c  /* Mac SCC serial type (normal, IOP) */
+#define BI_MAC_ETHTYPE         0x801d  /* Mac builtin ethernet type (Sonic, MACE */
+#define BI_MAC_ETHBASE         0x801e  /* Mac builtin ethernet base address */
+#define BI_MAC_PMU             0x801f  /* Mac power management / poweroff hardware */
+#define BI_MAC_IOP_SWIM                0x8020  /* Mac SWIM floppy IOP */
+#define BI_MAC_IOP_ADB         0x8021  /* Mac ADB IOP */
+
+    /*
+     * Mac: compatibility with old booter data format (temporarily)
+     * Fields unused with the new bootinfo can be deleted now; instead of
+     * adding new fields the struct might be splitted into a hardware address
+     * part and a hardware type part
+     */
+
+#ifndef __ASSEMBLY__
+
+struct mac_booter_data
+{
+       unsigned long videoaddr;
+       unsigned long videorow;
+       unsigned long videodepth;
+       unsigned long dimensions;
+       unsigned long args;
+       unsigned long boottime;
+       unsigned long gmtbias;
+       unsigned long bootver;
+       unsigned long videological;
+       unsigned long sccbase;
+       unsigned long id;
+       unsigned long memsize;
+       unsigned long serialmf;
+       unsigned long serialhsk;
+       unsigned long serialgpi;
+       unsigned long printmf;
+       unsigned long printhsk;
+       unsigned long printgpi;
+       unsigned long cpuid;
+       unsigned long rombase;
+       unsigned long adbdelay;
+       unsigned long timedbra;
+};
+
+extern struct mac_booter_data
+       mac_bi_data;
+
 #endif
+
+    /*
+     *  Apollo-specific tags
+     */
+
+#define BI_APOLLO_MODEL         0x8000  /* model (u_long) */
+
+    /*
+     *  HP300-specific tags
+     */
+
+#define BI_HP300_MODEL         0x8000  /* model (u_long) */
+#define BI_HP300_UART_SCODE    0x8001  /* UART select code (u_long) */
+#define BI_HP300_UART_ADDR     0x8002  /* phys. addr of UART (u_long) */
+
+    /*
+     * Stuff for bootinfo interface versioning
+     *
+     * At the start of kernel code, a 'struct bootversion' is located.
+     * bootstrap checks for a matching version of the interface before booting
+     * a kernel, to avoid user confusion if kernel and bootstrap don't work
+     * together :-)
+     *
+     * If incompatible changes are made to the bootinfo interface, the major
+     * number below should be stepped (and the minor reset to 0) for the
+     * appropriate machine. If a change is backward-compatible, the minor
+     * should be stepped. "Backwards-compatible" means that booting will work,
+     * but certain features may not.
+     */
+
+#define BOOTINFOV_MAGIC                        0x4249561A      /* 'BIV^Z' */
+#define MK_BI_VERSION(major,minor)     (((major)<<16)+(minor))
+#define BI_VERSION_MAJOR(v)            (((v) >> 16) & 0xffff)
+#define BI_VERSION_MINOR(v)            ((v) & 0xffff)
+
+#ifndef __ASSEMBLY__
+
+struct bootversion {
+    unsigned short branch;
+    unsigned long magic;
+    struct {
+       unsigned long machtype;
+       unsigned long version;
+    } machversions[0];
+};
+
+#endif /* __ASSEMBLY__ */
+
+#define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
+#define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
+#define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
+#define MVME147_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
+#define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
+#define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
+#define Q40_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
+#define HP300_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
+
+#ifdef BOOTINFO_COMPAT_1_0
+
+    /*
+     *  Backwards compatibility with bootinfo interface version 1.0
+     */
+
+#define COMPAT_AMIGA_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
+#define COMPAT_ATARI_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
+#define COMPAT_MAC_BOOTI_VERSION      MK_BI_VERSION( 1, 0 )
+
+#include <linux/zorro.h>
+
+#define COMPAT_NUM_AUTO    16
+
+struct compat_bi_Amiga {
+    int model;
+    int num_autocon;
+    struct ConfigDev autocon[COMPAT_NUM_AUTO];
+    unsigned long chip_size;
+    unsigned char vblank;
+    unsigned char psfreq;
+    unsigned long eclock;
+    unsigned long chipset;
+    unsigned long hw_present;
+};
+
+struct compat_bi_Atari {
+    unsigned long hw_present;
+    unsigned long mch_cookie;
+};
+
+#ifndef __ASSEMBLY__
+
+struct compat_bi_Macintosh
+{
+       unsigned long videoaddr;
+       unsigned long videorow;
+       unsigned long videodepth;
+       unsigned long dimensions;
+       unsigned long args;
+       unsigned long boottime;
+       unsigned long gmtbias;
+       unsigned long bootver;
+       unsigned long videological;
+       unsigned long sccbase;
+       unsigned long id;
+       unsigned long memsize;
+       unsigned long serialmf;
+       unsigned long serialhsk;
+       unsigned long serialgpi;
+       unsigned long printmf;
+       unsigned long printhsk;
+       unsigned long printgpi;
+       unsigned long cpuid;
+       unsigned long rombase;
+       unsigned long adbdelay;
+       unsigned long timedbra;
+};
+
+#endif
+
+struct compat_mem_info {
+    unsigned long addr;
+    unsigned long size;
+};
+
+#define COMPAT_NUM_MEMINFO  4
+
+#define COMPAT_CPUB_68020 0
+#define COMPAT_CPUB_68030 1
+#define COMPAT_CPUB_68040 2
+#define COMPAT_CPUB_68060 3
+#define COMPAT_FPUB_68881 5
+#define COMPAT_FPUB_68882 6
+#define COMPAT_FPUB_68040 7
+#define COMPAT_FPUB_68060 8
+
+#define COMPAT_CPU_68020    (1<<COMPAT_CPUB_68020)
+#define COMPAT_CPU_68030    (1<<COMPAT_CPUB_68030)
+#define COMPAT_CPU_68040    (1<<COMPAT_CPUB_68040)
+#define COMPAT_CPU_68060    (1<<COMPAT_CPUB_68060)
+#define COMPAT_CPU_MASK     (31)
+#define COMPAT_FPU_68881    (1<<COMPAT_FPUB_68881)
+#define COMPAT_FPU_68882    (1<<COMPAT_FPUB_68882)
+#define COMPAT_FPU_68040    (1<<COMPAT_FPUB_68040)
+#define COMPAT_FPU_68060    (1<<COMPAT_FPUB_68060)
+#define COMPAT_FPU_MASK     (0xfe0)
+
+#define COMPAT_CL_SIZE      (256)
+
+struct compat_bootinfo {
+    unsigned long machtype;
+    unsigned long cputype;
+    struct compat_mem_info memory[COMPAT_NUM_MEMINFO];
+    int num_memory;
+    unsigned long ramdisk_size;
+    unsigned long ramdisk_addr;
+    char command_line[COMPAT_CL_SIZE];
+    union {
+       struct compat_bi_Amiga     bi_ami;
+       struct compat_bi_Atari     bi_ata;
+       struct compat_bi_Macintosh bi_mac;
+    } bi_un;
+};
+
+#define bi_amiga       bi_un.bi_ami
+#define bi_atari       bi_un.bi_ata
+#define bi_mac         bi_un.bi_mac
+
+#endif /* BOOTINFO_COMPAT_1_0 */
+
+
+#endif /* _M68K_BOOTINFO_H */
diff --git a/arch/m68k/include/asm/bootinfo_mm.h b/arch/m68k/include/asm/bootinfo_mm.h
deleted file mode 100644 (file)
index fb8a06b..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
-** asm/bootinfo.h -- Definition of the Linux/m68k boot information structure
-**
-** Copyright 1992 by Greg Harp
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-** Created 09/29/92 by Greg Harp
-**
-** 5/2/94 Roman Hodek:
-**   Added bi_atari part of the machine dependent union bi_un; for now it
-**   contains just a model field to distinguish between TT and Falcon.
-** 26/7/96 Roman Zippel:
-**   Renamed to setup.h; added some useful macros to allow gcc some
-**   optimizations if possible.
-** 5/10/96 Geert Uytterhoeven:
-**   Redesign of the boot information structure; renamed to bootinfo.h again
-** 27/11/96 Geert Uytterhoeven:
-**   Backwards compatibility with bootinfo interface version 1.0
-*/
-
-#ifndef _M68K_BOOTINFO_H
-#define _M68K_BOOTINFO_H
-
-
-    /*
-     *  Bootinfo definitions
-     *
-     *  This is an easily parsable and extendable structure containing all
-     *  information to be passed from the bootstrap to the kernel.
-     *
-     *  This way I hope to keep all future changes back/forewards compatible.
-     *  Thus, keep your fingers crossed...
-     *
-     *  This structure is copied right after the kernel bss by the bootstrap
-     *  routine.
-     */
-
-#ifndef __ASSEMBLY__
-
-struct bi_record {
-    unsigned short tag;                        /* tag ID */
-    unsigned short size;               /* size of record (in bytes) */
-    unsigned long data[0];             /* data */
-};
-
-#endif /* __ASSEMBLY__ */
-
-
-    /*
-     *  Tag Definitions
-     *
-     *  Machine independent tags start counting from 0x0000
-     *  Machine dependent tags start counting from 0x8000
-     */
-
-#define BI_LAST                        0x0000  /* last record (sentinel) */
-#define BI_MACHTYPE            0x0001  /* machine type (u_long) */
-#define BI_CPUTYPE             0x0002  /* cpu type (u_long) */
-#define BI_FPUTYPE             0x0003  /* fpu type (u_long) */
-#define BI_MMUTYPE             0x0004  /* mmu type (u_long) */
-#define BI_MEMCHUNK            0x0005  /* memory chunk address and size */
-                                       /* (struct mem_info) */
-#define BI_RAMDISK             0x0006  /* ramdisk address and size */
-                                       /* (struct mem_info) */
-#define BI_COMMAND_LINE                0x0007  /* kernel command line parameters */
-                                       /* (string) */
-
-    /*
-     *  Amiga-specific tags
-     */
-
-#define BI_AMIGA_MODEL         0x8000  /* model (u_long) */
-#define BI_AMIGA_AUTOCON       0x8001  /* AutoConfig device */
-                                       /* (struct ConfigDev) */
-#define BI_AMIGA_CHIP_SIZE     0x8002  /* size of Chip RAM (u_long) */
-#define BI_AMIGA_VBLANK                0x8003  /* VBLANK frequency (u_char) */
-#define BI_AMIGA_PSFREQ                0x8004  /* power supply frequency (u_char) */
-#define BI_AMIGA_ECLOCK                0x8005  /* EClock frequency (u_long) */
-#define BI_AMIGA_CHIPSET       0x8006  /* native chipset present (u_long) */
-#define BI_AMIGA_SERPER                0x8007  /* serial port period (u_short) */
-
-    /*
-     *  Atari-specific tags
-     */
-
-#define BI_ATARI_MCH_COOKIE    0x8000  /* _MCH cookie from TOS (u_long) */
-#define BI_ATARI_MCH_TYPE      0x8001  /* special machine type (u_long) */
-                                       /* (values are ATARI_MACH_* defines */
-
-/* mch_cookie values (upper word) */
-#define ATARI_MCH_ST           0
-#define ATARI_MCH_STE          1
-#define ATARI_MCH_TT           2
-#define ATARI_MCH_FALCON       3
-
-/* mch_type values */
-#define ATARI_MACH_NORMAL      0       /* no special machine type */
-#define ATARI_MACH_MEDUSA      1       /* Medusa 040 */
-#define ATARI_MACH_HADES       2       /* Hades 040 or 060 */
-#define ATARI_MACH_AB40                3       /* Afterburner040 on Falcon */
-
-    /*
-     *  VME-specific tags
-     */
-
-#define BI_VME_TYPE            0x8000  /* VME sub-architecture (u_long) */
-#define BI_VME_BRDINFO         0x8001  /* VME board information (struct) */
-
-/* BI_VME_TYPE codes */
-#define        VME_TYPE_TP34V          0x0034  /* Tadpole TP34V */
-#define VME_TYPE_MVME147       0x0147  /* Motorola MVME147 */
-#define VME_TYPE_MVME162       0x0162  /* Motorola MVME162 */
-#define VME_TYPE_MVME166       0x0166  /* Motorola MVME166 */
-#define VME_TYPE_MVME167       0x0167  /* Motorola MVME167 */
-#define VME_TYPE_MVME172       0x0172  /* Motorola MVME172 */
-#define VME_TYPE_MVME177       0x0177  /* Motorola MVME177 */
-#define VME_TYPE_BVME4000      0x4000  /* BVM Ltd. BVME4000 */
-#define VME_TYPE_BVME6000      0x6000  /* BVM Ltd. BVME6000 */
-
-/* BI_VME_BRDINFO is a 32 byte struct as returned by the Bug code on
- * Motorola VME boards.  Contains board number, Bug version, board
- * configuration options, etc.  See include/asm/mvme16xhw.h for details.
- */
-
-
-    /*
-     *  Macintosh-specific tags (all u_long)
-     */
-
-#define BI_MAC_MODEL           0x8000  /* Mac Gestalt ID (model type) */
-#define BI_MAC_VADDR           0x8001  /* Mac video base address */
-#define BI_MAC_VDEPTH          0x8002  /* Mac video depth */
-#define BI_MAC_VROW            0x8003  /* Mac video rowbytes */
-#define BI_MAC_VDIM            0x8004  /* Mac video dimensions */
-#define BI_MAC_VLOGICAL                0x8005  /* Mac video logical base */
-#define BI_MAC_SCCBASE         0x8006  /* Mac SCC base address */
-#define BI_MAC_BTIME           0x8007  /* Mac boot time */
-#define BI_MAC_GMTBIAS         0x8008  /* Mac GMT timezone offset */
-#define BI_MAC_MEMSIZE         0x8009  /* Mac RAM size (sanity check) */
-#define BI_MAC_CPUID           0x800a  /* Mac CPU type (sanity check) */
-#define BI_MAC_ROMBASE         0x800b  /* Mac system ROM base address */
-
-    /*
-     *  Macintosh hardware profile data - unused, see macintosh.h for
-     *  resonable type values
-     */
-
-#define BI_MAC_VIA1BASE                0x8010  /* Mac VIA1 base address (always present) */
-#define BI_MAC_VIA2BASE                0x8011  /* Mac VIA2 base address (type varies) */
-#define BI_MAC_VIA2TYPE                0x8012  /* Mac VIA2 type (VIA, RBV, OSS) */
-#define BI_MAC_ADBTYPE         0x8013  /* Mac ADB interface type */
-#define BI_MAC_ASCBASE         0x8014  /* Mac Apple Sound Chip base address */
-#define BI_MAC_SCSI5380                0x8015  /* Mac NCR 5380 SCSI (base address, multi) */
-#define BI_MAC_SCSIDMA         0x8016  /* Mac SCSI DMA (base address) */
-#define BI_MAC_SCSI5396                0x8017  /* Mac NCR 53C96 SCSI (base address, multi) */
-#define BI_MAC_IDETYPE         0x8018  /* Mac IDE interface type */
-#define BI_MAC_IDEBASE         0x8019  /* Mac IDE interface base address */
-#define BI_MAC_NUBUS           0x801a  /* Mac Nubus type (none, regular, pseudo) */
-#define BI_MAC_SLOTMASK                0x801b  /* Mac Nubus slots present */
-#define BI_MAC_SCCTYPE         0x801c  /* Mac SCC serial type (normal, IOP) */
-#define BI_MAC_ETHTYPE         0x801d  /* Mac builtin ethernet type (Sonic, MACE */
-#define BI_MAC_ETHBASE         0x801e  /* Mac builtin ethernet base address */
-#define BI_MAC_PMU             0x801f  /* Mac power management / poweroff hardware */
-#define BI_MAC_IOP_SWIM                0x8020  /* Mac SWIM floppy IOP */
-#define BI_MAC_IOP_ADB         0x8021  /* Mac ADB IOP */
-
-    /*
-     * Mac: compatibility with old booter data format (temporarily)
-     * Fields unused with the new bootinfo can be deleted now; instead of
-     * adding new fields the struct might be splitted into a hardware address
-     * part and a hardware type part
-     */
-
-#ifndef __ASSEMBLY__
-
-struct mac_booter_data
-{
-       unsigned long videoaddr;
-       unsigned long videorow;
-       unsigned long videodepth;
-       unsigned long dimensions;
-       unsigned long args;
-       unsigned long boottime;
-       unsigned long gmtbias;
-       unsigned long bootver;
-       unsigned long videological;
-       unsigned long sccbase;
-       unsigned long id;
-       unsigned long memsize;
-       unsigned long serialmf;
-       unsigned long serialhsk;
-       unsigned long serialgpi;
-       unsigned long printmf;
-       unsigned long printhsk;
-       unsigned long printgpi;
-       unsigned long cpuid;
-       unsigned long rombase;
-       unsigned long adbdelay;
-       unsigned long timedbra;
-};
-
-extern struct mac_booter_data
-       mac_bi_data;
-
-#endif
-
-    /*
-     *  Apollo-specific tags
-     */
-
-#define BI_APOLLO_MODEL         0x8000  /* model (u_long) */
-
-    /*
-     *  HP300-specific tags
-     */
-
-#define BI_HP300_MODEL         0x8000  /* model (u_long) */
-#define BI_HP300_UART_SCODE    0x8001  /* UART select code (u_long) */
-#define BI_HP300_UART_ADDR     0x8002  /* phys. addr of UART (u_long) */
-
-    /*
-     * Stuff for bootinfo interface versioning
-     *
-     * At the start of kernel code, a 'struct bootversion' is located.
-     * bootstrap checks for a matching version of the interface before booting
-     * a kernel, to avoid user confusion if kernel and bootstrap don't work
-     * together :-)
-     *
-     * If incompatible changes are made to the bootinfo interface, the major
-     * number below should be stepped (and the minor reset to 0) for the
-     * appropriate machine. If a change is backward-compatible, the minor
-     * should be stepped. "Backwards-compatible" means that booting will work,
-     * but certain features may not.
-     */
-
-#define BOOTINFOV_MAGIC                        0x4249561A      /* 'BIV^Z' */
-#define MK_BI_VERSION(major,minor)     (((major)<<16)+(minor))
-#define BI_VERSION_MAJOR(v)            (((v) >> 16) & 0xffff)
-#define BI_VERSION_MINOR(v)            ((v) & 0xffff)
-
-#ifndef __ASSEMBLY__
-
-struct bootversion {
-    unsigned short branch;
-    unsigned long magic;
-    struct {
-       unsigned long machtype;
-       unsigned long version;
-    } machversions[0];
-};
-
-#endif /* __ASSEMBLY__ */
-
-#define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
-#define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
-#define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
-#define MVME147_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
-#define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
-#define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
-#define Q40_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
-#define HP300_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
-
-#ifdef BOOTINFO_COMPAT_1_0
-
-    /*
-     *  Backwards compatibility with bootinfo interface version 1.0
-     */
-
-#define COMPAT_AMIGA_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
-#define COMPAT_ATARI_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
-#define COMPAT_MAC_BOOTI_VERSION      MK_BI_VERSION( 1, 0 )
-
-#include <linux/zorro.h>
-
-#define COMPAT_NUM_AUTO    16
-
-struct compat_bi_Amiga {
-    int model;
-    int num_autocon;
-    struct ConfigDev autocon[COMPAT_NUM_AUTO];
-    unsigned long chip_size;
-    unsigned char vblank;
-    unsigned char psfreq;
-    unsigned long eclock;
-    unsigned long chipset;
-    unsigned long hw_present;
-};
-
-struct compat_bi_Atari {
-    unsigned long hw_present;
-    unsigned long mch_cookie;
-};
-
-#ifndef __ASSEMBLY__
-
-struct compat_bi_Macintosh
-{
-       unsigned long videoaddr;
-       unsigned long videorow;
-       unsigned long videodepth;
-       unsigned long dimensions;
-       unsigned long args;
-       unsigned long boottime;
-       unsigned long gmtbias;
-       unsigned long bootver;
-       unsigned long videological;
-       unsigned long sccbase;
-       unsigned long id;
-       unsigned long memsize;
-       unsigned long serialmf;
-       unsigned long serialhsk;
-       unsigned long serialgpi;
-       unsigned long printmf;
-       unsigned long printhsk;
-       unsigned long printgpi;
-       unsigned long cpuid;
-       unsigned long rombase;
-       unsigned long adbdelay;
-       unsigned long timedbra;
-};
-
-#endif
-
-struct compat_mem_info {
-    unsigned long addr;
-    unsigned long size;
-};
-
-#define COMPAT_NUM_MEMINFO  4
-
-#define COMPAT_CPUB_68020 0
-#define COMPAT_CPUB_68030 1
-#define COMPAT_CPUB_68040 2
-#define COMPAT_CPUB_68060 3
-#define COMPAT_FPUB_68881 5
-#define COMPAT_FPUB_68882 6
-#define COMPAT_FPUB_68040 7
-#define COMPAT_FPUB_68060 8
-
-#define COMPAT_CPU_68020    (1<<COMPAT_CPUB_68020)
-#define COMPAT_CPU_68030    (1<<COMPAT_CPUB_68030)
-#define COMPAT_CPU_68040    (1<<COMPAT_CPUB_68040)
-#define COMPAT_CPU_68060    (1<<COMPAT_CPUB_68060)
-#define COMPAT_CPU_MASK     (31)
-#define COMPAT_FPU_68881    (1<<COMPAT_FPUB_68881)
-#define COMPAT_FPU_68882    (1<<COMPAT_FPUB_68882)
-#define COMPAT_FPU_68040    (1<<COMPAT_FPUB_68040)
-#define COMPAT_FPU_68060    (1<<COMPAT_FPUB_68060)
-#define COMPAT_FPU_MASK     (0xfe0)
-
-#define COMPAT_CL_SIZE      (256)
-
-struct compat_bootinfo {
-    unsigned long machtype;
-    unsigned long cputype;
-    struct compat_mem_info memory[COMPAT_NUM_MEMINFO];
-    int num_memory;
-    unsigned long ramdisk_size;
-    unsigned long ramdisk_addr;
-    char command_line[COMPAT_CL_SIZE];
-    union {
-       struct compat_bi_Amiga     bi_ami;
-       struct compat_bi_Atari     bi_ata;
-       struct compat_bi_Macintosh bi_mac;
-    } bi_un;
-};
-
-#define bi_amiga       bi_un.bi_ami
-#define bi_atari       bi_un.bi_ata
-#define bi_mac         bi_un.bi_mac
-
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
-#endif /* _M68K_BOOTINFO_H */
diff --git a/arch/m68k/include/asm/bootinfo_no.h b/arch/m68k/include/asm/bootinfo_no.h
deleted file mode 100644 (file)
index c12e526..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-
-/* Nothing for m68knommu */
index 997e0944ebc1568c2609bf3c13ef8fd73482f620..ef9a2e47352f0d8a03c55ccb2c32966b1e0d748f 100644 (file)
@@ -1,5 +1,30 @@
-#ifdef __uClinux__
-#include "bug_no.h"
+#ifndef _M68K_BUG_H
+#define _M68K_BUG_H
+
+#ifdef CONFIG_MMU
+#ifdef CONFIG_BUG
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#ifndef CONFIG_SUN3
+#define BUG() do { \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+       __builtin_trap(); \
+} while (0)
 #else
-#include "bug_mm.h"
+#define BUG() do { \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+       panic("BUG!"); \
+} while (0)
+#endif
+#else
+#define BUG() do { \
+       __builtin_trap(); \
+} while (0)
+#endif
+
+#define HAVE_ARCH_BUG
+#endif
+#endif /* CONFIG_MMU */
+
+#include <asm-generic/bug.h>
+
 #endif
diff --git a/arch/m68k/include/asm/bug_mm.h b/arch/m68k/include/asm/bug_mm.h
deleted file mode 100644 (file)
index e5b528d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _M68K_BUG_H
-#define _M68K_BUG_H
-
-
-#ifdef CONFIG_BUG
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-#ifndef CONFIG_SUN3
-#define BUG() do { \
-       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-       __builtin_trap(); \
-} while (0)
-#else
-#define BUG() do { \
-       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-       panic("BUG!"); \
-} while (0)
-#endif
-#else
-#define BUG() do { \
-       __builtin_trap(); \
-} while (0)
-#endif
-
-#define HAVE_ARCH_BUG
-#endif
-
-#include <asm-generic/bug.h>
-
-#endif
diff --git a/arch/m68k/include/asm/bug_no.h b/arch/m68k/include/asm/bug_no.h
deleted file mode 100644 (file)
index 70e7dc0..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef _M68KNOMMU_BUG_H
-#define _M68KNOMMU_BUG_H
-#include <asm-generic/bug.h>
-#endif
index 01f047d784ec1e6ca568a82a06afdb29ddd2bd01..d06207b9ba5ad25f449831d72975f1136b0d3207 100644 (file)
@@ -1,5 +1,20 @@
-#ifdef __uClinux__
-#include "bugs_no.h"
+/*
+ *  include/asm-m68k/bugs.h
+ *
+ *  Copyright (C) 1994  Linus Torvalds
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *     void check_bugs(void);
+ */
+
+#ifdef CONFIG_MMU
+extern void check_bugs(void);  /* in arch/m68k/kernel/setup.c */
 #else
-#include "bugs_mm.h"
+static void check_bugs(void)
+{
+}
 #endif
diff --git a/arch/m68k/include/asm/bugs_mm.h b/arch/m68k/include/asm/bugs_mm.h
deleted file mode 100644 (file)
index d019355..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  include/asm-m68k/bugs.h
- *
- *  Copyright (C) 1994  Linus Torvalds
- */
-
-/*
- * This is included by init/main.c to check for architecture-dependent bugs.
- *
- * Needs:
- *     void check_bugs(void);
- */
-
-extern void check_bugs(void);  /* in arch/m68k/kernel/setup.c */
diff --git a/arch/m68k/include/asm/bugs_no.h b/arch/m68k/include/asm/bugs_no.h
deleted file mode 100644 (file)
index 5f382da..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  include/asm-m68k/bugs.h
- *
- *  Copyright (C) 1994  Linus Torvalds
- */
-
-/*
- * This is included by init/main.c to check for architecture-dependent bugs.
- *
- * Needs:
- *     void check_bugs(void);
- */
-
-static void check_bugs(void)
-{
-}
index 599c29bc8f40c9a958edbeaabcaf36ee8482d44f..fed3fd30de7e468797a85ff5945119c436f92fce 100644 (file)
@@ -1,5 +1,11 @@
-#ifdef __uClinux__
-#include "cache_no.h"
-#else
-#include "cache_mm.h"
+/*
+ * include/asm-m68k/cache.h
+ */
+#ifndef __ARCH_M68K_CACHE_H
+#define __ARCH_M68K_CACHE_H
+
+/* bytes per L1 cache line */
+#define        L1_CACHE_SHIFT  4
+#define        L1_CACHE_BYTES  (1<< L1_CACHE_SHIFT)
+
 #endif
diff --git a/arch/m68k/include/asm/cache_mm.h b/arch/m68k/include/asm/cache_mm.h
deleted file mode 100644 (file)
index fed3fd3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * include/asm-m68k/cache.h
- */
-#ifndef __ARCH_M68K_CACHE_H
-#define __ARCH_M68K_CACHE_H
-
-/* bytes per L1 cache line */
-#define        L1_CACHE_SHIFT  4
-#define        L1_CACHE_BYTES  (1<< L1_CACHE_SHIFT)
-
-#endif
diff --git a/arch/m68k/include/asm/cache_no.h b/arch/m68k/include/asm/cache_no.h
deleted file mode 100644 (file)
index 24e9eac..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __ARCH_M68KNOMMU_CACHE_H
-#define __ARCH_M68KNOMMU_CACHE_H
-
-/* bytes per L1 cache line */
-#define        L1_CACHE_BYTES  16      /* this need to be at least 1 */
-
-/* m68k-elf-gcc  2.95.2 doesn't like these */
-
-#define __cacheline_aligned
-#define ____cacheline_aligned
-
-#endif
index 51b056dfaedd7f2bdfcb42582769eb546472257c..91fcc5358cfea7c77b44e62792bb1e6ae497180f 100644 (file)
@@ -1,5 +1,28 @@
-#ifdef __uClinux__
-#include "current_no.h"
+#ifndef _M68K_CURRENT_H
+#define _M68K_CURRENT_H
+
+#ifdef CONFIG_MMU
+
+register struct task_struct *current __asm__("%a2");
+
 #else
-#include "current_mm.h"
-#endif
+
+/*
+ *     Rather than dedicate a register (as the m68k source does), we
+ *     just keep a global,  we should probably just change it all to be
+ *     current and lose _current_task.
+ */
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static inline struct task_struct *get_current(void)
+{
+       return(current_thread_info()->task);
+}
+
+#define        current get_current()
+
+#endif /* CONFNIG_MMU */
+
+#endif /* !(_M68K_CURRENT_H) */
diff --git a/arch/m68k/include/asm/current_mm.h b/arch/m68k/include/asm/current_mm.h
deleted file mode 100644 (file)
index 8de8f8c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_CURRENT_H
-#define _M68K_CURRENT_H
-
-register struct task_struct *current __asm__("%a2");
-
-#endif /* !(_M68K_CURRENT_H) */
diff --git a/arch/m68k/include/asm/current_no.h b/arch/m68k/include/asm/current_no.h
deleted file mode 100644 (file)
index 53ee0f9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _M68KNOMMU_CURRENT_H
-#define _M68KNOMMU_CURRENT_H
-/*
- *     current.h
- *     (C) Copyright 2000, Lineo, David McCullough <davidm@uclinux.org>
- *     (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
- *
- *     rather than dedicate a register (as the m68k source does), we
- *     just keep a global,  we should probably just change it all to be
- *     current and lose _current_task.
- */
-
-#include <linux/thread_info.h>
-
-struct task_struct;
-
-static inline struct task_struct *get_current(void)
-{
-       return(current_thread_info()->task);
-}
-
-#define        current get_current()
-
-#endif /* _M68KNOMMU_CURRENT_H */
index d211d9f54276766317f725a168f0461008381b1f..edb66148a71dc85886e3112d9af2f08019d7856e 100644 (file)
@@ -1,5 +1,34 @@
-#ifdef __uClinux__
-#include "div64_no.h"
+#ifndef _M68K_DIV64_H
+#define _M68K_DIV64_H
+
+#ifdef CONFIG_MMU
+
+#include <linux/types.h>
+
+/* n = n / base; return rem; */
+
+#define do_div(n, base) ({                                     \
+       union {                                                 \
+               unsigned long n32[2];                           \
+               unsigned long long n64;                         \
+       } __n;                                                  \
+       unsigned long __rem, __upper;                           \
+                                                               \
+       __n.n64 = (n);                                          \
+       if ((__upper = __n.n32[0])) {                           \
+               asm ("divul.l %2,%1:%0"                         \
+                       : "=d" (__n.n32[0]), "=d" (__upper)     \
+                       : "d" (base), "0" (__n.n32[0]));        \
+       }                                                       \
+       asm ("divu.l %2,%1:%0"                                  \
+               : "=d" (__n.n32[1]), "=d" (__rem)               \
+               : "d" (base), "1" (__upper), "0" (__n.n32[1])); \
+       (n) = __n.n64;                                          \
+       __rem;                                                  \
+})
+
 #else
-#include "div64_mm.h"
-#endif
+#include <asm-generic/div64.h>
+#endif /* CONFIG_MMU */
+
+#endif /* _M68K_DIV64_H */
diff --git a/arch/m68k/include/asm/div64_mm.h b/arch/m68k/include/asm/div64_mm.h
deleted file mode 100644 (file)
index 8243c93..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _M68K_DIV64_H
-#define _M68K_DIV64_H
-
-#include <linux/types.h>
-
-/* n = n / base; return rem; */
-
-#define do_div(n, base) ({                                     \
-       union {                                                 \
-               unsigned long n32[2];                           \
-               unsigned long long n64;                         \
-       } __n;                                                  \
-       unsigned long __rem, __upper;                           \
-                                                               \
-       __n.n64 = (n);                                          \
-       if ((__upper = __n.n32[0])) {                           \
-               asm ("divul.l %2,%1:%0"                         \
-                       : "=d" (__n.n32[0]), "=d" (__upper)     \
-                       : "d" (base), "0" (__n.n32[0]));        \
-       }                                                       \
-       asm ("divu.l %2,%1:%0"                                  \
-               : "=d" (__n.n32[1]), "=d" (__rem)               \
-               : "d" (base), "1" (__upper), "0" (__n.n32[1])); \
-       (n) = __n.n64;                                          \
-       __rem;                                                  \
-})
-
-#endif /* _M68K_DIV64_H */
diff --git a/arch/m68k/include/asm/div64_no.h b/arch/m68k/include/asm/div64_no.h
deleted file mode 100644 (file)
index 6cd978c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/div64.h>
index f4a4c7638f898997c5346c8f1564b819dafdca9a..26f505488c1197dbe004cc6486d8c41c7285ab65 100644 (file)
@@ -1,5 +1,112 @@
-#ifdef __uClinux__
-#include "dma-mapping_no.h"
+#ifndef _M68K_DMA_MAPPING_H
+#define _M68K_DMA_MAPPING_H
+
+#include <asm/cache.h>
+
+struct scatterlist;
+
+#ifndef CONFIG_MMU_SUN3
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+       return 1;
+}
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+       return 0;
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+       return 1 << L1_CACHE_SHIFT;
+}
+
+static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
+{
+       return 0;
+}
+
+extern void *dma_alloc_coherent(struct device *, size_t,
+                               dma_addr_t *, gfp_t);
+extern void dma_free_coherent(struct device *, size_t,
+                             void *, dma_addr_t);
+
+static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
+                                         dma_addr_t *handle, gfp_t flag)
+{
+       return dma_alloc_coherent(dev, size, handle, flag);
+}
+static inline void dma_free_noncoherent(struct device *dev, size_t size,
+                                       void *addr, dma_addr_t handle)
+{
+       dma_free_coherent(dev, size, addr, handle);
+}
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+                                 enum dma_data_direction dir)
+{
+       /* we use coherent allocation, so not much to do here. */
+}
+
+extern dma_addr_t dma_map_single(struct device *, void *, size_t,
+                                enum dma_data_direction);
+static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
+                                   size_t size, enum dma_data_direction dir)
+{
+}
+
+extern dma_addr_t dma_map_page(struct device *, struct page *,
+                              unsigned long, size_t size,
+                              enum dma_data_direction);
+static inline void dma_unmap_page(struct device *dev, dma_addr_t address,
+                                 size_t size, enum dma_data_direction dir)
+{
+}
+
+extern int dma_map_sg(struct device *, struct scatterlist *, int,
+                     enum dma_data_direction);
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                               int nhwentries, enum dma_data_direction dir)
+{
+}
+
+extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
+                                      enum dma_data_direction);
+extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
+                                  enum dma_data_direction);
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+               dma_addr_t dma_handle, unsigned long offset, size_t size,
+               enum dma_data_direction direction)
+{
+       /* just sync everything for now */
+       dma_sync_single_for_device(dev, dma_handle, offset + size, direction);
+}
+
+static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
+                                          size_t size, enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                                      int nents, enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+               dma_addr_t dma_handle, unsigned long offset, size_t size,
+               enum dma_data_direction direction)
+{
+       /* just sync everything for now */
+       dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction);
+}
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t handle)
+{
+       return 0;
+}
+
 #else
-#include "dma-mapping_mm.h"
+#include <asm-generic/dma-mapping-broken.h>
 #endif
+
+#endif  /* _M68K_DMA_MAPPING_H */
diff --git a/arch/m68k/include/asm/dma-mapping_mm.h b/arch/m68k/include/asm/dma-mapping_mm.h
deleted file mode 100644 (file)
index 26f5054..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef _M68K_DMA_MAPPING_H
-#define _M68K_DMA_MAPPING_H
-
-#include <asm/cache.h>
-
-struct scatterlist;
-
-#ifndef CONFIG_MMU_SUN3
-static inline int dma_supported(struct device *dev, u64 mask)
-{
-       return 1;
-}
-
-static inline int dma_set_mask(struct device *dev, u64 mask)
-{
-       return 0;
-}
-
-static inline int dma_get_cache_alignment(void)
-{
-       return 1 << L1_CACHE_SHIFT;
-}
-
-static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
-{
-       return 0;
-}
-
-extern void *dma_alloc_coherent(struct device *, size_t,
-                               dma_addr_t *, gfp_t);
-extern void dma_free_coherent(struct device *, size_t,
-                             void *, dma_addr_t);
-
-static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
-                                         dma_addr_t *handle, gfp_t flag)
-{
-       return dma_alloc_coherent(dev, size, handle, flag);
-}
-static inline void dma_free_noncoherent(struct device *dev, size_t size,
-                                       void *addr, dma_addr_t handle)
-{
-       dma_free_coherent(dev, size, addr, handle);
-}
-static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-                                 enum dma_data_direction dir)
-{
-       /* we use coherent allocation, so not much to do here. */
-}
-
-extern dma_addr_t dma_map_single(struct device *, void *, size_t,
-                                enum dma_data_direction);
-static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
-                                   size_t size, enum dma_data_direction dir)
-{
-}
-
-extern dma_addr_t dma_map_page(struct device *, struct page *,
-                              unsigned long, size_t size,
-                              enum dma_data_direction);
-static inline void dma_unmap_page(struct device *dev, dma_addr_t address,
-                                 size_t size, enum dma_data_direction dir)
-{
-}
-
-extern int dma_map_sg(struct device *, struct scatterlist *, int,
-                     enum dma_data_direction);
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                               int nhwentries, enum dma_data_direction dir)
-{
-}
-
-extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
-                                      enum dma_data_direction);
-extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
-                                  enum dma_data_direction);
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
-{
-       /* just sync everything for now */
-       dma_sync_single_for_device(dev, dma_handle, offset + size, direction);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
-                                          size_t size, enum dma_data_direction dir)
-{
-}
-
-static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-                                      int nents, enum dma_data_direction dir)
-{
-}
-
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
-{
-       /* just sync everything for now */
-       dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction);
-}
-
-static inline int dma_mapping_error(struct device *dev, dma_addr_t handle)
-{
-       return 0;
-}
-
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif
-
-#endif  /* _M68K_DMA_MAPPING_H */
diff --git a/arch/m68k/include/asm/dma-mapping_no.h b/arch/m68k/include/asm/dma-mapping_no.h
deleted file mode 100644 (file)
index 1748f2b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68KNOMMU_DMA_MAPPING_H
-#define _M68KNOMMU_DMA_MAPPING_H
-
-#include <asm-generic/dma-mapping-broken.h>
-
-#endif  /* _M68KNOMMU_DMA_MAPPING_H */
index 04ce488bc63f8d5622c1894c00bbeda2781433c2..0b0f49eb876b11db0ce7eb6cd1703be2657fbd54 100644 (file)
@@ -1,5 +1,119 @@
-#ifdef __uClinux__
-#include "elf_no.h"
+#ifndef __ASMm68k_ELF_H
+#define __ASMm68k_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+/*
+ * 68k ELF relocation types
+ */
+#define R_68K_NONE     0
+#define R_68K_32       1
+#define R_68K_16       2
+#define R_68K_8                3
+#define R_68K_PC32     4
+#define R_68K_PC16     5
+#define R_68K_PC8      6
+#define R_68K_GOT32    7
+#define R_68K_GOT16    8
+#define R_68K_GOT8     9
+#define R_68K_GOT32O   10
+#define R_68K_GOT16O   11
+#define R_68K_GOT8O    12
+#define R_68K_PLT32    13
+#define R_68K_PLT16    14
+#define R_68K_PLT8     15
+#define R_68K_PLT32O   16
+#define R_68K_PLT16O   17
+#define R_68K_PLT8O    18
+#define R_68K_COPY     19
+#define R_68K_GLOB_DAT 20
+#define R_68K_JMP_SLOT 21
+#define R_68K_RELATIVE 22
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_m68kfp_struct elf_fpregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_68K)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS      ELFCLASS32
+#define ELF_DATA       ELFDATA2MSB
+#define ELF_ARCH       EM_68K
+
+/* For SVR4/m68k the function pointer to be registered with `atexit' is
+   passed in %a1.  Although my copy of the ABI has no such statement, it
+   is actually used on ASV.  */
+#define ELF_PLAT_INIT(_r, load_addr)   _r->a1 = 0
+
+#define USE_ELF_CORE_DUMP
+#ifndef CONFIG_SUN3
+#define ELF_EXEC_PAGESIZE      4096
 #else
-#include "elf_mm.h"
+#define ELF_EXEC_PAGESIZE      8192
+#endif
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+   use of this is to invoke "./ld.so someprog" to test out a new version of
+   the loader.  We need to make sure that it is out of the way of the program
+   that it will "exec", and that there is sufficient room for the brk.  */
+
+#ifndef CONFIG_SUN3
+#define ELF_ET_DYN_BASE         0xD0000000UL
+#else
+#define ELF_ET_DYN_BASE         0x0D800000UL
+#endif
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs)                               \
+       /* Bleech. */                                                   \
+       pr_reg[0] = regs->d1;                                           \
+       pr_reg[1] = regs->d2;                                           \
+       pr_reg[2] = regs->d3;                                           \
+       pr_reg[3] = regs->d4;                                           \
+       pr_reg[4] = regs->d5;                                           \
+       pr_reg[7] = regs->a0;                                           \
+       pr_reg[8] = regs->a1;                                           \
+       pr_reg[9] = regs->a2;                                           \
+       pr_reg[14] = regs->d0;                                          \
+       pr_reg[15] = rdusp();                                           \
+       pr_reg[16] = regs->orig_d0;                                     \
+       pr_reg[17] = regs->sr;                                          \
+       pr_reg[18] = regs->pc;                                          \
+       pr_reg[19] = (regs->format << 12) | regs->vector;               \
+       {                                                               \
+         struct switch_stack *sw = ((struct switch_stack *)regs) - 1;  \
+         pr_reg[5] = sw->d6;                                           \
+         pr_reg[6] = sw->d7;                                           \
+         pr_reg[10] = sw->a3;                                          \
+         pr_reg[11] = sw->a4;                                          \
+         pr_reg[12] = sw->a5;                                          \
+         pr_reg[13] = sw->a6;                                          \
+       }
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  */
+
+#define ELF_HWCAP      (0)
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.  */
+
+#define ELF_PLATFORM  (NULL)
+
+#define SET_PERSONALITY(ex) set_personality(PER_LINUX)
+
 #endif
diff --git a/arch/m68k/include/asm/elf_mm.h b/arch/m68k/include/asm/elf_mm.h
deleted file mode 100644 (file)
index 0b0f49e..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef __ASMm68k_ELF_H
-#define __ASMm68k_ELF_H
-
-/*
- * ELF register definitions..
- */
-
-#include <asm/ptrace.h>
-#include <asm/user.h>
-
-/*
- * 68k ELF relocation types
- */
-#define R_68K_NONE     0
-#define R_68K_32       1
-#define R_68K_16       2
-#define R_68K_8                3
-#define R_68K_PC32     4
-#define R_68K_PC16     5
-#define R_68K_PC8      6
-#define R_68K_GOT32    7
-#define R_68K_GOT16    8
-#define R_68K_GOT8     9
-#define R_68K_GOT32O   10
-#define R_68K_GOT16O   11
-#define R_68K_GOT8O    12
-#define R_68K_PLT32    13
-#define R_68K_PLT16    14
-#define R_68K_PLT8     15
-#define R_68K_PLT32O   16
-#define R_68K_PLT16O   17
-#define R_68K_PLT8O    18
-#define R_68K_COPY     19
-#define R_68K_GLOB_DAT 20
-#define R_68K_JMP_SLOT 21
-#define R_68K_RELATIVE 22
-
-typedef unsigned long elf_greg_t;
-
-#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef struct user_m68kfp_struct elf_fpregset_t;
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ((x)->e_machine == EM_68K)
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS      ELFCLASS32
-#define ELF_DATA       ELFDATA2MSB
-#define ELF_ARCH       EM_68K
-
-/* For SVR4/m68k the function pointer to be registered with `atexit' is
-   passed in %a1.  Although my copy of the ABI has no such statement, it
-   is actually used on ASV.  */
-#define ELF_PLAT_INIT(_r, load_addr)   _r->a1 = 0
-
-#define USE_ELF_CORE_DUMP
-#ifndef CONFIG_SUN3
-#define ELF_EXEC_PAGESIZE      4096
-#else
-#define ELF_EXEC_PAGESIZE      8192
-#endif
-
-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-   use of this is to invoke "./ld.so someprog" to test out a new version of
-   the loader.  We need to make sure that it is out of the way of the program
-   that it will "exec", and that there is sufficient room for the brk.  */
-
-#ifndef CONFIG_SUN3
-#define ELF_ET_DYN_BASE         0xD0000000UL
-#else
-#define ELF_ET_DYN_BASE         0x0D800000UL
-#endif
-
-#define ELF_CORE_COPY_REGS(pr_reg, regs)                               \
-       /* Bleech. */                                                   \
-       pr_reg[0] = regs->d1;                                           \
-       pr_reg[1] = regs->d2;                                           \
-       pr_reg[2] = regs->d3;                                           \
-       pr_reg[3] = regs->d4;                                           \
-       pr_reg[4] = regs->d5;                                           \
-       pr_reg[7] = regs->a0;                                           \
-       pr_reg[8] = regs->a1;                                           \
-       pr_reg[9] = regs->a2;                                           \
-       pr_reg[14] = regs->d0;                                          \
-       pr_reg[15] = rdusp();                                           \
-       pr_reg[16] = regs->orig_d0;                                     \
-       pr_reg[17] = regs->sr;                                          \
-       pr_reg[18] = regs->pc;                                          \
-       pr_reg[19] = (regs->format << 12) | regs->vector;               \
-       {                                                               \
-         struct switch_stack *sw = ((struct switch_stack *)regs) - 1;  \
-         pr_reg[5] = sw->d6;                                           \
-         pr_reg[6] = sw->d7;                                           \
-         pr_reg[10] = sw->a3;                                          \
-         pr_reg[11] = sw->a4;                                          \
-         pr_reg[12] = sw->a5;                                          \
-         pr_reg[13] = sw->a6;                                          \
-       }
-
-/* This yields a mask that user programs can use to figure out what
-   instruction set this cpu supports.  */
-
-#define ELF_HWCAP      (0)
-
-/* This yields a string that ld.so will use to load implementation
-   specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.  */
-
-#define ELF_PLATFORM  (NULL)
-
-#define SET_PERSONALITY(ex) set_personality(PER_LINUX)
-
-#endif
diff --git a/arch/m68k/include/asm/elf_no.h b/arch/m68k/include/asm/elf_no.h
deleted file mode 100644 (file)
index b804683..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#ifndef __ASMm68k_ELF_H
-#define __ASMm68k_ELF_H
-
-/*
- * ELF register definitions..
- */
-
-#include <asm/ptrace.h>
-#include <asm/user.h>
-
-/*
- * 68k ELF relocation types
- */
-#define R_68K_NONE  0
-#define R_68K_32    1
-#define R_68K_16    2
-#define R_68K_8     3
-#define R_68K_PC32  4
-#define R_68K_PC16  5
-#define R_68K_PC8   6
-#define R_68K_GOT32 7
-#define R_68K_GOT16 8
-#define R_68K_GOT8  9
-#define R_68K_GOT32O    10
-#define R_68K_GOT16O    11
-#define R_68K_GOT8O 12
-#define R_68K_PLT32 13
-#define R_68K_PLT16 14
-#define R_68K_PLT8  15
-#define R_68K_PLT32O    16
-#define R_68K_PLT16O    17
-#define R_68K_PLT8O 18
-#define R_68K_COPY  19
-#define R_68K_GLOB_DAT  20
-#define R_68K_JMP_SLOT  21
-#define R_68K_RELATIVE  22
-
-typedef unsigned long elf_greg_t;
-
-#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef struct user_m68kfp_struct elf_fpregset_t;
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ((x)->e_machine == EM_68K)
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS      ELFCLASS32
-#define ELF_DATA       ELFDATA2MSB
-#define ELF_ARCH       EM_68K
-
-/* For SVR4/m68k the function pointer to be registered with `atexit' is
-   passed in %a1.  Although my copy of the ABI has no such statement, it
-   is actually used on ASV.  */
-#define ELF_PLAT_INIT(_r, load_addr)   _r->a1 = 0
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE      4096
-
-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-   use of this is to invoke "./ld.so someprog" to test out a new version of
-   the loader.  We need to make sure that it is out of the way of the program
-   that it will "exec", and that there is sufficient room for the brk.  */
-
-#define ELF_ET_DYN_BASE         0xD0000000UL
-
-#define ELF_CORE_COPY_REGS(pr_reg, regs)                               \
-       /* Bleech. */                                                   \
-       pr_reg[0] = regs->d1;                                           \
-       pr_reg[1] = regs->d2;                                           \
-       pr_reg[2] = regs->d3;                                           \
-       pr_reg[3] = regs->d4;                                           \
-       pr_reg[4] = regs->d5;                                           \
-       pr_reg[7] = regs->a0;                                           \
-       pr_reg[8] = regs->a1;                                           \
-       pr_reg[14] = regs->d0;                                          \
-       pr_reg[15] = rdusp();                                           \
-       pr_reg[16] = 0 /* regs->orig_d0 */;                             \
-       pr_reg[17] = regs->sr;                                          \
-       pr_reg[18] = regs->pc;                                          \
-       /* pr_reg[19] = (regs->format << 12) | regs->vector; */         \
-       {                                                               \
-         struct switch_stack *sw = ((struct switch_stack *)regs) - 1;  \
-         pr_reg[5] = sw->d6;                                           \
-         pr_reg[6] = sw->d7;                                           \
-         pr_reg[10] = sw->a3;                                          \
-         pr_reg[11] = sw->a4;                                          \
-         pr_reg[12] = sw->a5;                                          \
-         pr_reg[13] = sw->a6;                                          \
-       }
-
-/* This yields a mask that user programs can use to figure out what
-   instruction set this cpu supports.  */
-
-#define ELF_HWCAP      (0)
-
-/* This yields a string that ld.so will use to load implementation
-   specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.  */
-
-#define ELF_PLATFORM  (NULL)
-
-#define SET_PERSONALITY(ex) set_personality(PER_LINUX)
-
-#endif
index 97bcaefd2064e0776e0fb30d00dfa193cb4958ed..be4e4c6797e822eb497e72d59f33145efbb099f1 100644 (file)
@@ -1,5 +1,38 @@
-#ifdef __uClinux__
-#include "fb_no.h"
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+
+#ifdef CONFIG_MMU
+#ifdef CONFIG_SUN3
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+                               unsigned long off)
+{
+       pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
+}
 #else
-#include "fb_mm.h"
-#endif
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+                               unsigned long off)
+{
+       if (CPU_IS_020_OR_030)
+               pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
+       if (CPU_IS_040_OR_060) {
+               pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
+               /* Use no-cache mode, serialized */
+               pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
+       }
+}
+#endif /* CONFIG_SUN3 */
+#else
+#define fb_pgprotect(...) do {} while (0)
+#endif /* CONFIG_MMU */
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+       return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/arch/m68k/include/asm/fb_mm.h b/arch/m68k/include/asm/fb_mm.h
deleted file mode 100644 (file)
index 380b97a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _ASM_FB_H_
-#define _ASM_FB_H_
-
-#include <linux/fb.h>
-#include <linux/fs.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-
-#ifdef CONFIG_SUN3
-static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
-                               unsigned long off)
-{
-       pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
-}
-#else
-static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
-                               unsigned long off)
-{
-       if (CPU_IS_020_OR_030)
-               pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
-       if (CPU_IS_040_OR_060) {
-               pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
-               /* Use no-cache mode, serialized */
-               pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
-       }
-}
-#endif /* CONFIG_SUN3 */
-
-static inline int fb_is_primary_device(struct fb_info *info)
-{
-       return 0;
-}
-
-#endif /* _ASM_FB_H_ */
diff --git a/arch/m68k/include/asm/fb_no.h b/arch/m68k/include/asm/fb_no.h
deleted file mode 100644 (file)
index c7df380..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _ASM_FB_H_
-#define _ASM_FB_H_
-#include <linux/fb.h>
-
-#define fb_pgprotect(...) do {} while (0)
-
-static inline int fb_is_primary_device(struct fb_info *info)
-{
-       return 0;
-}
-
-#endif /* _ASM_FB_H_ */
index e19bc5ed9c377480400782004f7719be439c0d6a..ffb6b8cfc6d59c73851c82060ff5bcbedeb8c615 100644 (file)
@@ -1,5 +1,21 @@
-#ifdef __uClinux__
-#include "fpu_no.h"
+#ifndef __M68K_FPU_H
+#define __M68K_FPU_H
+
+
+/*
+ * MAX floating point unit state size (FSAVE/FRESTORE)
+ */
+
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+#define FPSTATESIZE (216)
+#elif defined(CONFIG_M68040)
+#define FPSTATESIZE (96)
+#elif defined(CONFIG_M68KFPU_EMU)
+#define FPSTATESIZE (28)
+#elif defined(CONFIG_M68060)
+#define FPSTATESIZE (12)
 #else
-#include "fpu_mm.h"
+#define FPSTATESIZE (0)
 #endif
+
+#endif /* __M68K_FPU_H */
diff --git a/arch/m68k/include/asm/fpu_mm.h b/arch/m68k/include/asm/fpu_mm.h
deleted file mode 100644 (file)
index ffb6b8c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __M68K_FPU_H
-#define __M68K_FPU_H
-
-
-/*
- * MAX floating point unit state size (FSAVE/FRESTORE)
- */
-
-#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
-#define FPSTATESIZE (216)
-#elif defined(CONFIG_M68040)
-#define FPSTATESIZE (96)
-#elif defined(CONFIG_M68KFPU_EMU)
-#define FPSTATESIZE (28)
-#elif defined(CONFIG_M68060)
-#define FPSTATESIZE (12)
-#else
-#define FPSTATESIZE (0)
-#endif
-
-#endif /* __M68K_FPU_H */
diff --git a/arch/m68k/include/asm/fpu_no.h b/arch/m68k/include/asm/fpu_no.h
deleted file mode 100644 (file)
index b16b2e4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __M68KNOMMU_FPU_H
-#define __M68KNOMMU_FPU_H
-
-
-/*
- * MAX floating point unit state size (FSAVE/FRESTORE)
- */
-#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
-#define FPSTATESIZE (216/sizeof(unsigned char))
-#elif defined(CONFIG_M68040)
-#define FPSTATESIZE (96/sizeof(unsigned char))
-#elif defined(CONFIG_M68KFPU_EMU)
-#define FPSTATESIZE (28/sizeof(unsigned char))
-#elif defined(CONFIG_M68060)
-#define FPSTATESIZE (12/sizeof(unsigned char))
-#else
-/* Assume no FP unit present then... */
-#define FPSTATESIZE (2) /* dummy size */
-#endif
-
-#endif /* __M68K_FPU_H */
index e19526015890e2c3bc937cbed6a1fe8bb3c1042d..eacef0951fbf63da8cafe3719033a0fa99559d78 100644 (file)
@@ -1,5 +1,6 @@
-#ifdef __uClinux__
-#include "hw_irq_no.h"
-#else
-#include "hw_irq_mm.h"
+#ifndef __ASM_M68K_HW_IRQ_H
+#define __ASM_M68K_HW_IRQ_H
+
+/* Dummy include. */
+
 #endif
diff --git a/arch/m68k/include/asm/hw_irq_mm.h b/arch/m68k/include/asm/hw_irq_mm.h
deleted file mode 100644 (file)
index eacef09..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_M68K_HW_IRQ_H
-#define __ASM_M68K_HW_IRQ_H
-
-/* Dummy include. */
-
-#endif
diff --git a/arch/m68k/include/asm/hw_irq_no.h b/arch/m68k/include/asm/hw_irq_no.h
deleted file mode 100644 (file)
index f3ec9e5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __M68KNOMMU_HW_IRQ_H__
-#define __M68KNOMMU_HW_IRQ_H__
-
-#endif /* __M68KNOMMU_HW_IRQ_H__ */
index 045d9fd122a216f4b5701373598f821431b7df53..c843c63d380161411f70e046e16c66705b9a6fac 100644 (file)
@@ -1,5 +1,21 @@
-#ifdef __uClinux__
-#include "kmap_types_no.h"
-#else
-#include "kmap_types_mm.h"
-#endif
+#ifndef __ASM_M68K_KMAP_TYPES_H
+#define __ASM_M68K_KMAP_TYPES_H
+
+enum km_type {
+       KM_BOUNCE_READ,
+       KM_SKB_SUNRPC_DATA,
+       KM_SKB_DATA_SOFTIRQ,
+       KM_USER0,
+       KM_USER1,
+       KM_BIO_SRC_IRQ,
+       KM_BIO_DST_IRQ,
+       KM_PTE0,
+       KM_PTE1,
+       KM_IRQ0,
+       KM_IRQ1,
+       KM_SOFTIRQ0,
+       KM_SOFTIRQ1,
+       KM_TYPE_NR
+};
+
+#endif /* __ASM_M68K_KMAP_TYPES_H */
diff --git a/arch/m68k/include/asm/kmap_types_mm.h b/arch/m68k/include/asm/kmap_types_mm.h
deleted file mode 100644 (file)
index c843c63..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __ASM_M68K_KMAP_TYPES_H
-#define __ASM_M68K_KMAP_TYPES_H
-
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
-
-#endif /* __ASM_M68K_KMAP_TYPES_H */
diff --git a/arch/m68k/include/asm/kmap_types_no.h b/arch/m68k/include/asm/kmap_types_no.h
deleted file mode 100644 (file)
index bfb6707..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __ASM_M68K_KMAP_TYPES_H
-#define __ASM_M68K_KMAP_TYPES_H
-
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
-
-#endif
index 1835fd20a82cd9c1c5d30e2e174ee40b520a4871..ce603451b55e33c4d7290b61cdd26fcf722ef2a0 100644 (file)
@@ -16,6 +16,7 @@
 #define MCFINT_VECBASE      64
 #define MCFINT_UART0        26          /* Interrupt number for UART0 */
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
+#define MCFINT_UART2        28          /* Interrupt number for UART2 */
 
 #define MCF_WTM_WCR    MCF_REG16(0xFC098000)
 
index fb90dcf784262b50ebba94dfffc0305f3e7e8027..9f70a01f73dc9960e00817963aceb75b5e89db24 100644 (file)
@@ -1,5 +1,26 @@
-#ifdef __uClinux__
-#include "mc146818rtc_no.h"
-#else
-#include "mc146818rtc_mm.h"
-#endif
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+
+#ifdef CONFIG_ATARI
+/* RTC in Atari machines */
+
+#include <asm/atarihw.h>
+
+#define RTC_PORT(x)    (TT_RTC_BAS + 2*(x))
+#define RTC_ALWAYS_BCD 0
+
+#define CMOS_READ(addr) ({ \
+atari_outb_p((addr),RTC_PORT(0)); \
+atari_inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+atari_outb_p((addr),RTC_PORT(0)); \
+atari_outb_p((val),RTC_PORT(1)); \
+})
+#endif /* CONFIG_ATARI */
+
+#endif /* _ASM_MC146818RTC_H */
diff --git a/arch/m68k/include/asm/mc146818rtc_mm.h b/arch/m68k/include/asm/mc146818rtc_mm.h
deleted file mode 100644 (file)
index 9f70a01..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Machine dependent access functions for RTC registers.
- */
-#ifndef _ASM_MC146818RTC_H
-#define _ASM_MC146818RTC_H
-
-
-#ifdef CONFIG_ATARI
-/* RTC in Atari machines */
-
-#include <asm/atarihw.h>
-
-#define RTC_PORT(x)    (TT_RTC_BAS + 2*(x))
-#define RTC_ALWAYS_BCD 0
-
-#define CMOS_READ(addr) ({ \
-atari_outb_p((addr),RTC_PORT(0)); \
-atari_inb_p(RTC_PORT(1)); \
-})
-#define CMOS_WRITE(val, addr) ({ \
-atari_outb_p((addr),RTC_PORT(0)); \
-atari_outb_p((val),RTC_PORT(1)); \
-})
-#endif /* CONFIG_ATARI */
-
-#endif /* _ASM_MC146818RTC_H */
diff --git a/arch/m68k/include/asm/mc146818rtc_no.h b/arch/m68k/include/asm/mc146818rtc_no.h
deleted file mode 100644 (file)
index 907a048..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Machine dependent access functions for RTC registers.
- */
-#ifndef _M68KNOMMU_MC146818RTC_H
-#define _M68KNOMMU_MC146818RTC_H
-
-/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */
-
-#endif /* _M68KNOMMU_MC146818RTC_H */
diff --git a/arch/m68k/include/asm/mcfpci.h b/arch/m68k/include/asm/mcfpci.h
deleted file mode 100644 (file)
index f1507dd..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/****************************************************************************/
-
-/*
- *     mcfpci.h -- PCI bridge on ColdFire eval boards.
- *
- *     (C) Copyright 2000, Greg Ungerer (gerg@snapgear.com)
- *     (C) Copyright 2000, Lineo Inc. (www.lineo.com)
- */
-
-/****************************************************************************/
-#ifndef        mcfpci_h
-#define        mcfpci_h
-/****************************************************************************/
-
-
-#ifdef CONFIG_PCI
-
-/*
- *     Address regions in the PCI address space are not mapped into the
- *     normal memory space of the ColdFire. They must be accessed via
- *     handler routines. This is easy for I/O space (inb/outb/etc) but
- *     needs some code changes to support ordinary memory. Interrupts
- *     also need to be vectored through the PCI handler first, then it
- *     will call the actual driver sub-handlers.
- */
-
-/*
- *     Un-define all the standard I/O access routines.
- */
-#undef inb
-#undef inw
-#undef inl
-#undef inb_p
-#undef inw_p
-#undef insb
-#undef insw
-#undef insl
-#undef outb
-#undef outw
-#undef outl
-#undef outb_p
-#undef outw_p
-#undef outsb
-#undef outsw
-#undef outsl
-
-#undef request_irq
-#undef free_irq
-
-#undef bus_to_virt
-#undef virt_to_bus
-
-
-/*
- *     Re-direct all I/O memory accesses functions to PCI specific ones.
- */
-#define        inb     pci_inb
-#define        inw     pci_inw
-#define        inl     pci_inl
-#define        inb_p   pci_inb
-#define        inw_p   pci_inw
-#define        insb    pci_insb
-#define        insw    pci_insw
-#define        insl    pci_insl
-
-#define        outb    pci_outb
-#define        outw    pci_outw
-#define        outl    pci_outl
-#define        outb_p  pci_outb
-#define        outw_p  pci_outw
-#define        outsb   pci_outsb
-#define        outsw   pci_outsw
-#define        outsl   pci_outsl
-
-#define        request_irq     pci_request_irq
-#define        free_irq        pci_free_irq
-
-#define        virt_to_bus     pci_virt_to_bus
-#define        bus_to_virt     pci_bus_to_virt
-
-#define        CONFIG_COMEMPCI 1
-
-
-/*
- *     Prototypes of the real PCI functions (defined in bios32.c).
- */
-unsigned char  pci_inb(unsigned int addr);
-unsigned short pci_inw(unsigned int addr);
-unsigned int   pci_inl(unsigned int addr);
-void           pci_insb(void *addr, void *buf, int len);
-void           pci_insw(void *addr, void *buf, int len);
-void           pci_insl(void *addr, void *buf, int len);
-
-void           pci_outb(unsigned char val, unsigned int addr);
-void           pci_outw(unsigned short val, unsigned int addr);
-void           pci_outl(unsigned int val, unsigned int addr);
-void           pci_outsb(void *addr, void *buf, int len);
-void           pci_outsw(void *addr, void *buf, int len);
-void           pci_outsl(void *addr, void *buf, int len);
-
-int            pci_request_irq(unsigned int irq,
-                       void (*handler)(int, void *, struct pt_regs *),
-                       unsigned long flags,
-                       const char *device,
-                       void *dev_id);
-void           pci_free_irq(unsigned int irq, void *dev_id);
-
-void           *pci_bmalloc(int size);
-void           pci_bmfree(void *bmp, int len);
-void           pci_copytoshmem(unsigned long bmp, void *src, int size);
-void           pci_copyfromshmem(void *dst, unsigned long bmp, int size);
-unsigned long  pci_virt_to_bus(volatile void *address);
-void           *pci_bus_to_virt(unsigned long address);
-void           pci_bmcpyto(void *dst, void *src, int len);
-void           pci_bmcpyfrom(void *dst, void *src, int len);
-
-#endif /* CONFIG_PCI */
-/****************************************************************************/
-#endif /* mcfpci_h */
index a81d3946675fa7812cce2237deeafd1e0fdb68e0..8a11a63ee15a4e228d7622165f73095f59714326 100644 (file)
@@ -1,5 +1,13 @@
-#ifdef __uClinux__
-#include "mmu_no.h"
+#ifndef __MMU_H
+#define __MMU_H
+
+#ifdef CONFIG_MMU
+/* Default "unsigned long" context */
+typedef unsigned long mm_context_t;
 #else
-#include "mmu_mm.h"
+typedef struct {
+       unsigned long           end_brk;
+} mm_context_t;
+#endif
+
 #endif
index b440928fc6c79b592d59b39505fdd6cfc07dc28b..7d4341e55a99b85396757228e924c3b5acbbc095 100644 (file)
@@ -1,5 +1,175 @@
-#ifdef __uClinux__
-#include "mmu_context_no.h"
+#ifndef __M68K_MMU_CONTEXT_H
+#define __M68K_MMU_CONTEXT_H
+
+#include <asm-generic/mm_hooks.h>
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+#ifdef CONFIG_MMU
+#ifndef CONFIG_SUN3
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+
+static inline int init_new_context(struct task_struct *tsk,
+                                  struct mm_struct *mm)
+{
+       mm->context = virt_to_phys(mm->pgd);
+       return 0;
+}
+
+#define destroy_context(mm)            do { } while(0)
+
+static inline void switch_mm_0230(struct mm_struct *mm)
+{
+       unsigned long crp[2] = {
+               0x80000000 | _PAGE_TABLE, mm->context
+       };
+       unsigned long tmp;
+
+       asm volatile (".chip 68030");
+
+       /* flush MC68030/MC68020 caches (they are virtually addressed) */
+       asm volatile (
+               "movec %%cacr,%0;"
+               "orw %1,%0; "
+               "movec %0,%%cacr"
+               : "=d" (tmp) : "di" (FLUSH_I_AND_D));
+
+       /* Switch the root pointer. For a 030-only kernel,
+        * avoid flushing the whole ATC, we only need to
+        * flush the user entries. The 68851 does this by
+        * itself. Avoid a runtime check here.
+        */
+       asm volatile (
+#ifdef CPU_M68030_ONLY
+               "pmovefd %0,%%crp; "
+               "pflush #0,#4"
 #else
-#include "mmu_context_mm.h"
+               "pmove %0,%%crp"
 #endif
+               : : "m" (crp[0]));
+
+       asm volatile (".chip 68k");
+}
+
+static inline void switch_mm_0460(struct mm_struct *mm)
+{
+       asm volatile (".chip 68040");
+
+       /* flush address translation cache (user entries) */
+       asm volatile ("pflushan");
+
+       /* switch the root pointer */
+       asm volatile ("movec %0,%%urp" : : "r" (mm->context));
+
+       if (CPU_IS_060) {
+               unsigned long tmp;
+
+               /* clear user entries in the branch cache */
+               asm volatile (
+                       "movec %%cacr,%0; "
+                       "orl %1,%0; "
+                       "movec %0,%%cacr"
+                       : "=d" (tmp): "di" (0x00200000));
+       }
+
+       asm volatile (".chip 68k");
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
+{
+       if (prev != next) {
+               if (CPU_IS_020_OR_030)
+                       switch_mm_0230(next);
+               else
+                       switch_mm_0460(next);
+       }
+}
+
+#define deactivate_mm(tsk,mm)  do { } while (0)
+
+static inline void activate_mm(struct mm_struct *prev_mm,
+                              struct mm_struct *next_mm)
+{
+       next_mm->context = virt_to_phys(next_mm->pgd);
+
+       if (CPU_IS_020_OR_030)
+               switch_mm_0230(next_mm);
+       else
+               switch_mm_0460(next_mm);
+}
+
+#else  /* CONFIG_SUN3 */
+#include <asm/sun3mmu.h>
+#include <linux/sched.h>
+
+extern unsigned long get_free_context(struct mm_struct *mm);
+extern void clear_context(unsigned long context);
+
+/* set the context for a new task to unmapped */
+static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       mm->context = SUN3_INVALID_CONTEXT;
+       return 0;
+}
+
+/* find the context given to this process, and if it hasn't already
+   got one, go get one for it. */
+static inline void get_mmu_context(struct mm_struct *mm)
+{
+       if(mm->context == SUN3_INVALID_CONTEXT)
+               mm->context = get_free_context(mm);
+}
+
+/* flush context if allocated... */
+static inline void destroy_context(struct mm_struct *mm)
+{
+       if(mm->context != SUN3_INVALID_CONTEXT)
+               clear_context(mm->context);
+}
+
+static inline void activate_context(struct mm_struct *mm)
+{
+       get_mmu_context(mm);
+       sun3_put_context(mm->context);
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
+{
+       activate_context(tsk->mm);
+}
+
+#define deactivate_mm(tsk,mm)  do { } while (0)
+
+static inline void activate_mm(struct mm_struct *prev_mm,
+                              struct mm_struct *next_mm)
+{
+       activate_context(next_mm);
+}
+
+#endif
+#else /* !CONFIG_MMU */
+
+static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       return 0;
+}
+
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
+{
+}
+
+#define destroy_context(mm)    do { } while (0)
+#define deactivate_mm(tsk,mm)  do { } while (0)
+
+static inline void activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
+{
+}
+
+#endif /* CONFIG_MMU */
+#endif /* __M68K_MMU_CONTEXT_H */
diff --git a/arch/m68k/include/asm/mmu_context_mm.h b/arch/m68k/include/asm/mmu_context_mm.h
deleted file mode 100644 (file)
index 894dacb..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-#ifndef __M68K_MMU_CONTEXT_H
-#define __M68K_MMU_CONTEXT_H
-
-#include <asm-generic/mm_hooks.h>
-
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-{
-}
-
-#ifndef CONFIG_SUN3
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-
-static inline int init_new_context(struct task_struct *tsk,
-                                  struct mm_struct *mm)
-{
-       mm->context = virt_to_phys(mm->pgd);
-       return 0;
-}
-
-#define destroy_context(mm)            do { } while(0)
-
-static inline void switch_mm_0230(struct mm_struct *mm)
-{
-       unsigned long crp[2] = {
-               0x80000000 | _PAGE_TABLE, mm->context
-       };
-       unsigned long tmp;
-
-       asm volatile (".chip 68030");
-
-       /* flush MC68030/MC68020 caches (they are virtually addressed) */
-       asm volatile (
-               "movec %%cacr,%0;"
-               "orw %1,%0; "
-               "movec %0,%%cacr"
-               : "=d" (tmp) : "di" (FLUSH_I_AND_D));
-
-       /* Switch the root pointer. For a 030-only kernel,
-        * avoid flushing the whole ATC, we only need to
-        * flush the user entries. The 68851 does this by
-        * itself. Avoid a runtime check here.
-        */
-       asm volatile (
-#ifdef CPU_M68030_ONLY
-               "pmovefd %0,%%crp; "
-               "pflush #0,#4"
-#else
-               "pmove %0,%%crp"
-#endif
-               : : "m" (crp[0]));
-
-       asm volatile (".chip 68k");
-}
-
-static inline void switch_mm_0460(struct mm_struct *mm)
-{
-       asm volatile (".chip 68040");
-
-       /* flush address translation cache (user entries) */
-       asm volatile ("pflushan");
-
-       /* switch the root pointer */
-       asm volatile ("movec %0,%%urp" : : "r" (mm->context));
-
-       if (CPU_IS_060) {
-               unsigned long tmp;
-
-               /* clear user entries in the branch cache */
-               asm volatile (
-                       "movec %%cacr,%0; "
-                       "orl %1,%0; "
-                       "movec %0,%%cacr"
-                       : "=d" (tmp): "di" (0x00200000));
-       }
-
-       asm volatile (".chip 68k");
-}
-
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
-{
-       if (prev != next) {
-               if (CPU_IS_020_OR_030)
-                       switch_mm_0230(next);
-               else
-                       switch_mm_0460(next);
-       }
-}
-
-#define deactivate_mm(tsk,mm)  do { } while (0)
-
-static inline void activate_mm(struct mm_struct *prev_mm,
-                              struct mm_struct *next_mm)
-{
-       next_mm->context = virt_to_phys(next_mm->pgd);
-
-       if (CPU_IS_020_OR_030)
-               switch_mm_0230(next_mm);
-       else
-               switch_mm_0460(next_mm);
-}
-
-#else  /* CONFIG_SUN3 */
-#include <asm/sun3mmu.h>
-#include <linux/sched.h>
-
-extern unsigned long get_free_context(struct mm_struct *mm);
-extern void clear_context(unsigned long context);
-
-/* set the context for a new task to unmapped */
-static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-       mm->context = SUN3_INVALID_CONTEXT;
-       return 0;
-}
-
-/* find the context given to this process, and if it hasn't already
-   got one, go get one for it. */
-static inline void get_mmu_context(struct mm_struct *mm)
-{
-       if(mm->context == SUN3_INVALID_CONTEXT)
-               mm->context = get_free_context(mm);
-}
-
-/* flush context if allocated... */
-static inline void destroy_context(struct mm_struct *mm)
-{
-       if(mm->context != SUN3_INVALID_CONTEXT)
-               clear_context(mm->context);
-}
-
-static inline void activate_context(struct mm_struct *mm)
-{
-       get_mmu_context(mm);
-       sun3_put_context(mm->context);
-}
-
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
-{
-       activate_context(tsk->mm);
-}
-
-#define deactivate_mm(tsk,mm)  do { } while (0)
-
-static inline void activate_mm(struct mm_struct *prev_mm,
-                              struct mm_struct *next_mm)
-{
-       activate_context(next_mm);
-}
-
-#endif
-#endif
diff --git a/arch/m68k/include/asm/mmu_context_no.h b/arch/m68k/include/asm/mmu_context_no.h
deleted file mode 100644 (file)
index 9ccee42..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __M68KNOMMU_MMU_CONTEXT_H
-#define __M68KNOMMU_MMU_CONTEXT_H
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm-generic/mm_hooks.h>
-
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-{
-}
-
-static inline int
-init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-       // mm->context = virt_to_phys(mm->pgd);
-       return(0);
-}
-
-#define destroy_context(mm)            do { } while(0)
-
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
-{
-}
-
-#define deactivate_mm(tsk,mm)  do { } while (0)
-
-static inline void activate_mm(struct mm_struct *prev_mm,
-                              struct mm_struct *next_mm)
-{
-}
-
-#endif
diff --git a/arch/m68k/include/asm/mmu_mm.h b/arch/m68k/include/asm/mmu_mm.h
deleted file mode 100644 (file)
index ccd36d2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __MMU_H
-#define __MMU_H
-
-/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
-
-#endif
diff --git a/arch/m68k/include/asm/mmu_no.h b/arch/m68k/include/asm/mmu_no.h
deleted file mode 100644 (file)
index e2da1e6..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __M68KNOMMU_MMU_H
-#define __M68KNOMMU_MMU_H
-
-/* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
-
-typedef struct {
-       unsigned long           end_brk;
-} mm_context_t;
-
-#endif /* __M68KNOMMU_MMU_H */
index 79b59d137dd0732daeca7d24ef15d9386a07e92d..5f21e11071bdfc1aad9bf5706ff47aa3e6c4a72f 100644 (file)
@@ -1,5 +1,48 @@
-#ifdef __uClinux__
-#include "module_no.h"
+#ifndef _ASM_M68K_MODULE_H
+#define _ASM_M68K_MODULE_H
+
+#ifdef CONFIG_MMU
+
+struct mod_arch_specific {
+       struct m68k_fixup_info *fixup_start, *fixup_end;
+};
+
+#define MODULE_ARCH_INIT {                             \
+       .fixup_start            = __start_fixup,        \
+       .fixup_end              = __stop_fixup,         \
+}
+
+
+enum m68k_fixup_type {
+       m68k_fixup_memoffset,
+       m68k_fixup_vnode_shift,
+};
+
+struct m68k_fixup_info {
+       enum m68k_fixup_type type;
+       void *addr;
+};
+
+#define m68k_fixup(type, addr)                 \
+       "       .section \".m68k_fixup\",\"aw\"\n"      \
+       "       .long " #type "," #addr "\n"    \
+       "       .previous\n"
+
+extern struct m68k_fixup_info __start_fixup[], __stop_fixup[];
+
+struct module;
+extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
+                        struct m68k_fixup_info *end);
+
 #else
-#include "module_mm.h"
-#endif
+
+struct mod_arch_specific {
+};
+
+#endif /* CONFIG_MMU */
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+
+#endif /* _ASM_M68K_MODULE_H */
diff --git a/arch/m68k/include/asm/module_mm.h b/arch/m68k/include/asm/module_mm.h
deleted file mode 100644 (file)
index 382d20a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _ASM_M68K_MODULE_H
-#define _ASM_M68K_MODULE_H
-
-struct mod_arch_specific {
-       struct m68k_fixup_info *fixup_start, *fixup_end;
-};
-
-#define MODULE_ARCH_INIT {                             \
-       .fixup_start            = __start_fixup,        \
-       .fixup_end              = __stop_fixup,         \
-}
-
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
-
-enum m68k_fixup_type {
-       m68k_fixup_memoffset,
-       m68k_fixup_vnode_shift,
-};
-
-struct m68k_fixup_info {
-       enum m68k_fixup_type type;
-       void *addr;
-};
-
-#define m68k_fixup(type, addr)                 \
-       "       .section \".m68k_fixup\",\"aw\"\n"      \
-       "       .long " #type "," #addr "\n"    \
-       "       .previous\n"
-
-extern struct m68k_fixup_info __start_fixup[], __stop_fixup[];
-
-struct module;
-extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
-                        struct m68k_fixup_info *end);
-
-#endif /* _ASM_M68K_MODULE_H */
diff --git a/arch/m68k/include/asm/module_no.h b/arch/m68k/include/asm/module_no.h
deleted file mode 100644 (file)
index 2e45ab5..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef ASM_M68KNOMMU_MODULE_H
-#define ASM_M68KNOMMU_MODULE_H
-
-struct mod_arch_specific {
-};
-
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
-#endif /* ASM_M68KNOMMU_MODULE_H */
index 66455c849fbbc7fed7f3aa948e90917a73ed5d2f..1780152d81dace541507110a04e4065f49fb3cdc 100644 (file)
@@ -1,5 +1,11 @@
-#ifdef __uClinux__
-#include "page_offset_no.h"
+/* This handles the memory map.. */
+
+#ifdef CONFIG_MMU
+#ifndef CONFIG_SUN3
+#define PAGE_OFFSET_RAW                0x00000000
 #else
-#include "page_offset_mm.h"
+#define PAGE_OFFSET_RAW                0x0E000000
+#endif
+#else
+#define        PAGE_OFFSET_RAW         CONFIG_RAMBASE
 #endif
diff --git a/arch/m68k/include/asm/page_offset_mm.h b/arch/m68k/include/asm/page_offset_mm.h
deleted file mode 100644 (file)
index 1cbdb7f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-/* This handles the memory map.. */
-#ifndef CONFIG_SUN3
-#define PAGE_OFFSET_RAW                0x00000000
-#else
-#define PAGE_OFFSET_RAW                0x0E000000
-#endif
-
diff --git a/arch/m68k/include/asm/page_offset_no.h b/arch/m68k/include/asm/page_offset_no.h
deleted file mode 100644 (file)
index d4e73e0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-/* This handles the memory map.. */
-#define        PAGE_OFFSET_RAW         CONFIG_RAMBASE
-
index dbea95373080d26236121b8c498fe89d0028e620..4ad0aea48ab4e9d2b5c96a278d09c2f3eadb3ce5 100644 (file)
@@ -1,5 +1,12 @@
-#ifdef __uClinux__
-#include "pci_no.h"
-#else
-#include "pci_mm.h"
-#endif
+#ifndef _ASM_M68K_PCI_H
+#define _ASM_M68K_PCI_H
+
+#include <asm-generic/pci-dma-compat.h>
+
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS    (1)
+
+#endif /* _ASM_M68K_PCI_H */
diff --git a/arch/m68k/include/asm/pci_mm.h b/arch/m68k/include/asm/pci_mm.h
deleted file mode 100644 (file)
index 4ad0aea..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _ASM_M68K_PCI_H
-#define _ASM_M68K_PCI_H
-
-#include <asm-generic/pci-dma-compat.h>
-
-/* The PCI address space does equal the physical memory
- * address space.  The networking and block device layers use
- * this boolean for bounce buffer decisions.
- */
-#define PCI_DMA_BUS_IS_PHYS    (1)
-
-#endif /* _ASM_M68K_PCI_H */
diff --git a/arch/m68k/include/asm/pci_no.h b/arch/m68k/include/asm/pci_no.h
deleted file mode 100644 (file)
index 9abbc03..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef M68KNOMMU_PCI_H
-#define        M68KNOMMU_PCI_H
-
-#include <asm/pci_mm.h>
-
-#ifdef CONFIG_COMEMPCI
-/*
- *     These are pretty much arbitary with the CoMEM implementation.
- *     We have the whole address space to ourselves.
- */
-#define PCIBIOS_MIN_IO         0x100
-#define PCIBIOS_MIN_MEM                0x00010000
-
-#define pcibios_scan_all_fns(a, b)     0
-
-/*
- * Return whether the given PCI device DMA address mask can
- * be supported properly.  For example, if your device can
- * only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
-{
-       return 1;
-}
-
-#endif /* CONFIG_COMEMPCI */
-
-#endif /* M68KNOMMU_PCI_H */
index 059cb73e78fc456006646659fcc076cca916f972..c294aad8a9000bd9d891d5a0a35b9987e5ed9c6b 100644 (file)
@@ -1,5 +1,19 @@
-#ifdef __uClinux__
-#include "pgalloc_no.h"
+#ifndef M68K_PGALLOC_H
+#define M68K_PGALLOC_H
+
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <asm/setup.h>
+
+#ifdef CONFIG_MMU
+#include <asm/virtconvert.h>
+#ifdef CONFIG_SUN3
+#include <asm/sun3_pgalloc.h>
 #else
-#include "pgalloc_mm.h"
+#include <asm/motorola_pgalloc.h>
 #endif
+
+extern void m68k_setup_node(int node);
+#endif
+
+#endif /* M68K_PGALLOC_H */
diff --git a/arch/m68k/include/asm/pgalloc_mm.h b/arch/m68k/include/asm/pgalloc_mm.h
deleted file mode 100644 (file)
index 4cb1a57..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#ifndef M68K_PGALLOC_H
-#define M68K_PGALLOC_H
-
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <asm/setup.h>
-#include <asm/virtconvert.h>
-
-
-#ifdef CONFIG_SUN3
-#include <asm/sun3_pgalloc.h>
-#else
-#include <asm/motorola_pgalloc.h>
-#endif
-
-extern void m68k_setup_node(int node);
-
-#endif /* M68K_PGALLOC_H */
diff --git a/arch/m68k/include/asm/pgalloc_no.h b/arch/m68k/include/asm/pgalloc_no.h
deleted file mode 100644 (file)
index d6352f6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _M68KNOMMU_PGALLOC_H
-#define _M68KNOMMU_PGALLOC_H
-
-#include <asm/setup.h>
-
-#define check_pgt_cache()      do { } while (0)
-
-#endif /* _M68KNOMMU_PGALLOC_H */
index 46251016e8212bdfef68b594e6ad1cf0e939248d..bf86b29fe64a2b025fe1890da80d90270e730912 100644 (file)
@@ -67,4 +67,6 @@ extern unsigned int kobjsize(const void *objp);
 
 #include <asm-generic/pgtable.h>
 
+#define check_pgt_cache()      do { } while (0)
+
 #endif /* _M68KNOMMU_PGTABLE_H */
index 5d3e038598441c58b459c37e30aa1e6b0a09ccc5..a4d08ea122ee3f310cd3f7caaf3205aa6b524fc1 100644 (file)
@@ -36,13 +36,16 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
         * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
         * by the RTC when initially set to a non-zero value.
         */
-       mach_hwclk(0, time);
+       if (mach_hwclk)
+               mach_hwclk(0, time);
        return RTC_24H;
 }
 
 static inline int set_rtc_time(struct rtc_time *time)
 {
-       return mach_hwclk(1, time);
+       if (mach_hwclk)
+               return mach_hwclk(1, time);
+       return -EINVAL;
 }
 
 static inline unsigned int get_rtc_ss(void)
index b7e528636252ec488d43efb2c5684a86ad25e1b4..e27ad902b1cff9bb26792f3fe99ee96a45fa8bc5 100644 (file)
@@ -1,5 +1,23 @@
-#ifdef __uClinux__
-#include "scatterlist_no.h"
-#else
-#include "scatterlist_mm.h"
+#ifndef _M68K_SCATTERLIST_H
+#define _M68K_SCATTERLIST_H
+
+#include <linux/types.h>
+
+struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
 #endif
+       unsigned long page_link;
+       unsigned int offset;
+       unsigned int length;
+
+       dma_addr_t dma_address; /* A place to hang host-specific addresses at. */
+};
+
+/* This is bogus and should go away. */
+#define ISA_DMA_THRESHOLD (0x00ffffff)
+
+#define sg_dma_address(sg)     ((sg)->dma_address)
+#define sg_dma_len(sg)         ((sg)->length)
+
+#endif /* !(_M68K_SCATTERLIST_H) */
diff --git a/arch/m68k/include/asm/scatterlist_mm.h b/arch/m68k/include/asm/scatterlist_mm.h
deleted file mode 100644 (file)
index d3a7a0e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _M68K_SCATTERLIST_H
-#define _M68K_SCATTERLIST_H
-
-#include <linux/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       unsigned int length;
-
-       __u32 dma_address;      /* A place to hang host-specific addresses at. */
-};
-
-/* This is bogus and should go away. */
-#define ISA_DMA_THRESHOLD (0x00ffffff)
-
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
-
-#endif /* !(_M68K_SCATTERLIST_H) */
diff --git a/arch/m68k/include/asm/scatterlist_no.h b/arch/m68k/include/asm/scatterlist_no.h
deleted file mode 100644 (file)
index afc4788..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _M68KNOMMU_SCATTERLIST_H
-#define _M68KNOMMU_SCATTERLIST_H
-
-#include <linux/mm.h>
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
-
-#define sg_dma_address(sg)      ((sg)->dma_address)
-#define sg_dma_len(sg)          ((sg)->length)
-
-#define ISA_DMA_THRESHOLD      (0xffffffff)
-
-#endif /* !(_M68KNOMMU_SCATTERLIST_H) */
index 82583bc004bd6a3fe5f40ca1a7ba58e46130bd3a..ee959219fdfe0fb1698e456344eeedfa39271ca2 100644 (file)
@@ -1,5 +1,63 @@
-#ifdef __uClinux__
-#include "segment_no.h"
+#ifndef _M68K_SEGMENT_H
+#define _M68K_SEGMENT_H
+
+/* define constants */
+/* Address spaces (FC0-FC2) */
+#define USER_DATA     (1)
+#ifndef __USER_DS
+#define __USER_DS     (USER_DATA)
+#endif
+#define USER_PROGRAM  (2)
+#define SUPER_DATA    (5)
+#ifndef __KERNEL_DS
+#define __KERNEL_DS   (SUPER_DATA)
+#endif
+#define SUPER_PROGRAM (6)
+#define CPU_SPACE     (7)
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+       unsigned long seg;
+} mm_segment_t;
+
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+#define USER_DS                MAKE_MM_SEG(__USER_DS)
+#define KERNEL_DS      MAKE_MM_SEG(__KERNEL_DS)
+
+/*
+ * Get/set the SFC/DFC registers for MOVES instructions
+ */
+
+static inline mm_segment_t get_fs(void)
+{
+#ifdef CONFIG_MMU
+       mm_segment_t _v;
+       __asm__ ("movec %/dfc,%0":"=r" (_v.seg):);
+
+       return _v;
 #else
-#include "segment_mm.h"
+       return USER_DS;
+#endif
+}
+
+static inline mm_segment_t get_ds(void)
+{
+    /* return the supervisor data space code */
+    return KERNEL_DS;
+}
+
+static inline void set_fs(mm_segment_t val)
+{
+#ifdef CONFIG_MMU
+       __asm__ __volatile__ ("movec %0,%/sfc\n\t"
+                             "movec %0,%/dfc\n\t"
+                             : /* no outputs */ : "r" (val.seg) : "memory");
 #endif
+}
+
+#define segment_eq(a,b)        ((a).seg == (b).seg)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _M68K_SEGMENT_H */
diff --git a/arch/m68k/include/asm/segment_mm.h b/arch/m68k/include/asm/segment_mm.h
deleted file mode 100644 (file)
index 7b0b2d3..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef _M68K_SEGMENT_H
-#define _M68K_SEGMENT_H
-
-/* define constants */
-/* Address spaces (FC0-FC2) */
-#define USER_DATA     (1)
-#ifndef __USER_DS
-#define __USER_DS     (USER_DATA)
-#endif
-#define USER_PROGRAM  (2)
-#define SUPER_DATA    (5)
-#ifndef __KERNEL_DS
-#define __KERNEL_DS   (SUPER_DATA)
-#endif
-#define SUPER_PROGRAM (6)
-#define CPU_SPACE     (7)
-
-#ifndef __ASSEMBLY__
-
-typedef struct {
-       unsigned long seg;
-} mm_segment_t;
-
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define USER_DS                MAKE_MM_SEG(__USER_DS)
-#define KERNEL_DS      MAKE_MM_SEG(__KERNEL_DS)
-
-/*
- * Get/set the SFC/DFC registers for MOVES instructions
- */
-
-static inline mm_segment_t get_fs(void)
-{
-       mm_segment_t _v;
-       __asm__ ("movec %/dfc,%0":"=r" (_v.seg):);
-
-       return _v;
-}
-
-static inline mm_segment_t get_ds(void)
-{
-    /* return the supervisor data space code */
-    return KERNEL_DS;
-}
-
-static inline void set_fs(mm_segment_t val)
-{
-       __asm__ __volatile__ ("movec %0,%/sfc\n\t"
-                             "movec %0,%/dfc\n\t"
-                             : /* no outputs */ : "r" (val.seg) : "memory");
-}
-
-#define segment_eq(a,b)        ((a).seg == (b).seg)
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _M68K_SEGMENT_H */
diff --git a/arch/m68k/include/asm/segment_no.h b/arch/m68k/include/asm/segment_no.h
deleted file mode 100644 (file)
index 42318eb..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _M68K_SEGMENT_H
-#define _M68K_SEGMENT_H
-
-/* define constants */
-/* Address spaces (FC0-FC2) */
-#define USER_DATA     (1)
-#ifndef __USER_DS
-#define __USER_DS     (USER_DATA)
-#endif
-#define USER_PROGRAM  (2)
-#define SUPER_DATA    (5)
-#ifndef __KERNEL_DS
-#define __KERNEL_DS   (SUPER_DATA)
-#endif
-#define SUPER_PROGRAM (6)
-#define CPU_SPACE     (7)
-
-#ifndef __ASSEMBLY__
-
-typedef struct {
-       unsigned long seg;
-} mm_segment_t;
-
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define USER_DS                MAKE_MM_SEG(__USER_DS)
-#define KERNEL_DS      MAKE_MM_SEG(__KERNEL_DS)
-
-/*
- * Get/set the SFC/DFC registers for MOVES instructions
- */
-
-static inline mm_segment_t get_fs(void)
-{
-    return USER_DS;
-}
-
-static inline mm_segment_t get_ds(void)
-{
-    /* return the supervisor data space code */
-    return KERNEL_DS;
-}
-
-static inline void set_fs(mm_segment_t val)
-{
-}
-
-#define segment_eq(a,b)        ((a).seg == (b).seg)
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _M68K_SEGMENT_H */
index 719762980578daffdaf4dfe67156f59eef4fbb78..b87f2f278f673feda6270d9bf36ce70fe6c126e1 100644 (file)
@@ -1,5 +1,18 @@
-#ifdef __uClinux__
-#include "timex_no.h"
-#else
-#include "timex_mm.h"
+/*
+ * linux/include/asm-m68k/timex.h
+ *
+ * m68k architecture timex specifications
+ */
+#ifndef _ASMm68k_TIMEX_H
+#define _ASMm68k_TIMEX_H
+
+#define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
+
+typedef unsigned long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+       return 0;
+}
+
 #endif
diff --git a/arch/m68k/include/asm/timex_mm.h b/arch/m68k/include/asm/timex_mm.h
deleted file mode 100644 (file)
index b87f2f2..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * linux/include/asm-m68k/timex.h
- *
- * m68k architecture timex specifications
- */
-#ifndef _ASMm68k_TIMEX_H
-#define _ASMm68k_TIMEX_H
-
-#define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-
-typedef unsigned long cycles_t;
-
-static inline cycles_t get_cycles(void)
-{
-       return 0;
-}
-
-#endif
diff --git a/arch/m68k/include/asm/timex_no.h b/arch/m68k/include/asm/timex_no.h
deleted file mode 100644 (file)
index 109050f..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * linux/include/asm-m68knommu/timex.h
- *
- * m68knommu architecture timex specifications
- */
-#ifndef _ASM_M68KNOMMU_TIMEX_H
-#define _ASM_M68KNOMMU_TIMEX_H
-
-#ifdef CONFIG_COLDFIRE
-#include <asm/coldfire.h>
-#define CLOCK_TICK_RATE        MCF_CLK
-#else
-#define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#endif
-
-typedef unsigned long cycles_t;
-
-static inline cycles_t get_cycles(void)
-{
-       return 0;
-}
-
-#endif
index b6f93b30951e0faa799a78aa0694f6b489a59c6e..a6b4ed4fc90faf9acdb31262fca3623f1f09cc40 100644 (file)
@@ -1,5 +1,267 @@
-#ifdef __uClinux__
-#include "tlbflush_no.h"
+#ifndef _M68K_TLBFLUSH_H
+#define _M68K_TLBFLUSH_H
+
+#ifdef CONFIG_MMU
+#ifndef CONFIG_SUN3
+
+#include <asm/current.h>
+
+static inline void flush_tlb_kernel_page(void *addr)
+{
+       if (CPU_IS_040_OR_060) {
+               mm_segment_t old_fs = get_fs();
+               set_fs(KERNEL_DS);
+               __asm__ __volatile__(".chip 68040\n\t"
+                                    "pflush (%0)\n\t"
+                                    ".chip 68k"
+                                    : : "a" (addr));
+               set_fs(old_fs);
+       } else if (CPU_IS_020_OR_030)
+               __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
+}
+
+/*
+ * flush all user-space atc entries.
+ */
+static inline void __flush_tlb(void)
+{
+       if (CPU_IS_040_OR_060)
+               __asm__ __volatile__(".chip 68040\n\t"
+                                    "pflushan\n\t"
+                                    ".chip 68k");
+       else if (CPU_IS_020_OR_030)
+               __asm__ __volatile__("pflush #0,#4");
+}
+
+static inline void __flush_tlb040_one(unsigned long addr)
+{
+       __asm__ __volatile__(".chip 68040\n\t"
+                            "pflush (%0)\n\t"
+                            ".chip 68k"
+                            : : "a" (addr));
+}
+
+static inline void __flush_tlb_one(unsigned long addr)
+{
+       if (CPU_IS_040_OR_060)
+               __flush_tlb040_one(addr);
+       else if (CPU_IS_020_OR_030)
+               __asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
+}
+
+#define flush_tlb() __flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+       if (CPU_IS_040_OR_060)
+               __asm__ __volatile__(".chip 68040\n\t"
+                                    "pflusha\n\t"
+                                    ".chip 68k");
+       else if (CPU_IS_020_OR_030)
+               __asm__ __volatile__("pflusha");
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+       if (mm == current->active_mm)
+               __flush_tlb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+       if (vma->vm_mm == current->active_mm) {
+               mm_segment_t old_fs = get_fs();
+               set_fs(USER_DS);
+               __flush_tlb_one(addr);
+               set_fs(old_fs);
+       }
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+                                  unsigned long start, unsigned long end)
+{
+       if (vma->vm_mm == current->active_mm)
+               __flush_tlb();
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       flush_tlb_all();
+}
+
 #else
-#include "tlbflush_mm.h"
+
+
+/* Reserved PMEGs. */
+extern char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
+extern unsigned long pmeg_vaddr[SUN3_PMEGS_NUM];
+extern unsigned char pmeg_alloc[SUN3_PMEGS_NUM];
+extern unsigned char pmeg_ctx[SUN3_PMEGS_NUM];
+
+/* Flush all userspace mappings one by one...  (why no flush command,
+   sun?) */
+static inline void flush_tlb_all(void)
+{
+       unsigned long addr;
+       unsigned char ctx, oldctx;
+
+       oldctx = sun3_get_context();
+       for(addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) {
+              for(ctx = 0; ctx < 8; ctx++) {
+                      sun3_put_context(ctx);
+                      sun3_put_segmap(addr, SUN3_INVALID_PMEG);
+              }
+       }
+
+       sun3_put_context(oldctx);
+       /* erase all of the userspace pmeg maps, we've clobbered them
+         all anyway */
+       for(addr = 0; addr < SUN3_INVALID_PMEG; addr++) {
+              if(pmeg_alloc[addr] == 1) {
+                      pmeg_alloc[addr] = 0;
+                      pmeg_ctx[addr] = 0;
+                      pmeg_vaddr[addr] = 0;
+              }
+       }
+
+}
+
+/* Clear user TLB entries within the context named in mm */
+static inline void flush_tlb_mm (struct mm_struct *mm)
+{
+     unsigned char oldctx;
+     unsigned char seg;
+     unsigned long i;
+
+     oldctx = sun3_get_context();
+     sun3_put_context(mm->context);
+
+     for(i = 0; i < TASK_SIZE; i += SUN3_PMEG_SIZE) {
+            seg = sun3_get_segmap(i);
+            if(seg == SUN3_INVALID_PMEG)
+                    continue;
+
+            sun3_put_segmap(i, SUN3_INVALID_PMEG);
+            pmeg_alloc[seg] = 0;
+            pmeg_ctx[seg] = 0;
+            pmeg_vaddr[seg] = 0;
+     }
+
+     sun3_put_context(oldctx);
+
+}
+
+/* Flush a single TLB page. In this case, we're limited to flushing a
+   single PMEG */
+static inline void flush_tlb_page (struct vm_area_struct *vma,
+                                  unsigned long addr)
+{
+       unsigned char oldctx;
+       unsigned char i;
+
+       oldctx = sun3_get_context();
+       sun3_put_context(vma->vm_mm->context);
+       addr &= ~SUN3_PMEG_MASK;
+       if((i = sun3_get_segmap(addr)) != SUN3_INVALID_PMEG)
+       {
+               pmeg_alloc[i] = 0;
+               pmeg_ctx[i] = 0;
+               pmeg_vaddr[i] = 0;
+               sun3_put_segmap (addr,  SUN3_INVALID_PMEG);
+       }
+       sun3_put_context(oldctx);
+
+}
+/* Flush a range of pages from TLB. */
+
+static inline void flush_tlb_range (struct vm_area_struct *vma,
+                     unsigned long start, unsigned long end)
+{
+       struct mm_struct *mm = vma->vm_mm;
+       unsigned char seg, oldctx;
+
+       start &= ~SUN3_PMEG_MASK;
+
+       oldctx = sun3_get_context();
+       sun3_put_context(mm->context);
+
+       while(start < end)
+       {
+               if((seg = sun3_get_segmap(start)) == SUN3_INVALID_PMEG)
+                    goto next;
+               if(pmeg_ctx[seg] == mm->context) {
+                       pmeg_alloc[seg] = 0;
+                       pmeg_ctx[seg] = 0;
+                       pmeg_vaddr[seg] = 0;
+               }
+               sun3_put_segmap(start, SUN3_INVALID_PMEG);
+       next:
+               start += SUN3_PMEG_SIZE;
+       }
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       flush_tlb_all();
+}
+
+/* Flush kernel page from TLB. */
+static inline void flush_tlb_kernel_page (unsigned long addr)
+{
+       sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG);
+}
+
 #endif
+
+#else /* !CONFIG_MMU */
+
+/*
+ * flush all user-space atc entries.
+ */
+static inline void __flush_tlb(void)
+{
+       BUG();
+}
+
+static inline void __flush_tlb_one(unsigned long addr)
+{
+       BUG();
+}
+
+#define flush_tlb() __flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+       BUG();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+       BUG();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+       BUG();
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+                                  unsigned long start, unsigned long end)
+{
+       BUG();
+}
+
+static inline void flush_tlb_kernel_page(unsigned long addr)
+{
+       BUG();
+}
+
+#endif /* CONFIG_MMU */
+
+#endif /* _M68K_TLBFLUSH_H */
diff --git a/arch/m68k/include/asm/tlbflush_mm.h b/arch/m68k/include/asm/tlbflush_mm.h
deleted file mode 100644 (file)
index acb6bf2..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-#ifndef _M68K_TLBFLUSH_H
-#define _M68K_TLBFLUSH_H
-
-
-#ifndef CONFIG_SUN3
-
-#include <asm/current.h>
-
-static inline void flush_tlb_kernel_page(void *addr)
-{
-       if (CPU_IS_040_OR_060) {
-               mm_segment_t old_fs = get_fs();
-               set_fs(KERNEL_DS);
-               __asm__ __volatile__(".chip 68040\n\t"
-                                    "pflush (%0)\n\t"
-                                    ".chip 68k"
-                                    : : "a" (addr));
-               set_fs(old_fs);
-       } else if (CPU_IS_020_OR_030)
-               __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
-}
-
-/*
- * flush all user-space atc entries.
- */
-static inline void __flush_tlb(void)
-{
-       if (CPU_IS_040_OR_060)
-               __asm__ __volatile__(".chip 68040\n\t"
-                                    "pflushan\n\t"
-                                    ".chip 68k");
-       else if (CPU_IS_020_OR_030)
-               __asm__ __volatile__("pflush #0,#4");
-}
-
-static inline void __flush_tlb040_one(unsigned long addr)
-{
-       __asm__ __volatile__(".chip 68040\n\t"
-                            "pflush (%0)\n\t"
-                            ".chip 68k"
-                            : : "a" (addr));
-}
-
-static inline void __flush_tlb_one(unsigned long addr)
-{
-       if (CPU_IS_040_OR_060)
-               __flush_tlb040_one(addr);
-       else if (CPU_IS_020_OR_030)
-               __asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
-}
-
-#define flush_tlb() __flush_tlb()
-
-/*
- * flush all atc entries (both kernel and user-space entries).
- */
-static inline void flush_tlb_all(void)
-{
-       if (CPU_IS_040_OR_060)
-               __asm__ __volatile__(".chip 68040\n\t"
-                                    "pflusha\n\t"
-                                    ".chip 68k");
-       else if (CPU_IS_020_OR_030)
-               __asm__ __volatile__("pflusha");
-}
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-       if (mm == current->active_mm)
-               __flush_tlb();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
-{
-       if (vma->vm_mm == current->active_mm) {
-               mm_segment_t old_fs = get_fs();
-               set_fs(USER_DS);
-               __flush_tlb_one(addr);
-               set_fs(old_fs);
-       }
-}
-
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-                                  unsigned long start, unsigned long end)
-{
-       if (vma->vm_mm == current->active_mm)
-               __flush_tlb();
-}
-
-static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-       flush_tlb_all();
-}
-
-#else
-
-
-/* Reserved PMEGs. */
-extern char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
-extern unsigned long pmeg_vaddr[SUN3_PMEGS_NUM];
-extern unsigned char pmeg_alloc[SUN3_PMEGS_NUM];
-extern unsigned char pmeg_ctx[SUN3_PMEGS_NUM];
-
-/* Flush all userspace mappings one by one...  (why no flush command,
-   sun?) */
-static inline void flush_tlb_all(void)
-{
-       unsigned long addr;
-       unsigned char ctx, oldctx;
-
-       oldctx = sun3_get_context();
-       for(addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) {
-              for(ctx = 0; ctx < 8; ctx++) {
-                      sun3_put_context(ctx);
-                      sun3_put_segmap(addr, SUN3_INVALID_PMEG);
-              }
-       }
-
-       sun3_put_context(oldctx);
-       /* erase all of the userspace pmeg maps, we've clobbered them
-         all anyway */
-       for(addr = 0; addr < SUN3_INVALID_PMEG; addr++) {
-              if(pmeg_alloc[addr] == 1) {
-                      pmeg_alloc[addr] = 0;
-                      pmeg_ctx[addr] = 0;
-                      pmeg_vaddr[addr] = 0;
-              }
-       }
-
-}
-
-/* Clear user TLB entries within the context named in mm */
-static inline void flush_tlb_mm (struct mm_struct *mm)
-{
-     unsigned char oldctx;
-     unsigned char seg;
-     unsigned long i;
-
-     oldctx = sun3_get_context();
-     sun3_put_context(mm->context);
-
-     for(i = 0; i < TASK_SIZE; i += SUN3_PMEG_SIZE) {
-            seg = sun3_get_segmap(i);
-            if(seg == SUN3_INVALID_PMEG)
-                    continue;
-
-            sun3_put_segmap(i, SUN3_INVALID_PMEG);
-            pmeg_alloc[seg] = 0;
-            pmeg_ctx[seg] = 0;
-            pmeg_vaddr[seg] = 0;
-     }
-
-     sun3_put_context(oldctx);
-
-}
-
-/* Flush a single TLB page. In this case, we're limited to flushing a
-   single PMEG */
-static inline void flush_tlb_page (struct vm_area_struct *vma,
-                                  unsigned long addr)
-{
-       unsigned char oldctx;
-       unsigned char i;
-
-       oldctx = sun3_get_context();
-       sun3_put_context(vma->vm_mm->context);
-       addr &= ~SUN3_PMEG_MASK;
-       if((i = sun3_get_segmap(addr)) != SUN3_INVALID_PMEG)
-       {
-               pmeg_alloc[i] = 0;
-               pmeg_ctx[i] = 0;
-               pmeg_vaddr[i] = 0;
-               sun3_put_segmap (addr,  SUN3_INVALID_PMEG);
-       }
-       sun3_put_context(oldctx);
-
-}
-/* Flush a range of pages from TLB. */
-
-static inline void flush_tlb_range (struct vm_area_struct *vma,
-                     unsigned long start, unsigned long end)
-{
-       struct mm_struct *mm = vma->vm_mm;
-       unsigned char seg, oldctx;
-
-       start &= ~SUN3_PMEG_MASK;
-
-       oldctx = sun3_get_context();
-       sun3_put_context(mm->context);
-
-       while(start < end)
-       {
-               if((seg = sun3_get_segmap(start)) == SUN3_INVALID_PMEG)
-                    goto next;
-               if(pmeg_ctx[seg] == mm->context) {
-                       pmeg_alloc[seg] = 0;
-                       pmeg_ctx[seg] = 0;
-                       pmeg_vaddr[seg] = 0;
-               }
-               sun3_put_segmap(start, SUN3_INVALID_PMEG);
-       next:
-               start += SUN3_PMEG_SIZE;
-       }
-}
-
-static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-       flush_tlb_all();
-}
-
-/* Flush kernel page from TLB. */
-static inline void flush_tlb_kernel_page (unsigned long addr)
-{
-       sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG);
-}
-
-#endif
-
-#endif /* _M68K_TLBFLUSH_H */
diff --git a/arch/m68k/include/asm/tlbflush_no.h b/arch/m68k/include/asm/tlbflush_no.h
deleted file mode 100644 (file)
index a470cfb..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _M68KNOMMU_TLBFLUSH_H
-#define _M68KNOMMU_TLBFLUSH_H
-
-/*
- * Copyright (C) 2000 Lineo, David McCullough <davidm@uclinux.org>
- * Copyright (C) 2000-2002, Greg Ungerer <gerg@snapgear.com>
- */
-
-#include <asm/setup.h>
-
-/*
- * flush all user-space atc entries.
- */
-static inline void __flush_tlb(void)
-{
-       BUG();
-}
-
-static inline void __flush_tlb_one(unsigned long addr)
-{
-       BUG();
-}
-
-#define flush_tlb() __flush_tlb()
-
-/*
- * flush all atc entries (both kernel and user-space entries).
- */
-static inline void flush_tlb_all(void)
-{
-       BUG();
-}
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-       BUG();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
-{
-       BUG();
-}
-
-static inline void flush_tlb_range(struct mm_struct *mm,
-                                  unsigned long start, unsigned long end)
-{
-       BUG();
-}
-
-static inline void flush_tlb_kernel_page(unsigned long addr)
-{
-       BUG();
-}
-
-#endif /* _M68KNOMMU_TLBFLUSH_H */
index b53cd160c0b33849d127a687f160d2cd6173d4be..e4e22669edc0669c55c1edc9a1947664b3c1d4bc 100644 (file)
@@ -1,5 +1,30 @@
-#ifdef __uClinux__
-#include "ucontext_no.h"
-#else
-#include "ucontext_mm.h"
+#ifndef _M68K_UCONTEXT_H
+#define _M68K_UCONTEXT_H
+
+typedef int greg_t;
+#define NGREG 18
+typedef greg_t gregset_t[NGREG];
+
+typedef struct fpregset {
+       int f_fpcntl[3];
+       int f_fpregs[8*3];
+} fpregset_t;
+
+struct mcontext {
+       int version;
+       gregset_t gregs;
+       fpregset_t fpregs;
+};
+
+#define MCONTEXT_VERSION 2
+
+struct ucontext {
+       unsigned long     uc_flags;
+       struct ucontext  *uc_link;
+       stack_t           uc_stack;
+       struct mcontext   uc_mcontext;
+       unsigned long     uc_filler[80];
+       sigset_t          uc_sigmask;   /* mask last for extensibility */
+};
+
 #endif
diff --git a/arch/m68k/include/asm/ucontext_mm.h b/arch/m68k/include/asm/ucontext_mm.h
deleted file mode 100644 (file)
index e4e2266..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _M68K_UCONTEXT_H
-#define _M68K_UCONTEXT_H
-
-typedef int greg_t;
-#define NGREG 18
-typedef greg_t gregset_t[NGREG];
-
-typedef struct fpregset {
-       int f_fpcntl[3];
-       int f_fpregs[8*3];
-} fpregset_t;
-
-struct mcontext {
-       int version;
-       gregset_t gregs;
-       fpregset_t fpregs;
-};
-
-#define MCONTEXT_VERSION 2
-
-struct ucontext {
-       unsigned long     uc_flags;
-       struct ucontext  *uc_link;
-       stack_t           uc_stack;
-       struct mcontext   uc_mcontext;
-       unsigned long     uc_filler[80];
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
-};
-
-#endif
diff --git a/arch/m68k/include/asm/ucontext_no.h b/arch/m68k/include/asm/ucontext_no.h
deleted file mode 100644 (file)
index 713a27f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _M68KNOMMU_UCONTEXT_H
-#define _M68KNOMMU_UCONTEXT_H
-
-typedef int greg_t;
-#define NGREG 18
-typedef greg_t gregset_t[NGREG];
-
-typedef struct fpregset {
-       int f_pcr;
-       int f_psr;
-       int f_fpiaddr;
-       int f_fpregs[8][3];
-} fpregset_t;
-
-struct mcontext {
-       int version;
-       gregset_t gregs;
-       fpregset_t fpregs;
-};
-
-#define MCONTEXT_VERSION 2
-
-struct ucontext {
-       unsigned long     uc_flags;
-       struct ucontext  *uc_link;
-       stack_t           uc_stack;
-       struct mcontext   uc_mcontext;
-       unsigned long     uc_filler[80];
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
-};
-
-#endif
index c640bba3bdf455f0d1830998198d7a74f2618ab4..019caa740c21122a9a39892f69831a060a549021 100644 (file)
@@ -1,5 +1,25 @@
-#ifdef __uClinux__
-#include "unaligned_no.h"
+#ifndef _ASM_M68K_UNALIGNED_H
+#define _ASM_M68K_UNALIGNED_H
+
+
+#ifdef CONFIG_COLDFIRE
+#include <linux/unaligned/be_struct.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
+
+#define get_unaligned  __get_unaligned_be
+#define put_unaligned  __put_unaligned_be
+
 #else
-#include "unaligned_mm.h"
+/*
+ * The m68k can do unaligned accesses itself. 
+ */
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
+
+#define get_unaligned  __get_unaligned_be
+#define put_unaligned  __put_unaligned_be
+
 #endif
+
+#endif /* _ASM_M68K_UNALIGNED_H */
diff --git a/arch/m68k/include/asm/unaligned_mm.h b/arch/m68k/include/asm/unaligned_mm.h
deleted file mode 100644 (file)
index 77698f2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _ASM_M68K_UNALIGNED_H
-#define _ASM_M68K_UNALIGNED_H
-
-/*
- * The m68k can do unaligned accesses itself.
- */
-#include <linux/unaligned/access_ok.h>
-#include <linux/unaligned/generic.h>
-
-#define get_unaligned  __get_unaligned_be
-#define put_unaligned  __put_unaligned_be
-
-#endif /* _ASM_M68K_UNALIGNED_H */
diff --git a/arch/m68k/include/asm/unaligned_no.h b/arch/m68k/include/asm/unaligned_no.h
deleted file mode 100644 (file)
index eb1ea4c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef _ASM_M68KNOMMU_UNALIGNED_H
-#define _ASM_M68KNOMMU_UNALIGNED_H
-
-
-#ifdef CONFIG_COLDFIRE
-#include <linux/unaligned/be_struct.h>
-#include <linux/unaligned/le_byteshift.h>
-#include <linux/unaligned/generic.h>
-
-#define get_unaligned  __get_unaligned_be
-#define put_unaligned  __put_unaligned_be
-
-#else
-/*
- * The m68k can do unaligned accesses itself. 
- */
-#include <linux/unaligned/access_ok.h>
-#include <linux/unaligned/generic.h>
-
-#define get_unaligned  __get_unaligned_be
-#define put_unaligned  __put_unaligned_be
-
-#endif
-
-#endif /* _ASM_M68KNOMMU_UNALIGNED_H */
index 632ce016014d27d6190d1776d86ecaa1503aeca6..ec37fb56c127a095ed8f5060c8af8ff6672f90d0 100644 (file)
@@ -233,7 +233,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
                       parent_tidptr, child_tidptr);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                 unsigned long unused,
                 struct task_struct * p, struct pt_regs * regs)
 {
index 7db41594d7b6b92d4beed91da8a6d847e16128af..54d980795fc45ceeaa021ad4fa98bd77f4d65508 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/rtc.h>
+#include <linux/platform_device.h>
 
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -159,3 +160,20 @@ int do_settimeofday(struct timespec *tv)
 }
 
 EXPORT_SYMBOL(do_settimeofday);
+
+
+static int __init rtc_init(void)
+{
+       struct platform_device *pdev;
+
+       if (!mach_hwclk)
+               return -ENODEV;
+
+       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return 0;
+}
+
+module_init(rtc_init);
index fd0fb303d885c1f048a9ec130695c8c3a4b8c21f..ce404bc9ccbdff8acf6c2160719964e4a0cfd6cd 100644 (file)
@@ -88,18 +88,18 @@ export PLATFORM BOARD MODEL CPUCLASS
 #
 # Some CFLAG additions based on specific CPU type.
 #
-cflags-$(CONFIG_M5206)         := -m5200
-cflags-$(CONFIG_M5206e)                := -m5200
-cflags-$(CONFIG_M520x)         := -m5307
+cflags-$(CONFIG_M5206)         := $(call cc-option,-mcpu=5206,-m5200)
+cflags-$(CONFIG_M5206e)                := $(call cc-option,-m5206e,-m5200)
+cflags-$(CONFIG_M520x)         := $(call cc-option,-mcpu=5208,-m5200)
 cflags-$(CONFIG_M523x)         := $(call cc-option,-mcpu=523x,-m5307)
-cflags-$(CONFIG_M5249)         := -m5200
+cflags-$(CONFIG_M5249)         := $(call cc-option,-mcpu=5249,-m5200)
 cflags-$(CONFIG_M5271)         := $(call cc-option,-mcpu=5271,-m5307)
-cflags-$(CONFIG_M5272)         := -m5307
+cflags-$(CONFIG_M5272)         := $(call cc-option,-mcpu=5271,-m5200)
 cflags-$(CONFIG_M5275)         := $(call cc-option,-mcpu=5275,-m5307)
 cflags-$(CONFIG_M528x)         := $(call cc-option,-m528x,-m5307)
-cflags-$(CONFIG_M5307)         := -m5307
+cflags-$(CONFIG_M5307)         := $(call cc-option,-m5307,-m5200)
 cflags-$(CONFIG_M532x)         := $(call cc-option,-mcpu=532x,-m5307)
-cflags-$(CONFIG_M5407)         := -m5200
+cflags-$(CONFIG_M5407)         := $(call cc-option,-m5407,-m5200)
 cflags-$(CONFIG_M68328)                := -m68000
 cflags-$(CONFIG_M68EZ328)      := -m68000
 cflags-$(CONFIG_M68VZ328)      := -m68000
index e10eafc52789e5f8dc3ca428449ff8fd0adb0b1e..93612580663851055d058e89321c791d6dfe4765 100644 (file)
@@ -9,10 +9,11 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 
 void *dma_alloc_coherent(struct device *dev, size_t size,
-                          dma_addr_t *dma_handle, int gfp)
+                          dma_addr_t *dma_handle, gfp_t gfp)
 {
        void *ret;
        /* ignore region specifiers */
@@ -34,3 +35,8 @@ void dma_free_coherent(struct device *dev, size_t size,
 {
        free_pages((unsigned long)vaddr, get_order(size));
 }
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+}
+
index bba1bb48a21f298d1b85ab5e66715d4674e60ad7..56e0f4c55a67bb32b9d9bdf4b147519de774f68d 100644 (file)
@@ -23,7 +23,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
        struct pt_regs *oldregs = set_irq_regs(regs);
 
        irq_enter();
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
        irq_exit();
 
        set_irq_regs(oldregs);
index 3f2d7745f31e8321f629b80dd1eceacced2a52e2..1e96c6eb631258f75946f9ab84f4ab26f1ab3890 100644 (file)
@@ -199,7 +199,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
         return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
 }
 
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                unsigned long usp, unsigned long topstk,
                struct task_struct * p, struct pt_regs * regs)
 {
index 3bf249c53e414834114bc845dde4b63afe8e2add..7befc0c357e0850a1635032c26c1632bd580c38c 100644 (file)
@@ -111,11 +111,7 @@ void __init paging_init(void)
        {
                unsigned long zones_size[MAX_NR_ZONES] = {0, };
 
-               zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT;
-               zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
-#ifdef CONFIG_HIGHMEM
-               zones_size[ZONE_HIGHMEM] = 0;
-#endif
+               zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
                free_area_init(zones_size);
        }
 }
index d299f7b8768a9981640733e60b51b5bb106a3bfb..9eab19d01eb1098f615694a577395fe77a693a31 100644 (file)
@@ -32,7 +32,8 @@ static struct mcf_platform_uart m5249_uart_platform[] = {
        {
                .mapbase        = MCF_MBAR + MCFUART_BASE2,
                .irq            = 74,
-       }
+       },
+       { },
 };
 
 static struct platform_device m5249_uart = {
@@ -50,12 +51,12 @@ static struct platform_device *m5249_devices[] __initdata = {
 static void __init m5249_uart_init_line(int line, int irq)
 {
        if (line == 0) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
                mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
        } else if (line == 1) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
                mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
        }
 }
index 724faf05852ae350ff827d09f76493d38fa65d76..44803bf70a6e0988868f3bd6a8815e1a35e2312c 100644 (file)
@@ -65,12 +65,12 @@ static struct platform_device *m5307_devices[] __initdata = {
 static void __init m5307_uart_init_line(int line, int irq)
 {
        if (line == 0) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
                mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
        } else if (line == 1) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
                mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
        }
 }
index 648b8b778211639fbf54ef9e7fae9d0e9e708e01..0ee8c1a200c87d5a4cad4e5e76421526fe947f1e 100644 (file)
@@ -56,12 +56,12 @@ static struct platform_device *m5407_devices[] __initdata = {
 static void __init m5407_uart_init_line(int line, int irq)
 {
        if (line == 0) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
                mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
        } else if (line == 1) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
                mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
        }
 }
index 4f416a91a829b38c9f130ecad667307ea0ef98f6..1bcb9372353fe8496966ce50f7a67cf2d32f80db 100644 (file)
@@ -14,7 +14,7 @@
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
 
-obj-$(CONFIG_COLDFIRE) += dma.o entry.o vectors.o
+obj-$(CONFIG_COLDFIRE) += clk.o dma.o entry.o vectors.o
 obj-$(CONFIG_M5206)    += timers.o
 obj-$(CONFIG_M5206e)   += timers.o
 obj-$(CONFIG_M520x)    += pit.o
diff --git a/arch/m68knommu/platform/coldfire/clk.c b/arch/m68knommu/platform/coldfire/clk.c
new file mode 100644 (file)
index 0000000..7cdbf44
--- /dev/null
@@ -0,0 +1,40 @@
+/***************************************************************************/
+
+/*
+ *     clk.c -- general ColdFire CPU kernel clk handling
+ *
+ *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <asm/coldfire.h>
+
+/***************************************************************************/
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       return NULL;
+}
+
+int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+}
+
+void clk_put(struct clk *clk)
+{
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return MCF_CLK;
+}
+
+/***************************************************************************/
index dc787190430a44d18bb2ff69d0f7ca5ee1e4452a..998e5db8cc0ff3f8027748f3442fc16e3d9872cb 100644 (file)
@@ -134,7 +134,7 @@ config MACH_JAZZ
        help
         This a family of machines based on the MIPS R4030 chipset which was
         used by several vendors to build RISC/os and Windows NT workstations.
-        Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and
+        Members include the Acer PICA, MIPS Magnum 4000, MIPS Millennium and
         Olivetti M700-10 workstations.
 
 config LASAT
index ac4fb912649d4e2397083864e06e62169f77a1d6..cb9bf820fe53b4640a7b72264be61deacf998fa7 100644 (file)
@@ -47,7 +47,6 @@ asmlinkage void plat_irq_dispatch(void)
 
 static struct irqaction cascade = {
        .handler        = no_action,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index 2bbc41a1623cae2a3972084af3ce8118b85adc93..43828ae796ec9d0d3276b50ffe5b8f0c29ea1b2f 100644 (file)
@@ -186,7 +186,6 @@ void emma2rh_gpio_irq_init(void)
 static struct irqaction irq_cascade = {
           .handler = no_action,
           .flags = 0,
-          .mask = CPU_MASK_NONE,
           .name = "cascade",
           .dev_id = NULL,
           .next = NULL,
index d8ff4cd89ab50731d68f360f04bf5b08d9b779be..1784fde2e28fc3ae4f69d338863c907148c56ba1 100644 (file)
@@ -31,24 +31,28 @@ static inline void gpio_set_value(unsigned gpio, int value)
 
 static inline int gpio_direction_input(unsigned gpio)
 {
-       return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
+       ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
+       return 0;
 }
 
 static inline int gpio_direction_output(unsigned gpio, int value)
 {
-       return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
+       ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
+       return 0;
 }
 
-static int gpio_intmask(unsigned gpio, int value)
+static inline int gpio_intmask(unsigned gpio, int value)
 {
-       return ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
-                               value ? 1 << gpio : 0);
+       ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
+                        value ? 1 << gpio : 0);
+       return 0;
 }
 
-static int gpio_polarity(unsigned gpio, int value)
+static inline int gpio_polarity(unsigned gpio, int value)
 {
-       return ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
-                                value ? 1 << gpio : 0);
+       ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
+                         value ? 1 << gpio : 0);
+       return 0;
 }
 
 
index 55d481569a1f494e1c33a71fe22bbfb8b88f9af4..07547231e078dd3ecd35a988b3cd73bfc30c3683 100644 (file)
@@ -26,7 +26,6 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
 #define parent_node(node)      (node)
 #define node_to_cpumask(node)  (hub_data(node)->h_cpus)
 #define cpumask_of_node(node)  (&hub_data(node)->h_cpus)
-#define node_to_first_cpu(node)        (cpumask_first(cpumask_of_node(node)))
 struct pci_bus;
 extern int pcibus_to_node(struct pci_bus *);
 
index 10e82441b49612ddf057618e56520df8e9fdce67..5b60a09a0f0894e8c8b1301683064b841a5b8e4b 100644 (file)
@@ -480,6 +480,8 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return ret;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
 
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
index a73e1531e151fc7b0645038bea939aba58e5ce09..40005010827cb4f72c1734778a520a74c7958153 100644 (file)
 #define __NR_dup3                      (__NR_Linux + 327)
 #define __NR_pipe2                     (__NR_Linux + 328)
 #define __NR_inotify_init1             (__NR_Linux + 329)
+#define __NR_preadv                    (__NR_Linux + 330)
+#define __NR_pwritev                   (__NR_Linux + 331)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            329
+#define __NR_Linux_syscalls            331
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                329
+#define __NR_O32_Linux_syscalls                331
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_dup3                      (__NR_Linux + 286)
 #define __NR_pipe2                     (__NR_Linux + 287)
 #define __NR_inotify_init1             (__NR_Linux + 288)
+#define __NR_preadv                    (__NR_Linux + 289)
+#define __NR_pwritev                   (__NR_Linux + 290)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            288
+#define __NR_Linux_syscalls            290
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         288
+#define __NR_64_Linux_syscalls         290
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_dup3                      (__NR_Linux + 290)
 #define __NR_pipe2                     (__NR_Linux + 291)
 #define __NR_inotify_init1             (__NR_Linux + 292)
+#define __NR_preadv                    (__NR_Linux + 293)
+#define __NR_pwritev                   (__NR_Linux + 294)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            292
+#define __NR_Linux_syscalls            294
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                292
+#define __NR_N32_Linux_syscalls                294
 
 #ifdef __KERNEL__
 
index 03965cb1b2527e23fd60a003284f51279b42a758..d9b6a5b5399d25b3959921288e84b08074571965 100644 (file)
@@ -134,7 +134,6 @@ static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id)
 static struct irqaction r4030_timer_irqaction = {
        .handler        = r4030_timer_interrupt,
        .flags          = IRQF_DISABLED,
-       .mask           = CPU_MASK_CPU0,
        .name           = "R4030 timer",
 };
 
index b820661678b0b948e7fb56e8332a28277df07a98..a5182a20769619dda6bc81a216f89e2059769052 100644 (file)
@@ -144,7 +144,6 @@ void __cpuinit sb1480_clockevent_init(void)
 
        action->handler = sibyte_counter_handler;
        action->flags   = IRQF_DISABLED | IRQF_PERCPU;
-       action->mask    = cpumask_of_cpu(cpu);
        action->name    = name;
        action->dev_id  = cd;
 
index a2eebaafda52c224ee385193bcb998984d9d790d..340f53e5c6b19cd686f2a45bd69dc3f139d581d1 100644 (file)
@@ -143,7 +143,6 @@ void __cpuinit sb1250_clockevent_init(void)
 
        action->handler = sibyte_counter_handler;
        action->flags   = IRQF_DISABLED | IRQF_PERCPU;
-       action->mask    = cpumask_of_cpu(cpu);
        action->name    = name;
        action->dev_id  = cd;
 
index f4d187825f96406612d16a6016ab8defcf997658..689719e34f085db04c1c09f8d18b89f1b9da91cd 100644 (file)
@@ -98,7 +98,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED | IRQF_NOBALANCING,
-       .mask = CPU_MASK_NONE,
        .name = "timer"
 };
 
@@ -121,7 +120,6 @@ void __init setup_pit_timer(void)
        cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
        clockevents_register_device(cd);
 
-       irq0.mask = cpumask_of_cpu(cpu);
        setup_irq(0, &irq0);
 }
 
index 413bd1d37f5499171e4337b78ee62f387152d811..01c0885a8061569dffe59d31e7ec7aee97588773 100644 (file)
@@ -306,7 +306,6 @@ static void init_8259A(int auto_eoi)
  */
 static struct irqaction irq2 = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 
index ca2e4026ad20b3c00365d0dc3b85904bbd2e273a..1eaaa450e20c3a83be8daf6cafe0e2935e45e5a1 100644 (file)
@@ -99,7 +99,7 @@ void flush_thread(void)
 {
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
        unsigned long unused, struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *ti = task_thread_info(p);
index 9ab70c3b5be6bac233e00568ac3ce9dd51f410e8..0b31b9bda0486988128d39d07d52ac2c0d0ad8d8 100644 (file)
@@ -650,6 +650,8 @@ einval:     li      v0, -ENOSYS
        sys     sys_dup3                3
        sys     sys_pipe2               2
        sys     sys_inotify_init1       1
+       sys     sys_preadv              6       /* 4330 */
+       sys     sys_pwritev             6
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index 9b46986671545dea233ce1f96aca4f59e7eb912a..c647fd6e722f7acb2872ad0f01491b6f2a2637e9 100644 (file)
@@ -487,4 +487,6 @@ sys_call_table:
        PTR     sys_dup3
        PTR     sys_pipe2
        PTR     sys_inotify_init1
+       PTR     sys_preadv
+       PTR     sys_pwritev                     /* 5390 */
        .size   sys_call_table,.-sys_call_table
index f61d6b0e5731dadfcac24715babed10639ce97d2..c2c16ef9218febbb8123e6bf320f1fc5ace5c79e 100644 (file)
@@ -413,4 +413,6 @@ EXPORT(sysn32_call_table)
        PTR     sys_dup3                        /* 5290 */
        PTR     sys_pipe2
        PTR     sys_inotify_init1
+       PTR     sys_preadv
+       PTR     sys_pwritev
        .size   sysn32_call_table,.-sysn32_call_table
index 60997f1f69d4e857861df014ab37e403f1d53c60..002fac27021e61c2ed5aeac2de56b8a01ac70651 100644 (file)
@@ -533,4 +533,6 @@ sys_call_table:
        PTR     sys_dup3
        PTR     sys_pipe2
        PTR     sys_inotify_init1
+       PTR     compat_sys_preadv               /* 4330 */
+       PTR     compat_sys_pwritev
        .size   sys_call_table,.-sys_call_table
index d1ac7a25c85613635cdc14dc7858ff44d921e099..1353fb135ed370969d9b2b7628a13cd041470542 100644 (file)
@@ -104,7 +104,6 @@ asmlinkage void plat_irq_dispatch(void)
 
 static struct irqaction cascade = {
        .handler        = no_action,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index 3e0b7beb1009b336c0eee30f2da22428d6196db2..1d0a09f3b832a69d4617f37222209fc1a569cc0b 100644 (file)
@@ -92,7 +92,6 @@ asmlinkage void plat_irq_dispatch(void)
 
 static struct irqaction cascade_irqaction = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 
index 060d28dca8a8b9b9d21452b6b0cf4c8c00ad88d8..4481656d10656f37a6e088dbb91aa50286216646 100644 (file)
@@ -42,6 +42,7 @@ void *__kmap_atomic(struct page *page, enum km_type type)
        if (!PageHighMem(page))
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -88,6 +89,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
 
        pagefault_disable();
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot));
index a1f21d9421e86e7002f99946864118de9d5000dc..6c5a630566f93d77997839577fbc5386c5830c97 100644 (file)
@@ -219,7 +219,7 @@ cont_nmi_dump(void)
                if (i == 1000) {
                        for_each_online_node(node)
                                if (NODEPDA(node)->dump_count == 0) {
-                                       cpu = node_to_first_cpu(node);
+                                       cpu = cpumask_first(cpumask_of_node(node));
                                        for (n=0; n < CNODE_NUM_CPUS(node); cpu++, n++) {
                                                CPUMASK_SETB(nmied_cpus, cpu);
                                                /*
index 5b47d6b65275ba6835043e8a050958ba014d0ed2..cbcd7eb83bd1a57a17f4157030c09b965cc91322 100644 (file)
@@ -221,7 +221,7 @@ static void __init ip27_smp_setup(void)
         * Assumption to be fixed: we're always booted on logical / physical
         * processor 0.  While we're always running on logical processor 0
         * this still means this is physical processor zero; it might for
-        * example be disabled in the firwware.
+        * example be disabled in the firmware.
         */
        alloc_cpupda(0, 0);
 }
index 0aefc5319a036c938d2db3cff9989ac72b12fa3e..83a0b3c359daecee88c87223beef876d9b35aab9 100644 (file)
@@ -115,14 +115,12 @@ extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
 struct irqaction memerr_irq = {
        .handler = crime_memerr_intr,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "CRIME memory error",
 };
 
 struct irqaction cpuerr_irq = {
        .handler = crime_cpuerr_intr,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "CRIME CPU error",
 };
 
index b4352a0c815178f09a90e7561b5fc966fd64eba4..5e687819cbc2aec4aec85dbada30184a345a6551 100644 (file)
@@ -359,7 +359,8 @@ void sni_rm200_init_8259A(void)
  * IRQ2 is cascade interrupt to second interrupt controller
  */
 static struct irqaction sni_rm200_irq2 = {
-       no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL
+       .handler = no_action,
+       .name = "cascade",
 };
 
 static struct resource sni_rm200_pic1_resource = {
index 92dd1a0ca3523023a30d887067c9e280864cfce5..9cc389109b19f42ee82f5d09f69b8d3e8de27024 100644 (file)
@@ -32,7 +32,6 @@ static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
 
 static struct irqaction cascade_irqaction = {
        .handler        = no_action,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index b28c9a60445bda4df1f4f83de51346b121e36067..234cf344cdceb1e39f550947ddae8d2331435d63 100644 (file)
@@ -193,7 +193,7 @@ void prepare_to_copy(struct task_struct *tsk)
  * set up the kernel stack for a new thread and copy arch-specific thread
  * control information
  */
-int copy_thread(int nr, unsigned long clone_flags,
+int copy_thread(unsigned long clone_flags,
                unsigned long c_usp, unsigned long ustk_size,
                struct task_struct *p, struct pt_regs *kregs)
 {
index e4606586f94ce5e08d35720ca8b4f7512db4aa34..395caf01b9099cc42c2b2e3b0148765df3de0ed9 100644 (file)
@@ -37,7 +37,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id);
 static struct irqaction timer_irq = {
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
        .name           = "timer",
 };
 
index aacf11d33723edc80aa3638ba5256e83d0c74bf2..9038f39d9d736320996f95e6bae5d10473895da0 100644 (file)
@@ -9,9 +9,13 @@ config PARISC
        def_bool y
        select HAVE_IDE
        select HAVE_OPROFILE
+       select HAVE_FUNCTION_TRACER if 64BIT
+       select HAVE_FUNCTION_GRAPH_TRACER if 64BIT
+       select HAVE_FUNCTION_TRACE_MCOUNT_TEST if 64BIT
        select RTC_CLASS
-       select RTC_DRV_PARISC
+       select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
+       select BUG
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
          in many of their workstations & servers (HP9000 700 and 800 series,
@@ -75,6 +79,9 @@ config GENERIC_HARDIRQS
 config GENERIC_IRQ_PROBE
        def_bool y
 
+config HAVE_LATENCYTOP_SUPPORT
+        def_bool y
+
 config IRQ_PER_CPU
        bool
        default y
@@ -83,6 +90,9 @@ config IRQ_PER_CPU
 config PM
        bool
 
+config STACKTRACE_SUPPORT
+       def_bool y
+
 config ISA_DMA_API
        bool
 
index 0d428278356dd2b526ff904b34d9f421dc35c5d1..da6f66901c92191c2069ba2dbd8144951584936b 100644 (file)
@@ -56,7 +56,9 @@ cflags-y      += -mdisable-fpregs
 
 # Without this, "ld -r" results in .text sections that are too big
 # (> 0x40000) for branches to reach stubs.
-cflags-y       += -ffunction-sections
+ifndef CONFIG_FUNCTION_TRACER
+  cflags-y     += -ffunction-sections
+endif
 
 # select which processor to optimise for
 cflags-$(CONFIG_PA7100)                += -march=1.1 -mschedule=7100
index edbfe25c5fc142475e26d7ffff051d5a61003731..ada3e5364d8254993f85d9586c51abb1278cb6bc 100644 (file)
@@ -25,7 +25,7 @@
  * Since "a" is usually an address, use one spinlock per cacheline.
  */
 #  define ATOMIC_HASH_SIZE 4
-#  define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
+#  define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) (a))/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
 
 extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
 
@@ -222,13 +222,13 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
-#define atomic_add(i,v)        ((void)(__atomic_add_return( ((int)i),(v))))
-#define atomic_sub(i,v)        ((void)(__atomic_add_return(-((int)i),(v))))
+#define atomic_add(i,v)        ((void)(__atomic_add_return( ((int)(i)),(v))))
+#define atomic_sub(i,v)        ((void)(__atomic_add_return(-((int)(i)),(v))))
 #define atomic_inc(v)  ((void)(__atomic_add_return(   1,(v))))
 #define atomic_dec(v)  ((void)(__atomic_add_return(  -1,(v))))
 
-#define atomic_add_return(i,v) (__atomic_add_return( ((int)i),(v)))
-#define atomic_sub_return(i,v) (__atomic_add_return(-((int)i),(v)))
+#define atomic_add_return(i,v) (__atomic_add_return( ((int)(i)),(v)))
+#define atomic_sub_return(i,v) (__atomic_add_return(-((int)(i)),(v)))
 #define atomic_inc_return(v)   (__atomic_add_return(   1,(v)))
 #define atomic_dec_return(v)   (__atomic_add_return(  -1,(v)))
 
@@ -289,13 +289,13 @@ 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_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_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)))
 
index b7ca6dc7fddc89d484f9a210ff24ea48eaf48d74..724395143f268c3727d716d9dd02cba87ca2c859 100644 (file)
@@ -97,6 +97,9 @@ void mark_rodata_ro(void);
 
 #ifdef CONFIG_PA8X00
 /* Only pa8800, pa8900 needs this */
+
+#include <asm/kmap_types.h>
+
 #define ARCH_HAS_KMAP
 
 void kunmap_parisc(void *addr);
index 7fa675799e6d2cad21304698f7dec833a12224e7..9c802eb4be8491e95f932c9efb487f4b751ac5d4 100644 (file)
@@ -168,6 +168,16 @@ typedef struct elf64_fdesc {
        __u64   gp;
 } Elf64_Fdesc;
 
+#ifdef __KERNEL__
+
+#ifdef CONFIG_64BIT
+#define Elf_Fdesc      Elf64_Fdesc
+#else
+#define Elf_Fdesc      Elf32_Fdesc
+#endif /*CONFIG_64BIT*/
+
+#endif /*__KERNEL__*/
+
 /* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
 
 #define PT_HP_TLS              (PT_LOOS + 0x0)
diff --git a/arch/parisc/include/asm/ftrace.h b/arch/parisc/include/asm/ftrace.h
new file mode 100644 (file)
index 0000000..2fa05dd
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _ASM_PARISC_FTRACE_H
+#define _ASM_PARISC_FTRACE_H
+
+#ifndef __ASSEMBLY__
+extern void mcount(void);
+
+/*
+ * Stack of return addresses for functions of a thread.
+ * Used in struct thread_info
+ */
+struct ftrace_ret_stack {
+       unsigned long ret;
+       unsigned long func;
+       unsigned long long calltime;
+};
+
+/*
+ * Primary handler of a function return.
+ * It relays on ftrace_return_to_handler.
+ * Defined in entry.S
+ */
+extern void return_to_handler(void);
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_PARISC_FTRACE_H */
index c3941f09a87891e79c52f05f182ed84e0f0fc0c9..7bc5125d7d4c9f83a1f7bcd6b4bf980d4fdbaea3 100644 (file)
@@ -36,16 +36,7 @@ void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
  */
 #define STRICT_MM_TYPECHECKS
 #ifdef STRICT_MM_TYPECHECKS
-typedef struct { unsigned long pte;
-#if !defined(CONFIG_64BIT)
-                 unsigned long future_flags;
- /* XXX: it's possible to remove future_flags and change BITS_PER_PTE_ENTRY
-        to 2, but then strangely the identical 32bit kernel boots on a
-        c3000(pa20), but not any longer on a 715(pa11).
-        Still investigating... HelgeD.
-  */
-#endif
-} pte_t; /* either 32 or 64bit */
+typedef struct { unsigned long pte; } pte_t; /* either 32 or 64bit */
 
 /* NOTE: even on 64 bits, these entries are __u32 because we allocate
  * the pmd and pgd in ZONE_DMA (i.e. under 4GB) */
@@ -111,7 +102,7 @@ extern int npmem_ranges;
 #define BITS_PER_PMD_ENTRY     2
 #define BITS_PER_PGD_ENTRY     2
 #else
-#define BITS_PER_PTE_ENTRY     3
+#define BITS_PER_PTE_ENTRY     2
 #define BITS_PER_PMD_ENTRY     2
 #define BITS_PER_PGD_ENTRY     BITS_PER_PMD_ENTRY
 #endif
index 430f1aeea0b896334a2ec6f1affbc7e44694d01f..4ca510b3c6f800e7dabe3affcf02c73b7f44dede 100644 (file)
@@ -49,6 +49,8 @@
 #define PDC_MODEL_CPU_ID       6       /* returns cpu-id (only newer machines!) */
 #define PDC_MODEL_CAPABILITIES 7       /* returns OS32/OS64-flags      */
 /* Values for PDC_MODEL_CAPABILITIES non-equivalent virtual aliasing support */
+#define  PDC_MODEL_OS64                        (1 << 0)
+#define  PDC_MODEL_OS32                        (1 << 1)
 #define  PDC_MODEL_IOPDIR_FDC          (1 << 2)
 #define  PDC_MODEL_NVA_MASK            (3 << 4)
 #define  PDC_MODEL_NVA_SUPPORTED       (0 << 4)
 
 #ifdef __KERNEL__
 
+#include <asm/page.h> /* for __PAGE_OFFSET */
+
 extern int pdc_type;
 
 /* Values for pdc_type */
index 470a4b88124da2fcfb8c9936f523abd2662079a2..a27d2e200fb2a62519ba1dc281ebf0d3abe8f8be 100644 (file)
        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
 
 /* This is the size of the initially mapped kernel memory */
-#ifdef CONFIG_64BIT
 #define KERNEL_INITIAL_ORDER   24      /* 0 to 1<<24 = 16MB */
-#else
-#define KERNEL_INITIAL_ORDER   23      /* 0 to 1<<23 = 8MB */
-#endif
 #define KERNEL_INITIAL_SIZE    (1 << KERNEL_INITIAL_ORDER)
 
 #if defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB)
 
 /* Definitions for 1st level */
 #define PGDIR_SHIFT    (PMD_SHIFT + BITS_PER_PMD)
+#if (PGDIR_SHIFT + PAGE_SHIFT + PGD_ORDER - BITS_PER_PGD_ENTRY) > BITS_PER_LONG
+#define BITS_PER_PGD   (BITS_PER_LONG - PGDIR_SHIFT)
+#else
 #define BITS_PER_PGD   (PAGE_SHIFT + PGD_ORDER - BITS_PER_PGD_ENTRY)
+#endif
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 #define PTRS_PER_PGD    (1UL << BITS_PER_PGD)
 #define USER_PTRS_PER_PGD       PTRS_PER_PGD
 
+#ifdef CONFIG_64BIT
 #define MAX_ADDRBITS   (PGDIR_SHIFT + BITS_PER_PGD)
 #define MAX_ADDRESS    (1UL << MAX_ADDRBITS)
-
 #define SPACEID_SHIFT  (MAX_ADDRBITS - 32)
+#else
+#define MAX_ADDRBITS   (BITS_PER_LONG)
+#define MAX_ADDRESS    (1UL << MAX_ADDRBITS)
+#define SPACEID_SHIFT  0
+#endif
 
 /* This calculates the number of initial pages we need for the initial
  * page tables */
index 6ef4b7867b1b356a933ebf1744e65739adc87838..21eb45a526299d15884aa7ca11ba545f82a8111f 100644 (file)
@@ -29,7 +29,8 @@ extern void smp_send_reschedule(int cpu);
 extern void smp_send_all_nop(void);
 
 extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
 #endif /* !ASSEMBLY */
 
index f3d2090a18dc316e5a4cbd388abb32e94717b764..fae03e136fa8619b6d1efc09d750992949ec3dc2 100644 (file)
@@ -187,6 +187,9 @@ static __inline__ int __raw_write_can_lock(raw_rwlock_t *rw)
        return !rw->counter;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 016d3fc4111c6bf3d22872dd23737cc880c15eb4..67db0722e6ca8d4e3c0e323e24ee137325e48c73 100644 (file)
@@ -11,10 +11,25 @@ obj-y               := cache.o pacache.o setup.o traps.o time.o irq.o \
                   process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \
                   topology.o
 
+ifdef CONFIG_FUNCTION_TRACER
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_cache.o = -pg
+CFLAGS_REMOVE_irq.o = -pg
+CFLAGS_REMOVE_pacache.o = -pg
+CFLAGS_REMOVE_perf.o = -pg
+CFLAGS_REMOVE_traps.o = -pg
+CFLAGS_REMOVE_unaligned.o = -pg
+CFLAGS_REMOVE_unwind.o = -pg
+endif
+
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_PA11)     += pci-dma.o
 obj-$(CONFIG_PCI)      += pci.o
 obj-$(CONFIG_MODULES)  += module.o
 obj-$(CONFIG_64BIT)    += binfmt_elf32.o sys_parisc32.o signal32.o
+obj-$(CONFIG_STACKTRACE)+= stacktrace.o
 # only supported for PCX-W/U in 64-bit mode at the moment
 obj-$(CONFIG_64BIT)    += perf.o perf_asm.o
+obj-$(CONFIG_FUNCTION_TRACER)          += ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o
index 0db9fdcb7709889d7ddef590a7e99c579d97acf0..ae3e70cd1e14e4acf2da03717d77d0b9ea0d7faa 100644 (file)
        STREG           \pte,0(\ptep)
        .endm
 
+       /* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
+        * to a CPU TLB 4k PFN (4k => 12 bits to shift) */
+       #define PAGE_ADD_SHIFT  (PAGE_SHIFT-12)
+
+       /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
+       .macro          convert_for_tlb_insert20 pte
+       extrd,u         \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
+                               64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
+       depdi           _PAGE_SIZE_ENCODING_DEFAULT,63,\
+                               (63-58)+PAGE_ADD_SHIFT,\pte
+       .endm
+
        /* Convert the pte and prot to tlb insertion values.  How
         * this happens is quite subtle, read below */
        .macro          make_insert_tlb spc,pte,prot
        depi            1,12,1,\prot
 
        /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
-       extrd,u         \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58),64-PAGE_SHIFT,\pte
-       depdi           _PAGE_SIZE_ENCODING_DEFAULT,63,63-58,\pte
+       convert_for_tlb_insert20 \pte
        .endm
 
        /* Identical macro to make_insert_tlb above, except it
 
        /* Get rid of prot bits and convert to page addr for iitlba */
 
-       depi            _PAGE_SIZE_ENCODING_DEFAULT,31,ASM_PFN_PTE_SHIFT,\pte
-       extru           \pte,24,25,\pte
+       depi            0,31,ASM_PFN_PTE_SHIFT,\pte
+       SHRREG          \pte,(ASM_PFN_PTE_SHIFT-(31-26)),\pte
        .endm
 
        /* This is for ILP32 PA2.0 only.  The TLB insertion needs
@@ -1244,10 +1255,9 @@ nadtlb_check_flush_20w:
        depdi,z         7,7,3,prot
        depdi           1,10,1,prot
 
-       /* Get rid of prot bits and convert to page addr for idtlbt */
+       /* Drop prot bits from pte and convert to page addr for idtlbt */
+       convert_for_tlb_insert20 pte
 
-       depdi           0,63,12,pte
-       extrd,u         pte,56,52,pte
        idtlbt          pte,prot
 
        rfir
@@ -1337,8 +1347,8 @@ nadtlb_check_flush_11:
 
        /* Get rid of prot bits and convert to page addr for idtlba */
 
-       depi            0,31,12,pte
-       extru           pte,24,25,pte
+       depi            0,31,ASM_PFN_PTE_SHIFT,pte
+       SHRREG          pte,(ASM_PFN_PTE_SHIFT-(31-26)),pte
 
        mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
@@ -1403,10 +1413,9 @@ nadtlb_check_flush_20:
        depdi,z         7,7,3,prot
        depdi           1,10,1,prot
 
-       /* Get rid of prot bits and convert to page addr for idtlbt */
+       /* Drop prot bits from pte and convert to page addr for idtlbt */
+       convert_for_tlb_insert20 pte
 
-       depdi           0,63,12,pte
-       extrd,u         pte,56,32,pte
        idtlbt          pte,prot
 
        rfir
@@ -2176,6 +2185,33 @@ syscall_do_resched:
 ENDPROC(syscall_exit)
 
 
+#ifdef CONFIG_FUNCTION_TRACER
+       .import ftrace_function_trampoline,code
+ENTRY(_mcount)
+       copy    %r3, %arg2
+       b       ftrace_function_trampoline
+       nop
+ENDPROC(_mcount)
+
+ENTRY(return_to_handler)
+       load32  return_trampoline, %rp
+       copy    %ret0, %arg0
+       copy    %ret1, %arg1
+       b       ftrace_return_to_handler
+       nop
+return_trampoline:
+       copy    %ret0, %rp
+       copy    %r23, %ret0
+       copy    %r24, %ret1
+
+.globl ftrace_stub
+ftrace_stub:
+       bv      %r0(%rp)
+       nop
+ENDPROC(return_to_handler)
+#endif /* CONFIG_FUNCTION_TRACER */
+
+
 get_register:
        /*
         * get_register is used by the non access tlb miss handlers to
index f6d241238a78b39b6a39467726d51e939fd3916d..4c247e02d9b1b0e0655e47ebc15470801b4d9881 100644 (file)
@@ -527,7 +527,11 @@ int pdc_model_capabilities(unsigned long *capabilities)
         pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
         retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
         convert_to_wide(pdc_result);
-        *capabilities = pdc_result[0];
+        if (retval == PDC_OK) {
+                *capabilities = pdc_result[0];
+        } else {
+                *capabilities = PDC_MODEL_OS32;
+        }
         spin_unlock_irqrestore(&pdc_lock, flags);
 
         return retval;
diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c
new file mode 100644 (file)
index 0000000..9877372
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Code for tracing calls in Linux kernel.
+ * Copyright (C) 2009 Helge Deller <deller@gmx.de>
+ *
+ * based on code for x86 which is:
+ * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
+ *
+ * future possible enhancements:
+ *     - add CONFIG_DYNAMIC_FTRACE
+ *     - add CONFIG_STACK_TRACER
+ */
+
+#include <linux/init.h>
+#include <linux/ftrace.h>
+
+#include <asm/sections.h>
+#include <asm/ftrace.h>
+
+
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+/* Add a function return address to the trace stack on thread info.*/
+static int push_return_trace(unsigned long ret, unsigned long long time,
+                               unsigned long func, int *depth)
+{
+       int index;
+
+       if (!current->ret_stack)
+               return -EBUSY;
+
+       /* The return trace stack is full */
+       if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
+               atomic_inc(&current->trace_overrun);
+               return -EBUSY;
+       }
+
+       index = ++current->curr_ret_stack;
+       barrier();
+       current->ret_stack[index].ret = ret;
+       current->ret_stack[index].func = func;
+       current->ret_stack[index].calltime = time;
+       *depth = index;
+
+       return 0;
+}
+
+/* Retrieve a function return address to the trace stack on thread info.*/
+static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
+{
+       int index;
+
+       index = current->curr_ret_stack;
+
+       if (unlikely(index < 0)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
+               /* Might as well panic, otherwise we have no where to go */
+               *ret = (unsigned long)
+                       dereference_function_descriptor(&panic);
+               return;
+       }
+
+       *ret = current->ret_stack[index].ret;
+       trace->func = current->ret_stack[index].func;
+       trace->calltime = current->ret_stack[index].calltime;
+       trace->overrun = atomic_read(&current->trace_overrun);
+       trace->depth = index;
+       barrier();
+       current->curr_ret_stack--;
+
+}
+
+/*
+ * Send the trace to the ring-buffer.
+ * @return the original return address.
+ */
+unsigned long ftrace_return_to_handler(unsigned long retval0,
+                                      unsigned long retval1)
+{
+       struct ftrace_graph_ret trace;
+       unsigned long ret;
+
+       pop_return_trace(&trace, &ret);
+       trace.rettime = cpu_clock(raw_smp_processor_id());
+       ftrace_graph_return(&trace);
+
+       if (unlikely(!ret)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
+               /* Might as well panic. What else to do? */
+               ret = (unsigned long)
+                       dereference_function_descriptor(&panic);
+       }
+
+       /* HACK: we hand over the old functions' return values
+          in %r23 and %r24. Assembly in entry.S will take care
+          and move those to their final registers %ret0 and %ret1 */
+       asm( "copy %0, %%r23 \n\t"
+            "copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) );
+
+       return ret;
+}
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+       unsigned long old;
+       unsigned long long calltime;
+       struct ftrace_graph_ent trace;
+
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               return;
+
+       old = *parent;
+       *parent = (unsigned long)
+                 dereference_function_descriptor(&return_to_handler);
+
+       if (unlikely(!__kernel_text_address(old))) {
+               ftrace_graph_stop();
+               *parent = old;
+               WARN_ON(1);
+               return;
+       }
+
+       calltime = cpu_clock(raw_smp_processor_id());
+
+       if (push_return_trace(old, calltime,
+                               self_addr, &trace.depth) == -EBUSY) {
+               *parent = old;
+               return;
+       }
+
+       trace.func = self_addr;
+
+       /* Only trace if the calling function expects to */
+       if (!ftrace_graph_entry(&trace)) {
+               current->curr_ret_stack--;
+               *parent = old;
+       }
+}
+
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+
+void ftrace_function_trampoline(unsigned long parent,
+                               unsigned long self_addr,
+                               unsigned long org_sp_gr3)
+{
+       extern ftrace_func_t ftrace_trace_function;
+
+       if (function_trace_stop)
+               return;
+
+       if (ftrace_trace_function != ftrace_stub) {
+               ftrace_trace_function(parent, self_addr);
+               return;
+       }
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       if (ftrace_graph_entry && ftrace_graph_return) {
+               unsigned long sp;
+               unsigned long *parent_rp;
+
+                asm volatile ("copy %%r30, %0" : "=r"(sp));
+               /* sanity check: is stack pointer which we got from
+                  assembler function in entry.S in a reasonable
+                  range compared to current stack pointer? */
+               if ((sp - org_sp_gr3) > 0x400)
+                       return;
+
+               /* calculate pointer to %rp in stack */
+               parent_rp = (unsigned long *) org_sp_gr3 - 0x10;
+               /* sanity check: parent_rp should hold parent */
+               if (*parent_rp != parent)
+                       return;
+               
+               prepare_ftrace_return(parent_rp, self_addr);
+               return;
+       }
+#endif
+}
+
index 1c740f5cbd6347f0046dc1560fb52dc806fd3103..4ea4229d765ccc0657148d4f2268931ea3d6b8f9 100644 (file)
@@ -311,12 +311,12 @@ unsigned long txn_alloc_addr(unsigned int virt_irq)
        next_cpu++; /* assign to "next" CPU we want this bugger on */
 
        /* validate entry */
-       while ((next_cpu < NR_CPUS) &&
+       while ((next_cpu < nr_cpu_ids) &&
                (!per_cpu(cpu_data, next_cpu).txn_addr ||
                 !cpu_online(next_cpu)))
                next_cpu++;
 
-       if (next_cpu >= NR_CPUS
+       if (next_cpu >= nr_cpu_ids
                next_cpu = 0;   /* nothing else, assign monarch */
 
        return txn_affinity_addr(virt_irq, next_cpu);
index 9013243ceccadec711c8f6dd42b2c50e3e0115e0..ecd1c50244470db01620f67615e5562b87d2bcec 100644 (file)
@@ -61,9 +61,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/bug.h>
-#include <linux/uaccess.h>
 
-#include <asm/sections.h>
 #include <asm/unwind.h>
 
 #if 0
@@ -115,8 +113,6 @@ struct got_entry {
        Elf32_Addr addr;
 };
 
-#define Elf_Fdesc      Elf32_Fdesc
-
 struct stub_entry {
        Elf32_Word insns[2]; /* each stub entry has two insns */
 };
@@ -125,8 +121,6 @@ struct got_entry {
        Elf64_Addr addr;
 };
 
-#define Elf_Fdesc      Elf64_Fdesc
-
 struct stub_entry {
        Elf64_Word insns[4]; /* each stub entry has four insns */
 };
@@ -916,15 +910,3 @@ void module_arch_cleanup(struct module *mod)
        deregister_unwind_table(mod);
        module_bug_cleanup(mod);
 }
-
-#ifdef CONFIG_64BIT
-void *dereference_function_descriptor(void *ptr)
-{
-       Elf64_Fdesc *desc = ptr;
-       void *p;
-
-       if (!probe_kernel_address(&desc->addr, p))
-               ptr = p;
-       return ptr;
-}
-#endif
index 0eecfbbc59cdcc99c2206cb299f32c986ff84b35..df653663d3dbdd7efdb858e48225f71d4eeebd0b 100644 (file)
@@ -153,5 +153,10 @@ EXPORT_SYMBOL(node_data);
 EXPORT_SYMBOL(pfnnid_map);
 #endif
 
+#ifdef CONFIG_FUNCTION_TRACER
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
+
 /* from pacache.S -- needed for copy_page */
 EXPORT_SYMBOL(copy_user_page_asm);
index b80e02a4d81de3d193ec1faae269b7614a783cf1..6f69101f90bb24df54b99259a5419f84a76dbb35 100644 (file)
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/kallsyms.h>
+#include <linux/uaccess.h>
 
 #include <asm/io.h>
 #include <asm/asm-offsets.h>
 #include <asm/pdc.h>
 #include <asm/pdc_chassis.h>
 #include <asm/pgalloc.h>
-#include <asm/uaccess.h>
 #include <asm/unwind.h>
+#include <asm/sections.h>
 
 /*
  * The idle thread. There's no useful work to be
@@ -231,8 +232,8 @@ sys_clone(unsigned long clone_flags, unsigned long usp,
           
           However, these last 3 args are only examined
           if the proper flags are set. */
-       int __user *child_tidptr;
-       int __user *parent_tidptr;
+       int __user *parent_tidptr = (int __user *)regs->gr[24];
+       int __user *child_tidptr  = (int __user *)regs->gr[22];
 
        /* usp must be word aligned.  This also prevents users from
         * passing in the value 1 (which is the signal for a special
@@ -243,16 +244,6 @@ sys_clone(unsigned long clone_flags, unsigned long usp,
        if (usp == 0)
          usp = regs->gr[30];
 
-       if (clone_flags & CLONE_PARENT_SETTID)
-         parent_tidptr = (int __user *)regs->gr[24];
-       else
-         parent_tidptr = NULL;
-       
-       if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
-         child_tidptr = (int __user *)regs->gr[22];
-       else
-         child_tidptr = NULL;
-
        return do_fork(clone_flags, usp, regs, 0, parent_tidptr, child_tidptr);
 }
 
@@ -263,7 +254,7 @@ sys_vfork(struct pt_regs *regs)
 }
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+copy_thread(unsigned long clone_flags, unsigned long usp,
            unsigned long unused,       /* in ia64 this is "user_stack_size" */
            struct task_struct * p, struct pt_regs * pregs)
 {
@@ -400,3 +391,15 @@ get_wchan(struct task_struct *p)
        } while (count++ < 16);
        return 0;
 }
+
+#ifdef CONFIG_64BIT
+void *dereference_function_descriptor(void *ptr)
+{
+       Elf64_Fdesc *desc = ptr;
+       void *p;
+
+       if (!probe_kernel_address(&desc->addr, p))
+               ptr = p;
+       return ptr;
+}
+#endif
index ecb609342feb73164114b4089aafafe3aa2d6f9d..e09d0f7fb6b047ad2c2cf34d95046f89f2263874 100644 (file)
@@ -100,8 +100,8 @@ static int __cpuinit processor_probe(struct parisc_device *dev)
        struct cpuinfo_parisc *p;
 
 #ifdef CONFIG_SMP
-       if (num_online_cpus() >= NR_CPUS) {
-               printk(KERN_INFO "num_online_cpus() >= NR_CPUS\n");
+       if (num_online_cpus() >= nr_cpu_ids) {
+               printk(KERN_INFO "num_online_cpus() >= nr_cpu_ids\n");
                return 1;
        }
 #else
@@ -214,7 +214,7 @@ static int __cpuinit processor_probe(struct parisc_device *dev)
         */
 #ifdef CONFIG_SMP
        if (cpuid) {
-               cpu_set(cpuid, cpu_present_map);
+               set_cpu_present(cpuid, true);
                cpu_up(cpuid);
        }
 #endif
@@ -364,6 +364,13 @@ show_cpuinfo (struct seq_file *m, void *v)
                                 boot_cpu_data.cpu_hz / 1000000,
                                 boot_cpu_data.cpu_hz % 1000000  );
 
+               seq_printf(m, "capabilities\t:");
+               if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32)
+                       seq_printf(m, " os32");
+               if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS64)
+                       seq_printf(m, " os64");
+               seq_printf(m, "\n");
+
                seq_printf(m, "model\t\t: %s\n"
                                "model name\t: %s\n",
                                 boot_cpu_data.pdc.sys_model_name,
index 9995d7ed58198c42de88223b51ff0d3ac4f75b3b..1fd0f0cec037f3fa19ce2630ee7311dc7cc34dbc 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/bitops.h>
+#include <linux/ftrace.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -113,14 +114,14 @@ halt_processor(void)
 {
        /* REVISIT : redirect I/O Interrupts to another CPU? */
        /* REVISIT : does PM *know* this CPU isn't available? */
-       cpu_clear(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), false);
        local_irq_disable();
        for (;;)
                ;
 }
 
 
-irqreturn_t
+irqreturn_t __irq_entry
 ipi_interrupt(int irq, void *dev_id) 
 {
        int this_cpu = smp_processor_id();
@@ -214,11 +215,11 @@ ipi_send(int cpu, enum ipi_message_type op)
 }
 
 static void
-send_IPI_mask(cpumask_t mask, enum ipi_message_type op)
+send_IPI_mask(const struct cpumask *mask, enum ipi_message_type op)
 {
        int cpu;
 
-       for_each_cpu_mask(cpu, mask)
+       for_each_cpu(cpu, mask)
                ipi_send(cpu, op);
 }
 
@@ -257,7 +258,7 @@ smp_send_all_nop(void)
        send_IPI_allbutself(IPI_NOP);
 }
 
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
        send_IPI_mask(mask, IPI_CALL_FUNC);
 }
@@ -296,13 +297,14 @@ smp_cpu_init(int cpunum)
        mb();
 
        /* Well, support 2.4 linux scheme as well. */
-       if (cpu_test_and_set(cpunum, cpu_online_map))
+       if (cpu_isset(cpunum, cpu_online_map))
        {
                extern void machine_halt(void); /* arch/parisc.../process.c */
 
                printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
                machine_halt();
        }  
+       set_cpu_online(cpunum, true);
 
        /* Initialise the idle task for this CPU */
        atomic_inc(&init_mm.mm_count);
@@ -424,8 +426,8 @@ void __init smp_prepare_boot_cpu(void)
        /* Setup BSP mappings */
        printk(KERN_INFO "SMP: bootstrap CPU ID is %d\n", bootstrap_processor);
 
-       cpu_set(bootstrap_processor, cpu_online_map);
-       cpu_set(bootstrap_processor, cpu_present_map);
+       set_cpu_online(bootstrap_processor, true);
+       set_cpu_present(bootstrap_processor, true);
 }
 
 
@@ -436,8 +438,7 @@ void __init smp_prepare_boot_cpu(void)
 */
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       cpus_clear(cpu_present_map);
-       cpu_set(0, cpu_present_map);
+       init_cpu_present(cpumask_of(0));
 
        parisc_max_cpus = max_cpus;
        if (!max_cpus)
diff --git a/arch/parisc/kernel/stacktrace.c b/arch/parisc/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..2fe914c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Stack trace management functions
+ *
+ *  Copyright (C) 2009 Helge Deller <deller@gmx.de>
+ *  based on arch/x86/kernel/stacktrace.c by Ingo Molnar <mingo@redhat.com>
+ *  and parisc unwind functions by Randolph Chung <tausq@debian.org>
+ *
+ *  TODO: Userspace stacktrace (CONFIG_USER_STACKTRACE_SUPPORT)
+ */
+#include <linux/module.h>
+#include <linux/stacktrace.h>
+
+#include <asm/unwind.h>
+
+static void dump_trace(struct task_struct *task, struct stack_trace *trace)
+{
+       struct unwind_frame_info info;
+
+       /* initialize unwind info */
+       if (task == current) {
+               unsigned long sp;
+               struct pt_regs r;
+HERE:
+               asm volatile ("copy %%r30, %0" : "=r"(sp));
+               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;
+               unwind_frame_init(&info, task, &r);
+       } else {
+               unwind_frame_init_from_blocked_task(&info, task);
+       }
+
+       /* unwind stack and save entries in stack_trace struct */
+       trace->nr_entries = 0;
+       while (trace->nr_entries < trace->max_entries) {
+               if (unwind_once(&info) < 0 || info.ip == 0)
+                       break;
+
+               if (__kernel_text_address(info.ip))
+                       trace->entries[trace->nr_entries++] = info.ip;
+       }
+}
+
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+       dump_trace(current, trace);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       dump_trace(tsk, trace);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
index 69b6eebc466ea4860261d6ff9c503bae308a748c..59fc1a43ec3ef094ae514694e549ab6b518aa05a 100644 (file)
@@ -365,17 +365,51 @@ tracesys_sigexit:
 
 
        /*********************************************************
-               Light-weight-syscall code
+               32/64-bit Light-Weight-Syscall ABI
 
-               r20 - lws number
-               r26,r25,r24,r23,r22 - Input registers
-               r28 - Function return register
-               r21 - Error code.
+               * - Indicates a hint for userspace inline asm
+               implementations.
 
-               Scracth: Any of the above that aren't being
-               currently used, including r1. 
+               Syscall number (caller-saves)
+               - %r20
+               * In asm clobber.
 
-               Return pointer: r31 (Not usable)
+               Argument registers (caller-saves)
+               - %r26, %r25, %r24, %r23, %r22
+               * In asm input.
+
+               Return registers (caller-saves)
+               - %r28 (return), %r21 (errno)
+               * In asm output.
+
+               Caller-saves registers
+               - %r1, %r27, %r29
+               - %r2 (return pointer)
+               - %r31 (ble link register)
+               * In asm clobber.
+
+               Callee-saves registers
+               - %r3-%r18
+               - %r30 (stack pointer)
+               * Not in asm clobber.
+
+               If userspace is 32-bit:
+               Callee-saves registers
+               - %r19 (32-bit PIC register)
+
+               Differences from 32-bit calling convention:
+               - Syscall number in %r20
+               - Additional argument register %r22 (arg4)
+               - Callee-saves %r19.
+
+               If userspace is 64-bit:
+               Callee-saves registers
+               - %r27 (64-bit PIC register)
+
+               Differences from 64-bit calling convention:
+               - Syscall number in %r20
+               - Additional argument register %r22 (arg4)
+               - Callee-saves %r27.
 
                Error codes returned by entry path:
 
@@ -473,7 +507,8 @@ lws_compare_and_swap64:
        b,n     lws_compare_and_swap
 #else
        /* If we are not a 64-bit kernel, then we don't
-        * implement having 64-bit input registers
+        * have 64-bit input registers, and calling
+        * the 64-bit LWS CAS returns ENOSYS.
         */
        b,n     lws_exit_nosys
 #endif
@@ -635,12 +670,15 @@ END(sys_call_table64)
        /*
                All light-weight-syscall atomic operations 
                will use this set of locks 
+
+               NOTE: The lws_lock_start symbol must be
+               at least 16-byte aligned for safe use
+               with ldcw.
        */
        .section .data
        .align  PAGE_SIZE
 ENTRY(lws_lock_start)
        /* lws locks */
-       .align 16
        .rept 16
        /* Keep locks aligned at 16-bytes */
        .word 1
index 9d46c43a415291a005fc8ff2ef7331d3ff8dbbb7..d4dd05674c6234b495acdb25431bb5fd9a437261 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/profile.h>
 #include <linux/clocksource.h>
 #include <linux/platform_device.h>
+#include <linux/ftrace.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -53,7 +54,7 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */
  * held off for an arbitrarily long period of time by interrupts being
  * disabled, so we may miss one or more ticks.
  */
-irqreturn_t timer_interrupt(int irq, void *dev_id)
+irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 {
        unsigned long now;
        unsigned long next_tick;
@@ -216,17 +217,14 @@ void __init start_cpu_itimer(void)
        per_cpu(cpu_data, cpu).it_value = next_tick;
 }
 
-struct platform_device rtc_parisc_dev = {
-       .name = "rtc-parisc",
+static struct platform_device rtc_generic_dev = {
+       .name = "rtc-generic",
        .id = -1,
 };
 
 static int __init rtc_init(void)
 {
-       int ret;
-
-       ret = platform_device_register(&rtc_parisc_dev);
-       if (ret < 0)
+       if (platform_device_register(&rtc_generic_dev) < 0)
                printk(KERN_ERR "unable to register rtc device...\n");
 
        /* not necessarily an error */
index ba658d2086f77decbc35404da73287338e27618a..c32f5d6d778ec7bd10c028cf40db645af659686a 100644 (file)
@@ -247,6 +247,8 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
 
        oops_in_progress = 1;
 
+       oops_enter();
+
        /* Amuse the user in a SPARC fashion */
        if (err) printk(
 KERN_CRIT "      _______________________________ \n"
@@ -293,6 +295,7 @@ KERN_CRIT "                     ||     ||\n");
                panic("Fatal exception");
        }
 
+       oops_exit();
        do_exit(SIGSEGV);
 }
 
@@ -494,7 +497,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
        panic(msg);
 }
 
-void handle_interruption(int code, struct pt_regs *regs)
+void notrace handle_interruption(int code, struct pt_regs *regs)
 {
        unsigned long fault_address = 0;
        unsigned long fault_space = 0;
index 1a3b6ccd362064e80b65412a62eee7e7b0f2182d..fd2cc4fd2b65adc5b84dd46639d4eaea1ea58d77 100644 (file)
@@ -54,6 +54,8 @@ SECTIONS
                TEXT_TEXT
                SCHED_TEXT
                LOCK_TEXT
+               KPROBES_TEXT
+               IRQENTRY_TEXT
                *(.text.do_softirq)
                *(.text.sys_exit)
                *(.text.do_sigaltstack)
index 9d704d9831d1612a84eb3a82c6e94bf17041ad7d..4356ceb1e366d9ed010706ac21dceb8ac24ba151 100644 (file)
@@ -456,6 +456,13 @@ void __init mem_init(void)
 {
        int codesize, reservedpages, datasize, initsize;
 
+       /* Do sanity checks on page table constants */
+       BUILD_BUG_ON(PTE_ENTRY_SIZE != sizeof(pte_t));
+       BUILD_BUG_ON(PMD_ENTRY_SIZE != sizeof(pmd_t));
+       BUILD_BUG_ON(PGD_ENTRY_SIZE != sizeof(pgd_t));
+       BUILD_BUG_ON(PAGE_SHIFT + BITS_PER_PTE + BITS_PER_PMD + BITS_PER_PGD
+                       > BITS_PER_LONG);
+
        high_memory = __va((max_pfn << PAGE_SHIFT));
 
 #ifndef CONFIG_DISCONTIGMEM
index ad6b1c084fe35ddcfdeb26695519237b49e7368f..9e08d8a69fdf48a78cc84c671815c9c1356ca3db 100644 (file)
@@ -228,6 +228,9 @@ config PPC_OF_PLATFORM_PCI
        depends on PPC64 # not supported on 32 bits yet
        default n
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
@@ -343,7 +346,7 @@ config PHYP_DUMP
        help
          Hypervisor-assisted dump is meant to be a kdump replacement
          offering robustness and speed not possible without system
-         hypervisor assistence.
+         hypervisor assistance.
 
          If unsure, say "N"
 
index 22091bbfdc9b8dd0919dea550aeb9aeb6178bf77..a1098e23221fb1debd36fc62bf54740f1829a3e4 100644 (file)
@@ -27,15 +27,6 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
-config DEBUG_PAGEALLOC
-        bool "Debug page memory allocations"
-        depends on DEBUG_KERNEL && !HIBERNATION
-        help
-          Unmap pages from the kernel linear mapping after free_pages().
-          This results in a large slowdown, but helps to find certain types
-          of memory corruptions.
-
-
 config HCALL_STATS
        bool "Hypervisor call instrumentation"
        depends on PPC_PSERIES && DEBUG_FS
index dea30910c136800cbe1bdb37fbe3e354376cf9d3..4319bd70a580beaa65a992eb92c6b94e91285c7c 100644 (file)
                };
 
                par_io@1400 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        reg = <0x1400 0x100>;
+                       ranges = <3 0x1448 0x18>;
+                       compatible = "fsl,mpc8323-qe-pario";
                        device_type = "par_io";
                        num-ports = <7>;
 
+                       qe_pio_d: gpio-controller@1448 {
+                               #gpio-cells = <2>;
+                               compatible = "fsl,mpc8323-qe-pario-bank";
+                               reg = <3 0x18>;
+                               gpio-controller;
+                       };
+
                        ucc2pio:ucc_pin@02 {
                                pio-map = <
                        /* port  pin  dir  open_drain  assignment  has_irq */
                };
 
                spi@4c0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        cell-index = <0>;
                        compatible = "fsl,spi";
                        reg = <0x4c0 0x40>;
                        interrupts = <2>;
                        interrupt-parent = <&qeic>;
+                       gpios = <&qe_pio_d 13 0>;
                        mode = "cpu-qe";
+
+                       mmc-slot@0 {
+                               compatible = "fsl,mpc8323rdb-mmc-slot",
+                                            "mmc-spi-slot";
+                               reg = <0>;
+                               gpios = <&qe_pio_d 14 1
+                                        &qe_pio_d 15 0>;
+                               voltage-ranges = <3300 3300>;
+                               spi-max-frequency = <50000000>;
+                       };
                };
 
                spi@500 {
index 545028f8648801ebf321fbcbdfdd987718434d40..684a73f4324f4ad203c71ef4eb09b5045ab60516 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/highmem.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/page.h>
@@ -94,6 +95,7 @@ static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgpro
        if (!PageHighMem(page))
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
index 3548159a1beb98b55ef6c7e39985da655f85920d..ba17d5d90a493c2128c75dd8712fa6c05e3df145 100644 (file)
@@ -114,6 +114,10 @@ extern int pci_domain_nr(struct pci_bus *bus);
 /* Decide whether to display the domain number in /proc */
 extern int pci_proc_domain(struct pci_bus *bus);
 
+/* MSI arch hooks */
+#define arch_setup_msi_irqs arch_setup_msi_irqs
+#define arch_teardown_msi_irqs arch_teardown_msi_irqs
+#define arch_msi_check_device arch_msi_check_device
 
 struct vm_area_struct;
 /* Map a range of PCI memory or I/O space for a device into user space */
index 67f1812698d2703e02cad2c561fd1d0e6c6d84b2..cdb6fd814de8880541d2c4130b33ea7e7b9f6234 100644 (file)
@@ -50,6 +50,9 @@ enum ps3_param_av_multi_out {
 
 enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
 
+extern u64 ps3_os_area_get_rtc_diff(void);
+extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
+
 /* dma routines */
 
 enum ps3_dma_page_size {
index 36864364e601cb22b6221fb824929973a2b2e688..c3b193121f81724a0a28d69eeb7b5be8c7c0b1a8 100644 (file)
@@ -287,6 +287,9 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
        rw->lock = 0;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  __spin_yield(lock)
 #define _raw_read_relax(lock)  __rw_yield(lock)
 #define _raw_write_relax(lock) __rw_yield(lock)
index cbf2c9404c37b4ac90431dfa864f29c5d1006071..c6efc3466aa6b84c4666cfec79ec319c38862804 100644 (file)
@@ -3,7 +3,4 @@
 
 static inline int arch_prepare_suspend(void) { return 0; }
 
-void save_processor_state(void);
-void restore_processor_state(void);
-
 #endif /* __ASM_POWERPC_SUSPEND_H */
index 375258559ae64fa26e09452c4e80ca978b2a3fe3..054a16d68082a852c460d96436e9f3b7bb3ce41c 100644 (file)
@@ -24,11 +24,6 @@ static inline cpumask_t node_to_cpumask(int node)
 
 #define cpumask_of_node(node) (&numa_cpumask_lookup_table[node])
 
-static inline int node_to_first_cpu(int node)
-{
-       return cpumask_first(cpumask_of_node(node));
-}
-
 int of_node_to_nid(struct device_node *device);
 
 struct pci_bus;
index 3bb7d3dd28be9e20d6e013127426e8c9c96e4861..8bbc12d20f5c9a11346874bb336fac33c7dcc6bc 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/msi.h>
+#include <linux/pci.h>
 
 #include <asm/machdep.h>
 
@@ -19,6 +20,10 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
                return -ENOSYS;
        }
 
+       /* PowerPC doesn't support multiple MSI yet */
+       if (type == PCI_CAP_ID_MSI && nvec > 1)
+               return 1;
+
        if (ppc_md.msi_check_device) {
                pr_debug("msi: Using platform check routine.\n");
                return ppc_md.msi_check_device(dev, nvec, type);
index eac064948780bed15a57c634aa363c4145349f96..7b44a33f03c230a07381f876f25da1fdb7871c6a 100644 (file)
@@ -598,7 +598,7 @@ void prepare_to_copy(struct task_struct *tsk)
 /*
  * Copy a thread..
  */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused, struct task_struct *p,
                struct pt_regs *regs)
 {
index 149cb112cd1ad398357d33ae766e3add6c6cfc01..13011a96a9779b274e77447dd5b72dae4e56142a 100644 (file)
@@ -669,7 +669,6 @@ static void remove_flash_pde(struct proc_dir_entry *dp)
 {
        if (dp) {
                kfree(dp->data);
-               dp->owner = NULL;
                remove_proc_entry(dp->name, dp->parent);
        }
 }
index c9564031a2a9c7878f9e9a694fe8e9ca3622a85e..926ea864e34f576b5b5b36518398fb83a83784f4 100644 (file)
@@ -1127,3 +1127,19 @@ void div128_by_32(u64 dividend_high, u64 dividend_low,
        dr->result_low  = ((u64)y << 32) + z;
 
 }
+
+static int __init rtc_init(void)
+{
+       struct platform_device *pdev;
+
+       if (!ppc_md.get_rtc_time)
+               return -ENODEV;
+
+       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return 0;
+}
+
+module_init(rtc_init);
index d3694498f3af517264d64a332f85733a5b1fbf73..819e59f6f7c7c31b680080bdcffe1171d4026058 100644 (file)
@@ -482,7 +482,7 @@ static void vio_cmo_balance(struct work_struct *work)
        cmo->excess.size = cmo->entitled - cmo->reserve.size;
        cmo->excess.free = cmo->excess.size - need;
 
-       cancel_delayed_work(container_of(work, struct delayed_work, work));
+       cancel_delayed_work(to_delayed_work(work));
        spin_unlock_irqrestore(&vio_cmo.lock, flags);
 }
 
index 2a1295f1983254c7a4083b65b83694ef83bf6129..567ded7c3b9be5fc3689be002e3e6163cdce3e8f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/spi/mmc_spi.h>
 #include <linux/mmc/host.h>
 #include <linux/of_platform.h>
+#include <linux/fsl_devices.h>
 
 #include <asm/time.h>
 #include <asm/ipic.h>
 #endif
 
 #ifdef CONFIG_QUICC_ENGINE
-static void mpc83xx_spi_activate_cs(u8 cs, u8 polarity)
+static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
+                                  struct spi_board_info *board_infos,
+                                  unsigned int num_board_infos,
+                                  void (*cs_control)(struct spi_device *dev,
+                                                     bool on))
 {
-       pr_debug("%s %d %d\n", __func__, cs, polarity);
-       par_io_data_set(3, 13, polarity);
+       struct device_node *np;
+       unsigned int i = 0;
+
+       for_each_compatible_node(np, type, compatible) {
+               int ret;
+               unsigned int j;
+               const void *prop;
+               struct resource res[2];
+               struct platform_device *pdev;
+               struct fsl_spi_platform_data pdata = {
+                       .cs_control = cs_control,
+               };
+
+               memset(res, 0, sizeof(res));
+
+               pdata.sysclk = sysclk;
+
+               prop = of_get_property(np, "reg", NULL);
+               if (!prop)
+                       goto err;
+               pdata.bus_num = *(u32 *)prop;
+
+               prop = of_get_property(np, "cell-index", NULL);
+               if (prop)
+                       i = *(u32 *)prop;
+
+               prop = of_get_property(np, "mode", NULL);
+               if (prop && !strcmp(prop, "cpu-qe"))
+                       pdata.qe_mode = 1;
+
+               for (j = 0; j < num_board_infos; j++) {
+                       if (board_infos[j].bus_num == pdata.bus_num)
+                               pdata.max_chipselect++;
+               }
+
+               if (!pdata.max_chipselect)
+                       continue;
+
+               ret = of_address_to_resource(np, 0, &res[0]);
+               if (ret)
+                       goto err;
+
+               ret = of_irq_to_resource(np, 0, &res[1]);
+               if (ret == NO_IRQ)
+                       goto err;
+
+               pdev = platform_device_alloc("mpc83xx_spi", i);
+               if (!pdev)
+                       goto err;
+
+               ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+               if (ret)
+                       goto unreg;
+
+               ret = platform_device_add_resources(pdev, res,
+                                                   ARRAY_SIZE(res));
+               if (ret)
+                       goto unreg;
+
+               ret = platform_device_add(pdev);
+               if (ret)
+                       goto unreg;
+
+               goto next;
+unreg:
+               platform_device_del(pdev);
+err:
+               pr_err("%s: registration failed\n", np->full_name);
+next:
+               i++;
+       }
+
+       return i;
 }
 
-static void mpc83xx_spi_deactivate_cs(u8 cs, u8 polarity)
+static int __init fsl_spi_init(struct spi_board_info *board_infos,
+                              unsigned int num_board_infos,
+                              void (*cs_control)(struct spi_device *spi,
+                                                 bool on))
 {
-       pr_debug("%s %d %d\n", __func__, cs, polarity);
-       par_io_data_set(3, 13, !polarity);
+       u32 sysclk = -1;
+       int ret;
+
+       /* SPI controller is either clocked from QE or SoC clock */
+       sysclk = get_brgfreq();
+       if (sysclk == -1) {
+               sysclk = fsl_get_sys_freq();
+               if (sysclk == -1)
+                       return -ENODEV;
+       }
+
+       ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
+                              num_board_infos, cs_control);
+       if (!ret)
+               of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
+                                num_board_infos, cs_control);
+
+       return spi_register_board_info(board_infos, num_board_infos);
+}
+
+static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
+{
+       pr_debug("%s %d %d\n", __func__, spi->chip_select, on);
+       par_io_data_set(3, 13, on);
 }
 
 static struct mmc_spi_platform_data mpc832x_mmc_pdata = {
@@ -74,9 +175,13 @@ static int __init mpc832x_spi_init(void)
        par_io_config_pin(3, 14, 2, 0, 0, 0); /* SD_INSERT, I */
        par_io_config_pin(3, 15, 2, 0, 0, 0); /* SD_PROTECT,I */
 
-       return fsl_spi_init(&mpc832x_spi_boardinfo, 1,
-                           mpc83xx_spi_activate_cs,
-                           mpc83xx_spi_deactivate_cs);
+       /*
+        * Don't bother with legacy stuff when device tree contains
+        * mmc-spi-slot node.
+        */
+       if (of_find_compatible_node(NULL, NULL, "mmc-spi-slot"))
+               return 0;
+       return fsl_spi_init(&mpc832x_spi_boardinfo, 1, mpc83xx_spi_cs_control);
 }
 machine_device_initcall(mpc832x_rdb, mpc832x_spi_init);
 #endif /* CONFIG_QUICC_ENGINE */
index 0a9e49104bdc42ccd506946e607dfa3361608768..458d91fba91d5f80ba7296c55752b0960eaca11d 100644 (file)
@@ -179,7 +179,6 @@ static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id)
 static struct irqaction mpc85xxcds_8259_irqaction = {
        .handler = mpc85xx_8259_cascade_action,
        .flags = IRQF_SHARED,
-       .mask = CPU_MASK_NONE,
        .name = "8259 cascade",
 };
 #endif /* PPC_I8259 */
index 0d9f75c74f8cdf22e83f13ba342c45f5b12a0d66..385acfc48397b8f2d2577326b78b49bb68b100f1 100644 (file)
@@ -44,7 +44,6 @@ static irqreturn_t timebase_interrupt(int irq, void *dev)
 
 static struct irqaction tbint_irqaction = {
        .handler = timebase_interrupt,
-       .mask = CPU_MASK_NONE,
        .name = "tbint",
 };
 
index ffa2a9fd53d03d0a8eace5eff8496d77a95e9cd0..e3e87078d03f844327f51ec9841c291ab20b812a 100644 (file)
@@ -293,7 +293,7 @@ config CPM
 config OF_RTC
        bool
        help
-         Uses information from the OF or flattened device tree to instatiate
+         Uses information from the OF or flattened device tree to instantiate
          platform devices for direct mapped RTC chips like the DS1742 or DS1743.
 
 source "arch/powerpc/sysdev/bestcomm/Kconfig"
index 64f068540d0dab1f33c21e2518f8aef23040239c..706eb5c7e2ee45c9cb71d5c09fc5517d12966df4 100644 (file)
@@ -635,7 +635,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode,
        if (dentry->d_inode)
                goto out_dput;
 
-       mode &= ~current->fs->umask;
+       mode &= ~current_umask();
 
        if (flags & SPU_CREATE_GANG)
                ret = spufs_create_gang(nd->path.dentry->d_inode,
index 272d79a8d2896ade7f8f36e22f2b6279077f6793..cd4ad9aea760d966505a977d9d92e5a7f1f33e38 100644 (file)
@@ -472,7 +472,6 @@ static void __init chrp_find_openpic(void)
 #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
 static struct irqaction xmon_irqaction = {
        .handler = xmon_irq,
-       .mask = CPU_MASK_NONE,
        .name = "XMON break",
 };
 #endif
index 6d149ae8ffa71c02928e3bdf52d9b6573e65283b..7039d8f1d3baa1dfdd73e2f9ac80a15fb1c9fb11 100644 (file)
@@ -266,7 +266,6 @@ static unsigned int pmac_pic_get_irq(void)
 static struct irqaction xmon_action = {
        .handler        = xmon_irq,
        .flags          = 0,
-       .mask           = CPU_MASK_NONE,
        .name           = "NMI - XMON"
 };
 #endif
@@ -274,7 +273,6 @@ static struct irqaction xmon_action = {
 static struct irqaction gatwick_cascade_action = {
        .handler        = gatwick_action,
        .flags          = IRQF_DISABLED,
-       .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
 
index bd8817b00fa4a80f3d2ab4649e6ef917ec9db8aa..cf1dbe758890df60d441cfbd79421db63e40834f 100644 (file)
@@ -385,7 +385,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr)
 static struct irqaction psurge_irqaction = {
        .handler = psurge_primary_intr,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "primary IPI",
 };
 
index e1c83c23b435a2f8032093def6afa1a844d5d1ab..86e392b1b049ab6855ac8b8f077a26b84a77132b 100644 (file)
@@ -808,6 +808,7 @@ u64 ps3_os_area_get_rtc_diff(void)
 {
        return saved_params.rtc_diff;
 }
+EXPORT_SYMBOL(ps3_os_area_get_rtc_diff);
 
 /**
  * ps3_os_area_set_rtc_diff - Set the rtc diff value.
@@ -823,6 +824,7 @@ void ps3_os_area_set_rtc_diff(u64 rtc_diff)
                os_area_queue_work();
        }
 }
+EXPORT_SYMBOL(ps3_os_area_set_rtc_diff);
 
 /**
  * ps3_os_area_get_av_multi_out - Returns the default video mode.
index 235c13ebacd9a459b2a584de9d536828e945c690..136aa0637d9c0bbc67e10f13b98d96f5540aa288 100644 (file)
@@ -64,8 +64,6 @@ int ps3_set_rtc_time(struct rtc_time *time);
 
 void __init ps3_os_area_save_params(void);
 void __init ps3_os_area_init(void);
-u64 ps3_os_area_get_rtc_diff(void);
-void ps3_os_area_set_rtc_diff(u64 rtc_diff);
 
 /* spu */
 
index 3331ccbb8d389c6d76dd4c548beeb3c30d6404b8..66181821322acc2dba892e26ef3a52182a3ca894 100644 (file)
@@ -270,8 +270,6 @@ define_machine(ps3) {
        .init_IRQ                       = ps3_init_IRQ,
        .panic                          = ps3_panic,
        .get_boot_time                  = ps3_get_boot_time,
-       .set_rtc_time                   = ps3_set_rtc_time,
-       .get_rtc_time                   = ps3_get_rtc_time,
        .set_dabr                       = ps3_set_dabr,
        .calibrate_decr                 = ps3_calibrate_decr,
        .progress                       = ps3_progress,
index d0daf7d6d3b26407d5ec87c0d5caef127943c4fe..b178a1e66c915e8ab6e85b0eec51830b6a05adf1 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/platform_device.h>
 
 #include <asm/rtc.h>
 #include <asm/lv1call.h>
@@ -74,23 +75,20 @@ static u64 read_rtc(void)
        return rtc_val;
 }
 
-int ps3_set_rtc_time(struct rtc_time *tm)
+unsigned long __init ps3_get_boot_time(void)
 {
-       u64 now = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-               tm->tm_hour, tm->tm_min, tm->tm_sec);
-
-       ps3_os_area_set_rtc_diff(now - read_rtc());
-       return 0;
+       return read_rtc() + ps3_os_area_get_rtc_diff();
 }
 
-void ps3_get_rtc_time(struct rtc_time *tm)
+static int __init ps3_rtc_init(void)
 {
-       to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm);
-       tm->tm_year -= 1900;
-       tm->tm_mon -= 1;
-}
+       struct platform_device *pdev;
 
-unsigned long __init ps3_get_boot_time(void)
-{
-       return read_rtc() + ps3_os_area_get_rtc_diff();
+       pdev = platform_device_register_simple("rtc-ps3", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return 0;
 }
+
+module_init(ps3_rtc_init);
index 0b192a1c429d3b85a1d13292277095d02abee1e3..29e427085efb23727073caf41382b88563f6f233 100644 (file)
@@ -9,8 +9,8 @@ config PPC_BESTCOMM
        select PPC_LIB_RHEAP
        help
          BestComm is the name of the communication coprocessor found
-         on the Freescale MPC5200 family of processor. It's usage is
-         optionnal for some drivers (like ATA), but required for
+         on the Freescale MPC5200 family of processor.  Its usage is
+         optional for some drivers (like ATA), but required for
          others (like FEC).
 
          If you want to use drivers that require DMA operations,
index 490473ce81030475fbfa6075a2c76612dcd48b0e..82424cd7e1287bcc009b81f2327b078229a6050f 100644 (file)
@@ -119,7 +119,6 @@ static irqreturn_t cpm_error_interrupt(int irq, void *dev)
 
 static struct irqaction cpm_error_irqaction = {
        .handler = cpm_error_interrupt,
-       .mask = CPU_MASK_NONE,
        .name = "error",
 };
 
index a01c89d3f9bdb47450bbd3514a769d02c0843195..afe8dbc964aa14cf3390dbd991878caeba1262d6 100644 (file)
@@ -417,115 +417,6 @@ err:
 
 arch_initcall(fsl_usb_of_init);
 
-static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
-                                  struct spi_board_info *board_infos,
-                                  unsigned int num_board_infos,
-                                  void (*activate_cs)(u8 cs, u8 polarity),
-                                  void (*deactivate_cs)(u8 cs, u8 polarity))
-{
-       struct device_node *np;
-       unsigned int i = 0;
-
-       for_each_compatible_node(np, type, compatible) {
-               int ret;
-               unsigned int j;
-               const void *prop;
-               struct resource res[2];
-               struct platform_device *pdev;
-               struct fsl_spi_platform_data pdata = {
-                       .activate_cs = activate_cs,
-                       .deactivate_cs = deactivate_cs,
-               };
-
-               memset(res, 0, sizeof(res));
-
-               pdata.sysclk = sysclk;
-
-               prop = of_get_property(np, "reg", NULL);
-               if (!prop)
-                       goto err;
-               pdata.bus_num = *(u32 *)prop;
-
-               prop = of_get_property(np, "cell-index", NULL);
-               if (prop)
-                       i = *(u32 *)prop;
-
-               prop = of_get_property(np, "mode", NULL);
-               if (prop && !strcmp(prop, "cpu-qe"))
-                       pdata.qe_mode = 1;
-
-               for (j = 0; j < num_board_infos; j++) {
-                       if (board_infos[j].bus_num == pdata.bus_num)
-                               pdata.max_chipselect++;
-               }
-
-               if (!pdata.max_chipselect)
-                       continue;
-
-               ret = of_address_to_resource(np, 0, &res[0]);
-               if (ret)
-                       goto err;
-
-               ret = of_irq_to_resource(np, 0, &res[1]);
-               if (ret == NO_IRQ)
-                       goto err;
-
-               pdev = platform_device_alloc("mpc83xx_spi", i);
-               if (!pdev)
-                       goto err;
-
-               ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
-               if (ret)
-                       goto unreg;
-
-               ret = platform_device_add_resources(pdev, res,
-                                                   ARRAY_SIZE(res));
-               if (ret)
-                       goto unreg;
-
-               ret = platform_device_add(pdev);
-               if (ret)
-                       goto unreg;
-
-               goto next;
-unreg:
-               platform_device_del(pdev);
-err:
-               pr_err("%s: registration failed\n", np->full_name);
-next:
-               i++;
-       }
-
-       return i;
-}
-
-int __init fsl_spi_init(struct spi_board_info *board_infos,
-                       unsigned int num_board_infos,
-                       void (*activate_cs)(u8 cs, u8 polarity),
-                       void (*deactivate_cs)(u8 cs, u8 polarity))
-{
-       u32 sysclk = -1;
-       int ret;
-
-#ifdef CONFIG_QUICC_ENGINE
-       /* SPI controller is either clocked from QE or SoC clock */
-       sysclk = get_brgfreq();
-#endif
-       if (sysclk == -1) {
-               sysclk = fsl_get_sys_freq();
-               if (sysclk == -1)
-                       return -ENODEV;
-       }
-
-       ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
-                              num_board_infos, activate_cs, deactivate_cs);
-       if (!ret)
-               of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
-                                num_board_infos, activate_cs, deactivate_cs);
-
-       return spi_register_board_info(board_infos, num_board_infos);
-}
-
 #if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx)
 static __be32 __iomem *rstcr;
 
index 9c744e4285a023c21fe7d7e12876e4443fc43a51..42381bb6cd5155297432fba52ff955af8989f05e 100644 (file)
@@ -4,6 +4,8 @@
 
 #include <asm/mmu.h>
 
+struct spi_device;
+
 extern phys_addr_t get_immrbase(void);
 #if defined(CONFIG_CPM2) || defined(CONFIG_QUICC_ENGINE) || defined(CONFIG_8xx)
 extern u32 get_brgfreq(void);
@@ -17,11 +19,6 @@ extern u32 fsl_get_sys_freq(void);
 struct spi_board_info;
 struct device_node;
 
-extern int fsl_spi_init(struct spi_board_info *board_infos,
-                       unsigned int num_board_infos,
-                       void (*activate_cs)(u8 cs, u8 polarity),
-                       void (*deactivate_cs)(u8 cs, u8 polarity));
-
 extern void fsl_rstcr_restart(char *cmd);
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
index 2a8af5e16345d45f778e657a2f4c24363946edf3..dcb667c4375af26cb873710fde1bd0508ee18b35 100644 (file)
@@ -72,6 +72,9 @@ config PGSTE
 config VIRT_CPU_ACCOUNTING
        def_bool y
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 mainmenu "Linux Kernel Configuration"
 
 config S390
index 4599fa06bd82a759d322dcd25a85bbfb6edfb369..2283933a9a93eef48b2de37aefe944540af03ff4 100644 (file)
@@ -6,12 +6,4 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
-config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL
-       help
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a slowdown, but helps to find certain types of
-         memory corruptions.
-
 endmenu
index b1e892a43816974660b7fc73f8ecd085a83b41de..704dd396257b4c168b4082d5888c517ca7c378b4 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <asm/ebcdic.h>
index 6dccb071aec3df5158f84b4b4d1afce3ce5cd354..619bf94b11f16f5214b15695fb7fd4e1331a7443 100644 (file)
@@ -456,6 +456,8 @@ struct ciw {
 #define CIO_OPER       0x0004
 /* Sick revalidation of device. */
 #define CIO_REVALIDATE 0x0008
+/* Device did not respond in time. */
+#define CIO_BOXED      0x0010
 
 /**
  * struct ccw_dev_id - unique identifier for ccw devices
index 2009158a4502cf859e242ab5068efd74eb75949f..72137bc907acda6c36e2e1839c88e766b88e2dbc 100644 (file)
@@ -92,12 +92,6 @@ extern void arch_send_call_function_ipi(cpumask_t mask);
 #endif
 
 #ifndef CONFIG_SMP
-static inline void smp_send_stop(void)
-{
-       /* Disable all interrupts/machine checks */
-       __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
-}
-
 #define hard_smp_processor_id()                0
 #define smp_cpu_not_running(cpu)       1
 #endif
index df84ae96915f5342b4f86a76d0ac09651e12c4bd..f3861b09ebb08a2ef2a1081f623f59429b1c6049 100644 (file)
@@ -172,6 +172,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return _raw_write_trylock_retry(rw);
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
 
index b48e961a38f6ee08f0a12b5e7ffc1348fd7c4dcb..a3acd8e60aff70886b058afdc8bce0a441b60e62 100644 (file)
@@ -160,7 +160,7 @@ void release_thread(struct task_struct *dead_task)
 {
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
+int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index 8d50d527c595ff45be4a221cc8d4c6ad6956dca8..2d52b515c2418a7ca4a3993a2f6d58957b7b6755 100644 (file)
@@ -640,10 +640,10 @@ config GUSA_RB
        depends on GUSA && CPU_SH3 || (CPU_SH4 && !CPU_SH4A)
        help
          Enabling this option will allow the kernel to implement some
-         atomic operations using a software implemention of load-locked/
+         atomic operations using a software implementation of load-locked/
          store-conditional (LLSC). On machines which do not have hardware
          LLSC, this should be more efficient than the other alternative of
-         disabling insterrupts around the atomic sequence.
+         disabling interrupts around the atomic sequence.
 
 endmenu
 
index e793181d64da33395ee432189d112fd6b821c0cc..60283565f89b56a83582053a8624cf49fec801b3 100644 (file)
@@ -216,6 +216,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return (oldval > (RW_LOCK_BIAS - 1));
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 066f0fba590e228e0467681dd8b1c4c5c22f6e36..a3f239545897ea5ed72b68714bfc1f8d2f9426c1 100644 (file)
@@ -33,7 +33,6 @@
 
 #define node_to_cpumask(node)  ((void)node, cpu_online_map)
 #define cpumask_of_node(node)  ((void)node, cpu_online_mask)
-#define node_to_first_cpu(node)        ((void)(node),0)
 
 #define pcibus_to_node(bus)    ((void)(bus), -1)
 #define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
index ddafbbbab2abe041dbdca39aa000dc4637f21137..694bc15f84fdd9ddbc14839999e7bb6c9f27b9e5 100644 (file)
@@ -170,7 +170,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index c90c7e5e5feee930fc641d3a97403958d2992ea3..96be839040f88f4fe5e606af0eb06ce7d0986626 100644 (file)
@@ -425,7 +425,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 
 asmlinkage void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index 59d2a03e8b3c475763ff1d228e6177454f27fe1d..988c77c3723124507ca8f772c1139cefc0925140 100644 (file)
@@ -284,7 +284,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED,
-       .mask = CPU_MASK_NONE,
        .name = "timer",
 };
 
index c127293271e1f4072140e334697346bb0ab24779..9aa348658ae33905fe8b821bc3066d5e90a00d79 100644 (file)
@@ -109,7 +109,6 @@ static struct irqaction cmt_irq = {
        .name           = "timer",
        .handler        = cmt_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .mask           = CPU_MASK_NONE,
 };
 
 static void cmt_clk_init(struct clk *clk)
index 9a77ae86b403132a0483c964d2bf83af53794f72..9b0ef01264794f6c2a04054b06a906dcb547c2c0 100644 (file)
@@ -115,7 +115,6 @@ static struct irqaction mtu2_irq = {
        .name           = "timer",
        .handler        = mtu2_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .mask           = CPU_MASK_NONE,
 };
 
 static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 };
index 10b5a6f17cc0a197341458412ba4d5bc906295ac..c5d3396f596012941853134d726244f504887939 100644 (file)
@@ -162,7 +162,6 @@ static struct irqaction tmu0_irq = {
        .name           = "periodic/oneshot timer",
        .handler        = tmu_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .mask           = CPU_MASK_NONE,
 };
 
 static void __init tmu_clk_init(struct clk *clk)
index c3ea215334f60cd372b158efded8bb87502d1cfb..cc12cd48bbc51a41bc157681de49a2b1eeb102d3 100644 (file)
@@ -124,6 +124,9 @@ config ARCH_NO_VIRT_TO_BUS
 config OF
        def_bool y
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y if SPARC64
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
index b8a15e271bfaacc2e6ce0e789fcb501b792f27b9..90d5fe223a7458953e866aa376ebd8e5591f244b 100644 (file)
@@ -22,14 +22,6 @@ config DEBUG_DCFLUSH
 config STACK_DEBUG
        bool "Stack Overflow Detection Support"
 
-config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on SPARC64 && DEBUG_KERNEL && !HIBERNATION
-       help
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a large slowdown, but helps to find certain types
-         of memory corruptions.
-
 config MCOUNT
        bool
        depends on SPARC64
index 5693ab4826067056873803b6324b437e6275453f..666a73fef28dad76765a89eab95bb93c3eee232c 100644 (file)
@@ -121,8 +121,8 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
         * local TLB.
         */
        cpu = smp_processor_id();
-       if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) {
-               cpu_set(cpu, mm->cpu_vm_mask);
+       if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) {
+               cpumask_set_cpu(cpu, mm_cpumask(mm));
                __flush_tlb_mm(CTX_HWBITS(mm->context),
                               SECONDARY_CONTEXT);
        }
@@ -141,8 +141,8 @@ static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm
        if (!CTX_VALID(mm->context))
                get_new_mmu_context(mm);
        cpu = smp_processor_id();
-       if (!cpu_isset(cpu, mm->cpu_vm_mask))
-               cpu_set(cpu, mm->cpu_vm_mask);
+       if (!cpumask_test_cpu(cpu, mm_cpumask(mm)))
+               cpumask_set_cpu(cpu, mm_cpumask(mm));
 
        load_secondary_context(mm);
        __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
index 57224dd37b3a59967bdf5ee7e527f551ec700229..becb6bf353a9c36de3b40c3d7dcbc4b80a5e6c47 100644 (file)
@@ -35,7 +35,8 @@ extern cpumask_t cpu_core_map[NR_CPUS];
 extern int sparc64_multi_core;
 
 extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
 /*
  *     General functions that each host system must provide.
index bf2d532593e3900ed9838fdf4334d0a2ae5b91db..46f91ab66a50d6ae792ef5d8d260cea30a54bd39 100644 (file)
@@ -177,6 +177,8 @@ static inline int __read_trylock(raw_rwlock_t *rw)
 #define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0)
 
 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+#define __raw_read_lock_flags(rw, flags)   __raw_read_lock(rw)
+#define __raw_write_lock_flags(rw, flags)  __raw_write_lock(rw)
 
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
index c4d274d330e98b848489c3aeb64cf8516f6f7b4f..f6b2b92ad8d29a7864298024c00092dcb21d934c 100644 (file)
@@ -211,9 +211,11 @@ static int inline __write_trylock(raw_rwlock_t *lock)
 }
 
 #define __raw_read_lock(p)     __read_lock(p)
+#define __raw_read_lock_flags(p, f) __read_lock(p)
 #define __raw_read_trylock(p)  __read_trylock(p)
 #define __raw_read_unlock(p)   __read_unlock(p)
 #define __raw_write_lock(p)    __write_lock(p)
+#define __raw_write_lock_flags(p, f) __write_lock(p)
 #define __raw_write_unlock(p)  __write_unlock(p)
 #define __raw_write_trylock(p) __write_trylock(p)
 
index 79c1ae2b42a346ec11aa284a9719a926212741f3..751c8c17f5a037df797dbb148cf72d39f0521c93 100644 (file)
@@ -126,7 +126,7 @@ extern void flushw_all(void);
 #define switch_to(prev, next, last) do {                                               \
        SWITCH_ENTER(prev);                                                             \
        SWITCH_DO_LAZY_FPU(next);                                                       \
-       cpu_set(smp_processor_id(), next->active_mm->cpu_vm_mask);                      \
+       cpumask_set_cpu(smp_processor_id(), mm_cpumask(next->active_mm));               \
        __asm__ __volatile__(                                                           \
        "sethi  %%hi(here - 0x8), %%o7\n\t"                                             \
        "mov    %%g6, %%g3\n\t"                                                         \
index 5bc0b8fd63744f477f7ade478e42922175649c28..e5ea8d332421d1ad1441541c8e013d62d099e444 100644 (file)
@@ -28,11 +28,6 @@ static inline cpumask_t node_to_cpumask(int node)
 #define node_to_cpumask_ptr_next(v, node)      \
                           v = &(numa_cpumask_lookup_table[node])
 
-static inline int node_to_first_cpu(int node)
-{
-       return cpumask_first(cpumask_of_node(node));
-}
-
 struct pci_bus;
 #ifdef CONFIG_PCI
 extern int pcibus_to_node(struct pci_bus *pbus);
@@ -43,13 +38,9 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
 }
 #endif
 
-#define pcibus_to_cpumask(bus) \
-       (pcibus_to_node(bus) == -1 ? \
-        CPU_MASK_ALL : \
-        node_to_cpumask(pcibus_to_node(bus)))
 #define cpumask_of_pcibus(bus) \
        (pcibus_to_node(bus) == -1 ? \
-        CPU_MASK_ALL_PTR : \
+        cpu_all_mask : \
         cpumask_of_node(pcibus_to_node(bus)))
 
 #define SD_NODE_INIT (struct sched_domain) {           \
@@ -89,7 +80,6 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
 #define smt_capable()                          (sparc64_multi_core)
 #endif /* CONFIG_SMP */
 
-#define cpu_coregroup_map(cpu)                 (cpu_core_map[cpu])
 #define cpu_coregroup_mask(cpu)                        (&cpu_core_map[cpu])
 
 #endif /* _ASM_SPARC64_TOPOLOGY_H */
index 57c39843fb2a446c68849e5326496d4e5756cd0d..90350f838f05efa92a9739d4e4a03079f5f0ae55 100644 (file)
@@ -653,7 +653,7 @@ static void __cpuinit dr_cpu_data(struct ds_info *dp,
                if (cpu_list[i] == CPU_SENTINEL)
                        continue;
 
-               if (cpu_list[i] < NR_CPUS)
+               if (cpu_list[i] < nr_cpu_ids)
                        cpu_set(cpu_list[i], mask);
        }
 
index a46c3a21e26ded67dc59b816e9c8b8f5f7eade1f..3a1b7bf03cff144c72a135fc20adaee8d21990e0 100644 (file)
@@ -686,7 +686,7 @@ tlb_fixup_done:
         * point.
         *
         * There used to be enormous complexity wrt. transferring
-        * over from the firwmare's trap table to the Linux kernel's.
+        * over from the firmware's trap table to the Linux kernel's.
         * For example, there was a chicken & egg problem wrt. building
         * the OBP page tables, yet needing to be on the Linux kernel
         * trap table (to translate PAGE_OFFSET addresses) in order to
index 44dd5ee64339219257a2457d85afd364f2526f58..ad800b80c718285e046d47d8c652c54aa22049da 100644 (file)
@@ -439,7 +439,6 @@ static int request_fast_irq(unsigned int irq,
        flush_cache_all();
 
        action->flags = irqflags;
-       cpus_clear(action->mask);
        action->name = devname;
        action->dev_id = NULL;
        action->next = NULL;
@@ -574,7 +573,6 @@ int request_irq(unsigned int irq,
 
        action->handler = handler;
        action->flags = irqflags;
-       cpus_clear(action->mask);
        action->name = devname;
        action->next = NULL;
        action->dev_id = dev_id;
index d0d6a515499ac952f487a49e389b2bdd5519bd02..5deabe921a47b6ebdcd5f6371faf7eaab3c135e4 100644 (file)
@@ -266,12 +266,12 @@ static int irq_choose_cpu(unsigned int virt_irq)
                spin_lock_irqsave(&irq_rover_lock, flags);
 
                while (!cpu_online(irq_rover)) {
-                       if (++irq_rover >= NR_CPUS)
+                       if (++irq_rover >= nr_cpu_ids)
                                irq_rover = 0;
                }
                cpuid = irq_rover;
                do {
-                       if (++irq_rover >= NR_CPUS)
+                       if (++irq_rover >= nr_cpu_ids)
                                irq_rover = 0;
                } while (!cpu_online(irq_rover));
 
index adaaed4ea2fb6821ca2a85c7afe61d2a07208f1d..00d034ea2164d63148d7b0ff04538420b163c513 100644 (file)
@@ -126,7 +126,6 @@ static int __init led_init(void)
        led = proc_create("led", 0, NULL, &led_proc_fops);
        if (!led)
                return -ENOMEM;
-       led->owner = THIS_MODULE;
 
        printk(KERN_INFO
               "led: version %s, Lars Kotthoff <metalhead@metalhead.ws>\n",
index 3f79f0c23a084d4a80ae572be79db9e0f747d66c..f0e6ed23a468ec10c6b7ba78ad8d5890295f7f82 100644 (file)
@@ -567,7 +567,7 @@ static void __init report_platform_properties(void)
                        max_cpu = NR_CPUS;
                }
                for (i = 0; i < max_cpu; i++)
-                       cpu_set(i, cpu_possible_map);
+                       set_cpu_possible(i, true);
        }
 #endif
 
index f3577223c8630e2d40002c72026755c72bb3bcfe..2c0cc72d295b079cfab695197eff38fcbd54d586 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include <linux/kernel_stat.h>
+#include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/kdebug.h>
 #include <linux/delay.h>
@@ -206,13 +207,33 @@ void nmi_adjust_hz(unsigned int new_hz)
 }
 EXPORT_SYMBOL_GPL(nmi_adjust_hz);
 
+static int nmi_shutdown(struct notifier_block *nb, unsigned long cmd, void *p)
+{
+       on_each_cpu(stop_watchdog, NULL, 1);
+       return 0;
+}
+
+static struct notifier_block nmi_reboot_notifier = {
+       .notifier_call = nmi_shutdown,
+};
+
 int __init nmi_init(void)
 {
+       int err;
+
        nmi_usable = 1;
 
        on_each_cpu(start_watchdog, NULL, 1);
 
-       return check_nmi_watchdog();
+       err = check_nmi_watchdog();
+       if (!err) {
+               err = register_reboot_notifier(&nmi_reboot_notifier);
+               if (err) {
+                       nmi_usable = 0;
+                       on_each_cpu(stop_watchdog, NULL, 1);
+               }
+       }
+       return err;
 }
 
 static int __init setup_nmi_watchdog(char *str)
index f4bee35a1b46a4dc5ff7446eba219190f0d39098..2830b415e2147ecfda36acc99d620408472128bd 100644 (file)
@@ -455,7 +455,7 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
  */
 extern void ret_from_fork(void);
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index a73954b87f0a511ad7431b4b33f82216f22e2b7c..4041f94e7724f89de745f2be540342c7ab3ade40 100644 (file)
@@ -561,7 +561,7 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
  * Parent -->  %o0 == childs  pid, %o1 == 0
  * Child  -->  %o0 == parents pid, %o1 == 1
  */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
index edecca7b811655546a7aba9d108414ae36c31703..ca55c7012f7751d4338a1c6fc1153124ef0f6966 100644 (file)
@@ -518,8 +518,8 @@ void __init of_fill_in_cpu_data(void)
                }
 
 #ifdef CONFIG_SMP
-               cpu_set(cpuid, cpu_present_map);
-               cpu_set(cpuid, cpu_possible_map);
+               set_cpu_present(cpuid, true);
+               set_cpu_possible(cpuid, true);
 #endif
        }
 
index 1e5ac4e282e1285030aaa43380b91c01b7bcff48..132d81fb26162657b0391a11e56e23fce9bf604d 100644 (file)
@@ -70,13 +70,12 @@ void __init smp_cpus_done(unsigned int max_cpus)
        extern void smp4m_smp_done(void);
        extern void smp4d_smp_done(void);
        unsigned long bogosum = 0;
-       int cpu, num;
+       int cpu, num = 0;
 
-       for (cpu = 0, num = 0; cpu < NR_CPUS; cpu++)
-               if (cpu_online(cpu)) {
-                       num++;
-                       bogosum += cpu_data(cpu).udelay_val;
-               }
+       for_each_online_cpu(cpu) {
+               num++;
+               bogosum += cpu_data(cpu).udelay_val;
+       }
 
        printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
                num, bogosum/(500000/HZ),
@@ -144,7 +143,7 @@ void smp_flush_tlb_all(void)
 void smp_flush_cache_mm(struct mm_struct *mm)
 {
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
@@ -155,12 +154,13 @@ void smp_flush_cache_mm(struct mm_struct *mm)
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask)) {
                        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
                        if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
-                               mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
+                               cpumask_copy(mm_cpumask(mm),
+                                            cpumask_of(smp_processor_id()));
                }
                local_flush_tlb_mm(mm);
        }
@@ -172,7 +172,7 @@ void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
        struct mm_struct *mm = vma->vm_mm;
 
        if (mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end);
@@ -186,7 +186,7 @@ void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        struct mm_struct *mm = vma->vm_mm;
 
        if (mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end);
@@ -199,7 +199,7 @@ void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page);
@@ -212,7 +212,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpumask_t cpu_mask = *mm_cpumask(mm);
                cpu_clear(smp_processor_id(), cpu_mask);
                if (!cpus_empty(cpu_mask))
                        xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
@@ -241,7 +241,7 @@ void smp_flush_page_to_ram(unsigned long page)
 
 void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
 {
-       cpumask_t cpu_mask = mm->cpu_vm_mask;
+       cpumask_t cpu_mask = *mm_cpumask(mm);
        cpu_clear(smp_processor_id(), cpu_mask);
        if (!cpus_empty(cpu_mask))
                xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
@@ -332,8 +332,8 @@ void __init smp_setup_cpu_possible_map(void)
        instance = 0;
        while (!cpu_find_by_instance(instance, NULL, &mid)) {
                if (mid < NR_CPUS) {
-                       cpu_set(mid, cpu_possible_map);
-                       cpu_set(mid, cpu_present_map);
+                       set_cpu_possible(mid, true);
+                       set_cpu_present(mid, true);
                }
                instance++;
        }
@@ -351,8 +351,8 @@ void __init smp_prepare_boot_cpu(void)
                printk("boot cpu id != 0, this could work but is untested\n");
 
        current_thread_info()->cpu = cpuid;
-       cpu_set(cpuid, cpu_online_map);
-       cpu_set(cpuid, cpu_possible_map);
+       set_cpu_online(cpuid, true);
+       set_cpu_possible(cpuid, true);
 }
 
 int __cpuinit __cpu_up(unsigned int cpu)
index 79457f682b5ac05b693d185223ddd7ea8f9335b6..708e12a26b0528919065429d66c1bdf32ab4a5aa 100644 (file)
@@ -808,9 +808,9 @@ static void smp_start_sync_tick_client(int cpu)
 
 extern unsigned long xcall_call_function;
 
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
-       xcall_deliver((u64) &xcall_call_function, 0, 0, &mask);
+       xcall_deliver((u64) &xcall_call_function, 0, 0, mask);
 }
 
 extern unsigned long xcall_call_function_single;
@@ -850,7 +850,7 @@ static void tsb_sync(void *info)
 
 void smp_tsb_sync(struct mm_struct *mm)
 {
-       smp_call_function_mask(mm->cpu_vm_mask, tsb_sync, mm, 1);
+       smp_call_function_many(mm_cpumask(mm), tsb_sync, mm, 1);
 }
 
 extern unsigned long xcall_flush_tlb_mm;
@@ -1055,13 +1055,13 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
        int cpu = get_cpu();
 
        if (atomic_read(&mm->mm_users) == 1) {
-               mm->cpu_vm_mask = cpumask_of_cpu(cpu);
+               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
                goto local_flush_and_out;
        }
 
        smp_cross_call_masked(&xcall_flush_tlb_mm,
                              ctx, 0, 0,
-                             &mm->cpu_vm_mask);
+                             mm_cpumask(mm));
 
 local_flush_and_out:
        __flush_tlb_mm(ctx, SECONDARY_CONTEXT);
@@ -1075,11 +1075,11 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long
        int cpu = get_cpu();
 
        if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
-               mm->cpu_vm_mask = cpumask_of_cpu(cpu);
+               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
        else
                smp_cross_call_masked(&xcall_flush_tlb_pending,
                                      ctx, nr, (unsigned long) vaddrs,
-                                     &mm->cpu_vm_mask);
+                                     mm_cpumask(mm));
 
        __flush_tlb_pending(ctx, nr, vaddrs);
 
index 3369fef5b4b3acd2749ddcbefd1befd37df2e15b..ab036a72de5a16460cdb8b548dbcf15bb2e04db6 100644 (file)
@@ -326,7 +326,6 @@ int sun4d_request_irq(unsigned int irq,
 
        action->handler = handler;
        action->flags = irqflags;
-       cpus_clear(action->mask);
        action->name = devname;
        action->next = NULL;
        action->dev_id = dev_id;
index 50afaed99c8a13d74b4e873eca58c5528563ba48..54fb02468f0d57ef00ce78c610609ba43d0c1702 100644 (file)
@@ -150,7 +150,7 @@ void __cpuinit smp4d_callin(void)
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
        cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
        spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-       cpu_set(cpuid, cpu_online_map);
+       set_cpu_online(cpuid, true);
 
 }
 
@@ -228,11 +228,10 @@ void __init smp4d_smp_done(void)
        /* setup cpu list for irq rotation */
        first = 0;
        prev = &first;
-       for (i = 0; i < NR_CPUS; i++)
-               if (cpu_online(i)) {
-                       *prev = i;
-                       prev = &cpu_data(i).next;
-               }
+       for_each_online_cpu(i) {
+               *prev = i;
+               prev = &cpu_data(i).next;
+       }
        *prev = first;
        local_flush_cache_all();
 
index 8040376c4890cc11c95e7c783f331abc7becb456..960b113d0006f4ff61de665c2383dd4b522a4622 100644 (file)
@@ -113,7 +113,7 @@ void __cpuinit smp4m_callin(void)
 
        local_irq_enable();
 
-       cpu_set(cpuid, cpu_online_map);
+       set_cpu_online(cpuid, true);
 }
 
 /*
@@ -186,11 +186,9 @@ void __init smp4m_smp_done(void)
        /* setup cpu list for irq rotation */
        first = 0;
        prev = &first;
-       for (i = 0; i < NR_CPUS; i++) {
-               if (cpu_online(i)) {
-                       *prev = i;
-                       prev = &cpu_data(i).next;
-               }
+       for_each_online_cpu(i) {
+               *prev = i;
+               prev = &cpu_data(i).next;
        }
        *prev = first;
        local_flush_cache_all();
index 752d0c9fb54469e464271bac8c56371197fd8938..7916feba6e4a03a0e1f5c203932e3cb856593b8f 100644 (file)
@@ -39,6 +39,7 @@ void *kmap_atomic(struct page *page, enum km_type type)
        if (!PageHighMem(page))
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 
index 00373ce2d8fbd872f838ece2de6cd49afd6e45a7..2c8dfeb7ab04b24634bba62532f6ac62a510059b 100644 (file)
@@ -1092,7 +1092,7 @@ static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md,
                if (strcmp(name, "cpu"))
                        continue;
                id = mdesc_get_property(md, target, "id", NULL);
-               if (*id < NR_CPUS)
+               if (*id < nr_cpu_ids)
                        cpu_set(*id, *mask);
        }
 }
index fe7ed08390bb720e1c4be141aa5a072f58b843ec..06c9a7d98206f0256c23a281381bf2d6ab7ca441 100644 (file)
@@ -1425,7 +1425,7 @@ static void __init init_vac_layout(void)
                                min_line_size = vac_line_size;
                        //FIXME: cpus not contiguous!!
                        cpu++;
-                       if (cpu >= NR_CPUS || !cpu_online(cpu))
+                       if (cpu >= nr_cpu_ids || !cpu_online(cpu))
                                break;
 #else
                        break;
index 434224e2229ff6afde1556b5541b83200466c99e..434ba121e3c59a30009117fd6f1c146f516270a6 100644 (file)
@@ -757,7 +757,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
        void (*proc)(unsigned char *, unsigned char *, void *);
        unsigned char addr_buf[4], netmask_buf[4];
 
-       if (dev->open != uml_net_open)
+       if (dev->netdev_ops->ndo_open != uml_net_open)
                return NOTIFY_DONE;
 
        lp = netdev_priv(dev);
index 96b80b565eeb7950296d3633b85df8a8eeb7b16b..d8ba6153f9125bb2d749d850e8630bae6fb80a7b 100644 (file)
@@ -19,13 +19,3 @@ extern const struct net_user_info pcap_user_info;
 
 extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 9117609a575dd60bbcd5e2ae86950b3a4433567b..372a80c0556a275cdf5454b638efa7057d80007d 100644 (file)
@@ -18,13 +18,3 @@ extern void port_remove_dev(void *d);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 98412aa6660722aa3d3d1138b4a49ba4abf81752..314d17725ce6b1c2892ce29f868118af6ddadde4 100644 (file)
@@ -11,13 +11,3 @@ extern void ssl_receive_char(int line, char ch);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 505a3d5bea5eb5ce51b4c0a88cc11a8d55da6dad..6d8275f71fd40a0c752370ece8ae2c5548d4d110 100644 (file)
@@ -9,13 +9,3 @@
 extern void save_console_flags(void);
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0a868118cf06b2bb2aece4afbbd89d18228d43dc..f934225fd8ef9c702c869c274df0c271c9a6a20b 100644 (file)
  * James McMechan
  */
 
-#define MAJOR_NR UBD_MAJOR
 #define UBD_SHIFT 4
 
 #include "linux/kernel.h"
 #include "linux/module.h"
 #include "linux/blkdev.h"
+#include "linux/ata.h"
 #include "linux/hdreg.h"
 #include "linux/init.h"
 #include "linux/cdrom.h"
@@ -115,7 +115,7 @@ static struct block_device_operations ubd_blops = {
 };
 
 /* Protected by ubd_lock */
-static int fake_major = MAJOR_NR;
+static int fake_major = UBD_MAJOR;
 static struct gendisk *ubd_gendisk[MAX_DEV];
 static struct gendisk *fake_gendisk[MAX_DEV];
 
@@ -299,7 +299,7 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out)
                }
 
                mutex_lock(&ubd_lock);
-               if(fake_major != MAJOR_NR){
+               if (fake_major != UBD_MAJOR) {
                        *error_out = "Can't assign a fake major twice";
                        goto out1;
                }
@@ -818,13 +818,13 @@ static int ubd_disk_register(int major, u64 size, int unit,
        disk->first_minor = unit << UBD_SHIFT;
        disk->fops = &ubd_blops;
        set_capacity(disk, size / 512);
-       if(major == MAJOR_NR)
+       if (major == UBD_MAJOR)
                sprintf(disk->disk_name, "ubd%c", 'a' + unit);
        else
                sprintf(disk->disk_name, "ubd_fake%d", unit);
 
        /* sysfs register (not for ide fake devices) */
-       if (major == MAJOR_NR) {
+       if (major == UBD_MAJOR) {
                ubd_devs[unit].pdev.id   = unit;
                ubd_devs[unit].pdev.name = DRIVER_NAME;
                ubd_devs[unit].pdev.dev.release = ubd_device_release;
@@ -871,13 +871,13 @@ static int ubd_add(int n, char **error_out)
        ubd_dev->queue->queuedata = ubd_dev;
 
        blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
-       err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
+       err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
        if(err){
                *error_out = "Failed to register device";
                goto out_cleanup;
        }
 
-       if(fake_major != MAJOR_NR)
+       if (fake_major != UBD_MAJOR)
                ubd_disk_register(fake_major, ubd_dev->size, n,
                                  &fake_gendisk[n]);
 
@@ -1059,10 +1059,10 @@ static int __init ubd_init(void)
        char *error;
        int i, err;
 
-       if (register_blkdev(MAJOR_NR, "ubd"))
+       if (register_blkdev(UBD_MAJOR, "ubd"))
                return -1;
 
-       if (fake_major != MAJOR_NR) {
+       if (fake_major != UBD_MAJOR) {
                char name[sizeof("ubd_nnn\0")];
 
                snprintf(name, sizeof(name), "ubd_%d", fake_major);
@@ -1309,16 +1309,15 @@ static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
                     unsigned int cmd, unsigned long arg)
 {
        struct ubd *ubd_dev = bdev->bd_disk->private_data;
-       struct hd_driveid ubd_id = {
-               .cyls           = 0,
-               .heads          = 128,
-               .sectors        = 32,
-       };
+       u16 ubd_id[ATA_ID_WORDS];
 
        switch (cmd) {
                struct cdrom_volctrl volume;
        case HDIO_GET_IDENTITY:
-               ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
+               memset(&ubd_id, 0, ATA_ID_WORDS * 2);
+               ubd_id[ATA_ID_CYLS]     = ubd_dev->size / (128 * 32 * 512);
+               ubd_id[ATA_ID_HEADS]    = 128;
+               ubd_id[ATA_ID_SECTORS]  = 32;
                if(copy_to_user((char __user *) arg, (char *) &ubd_id,
                                 sizeof(ubd_id)))
                        return -EFAULT;
index f33a6e77b18619b9ef3245a216a251563b8da6b4..56b9c4aba423b0b57b64d049d85cb43260f67e5a 100644 (file)
@@ -10,13 +10,3 @@ extern int xterm_fd(int socket, int *pid_out);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 62ddba6fc73393b82b39ac6569f0f0639577c873..272a81e0ce149853c03a1bed918232a957c82505 100644 (file)
@@ -8,13 +8,3 @@
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 2cf35c21d6940aee79c0dedfc5115c00e438247b..cf259de5153160be38b8d2073d0fe111e05a4f4c 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0d8bf33ffd4235287a2028b9c9d90fcf1e0dfc54..ddcd774fc2a06f3887d5a24ffaa25f2055edd034 100644 (file)
@@ -19,13 +19,3 @@ extern struct foo me;
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 9062a6e72241f60235b0c6f4c2bd41dd9c00ab6d..718984359f8c8876d84a2a902fa0b6fa6b4cb933 100644 (file)
@@ -60,13 +60,3 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0446f456b428687b07ba689899cbefe4151d3fe7..084de4a9fc701412492b315e4162e693884beb8b 100644 (file)
@@ -134,13 +134,3 @@ static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index ce9514f5721125cd1bc8a0c383933ada72c7907b..76078490c2581c92a2c40cc039419e918f8b6f9d 100644 (file)
@@ -20,13 +20,3 @@ extern int setup_signal_stack_si(unsigned long stack_top, int sig,
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 439b9a8149859ebac6da333313fcf005c22975c5..22673bcc273d1747c618d864e9d660d344ac1f4f 100644 (file)
@@ -10,13 +10,3 @@ extern int load_initrd(char *filename, void *buf, int size);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index fba3895274f9ba9e2834cdb063b76f1cf295f5e9..b05d22f3d84e2450420a38adf8f641a106d5e236 100644 (file)
@@ -16,13 +16,3 @@ extern int um_request_irq(unsigned int irq, int fd, int type,
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index cb7e196d366b57ff4f4370e184d08274a71dc83e..69be0fd0ce4b93c2a920dbd8e7460f9102f84c07 100644 (file)
@@ -18,13 +18,3 @@ extern void register_remapper(struct remapper *info);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index bb66517f0739e655057ff20dab63ed300cf48341..3845051f1b10a34bbd83a96bad9a23bab30b057d 100644 (file)
@@ -14,13 +14,3 @@ extern int kernel_fd;
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 499e5e95e60937c887c36a50ce91081e0de462bd..388ec0a3ea9b0f57cfffe0ad14eb411934069df5 100644 (file)
@@ -28,7 +28,7 @@ $(obj)/config.tmp: $(objtree)/.config FORCE
        $(call if_changed,quote1)
 
 quiet_cmd_quote1 = QUOTE   $@
-      cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \
+      cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n",/' \
                   $< > $@
 
 $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
@@ -36,9 +36,9 @@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
 
 quiet_cmd_quote2 = QUOTE   $@
       cmd_quote2 = sed -e '/CONFIG/{'          \
-                 -e 's/"CONFIG"\;/""/'        \
+                 -e 's/"CONFIG"//'            \
                  -e 'r $(obj)/config.tmp'     \
                  -e 'a \'                     \
-                 -e '""\;'                    \
+                 -e '""'                      \
                  -e '}'                       \
                  $< > $@
index c062cbfe386e22a153ab43833bffa96932eac874..b7a43feafde773aeb4998675be30074ee5613c32 100644 (file)
@@ -7,11 +7,15 @@
 #include <stdlib.h>
 #include "init.h"
 
-static __initdata char *config = "CONFIG";
+static __initdata const char *config[] = {
+"CONFIG"
+};
 
 static int __init print_config(char *line, int *add)
 {
-       printf("%s", config);
+       int i;
+       for (i = 0; i < sizeof(config)/sizeof(config[0]); i++)
+               printf("%s", config[i]);
        exit(0);
 }
 
@@ -20,13 +24,3 @@ __uml_setup("--showconfig", print_config,
 "    Prints the config file that this UML binary was generated from.\n\n"
 );
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index a1c6d07cac3e46b2f3460e04729cf6a2ca203571..4a28a1568d856c7b1605743ca33c143921caacd4 100644 (file)
@@ -179,7 +179,7 @@ void fork_handler(void)
        userspace(&current->thread.regs.regs);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long stack_top, struct task_struct * p,
                struct pt_regs *regs)
 {
index c4df705b835937f9256cafe43fcd92c9830eba59..a4625c7b2bf990a78dc49f5785b48393dba00baf 100644 (file)
@@ -127,7 +127,8 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])
 
        fs = get_fs();
        set_fs(KERNEL_DS);
-       ret = um_execve(filename, argv, envp);
+       ret = um_execve((char *)filename, (char __user *__user *)argv,
+                       (char __user *__user *) envp);
        set_fs(fs);
 
        return ret;
index 183db26d01bf2050bddb5c7db862ed4dd2b6927d..02ee9adff54ad2a8913e94aee9bf927723194e58 100644 (file)
@@ -244,7 +244,7 @@ static void __init check_sysemu(void)
 
        if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
                   (void *) PTRACE_O_TRACESYSGOOD) < 0))
-               fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
+               fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
 
        while (1) {
                count++;
@@ -252,12 +252,12 @@ static void __init check_sysemu(void)
                        goto fail;
                CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
                if (n < 0)
-                       fatal_perror("check_ptrace : wait failed");
+                       fatal_perror("check_sysemu: wait failed");
 
                if (WIFSTOPPED(status) &&
                    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
                        if (!count) {
-                               non_fatal("check_ptrace : SYSEMU_SINGLESTEP "
+                               non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
                                          "doesn't singlestep");
                                goto fail;
                        }
@@ -271,7 +271,7 @@ static void __init check_sysemu(void)
                else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
                        count++;
                else {
-                       non_fatal("check_ptrace : expected SIGTRAP or "
+                       non_fatal("check_sysemu: expected SIGTRAP or "
                                  "(SIGTRAP | 0x80), got status = %d\n",
                                  status);
                        goto fail;
index 93fd723344e54fef2cc64c12b10023cc3538d61f..2a18a884ca1bcf903849b97457bf01bbe351bd61 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 0cb4645cbeb8fc69ad454ddc328e91d3002bf5fc..ed47445f3905f9b71f4f5cbb367e45d4bba555f0 100644 (file)
@@ -199,13 +199,3 @@ static __inline__ __wsum csum_and_copy_to_user(const void *src,
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 00e5f5203eea337abd3a3e0ee115d6795ab0e4d3..c6260dd6ebb9f3338eee3b7f7242fe419e096b64 100644 (file)
@@ -9,6 +9,17 @@
 
 #define old_mmap old_mmap_i386
 
+#define ptregs_fork sys_fork
+#define ptregs_execve sys_execve
+#define ptregs_iopl sys_iopl
+#define ptregs_vm86old sys_vm86old
+#define ptregs_sigreturn sys_sigreturn
+#define ptregs_clone sys_clone
+#define ptregs_vm86 sys_vm86
+#define ptregs_rt_sigreturn sys_rt_sigreturn
+#define ptregs_sigaltstack sys_sigaltstack
+#define ptregs_vfork sys_vfork
+
 .section .rodata,"a"
 
 #include "../../x86/kernel/syscall_table_32.S"
index 42dd8fb6f2f94b844f4216d2f9f644ebf6a5e9cb..0f0f4e6fd334f9a5152758c7697728d7148ade6d 100644 (file)
@@ -14,13 +14,3 @@ struct sys_pt_regs {
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index f15fb25260ba0c9cc47be5c41cd6b512e464cf83..76b43161e7795415209463441a66ee12bfb01531 100644 (file)
@@ -8,13 +8,3 @@
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 4a1f46ef1ebc3e1cb1d3931f315ce2a0983b6570..5f6700c415584e5d54d9350d85e9848ee3772dc6 100644 (file)
@@ -8,13 +8,3 @@
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 373061c50129b8796e8deb05221e1528eb79e431..1c11aed9c719646795ddc2e45824ee8dac053170 100644 (file)
@@ -40,14 +40,3 @@ void shove_aux_table(unsigned long sp)
 }
 /* END stuff taken from arch/ppc/kernel/process.c */
 
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 8e71b47f2b8ed86f9bee12696b773c3e99f011e8..66ef155248f1d1b8365e511524d21c7067c5d888 100644 (file)
@@ -56,13 +56,3 @@ int peek_user(struct task_struct *child, long addr, long data)
        return put_user(tmp, (unsigned long *) data);
 }
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index ff0b9c077a13c037d6daf60ce7ae2ecf8afa04fb..224d2403c37bb243bbb47c364e725d690d8e44fc 100644 (file)
@@ -27,13 +27,3 @@ int ptrace_setregs(long pid, unsigned long *regs_in)
     }
     return 0;
 }
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index df2397dba3e5282f63b134cab7d59719b1b5461a..0e3230e937e14fd3260f5dad2d1e6167c0b3c975 100644 (file)
@@ -91,13 +91,3 @@ extern void shove_aux_table(unsigned long sp);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index f20d965de9c72af3eb930b167825a09753623ab2..b7286f0a1e00dd40a7221e02322389b7e5812201 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 679df351e19b6b82f06cf4c1f632732181f359cc..1ff81552251c7571d7b3fdda6a640d64def977f1 100644 (file)
@@ -41,13 +41,3 @@ int old_mmap(unsigned long addr, unsigned long len,
 
 #define LAST_ARCH_SYSCALL __NR_fadvise64
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 4bdc15c89eddd3ddd3109404313baf87cffdcd67..40694d0f3d15ab6d8db6f415c9c1509e722044f9 100644 (file)
@@ -2,13 +2,3 @@
 #include "asm/sigcontext.h"
 #include "sysdep/ptrace.h"
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 270ed9586b68542563e3d94cf8dc49d9d7a99256..6c083663b8d9d084d83587da921412ccbef3bd54 100644 (file)
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 35b5491d3e96b77888d035e84bae59d36dc44f72..8eb79c2d07d583d55835700c1bd6c7193156a008 100644 (file)
@@ -18,13 +18,3 @@ struct mod_arch_specific
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 3f59a0a4f156044eec4ffe943306428f0da2d99f..3f8df8abf34738cc28a7214a830f05b9276a7fb5 100644 (file)
@@ -14,12 +14,3 @@ unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS;
 unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS;
 unsigned long vm_force_exec32 = PROT_EXEC;
 
-/* Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 45161b816313f23bf1793d880de83429601bc407..5696cec7b4b0ab26d0b02d28060e3926ecb5295e 100644 (file)
@@ -165,6 +165,9 @@ config AUDIT_ARCH
 config ARCH_SUPPORTS_OPTIMIZED_INLINING
        def_bool y
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 # Use the generic interrupt handling code in kernel/irq/:
 config GENERIC_HARDIRQS
        bool
@@ -1141,7 +1144,7 @@ config NODES_SHIFT
        depends on NEED_MULTIPLE_NODES
        ---help---
          Specify the maximum number of NUMA Nodes available on the target
-         system.  Increases memory reserved to accomodate various tables.
+         system.  Increases memory reserved to accommodate various tables.
 
 config HAVE_ARCH_BOOTMEM
        def_bool y
@@ -1319,7 +1322,7 @@ config MTRR_SANITIZER
          add writeback entries.
 
          Can be disabled with disable_mtrr_cleanup on the kernel command line.
-         The largest mtrr entry size for a continous block can be set with
+         The largest mtrr entry size for a continuous block can be set with
          mtrr_chunk_size.
 
          If unsure, say Y.
@@ -1834,8 +1837,8 @@ config PCI_MMCONFIG
 
 config DMAR
        bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
-       depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL
-       ---help---
+       depends on PCI_MSI && ACPI && EXPERIMENTAL
+       help
          DMA remapping (DMAR) devices support enables independent address
          translations for Direct Memory Access (DMA) from devices.
          These DMA remapping devices are reported via ACPI tables
index fdb45df608b627c4efd79bba410ab4a0cb0f9b4a..d8359e73317f8dfb8b929f15f555f5593469e7fd 100644 (file)
@@ -72,14 +72,6 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
-config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL
-       ---help---
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a large slowdown, but helps to find certain types
-         of memory corruptions.
-
 config DEBUG_PER_CPU_MAPS
        bool "Debug access to per_cpu maps"
        depends on DEBUG_KERNEL
index 8c3c25f35578a00c140440131a69ae539038f950..5054c2ddd1a03471b4423e7c9eb1719dca667901 100644 (file)
@@ -2,6 +2,7 @@
  *
  *   Copyright (C) 1991, 1992 Linus Torvalds
  *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author H. Peter Anvin
  *
  *   This file is part of the Linux kernel, and is made available under
  *   the terms of the GNU General Public License version 2.
 
 #define SMAP   0x534d4150      /* ASCII "SMAP" */
 
+struct e820_ext_entry {
+       struct e820entry std;
+       u32 ext_flags;
+} __attribute__((packed));
+
 static int detect_memory_e820(void)
 {
        int count = 0;
        u32 next = 0;
-       u32 size, id;
+       u32 size, id, edi;
        u8 err;
        struct e820entry *desc = boot_params.e820_map;
+       static struct e820_ext_entry buf; /* static so it is zeroed */
+
+       /*
+        * Set this here so that if the BIOS doesn't change this field
+        * but still doesn't change %ecx, we're still okay...
+        */
+       buf.ext_flags = 1;
 
        do {
-               size = sizeof(struct e820entry);
+               size = sizeof buf;
 
-               /* Important: %edx is clobbered by some BIOSes,
-                  so it must be either used for the error output
-                  or explicitly marked clobbered. */
-               asm("int $0x15; setc %0"
+               /* Important: %edx and %esi are clobbered by some BIOSes,
+                  so they must be either used for the error output
+                  or explicitly marked clobbered.  Given that, assume there
+                  is something out there clobbering %ebp and %edi, too. */
+               asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0"
                    : "=d" (err), "+b" (next), "=a" (id), "+c" (size),
-                     "=m" (*desc)
-                   : "D" (desc), "d" (SMAP), "a" (0xe820));
+                     "=D" (edi), "+m" (buf)
+                   : "D" (&buf), "d" (SMAP), "a" (0xe820)
+                   : "esi");
 
                /* BIOSes which terminate the chain with CF = 1 as opposed
                   to %ebx = 0 don't always report the SMAP signature on
@@ -51,8 +66,14 @@ static int detect_memory_e820(void)
                        break;
                }
 
+               /* ACPI 3.0 added the extended flags support.  If bit 0
+                  in the extended flags is zero, we're supposed to simply
+                  ignore the entry -- a backwards incompatible change! */
+               if (size > 20 && !(buf.ext_flags & 1))
+                       continue;
+
+               *desc++ = buf.std;
                count++;
-               desc++;
        } while (next && count < ARRAY_SIZE(boot_params.e820_map));
 
        return boot_params.e820_entries = count;
index db0c803170ab9e925dbfe2a22c17d0be23824d6e..a505202086e8741a916e696ccfb664d3f3e0f8ef 100644 (file)
@@ -828,4 +828,6 @@ ia32_sys_call_table:
        .quad sys_dup3                  /* 330 */
        .quad sys_pipe2
        .quad sys_inotify_init1
+       .quad compat_sys_preadv
+       .quad compat_sys_pwritev
 ia32_syscall_end:
index 43894428c3c2a7d871bd5d49bcc0b2e136405e13..0f4ee7148afe2e0b7648ab8f89a544508bdf3309 100644 (file)
 
 #ifndef __ASSEMBLY__
 #include <asm/hw_irq.h>
+#include <asm/kvm_para.h>
 
 /*G:031 But first, how does our Guest contact the Host to ask for privileged
  * operations?  There are two ways: the direct way is to make a "hypercall",
  * to make requests of the Host Itself.
  *
- * Our hypercall mechanism uses the highest unused trap code (traps 32 and
- * above are used by real hardware interrupts).  Fifteen hypercalls are
+ * We use the KVM hypercall mechanism. Eighteen hypercalls are
  * available: the hypercall number is put in the %eax register, and the
- * arguments (when required) are placed in %edx, %ebx and %ecx.  If a return
+ * arguments (when required) are placed in %ebx, %ecx and %edx.  If a return
  * value makes sense, it's returned in %eax.
  *
  * Grossly invalid calls result in Sudden Death at the hands of the vengeful
  * Host, rather than returning failure.  This reflects Winston Churchill's
  * definition of a gentleman: "someone who is only rude intentionally". */
-static inline unsigned long
-hcall(unsigned long call,
-      unsigned long arg1, unsigned long arg2, unsigned long arg3)
-{
-       /* "int" is the Intel instruction to trigger a trap. */
-       asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
-                    /* The call in %eax (aka "a") might be overwritten */
-                    : "=a"(call)
-                      /* The arguments are in %eax, %edx, %ebx & %ecx */
-                    : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3)
-                      /* "memory" means this might write somewhere in memory.
-                       * This isn't true for all calls, but it's safe to tell
-                       * gcc that it might happen so it doesn't get clever. */
-                    : "memory");
-       return call;
-}
 /*:*/
 
 /* Can't use our min() macro here: needs to be a constant */
@@ -64,7 +48,7 @@ hcall(unsigned long call,
 #define LHCALL_RING_SIZE 64
 struct hcall_args {
        /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */
-       unsigned long arg0, arg2, arg3, arg1;
+       unsigned long arg0, arg1, arg2, arg3;
 };
 
 #endif /* !__ASSEMBLY__ */
index a977de23cb4d83320e5255de21ffc073a0859403..a0301bfeb954d457eaf080a14ee0f2a872ccc519 100644 (file)
@@ -86,6 +86,9 @@ static inline void early_quirks(void) { }
 
 extern void pci_iommu_alloc(void);
 
+/* MSI arch hook */
+#define arch_setup_msi_irqs arch_setup_msi_irqs
+
 #endif  /* __KERNEL__ */
 
 #ifdef CONFIG_X86_32
index 3a569665668020755ac910307ee21114f7f7a7ca..e5e6caffec87ab61063cd8c356ebd8f59523b00b 100644 (file)
@@ -295,6 +295,9 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
                     : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory");
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index a5074bd0f8be5a268888237d14668b5ea9eb4ab4..48dcfa62ea07eb5985ef61c526ed767da3795283 100644 (file)
@@ -24,28 +24,4 @@ struct saved_context {
        unsigned long return_address;
 } __attribute__((packed));
 
-#ifdef CONFIG_ACPI
-extern unsigned long saved_eip;
-extern unsigned long saved_esp;
-extern unsigned long saved_ebp;
-extern unsigned long saved_ebx;
-extern unsigned long saved_esi;
-extern unsigned long saved_edi;
-
-static inline void acpi_save_register_state(unsigned long return_point)
-{
-       saved_eip = return_point;
-       asm volatile("movl %%esp,%0" : "=m" (saved_esp));
-       asm volatile("movl %%ebp,%0" : "=m" (saved_ebp));
-       asm volatile("movl %%ebx,%0" : "=m" (saved_ebx));
-       asm volatile("movl %%edi,%0" : "=m" (saved_edi));
-       asm volatile("movl %%esi,%0" : "=m" (saved_esi));
-}
-
-#define acpi_restore_register_state()  do {} while (0)
-
-/* routines for saving/restoring kernel state */
-extern int acpi_save_state_mem(void);
-#endif
-
 #endif /* _ASM_X86_SUSPEND_32_H */
index 77cfb2cfb386d5b1a1727807b2a7c84ee8fc4c6c..744299c0b7749829a2af79dc76eb10f0fbfa6a55 100644 (file)
@@ -217,10 +217,6 @@ static inline cpumask_t node_to_cpumask(int node)
 {
        return cpu_online_map;
 }
-static inline int node_to_first_cpu(int node)
-{
-       return first_cpu(cpu_online_map);
-}
 
 static inline void setup_node_to_cpumask_map(void) { }
 
@@ -237,14 +233,6 @@ static inline void setup_node_to_cpumask_map(void) { }
 
 #include <asm-generic/topology.h>
 
-#ifdef CONFIG_NUMA
-/* Returns the number of the first CPU on Node 'node'. */
-static inline int node_to_first_cpu(int node)
-{
-       return cpumask_first(cpumask_of_node(node));
-}
-#endif
-
 extern cpumask_t cpu_coregroup_map(int cpu);
 extern const struct cpumask *cpu_coregroup_mask(int cpu);
 
index f2bba78430a4d2628ca83203e193dcb6ee78a247..6e72d74cf8dc74b7720f5cb79ba355a926e7fa6e 100644 (file)
 #define __NR_dup3              330
 #define __NR_pipe2             331
 #define __NR_inotify_init1     332
+#define __NR_preadv            333
+#define __NR_pwritev           334
 
 #ifdef __KERNEL__
 
index d2e415e6666f63d314270ef57a26dae73e3fac01..f81829462325f6328a6e6d9c3667da02e9f616d0 100644 (file)
@@ -653,6 +653,10 @@ __SYSCALL(__NR_dup3, sys_dup3)
 __SYSCALL(__NR_pipe2, sys_pipe2)
 #define __NR_inotify_init1                     294
 __SYSCALL(__NR_inotify_init1, sys_inotify_init1)
+#define __NR_preadv                            295
+__SYSCALL(__NR_preadv, sys_preadv)
+#define __NR_pwritev                           296
+__SYSCALL(__NR_pwritev, sys_pwritev)
 
 
 #ifndef __NO_STUBS
index 9f4dfba33b2899a17ee672c19a4891b09ac816dc..d3a98ea1062ef936c7825f1387a4d2f4b83c65b9 100644 (file)
 #ifndef _ASM_X86_UV_UV_HUB_H
 #define _ASM_X86_UV_UV_HUB_H
 
+#ifdef CONFIG_X86_64
 #include <linux/numa.h>
 #include <linux/percpu.h>
 #include <linux/timer.h>
 #include <asm/types.h>
 #include <asm/percpu.h>
+#include <asm/uv/uv_mmrs.h>
 
 
 /*
@@ -397,6 +399,7 @@ static inline void uv_set_scir_bits(unsigned char value)
                uv_write_local_mmr8(uv_hub_info->scir.offset, value);
        }
 }
+
 static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
 {
        if (uv_cpu_hub_info(cpu)->scir.state != value) {
@@ -405,4 +408,15 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
        }
 }
 
+static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
+{
+       unsigned long val;
+
+       val = (1UL << UVH_IPI_INT_SEND_SHFT) |
+                       ((apicid & 0x3f) << UVH_IPI_INT_APIC_ID_SHFT) |
+                       (vector << UVH_IPI_INT_VECTOR_SHFT);
+       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+}
+
+#endif /* CONFIG_X86_64 */
 #endif /* _ASM_X86_UV_UV_HUB_H */
index dd627793a23444d109fa966cda31bc43d14a83e2..db68ac8a5ac285207b4f274ede74622e8a7e23c6 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -242,6 +243,158 @@ union uvh_event_occurred0_u {
 #define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL
 #define UVH_EVENT_OCCURRED0_ALIAS_32 0x005f0
 
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
+
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
+
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR0_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR0_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR0_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr0_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr0_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL
+
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int0_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR1_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL
+
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0
+#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8
+#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT 11
+#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT 12
+#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT 13
+#define UVH_GR1_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT 15
+#define UVH_GR1_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT 16
+#define UVH_GR1_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT 32
+#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_gr1_tlb_int1_config_u {
+    unsigned long      v;
+    struct uvh_gr1_tlb_int1_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
 /* ========================================================================= */
 /*                               UVH_INT_CMPB                                */
 /* ========================================================================= */
index c5962fe3796fbabe71024e3892354e8297d23a5f..a97db99dad52fedd4bbcf6fe9d46bed8784f5e1f 100644 (file)
@@ -1928,6 +1928,12 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
        return paddr;
 }
 
+static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
+                                   unsigned long cap)
+{
+       return 0;
+}
+
 static struct iommu_ops amd_iommu_ops = {
        .domain_init = amd_iommu_domain_init,
        .domain_destroy = amd_iommu_domain_destroy,
@@ -1936,5 +1942,6 @@ static struct iommu_ops amd_iommu_ops = {
        .map = amd_iommu_map_range,
        .unmap = amd_iommu_unmap_range,
        .iova_to_phys = amd_iommu_iova_to_phys,
+       .domain_has_cap = amd_iommu_domain_has_cap,
 };
 
index da99ffcdfde62a006bcbcf84a496c4f4ea8de755..1bb5c6cee3ebb140e30e421c05615bf94b001936 100644 (file)
@@ -3468,6 +3468,10 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        struct intel_iommu *iommu = NULL;
        int index = 0;
 
+       /* x86 doesn't support multiple MSI yet */
+       if (type == PCI_CAP_ID_MSI && nvec > 1)
+               return 1;
+
        irq_want = nr_irqs_gsi;
        sub_handle = 0;
        list_for_each_entry(msidesc, &dev->msi_list, list) {
index 1bd6da1f8fadba5b0fd96c97355122629e9cc30d..1248318436e8903b7ac3527ee1bbe59203325d24 100644 (file)
@@ -118,17 +118,12 @@ static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 
 static void uv_send_IPI_one(int cpu, int vector)
 {
-       unsigned long val, apicid;
+       unsigned long apicid;
        int pnode;
 
        apicid = per_cpu(x86_cpu_to_apicid, cpu);
        pnode = uv_apicid_to_pnode(apicid);
-
-       val = (1UL << UVH_IPI_INT_SEND_SHFT) |
-             (apicid << UVH_IPI_INT_APIC_ID_SHFT) |
-             (vector << UVH_IPI_INT_VECTOR_SHFT);
-
-       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+       uv_hub_send_ipi(pnode, apicid, vector);
 }
 
 static void uv_send_IPI_mask(const struct cpumask *mask, int vector)
index 10033fe718e0ad574f57a4f54c9d67efb72cb23e..ac7783a6743230693540178af6c13e9bfa98a383 100644 (file)
@@ -1190,8 +1190,10 @@ static int suspend(int vetoable)
        struct apm_user *as;
 
        device_suspend(PMSG_SUSPEND);
-       local_irq_disable();
+
        device_power_down(PMSG_SUSPEND);
+
+       local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
 
        local_irq_enable();
@@ -1209,9 +1211,12 @@ static int suspend(int vetoable)
        if (err != APM_SUCCESS)
                apm_error("suspend", err);
        err = (err == APM_SUCCESS) ? 0 : -EIO;
+
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
        local_irq_enable();
+
+       device_power_up(PMSG_RESUME);
+
        device_resume(PMSG_RESUME);
        queue_event(APM_NORMAL_RESUME, NULL);
        spin_lock(&user_list_lock);
@@ -1228,8 +1233,9 @@ static void standby(void)
 {
        int err;
 
-       local_irq_disable();
        device_power_down(PMSG_SUSPEND);
+
+       local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
        local_irq_enable();
 
@@ -1239,8 +1245,9 @@ static void standby(void)
 
        local_irq_disable();
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
        local_irq_enable();
+
+       device_power_up(PMSG_RESUME);
 }
 
 static apm_event_t get_event(void)
index fbf2f33e3080c24c3b17db173fd023fcc66527ae..5a6aa1c1162f06492a27cee3ac754b16e7fa57e0 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/thread_info.h>
 #include <asm/bootparam.h>
 #include <asm/elf.h>
+#include <asm/suspend.h>
 
 #include <xen/interface/xen.h>
 
index 8793ab33e2c16406632513ecdc2febefe26c66a3..e72f062fb4b5fd841617a3e7f7c766e64bf4428f 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/thread_info.h>
 #include <asm/ia32.h>
 #include <asm/bootparam.h>
+#include <asm/suspend.h>
 
 #include <xen/interface/xen.h>
 
index 4c4214690dd10a4c32fc787e03bce6e7cba315d9..fb73a52913a4f883ca42010de302e3e909189fe7 100644 (file)
@@ -377,10 +377,6 @@ static const struct file_operations mtrr_fops = {
        .release = mtrr_close,
 };
 
-
-static struct proc_dir_entry *proc_root_mtrr;
-
-
 static int mtrr_seq_show(struct seq_file *seq, void *offset)
 {
        char factor;
@@ -423,11 +419,7 @@ static int __init mtrr_if_init(void)
            (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
                return -ENODEV;
 
-       proc_root_mtrr =
-               proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops);
-
-       if (proc_root_mtrr)
-               proc_root_mtrr->owner = THIS_MODULE;
+       proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops);
        return 0;
 }
 
index bc132610544829de0f38a12dd8461d73104b39a2..368b0a8836f902be69531754a72fb75e7b9a4e24 100644 (file)
@@ -50,7 +50,6 @@ static irqreturn_t math_error_irq(int cpl, void *dev_id)
  */
 static struct irqaction fpu_irq = {
        .handler = math_error_irq,
-       .mask = CPU_MASK_NONE,
        .name = "fpu",
 };
 
@@ -83,7 +82,6 @@ void __init init_ISA_irqs(void)
  */
 static struct irqaction irq2 = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 
index c7a49e0ffbfbc0b4b2b0cd12b01d5294ca73745c..8cd10537fd46f7480b6db9807db276ada5b390af 100644 (file)
@@ -45,7 +45,6 @@
 
 static struct irqaction irq2 = {
        .handler = no_action,
-       .mask = CPU_MASK_NONE,
        .name = "cascade",
 };
 DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
index 8815f3c7fec75e5d4a4d1cb17609ef0eed004515..846510b78a092324bfa7adc61ee72ee25e8792cc 100644 (file)
@@ -348,7 +348,6 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
 static struct irqaction mfgptirq  = {
        .handler = mfgpt_tick,
        .flags = IRQF_DISABLED | IRQF_NOBALANCING,
-       .mask = CPU_MASK_NONE,
        .name = "mfgpt-timer"
 };
 
index c7c4776ff630238a2f8989c865cd0d2ac69f2ef8..90f5b9ef5defbd44c6bb2d0ad0489bdafb1cca08 100644 (file)
@@ -300,8 +300,7 @@ fs_initcall(pci_iommu_init);
 static __devinit void via_no_dac(struct pci_dev *dev)
 {
        if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
-               printk(KERN_INFO
-                       "PCI: VIA PCI bridge detected. Disabling DAC.\n");
+               dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n");
                forbid_dac = 1;
        }
 }
index 14014d766cadba461c27705a0626560dc308bb70..76f8f84043a2a4693123648d92d08c22ca7f5f25 100644 (file)
@@ -245,7 +245,7 @@ void prepare_to_copy(struct task_struct *tsk)
        unlazy_fpu(tsk);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
        unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
 {
index abb7e6a7f0c62c813de2331349c5aa4a348d14b1..b751a41392b1b997d3c9a3235ba85b2372bdf7a3 100644 (file)
@@ -278,7 +278,7 @@ void prepare_to_copy(struct task_struct *tsk)
        unlazy_fpu(tsk);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
 {
index 19378715f4157b5202d823f9d751dd1f07c08b38..b7cc21bc6ae0e43b1a3f2fb406a60cd4d005a246 100644 (file)
@@ -1455,6 +1455,6 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
         * system call instruction.
         */
        if (test_thread_flag(TIF_SINGLESTEP) &&
-           tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
+           tracehook_consider_fatal_signal(current, SIGTRAP))
                send_sigtrap(current, regs, 0, TRAP_BRKPT);
 }
index a0d26237d7cf141462a2d20941f8bd99d4195e57..b4158439bf634d254852cceab2c30d26f943f7ea 100644 (file)
@@ -1049,7 +1049,6 @@ void __init x86_quirk_trap_init(void)
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
        .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
-       .mask = CPU_MASK_NONE,
        .name = "timer"
 };
 
index 3bdb64829b82718f42bafed884f55d1dbe9e65a2..ff5c8736b491b8ff2c4835c5a19a51ad63633de1 100644 (file)
@@ -332,3 +332,5 @@ ENTRY(sys_call_table)
        .long sys_dup3                  /* 330 */
        .long sys_pipe2
        .long sys_inotify_init1
+       .long sys_preadv
+       .long sys_pwritev
index 241ec3923f611bf03cb266362409924daabf1f6f..5ba343e6184449775c51f21717ef985f8d7249d0 100644 (file)
@@ -116,7 +116,6 @@ unsigned long __init calibrate_cpu(void)
 static struct irqaction irq0 = {
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING | IRQF_TIMER,
-       .mask           = CPU_MASK_NONE,
        .name           = "timer"
 };
 
@@ -125,7 +124,6 @@ void __init hpet_time_init(void)
        if (!hpet_enable())
                setup_pit_timer();
 
-       irq0.mask = cpumask_of_cpu(0);
        setup_irq(0, &irq0);
 }
 
index 33a788d5879c3186182201736330723fa3669164..d303369a7baddc48966443fff136f2266f010810 100644 (file)
@@ -202,7 +202,6 @@ static struct irqaction vmi_clock_action  = {
        .name           = "vmi-timer",
        .handler        = vmi_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
-       .mask           = CPU_MASK_ALL,
 };
 
 static void __devinit vmi_time_init_clockevent(void)
index 90e44a10e68a6b5eb252655490be4b1e6c6d4941..e94a11e42f9864a35e197d9fdf7919accc8ba095 100644 (file)
@@ -107,7 +107,7 @@ static void async_hcall(unsigned long call, unsigned long arg1,
        local_irq_save(flags);
        if (lguest_data.hcall_status[next_call] != 0xFF) {
                /* Table full, so do normal hcall which will flush table. */
-               hcall(call, arg1, arg2, arg3);
+               kvm_hypercall3(call, arg1, arg2, arg3);
        } else {
                lguest_data.hcalls[next_call].arg0 = call;
                lguest_data.hcalls[next_call].arg1 = arg1;
@@ -134,13 +134,32 @@ static void async_hcall(unsigned long call, unsigned long arg1,
  *
  * So, when we're in lazy mode, we call async_hcall() to store the call for
  * future processing: */
-static void lazy_hcall(unsigned long call,
+static void lazy_hcall1(unsigned long call,
+                      unsigned long arg1)
+{
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
+               kvm_hypercall1(call, arg1);
+       else
+               async_hcall(call, arg1, 0, 0);
+}
+
+static void lazy_hcall2(unsigned long call,
+                      unsigned long arg1,
+                      unsigned long arg2)
+{
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
+               kvm_hypercall2(call, arg1, arg2);
+       else
+               async_hcall(call, arg1, arg2, 0);
+}
+
+static void lazy_hcall3(unsigned long call,
                       unsigned long arg1,
                       unsigned long arg2,
                       unsigned long arg3)
 {
        if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
-               hcall(call, arg1, arg2, arg3);
+               kvm_hypercall3(call, arg1, arg2, arg3);
        else
                async_hcall(call, arg1, arg2, arg3);
 }
@@ -150,7 +169,7 @@ static void lazy_hcall(unsigned long call,
 static void lguest_leave_lazy_mode(void)
 {
        paravirt_leave_lazy(paravirt_get_lazy_mode());
-       hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+       kvm_hypercall0(LHCALL_FLUSH_ASYNC);
 }
 
 /*G:033
@@ -229,7 +248,7 @@ static void lguest_write_idt_entry(gate_desc *dt,
        /* Keep the local copy up to date. */
        native_write_idt_entry(dt, entrynum, g);
        /* Tell Host about this new entry. */
-       hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]);
+       kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]);
 }
 
 /* Changing to a different IDT is very rare: we keep the IDT up-to-date every
@@ -241,7 +260,7 @@ static void lguest_load_idt(const struct desc_ptr *desc)
        struct desc_struct *idt = (void *)desc->address;
 
        for (i = 0; i < (desc->size+1)/8; i++)
-               hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
+               kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
 }
 
 /*
@@ -261,8 +280,8 @@ static void lguest_load_idt(const struct desc_ptr *desc)
  */
 static void lguest_load_gdt(const struct desc_ptr *desc)
 {
-       BUG_ON((desc->size+1)/8 != GDT_ENTRIES);
-       hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0);
+       BUG_ON((desc->size + 1) / 8 != GDT_ENTRIES);
+       kvm_hypercall2(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES);
 }
 
 /* For a single GDT entry which changes, we do the lazy thing: alter our GDT,
@@ -272,7 +291,7 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum,
                                   const void *desc, int type)
 {
        native_write_gdt_entry(dt, entrynum, desc, type);
-       hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0);
+       kvm_hypercall2(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES);
 }
 
 /* OK, I lied.  There are three "thread local storage" GDT entries which change
@@ -284,7 +303,7 @@ static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
         * can't handle us removing entries we're currently using.  So we clear
         * the GS register here: if it's needed it'll be reloaded anyway. */
        lazy_load_gs(0);
-       lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0);
+       lazy_hcall2(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu);
 }
 
 /*G:038 That's enough excitement for now, back to ploughing through each of
@@ -382,7 +401,7 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
 static unsigned long current_cr0;
 static void lguest_write_cr0(unsigned long val)
 {
-       lazy_hcall(LHCALL_TS, val & X86_CR0_TS, 0, 0);
+       lazy_hcall1(LHCALL_TS, val & X86_CR0_TS);
        current_cr0 = val;
 }
 
@@ -396,7 +415,7 @@ static unsigned long lguest_read_cr0(void)
  * the vowels have been optimized out. */
 static void lguest_clts(void)
 {
-       lazy_hcall(LHCALL_TS, 0, 0, 0);
+       lazy_hcall1(LHCALL_TS, 0);
        current_cr0 &= ~X86_CR0_TS;
 }
 
@@ -418,7 +437,7 @@ static bool cr3_changed = false;
 static void lguest_write_cr3(unsigned long cr3)
 {
        lguest_data.pgdir = cr3;
-       lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0);
+       lazy_hcall1(LHCALL_NEW_PGTABLE, cr3);
        cr3_changed = true;
 }
 
@@ -490,11 +509,17 @@ static void lguest_write_cr4(unsigned long val)
  * into a process' address space.  We set the entry then tell the Host the
  * toplevel and address this corresponds to.  The Guest uses one pagetable per
  * process, so we need to tell the Host which one we're changing (mm->pgd). */
+static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
+                              pte_t *ptep)
+{
+       lazy_hcall3(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low);
+}
+
 static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pteval)
 {
        *ptep = pteval;
-       lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low);
+       lguest_pte_update(mm, addr, ptep);
 }
 
 /* The Guest calls this to set a top-level entry.  Again, we set the entry then
@@ -503,8 +528,8 @@ static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
 static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
        *pmdp = pmdval;
-       lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
-                  (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+       lazy_hcall2(LHCALL_SET_PMD, __pa(pmdp) & PAGE_MASK,
+                  (__pa(pmdp) & (PAGE_SIZE - 1)) / 4);
 }
 
 /* There are a couple of legacy places where the kernel sets a PTE, but we
@@ -520,7 +545,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval)
 {
        *ptep = pteval;
        if (cr3_changed)
-               lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+               lazy_hcall1(LHCALL_FLUSH_TLB, 1);
 }
 
 /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on
@@ -536,7 +561,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval)
 static void lguest_flush_tlb_single(unsigned long addr)
 {
        /* Simply set it to zero: if it was not, it will fault back in. */
-       lazy_hcall(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0);
+       lazy_hcall3(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0);
 }
 
 /* This is what happens after the Guest has removed a large number of entries.
@@ -544,7 +569,7 @@ static void lguest_flush_tlb_single(unsigned long addr)
  * have changed, ie. virtual addresses below PAGE_OFFSET. */
 static void lguest_flush_tlb_user(void)
 {
-       lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0);
+       lazy_hcall1(LHCALL_FLUSH_TLB, 0);
 }
 
 /* This is called when the kernel page tables have changed.  That's not very
@@ -552,7 +577,7 @@ static void lguest_flush_tlb_user(void)
  * slow), so it's worth separating this from the user flushing above. */
 static void lguest_flush_tlb_kernel(void)
 {
-       lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+       lazy_hcall1(LHCALL_FLUSH_TLB, 1);
 }
 
 /*
@@ -689,7 +714,7 @@ static int lguest_clockevent_set_next_event(unsigned long delta,
        }
 
        /* Please wake us this far in the future. */
-       hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
+       kvm_hypercall1(LHCALL_SET_CLOCKEVENT, delta);
        return 0;
 }
 
@@ -700,7 +725,7 @@ static void lguest_clockevent_set_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
                /* A 0 argument shuts the clock down. */
-               hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
+               kvm_hypercall0(LHCALL_SET_CLOCKEVENT);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                /* This is what we expect. */
@@ -775,8 +800,8 @@ static void lguest_time_init(void)
 static void lguest_load_sp0(struct tss_struct *tss,
                            struct thread_struct *thread)
 {
-       lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->sp0,
-                  THREAD_SIZE/PAGE_SIZE);
+       lazy_hcall3(LHCALL_SET_STACK, __KERNEL_DS | 0x1, thread->sp0,
+                  THREAD_SIZE / PAGE_SIZE);
 }
 
 /* Let's just say, I wouldn't do debugging under a Guest. */
@@ -849,7 +874,7 @@ static void set_lguest_basic_apic_ops(void)
 /* STOP!  Until an interrupt comes in. */
 static void lguest_safe_halt(void)
 {
-       hcall(LHCALL_HALT, 0, 0, 0);
+       kvm_hypercall0(LHCALL_HALT);
 }
 
 /* The SHUTDOWN hypercall takes a string to describe what's happening, and
@@ -859,7 +884,8 @@ static void lguest_safe_halt(void)
  * rather than virtual addresses, so we use __pa() here. */
 static void lguest_power_off(void)
 {
-       hcall(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF, 0);
+       kvm_hypercall2(LHCALL_SHUTDOWN, __pa("Power down"),
+                                       LGUEST_SHUTDOWN_POWEROFF);
 }
 
 /*
@@ -869,7 +895,7 @@ static void lguest_power_off(void)
  */
 static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
 {
-       hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0);
+       kvm_hypercall2(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF);
        /* The hcall won't return, but to keep gcc happy, we're "done". */
        return NOTIFY_DONE;
 }
@@ -910,7 +936,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
                len = sizeof(scratch) - 1;
        scratch[len] = '\0';
        memcpy(scratch, buf, len);
-       hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0);
+       kvm_hypercall1(LHCALL_NOTIFY, __pa(scratch));
 
        /* This routine returns the number of bytes actually written. */
        return len;
@@ -920,7 +946,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
  * Launcher to reboot us. */
 static void lguest_restart(char *reason)
 {
-       hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0);
+       kvm_hypercall2(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART);
 }
 
 /*G:050
@@ -1040,6 +1066,8 @@ __init void lguest_init(void)
        pv_mmu_ops.read_cr3 = lguest_read_cr3;
        pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu;
        pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mode;
+       pv_mmu_ops.pte_update = lguest_pte_update;
+       pv_mmu_ops.pte_update_defer = lguest_pte_update;
 
 #ifdef CONFIG_X86_LOCAL_APIC
        /* apic read/write intercepts */
index 10b9bd35a8ff9fbfb233883f23b970264eeb34d9..f795419894718796d48050f80a6b279a6a875dff 100644 (file)
@@ -27,8 +27,8 @@ ENTRY(lguest_entry)
        /* We make the "initialization" hypercall now to tell the Host about
         * us, and also find out where it put our page tables. */
        movl $LHCALL_LGUEST_INIT, %eax
-       movl $lguest_data - __PAGE_OFFSET, %edx
-       int $LGUEST_TRAP_ENTRY
+       movl $lguest_data - __PAGE_OFFSET, %ebx
+       .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
 
        /* Set up the initial stack so we can run C code. */
        movl $(init_thread_union+THREAD_SIZE),%esp
index 522db5e3d0bf973e54ca71e33201454c4aadefda..8126e8d1a2a4a789509cb49af563b6cbb76395ae 100644 (file)
@@ -19,49 +19,6 @@ void kunmap(struct page *page)
        kunmap_high(page);
 }
 
-static void debug_kmap_atomic_prot(enum km_type type)
-{
-#ifdef CONFIG_DEBUG_HIGHMEM
-       static unsigned warn_count = 10;
-
-       if (unlikely(warn_count == 0))
-               return;
-
-       if (unlikely(in_interrupt())) {
-               if (in_irq()) {
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_BIO_SRC_IRQ && type != KM_BIO_DST_IRQ &&
-                           type != KM_BOUNCE_READ) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               } else if (!irqs_disabled()) {  /* softirq */
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
-                           type != KM_SKB_SUNRPC_DATA &&
-                           type != KM_SKB_DATA_SOFTIRQ &&
-                           type != KM_BOUNCE_READ) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               }
-       }
-
-       if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
-                       type == KM_BIO_SRC_IRQ || type == KM_BIO_DST_IRQ) {
-               if (!irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
-               if (irq_count() == 0 && !irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       }
-#endif
-}
-
 /*
  * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
  * no global lock is needed and because the kmap code must perform a global TLB
@@ -81,7 +38,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic_prot(type);
+       debug_kmap_atomic(type);
 
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
index 699c9b2895ae8cc1225d14dd15eac4fe68384151..e331f77348a787608c0c6cfe82bd022d81eb42aa 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/iomap.h>
 #include <asm/pat.h>
 #include <linux/module.h>
+#include <linux/highmem.h>
 
 int is_io_mapping_possible(resource_size_t base, unsigned long size)
 {
@@ -38,6 +39,7 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
 
        pagefault_disable();
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR * smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        set_pte(kmap_pte - idx, pfn_pte(pfn, prot));
index f6adf2c6d7514148eb7e6221dea010f55158f97d..aaf26ae58cd5cadb73ae168cd7f46edf9cc2b4f3 100644 (file)
@@ -69,11 +69,12 @@ void early_dump_pci_device(u8 bus, u8 slot, u8 func)
        int j;
        u32 val;
 
-       printk(KERN_INFO "PCI: %02x:%02x:%02x", bus, slot, func);
+       printk(KERN_INFO "pci 0000:%02x:%02x.%d config space:",
+              bus, slot, func);
 
        for (i = 0; i < 256; i += 4) {
                if (!(i & 0x0f))
-                       printk("\n%04x:",i);
+                       printk("\n  %02x:",i);
 
                val = read_pci_config(bus, slot, func, i);
                for (j = 0; j < 4; j++) {
@@ -96,20 +97,22 @@ void early_dump_pci_devices(void)
                        for (func = 0; func < 8; func++) {
                                u32 class;
                                u8 type;
+
                                class = read_pci_config(bus, slot, func,
                                                        PCI_CLASS_REVISION);
                                if (class == 0xffffffff)
-                                       break;
+                                       continue;
 
                                early_dump_pci_device(bus, slot, func);
 
-                               /* No multi-function device? */
-                               type = read_pci_config_byte(bus, slot, func,
+                               if (func == 0) {
+                                       type = read_pci_config_byte(bus, slot,
+                                                                   func,
                                                               PCI_HEADER_TYPE);
-                               if (!(type & 0x80))
-                                       break;
+                                       if (!(type & 0x80))
+                                               break;
+                               }
                        }
                }
        }
 }
-
index 9c49919e4d1c08d6d098aa34feb8cd46fb97e623..6dd89555fbfa9bdddd8f797f6fe48231ef773be9 100644 (file)
@@ -494,26 +494,6 @@ static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015,
                          pci_siemens_interrupt_controller);
 
-/*
- * Regular PCI devices have 256 bytes, but AMD Family 10h/11h CPUs have
- * 4096 bytes configuration space for each function of their processor
- * configuration space.
- */
-static void amd_cpu_pci_cfg_space_size(struct pci_dev *dev)
-{
-       dev->cfg_size = pci_cfg_space_size_ext(dev);
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1300, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1301, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1302, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1303, amd_cpu_pci_cfg_space_size);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1304, amd_cpu_pci_cfg_space_size);
-
 /*
  * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from
  * confusing the PCI engine:
index f234a37bd428c73aa0e8623079bfbe5e06923948..f1817f71e009a274bab8b4ed4fe9f0a3baadd75e 100644 (file)
@@ -258,24 +258,7 @@ void pcibios_set_master(struct pci_dev *dev)
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
 
-static void pci_unmap_page_range(struct vm_area_struct *vma)
-{
-       u64 addr = (u64)vma->vm_pgoff << PAGE_SHIFT;
-       free_memtype(addr, addr + vma->vm_end - vma->vm_start);
-}
-
-static void pci_track_mmap_page_range(struct vm_area_struct *vma)
-{
-       u64 addr = (u64)vma->vm_pgoff << PAGE_SHIFT;
-       unsigned long flags = pgprot_val(vma->vm_page_prot)
-                                               & _PAGE_CACHE_MASK;
-
-       reserve_memtype(addr, addr + vma->vm_end - vma->vm_start, flags, NULL);
-}
-
 static struct vm_operations_struct pci_mmap_ops = {
-       .open  = pci_track_mmap_page_range,
-       .close = pci_unmap_page_range,
        .access = generic_access_phys,
 };
 
@@ -283,11 +266,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
        unsigned long prot;
-       u64 addr = vma->vm_pgoff << PAGE_SHIFT;
-       unsigned long len = vma->vm_end - vma->vm_start;
-       unsigned long flags;
-       unsigned long new_flags;
-       int retval;
 
        /* I/O space cannot be accessed via normal processor loads and
         * stores on this platform.
@@ -308,30 +286,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
        vma->vm_page_prot = __pgprot(prot);
 
-       flags = pgprot_val(vma->vm_page_prot) & _PAGE_CACHE_MASK;
-       retval = reserve_memtype(addr, addr + len, flags, &new_flags);
-       if (retval)
-               return retval;
-
-       if (flags != new_flags) {
-               if (!is_new_memtype_allowed(flags, new_flags)) {
-                       free_memtype(addr, addr+len);
-                       return -EINVAL;
-               }
-               flags = new_flags;
-               vma->vm_page_prot = __pgprot(
-                       (pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK) |
-                       flags);
-       }
-
-       if (((vma->vm_pgoff < max_low_pfn_mapped) ||
-            (vma->vm_pgoff >= (1UL<<(32 - PAGE_SHIFT)) &&
-             vma->vm_pgoff < max_pfn_mapped)) &&
-           ioremap_change_attr((unsigned long)__va(addr), len, flags)) {
-               free_memtype(addr, addr + len);
-               return -EINVAL;
-       }
-
        if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                               vma->vm_end - vma->vm_start,
                               vma->vm_page_prot))
index f1065b129e9cf981fa52c374dcf3bf2c4987fe36..4061bb0f267de399ef8d05720a8c735712be8299 100644 (file)
@@ -50,8 +50,6 @@ static int __init pci_legacy_init(void)
        if (pci_root_bus)
                pci_bus_add_devices(pci_root_bus);
 
-       pcibios_fixup_peer_bridges();
-
        return 0;
 }
 
@@ -67,6 +65,7 @@ int __init pci_subsys_init(void)
        pci_visws_init();
 #endif
        pci_legacy_init();
+       pcibios_fixup_peer_bridges();
        pcibios_irq_init();
        pcibios_init();
 
index 89bf9242c80a3b068fa2c1fcf3f6cba4b447193d..905bb526b13350e88e258c69162240f5e99fbee3 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
+#include <linux/sort.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static int __initdata pci_mmcfg_resources_inserted;
 
+static __init int extend_mmcfg(int num)
+{
+       struct acpi_mcfg_allocation *new;
+       int new_num = pci_mmcfg_config_num + num;
+
+       new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL);
+       if (!new)
+               return -1;
+
+       if (pci_mmcfg_config) {
+               memcpy(new, pci_mmcfg_config,
+                        sizeof(pci_mmcfg_config[0]) * new_num);
+               kfree(pci_mmcfg_config);
+       }
+       pci_mmcfg_config = new;
+
+       return 0;
+}
+
+static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end)
+{
+       int i = pci_mmcfg_config_num;
+
+       pci_mmcfg_config_num++;
+       pci_mmcfg_config[i].address = addr;
+       pci_mmcfg_config[i].pci_segment = segment;
+       pci_mmcfg_config[i].start_bus_number = start;
+       pci_mmcfg_config[i].end_bus_number = end;
+}
+
 static const char __init *pci_mmcfg_e7520(void)
 {
        u32 win;
        raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
 
        win = win & 0xf000;
-       if(win == 0x0000 || win == 0xf000)
-               pci_mmcfg_config_num = 0;
-       else {
-               pci_mmcfg_config_num = 1;
-               pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
-               if (!pci_mmcfg_config)
-                       return NULL;
-               pci_mmcfg_config[0].address = win << 16;
-               pci_mmcfg_config[0].pci_segment = 0;
-               pci_mmcfg_config[0].start_bus_number = 0;
-               pci_mmcfg_config[0].end_bus_number = 255;
-       }
+       if (win == 0x0000 || win == 0xf000)
+               return NULL;
+
+       if (extend_mmcfg(1) == -1)
+               return NULL;
+
+       fill_one_mmcfg(win << 16, 0, 0, 255);
 
        return "Intel Corporation E7520 Memory Controller Hub";
 }
@@ -50,13 +76,11 @@ static const char __init *pci_mmcfg_intel_945(void)
 {
        u32 pciexbar, mask = 0, len = 0;
 
-       pci_mmcfg_config_num = 1;
-
        raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
 
        /* Enable bit */
        if (!(pciexbar & 1))
-               pci_mmcfg_config_num = 0;
+               return NULL;
 
        /* Size bits */
        switch ((pciexbar >> 1) & 3) {
@@ -73,28 +97,23 @@ static const char __init *pci_mmcfg_intel_945(void)
                len  = 0x04000000U;
                break;
        default:
-               pci_mmcfg_config_num = 0;
+               return NULL;
        }
 
        /* Errata #2, things break when not aligned on a 256Mb boundary */
        /* Can only happen in 64M/128M mode */
 
        if ((pciexbar & mask) & 0x0fffffffU)
-               pci_mmcfg_config_num = 0;
+               return NULL;
 
        /* Don't hit the APIC registers and their friends */
        if ((pciexbar & mask) >= 0xf0000000U)
-               pci_mmcfg_config_num = 0;
-
-       if (pci_mmcfg_config_num) {
-               pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
-               if (!pci_mmcfg_config)
-                       return NULL;
-               pci_mmcfg_config[0].address = pciexbar & mask;
-               pci_mmcfg_config[0].pci_segment = 0;
-               pci_mmcfg_config[0].start_bus_number = 0;
-               pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
-       }
+               return NULL;
+
+       if (extend_mmcfg(1) == -1)
+               return NULL;
+
+       fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1);
 
        return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
 }
@@ -138,22 +157,77 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
                busnbits = 8;
        }
 
-       pci_mmcfg_config_num = (1 << segnbits);
-       pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) *
-                                  pci_mmcfg_config_num, GFP_KERNEL);
-       if (!pci_mmcfg_config)
+       if (extend_mmcfg(1 << segnbits) == -1)
                return NULL;
 
-       for (i = 0; i < (1 << segnbits); i++) {
-               pci_mmcfg_config[i].address = base + (1<<28) * i;
-               pci_mmcfg_config[i].pci_segment = i;
-               pci_mmcfg_config[i].start_bus_number = 0;
-               pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
-       }
+       for (i = 0; i < (1 << segnbits); i++)
+               fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1);
 
        return "AMD Family 10h NB";
 }
 
+static bool __initdata mcp55_checked;
+static const char __init *pci_mmcfg_nvidia_mcp55(void)
+{
+       int bus;
+       int mcp55_mmconf_found = 0;
+
+       static const u32 extcfg_regnum          = 0x90;
+       static const u32 extcfg_regsize         = 4;
+       static const u32 extcfg_enable_mask     = 1<<31;
+       static const u32 extcfg_start_mask      = 0xff<<16;
+       static const int extcfg_start_shift     = 16;
+       static const u32 extcfg_size_mask       = 0x3<<28;
+       static const int extcfg_size_shift      = 28;
+       static const int extcfg_sizebus[]       = {0x100, 0x80, 0x40, 0x20};
+       static const u32 extcfg_base_mask[]     = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff};
+       static const int extcfg_base_lshift     = 25;
+
+       /*
+        * do check if amd fam10h already took over
+        */
+       if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
+               return NULL;
+
+       mcp55_checked = true;
+       for (bus = 0; bus < 256; bus++) {
+               u64 base;
+               u32 l, extcfg;
+               u16 vendor, device;
+               int start, size_index, end;
+
+               raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l);
+               vendor = l & 0xffff;
+               device = (l >> 16) & 0xffff;
+
+               if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
+                       continue;
+
+               raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum,
+                                 extcfg_regsize, &extcfg);
+
+               if (!(extcfg & extcfg_enable_mask))
+                       continue;
+
+               if (extend_mmcfg(1) == -1)
+                       continue;
+
+               size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
+               base = extcfg & extcfg_base_mask[size_index];
+               /* base could > 4G */
+               base <<= extcfg_base_lshift;
+               start = (extcfg & extcfg_start_mask) >> extcfg_start_shift;
+               end = start + extcfg_sizebus[size_index] - 1;
+               fill_one_mmcfg(base, 0, start, end);
+               mcp55_mmconf_found++;
+       }
+
+       if (!mcp55_mmconf_found)
+               return NULL;
+
+       return "nVidia MCP55";
+}
+
 struct pci_mmcfg_hostbridge_probe {
        u32 bus;
        u32 devfn;
@@ -171,8 +245,52 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
          0x1200, pci_mmcfg_amd_fam10h },
        { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
          0x1200, pci_mmcfg_amd_fam10h },
+       { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA,
+         0x0369, pci_mmcfg_nvidia_mcp55 },
 };
 
+static int __init cmp_mmcfg(const void *x1, const void *x2)
+{
+       const typeof(pci_mmcfg_config[0]) *m1 = x1;
+       const typeof(pci_mmcfg_config[0]) *m2 = x2;
+       int start1, start2;
+
+       start1 = m1->start_bus_number;
+       start2 = m2->start_bus_number;
+
+       return start1 - start2;
+}
+
+static void __init pci_mmcfg_check_end_bus_number(void)
+{
+       int i;
+       typeof(pci_mmcfg_config[0]) *cfg, *cfgx;
+
+       /* sort them at first */
+       sort(pci_mmcfg_config, pci_mmcfg_config_num,
+                sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL);
+
+       /* last one*/
+       if (pci_mmcfg_config_num > 0) {
+               i = pci_mmcfg_config_num - 1;
+               cfg = &pci_mmcfg_config[i];
+               if (cfg->end_bus_number < cfg->start_bus_number)
+                       cfg->end_bus_number = 255;
+       }
+
+       /* don't overlap please */
+       for (i = 0; i < pci_mmcfg_config_num - 1; i++) {
+               cfg = &pci_mmcfg_config[i];
+               cfgx = &pci_mmcfg_config[i+1];
+
+               if (cfg->end_bus_number < cfg->start_bus_number)
+                       cfg->end_bus_number = 255;
+
+               if (cfg->end_bus_number >= cfgx->start_bus_number)
+                       cfg->end_bus_number = cfgx->start_bus_number - 1;
+       }
+}
+
 static int __init pci_mmcfg_check_hostbridge(void)
 {
        u32 l;
@@ -186,31 +304,33 @@ static int __init pci_mmcfg_check_hostbridge(void)
 
        pci_mmcfg_config_num = 0;
        pci_mmcfg_config = NULL;
-       name = NULL;
 
-       for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
+       for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
                bus =  pci_mmcfg_probes[i].bus;
                devfn = pci_mmcfg_probes[i].devfn;
                raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
                vendor = l & 0xffff;
                device = (l >> 16) & 0xffff;
 
+               name = NULL;
                if (pci_mmcfg_probes[i].vendor == vendor &&
                    pci_mmcfg_probes[i].device == device)
                        name = pci_mmcfg_probes[i].probe();
-       }
 
-       if (name) {
-               printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
-                      name, pci_mmcfg_config_num ? "with" : "without");
+               if (name)
+                       printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n",
+                              name);
        }
 
-       return name != NULL;
+       /* some end_bus_number is crazy, fix it */
+       pci_mmcfg_check_end_bus_number();
+
+       return pci_mmcfg_config_num != 0;
 }
 
 static void __init pci_mmcfg_insert_resources(void)
 {
-#define PCI_MMCFG_RESOURCE_NAME_LEN 19
+#define PCI_MMCFG_RESOURCE_NAME_LEN 24
        int i;
        struct resource *res;
        char *names;
@@ -228,9 +348,10 @@ static void __init pci_mmcfg_insert_resources(void)
                struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
                num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
                res->name = names;
-               snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
-                        cfg->pci_segment);
-               res->start = cfg->address;
+               snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN,
+                        "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment,
+                        cfg->start_bus_number, cfg->end_bus_number);
+               res->start = cfg->address + (cfg->start_bus_number << 20);
                res->end = res->start + (num_buses << 20) - 1;
                res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                insert_resource(&iomem_resource, res);
@@ -354,8 +475,6 @@ static void __init pci_mmcfg_reject_broken(int early)
            (pci_mmcfg_config[0].address == 0))
                return;
 
-       cfg = &pci_mmcfg_config[0];
-
        for (i = 0; i < pci_mmcfg_config_num; i++) {
                int valid = 0;
                u64 addr, size;
@@ -423,10 +542,10 @@ static void __init __pci_mmcfg_init(int early)
                        known_bridge = 1;
        }
 
-       if (!known_bridge) {
+       if (!known_bridge)
                acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
-               pci_mmcfg_reject_broken(early);
-       }
+
+       pci_mmcfg_reject_broken(early);
 
        if ((pci_mmcfg_config_num == 0) ||
            (pci_mmcfg_config == NULL) ||
index 30007ffc8e11d203922d2c8304c5d0bdb909ef33..94349f8b2f964b969f7cc576ad92a50cfac75049 100644 (file)
@@ -112,13 +112,18 @@ static struct pci_raw_ops pci_mmcfg = {
 static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
 {
        void __iomem *addr;
-       u32 size;
-
-       size = (cfg->end_bus_number + 1) << 20;
-       addr = ioremap_nocache(cfg->address, size);
+       u64 start, size;
+
+       start = cfg->start_bus_number;
+       start <<= 20;
+       start += cfg->address;
+       size = cfg->end_bus_number + 1 - cfg->start_bus_number;
+       size <<= 20;
+       addr = ioremap_nocache(start, size);
        if (addr) {
                printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n",
-                      cfg->address, cfg->address + size - 1);
+                      start, start + size - 1);
+               addr -= cfg->start_bus_number << 20;
        }
        return addr;
 }
@@ -157,7 +162,7 @@ void __init pci_mmcfg_arch_free(void)
 
        for (i = 0; i < pci_mmcfg_config_num; ++i) {
                if (pci_mmcfg_virt[i].virt) {
-                       iounmap(pci_mmcfg_virt[i].virt);
+                       iounmap(pci_mmcfg_virt[i].virt + (pci_mmcfg_virt[i].cfg->start_bus_number << 20));
                        pci_mmcfg_virt[i].virt = NULL;
                        pci_mmcfg_virt[i].cfg = NULL;
                }
index 274d06082f4851bfcf71c621f7a62db447e54876..ce702c5b3a2c13fded43ab9629c6210352b3772a 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/mtrr.h>
 #include <asm/mce.h>
 #include <asm/xcr.h>
+#include <asm/suspend.h>
 
 static struct saved_context saved_context;
 
index e3b6cf70d62c504d42f757980ddf562a5cc1ac30..5343540f26074bac105a66790733e66723e1e615 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/pgtable.h>
 #include <asm/mtrr.h>
 #include <asm/xcr.h>
+#include <asm/suspend.h>
 
 static void fix_processor_context(void);
 
index 6dd000dd793394c398a8d02dd9254d6a68fd963b..65fdc86e923fd92175b95bfef56ad1c82d64bc2d 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mtrr.h>
+#include <asm/suspend.h>
 
 /* References to section boundaries */
 extern const void __nosave_begin, __nosave_end;
index 981200830432fde49cad084c1ecd0855c1cbab9f..fa6dc4dd3b193597aea23f0516014f5d1f5005db 100644 (file)
@@ -4,16 +4,13 @@
 mainmenu "Linux/Xtensa Kernel Configuration"
 
 config FRAME_POINTER
-       bool
-       default n
+       def_bool n
 
 config ZONE_DMA
-       bool
-       default y
+       def_bool y
 
 config XTENSA
-       bool
-       default y
+       def_bool y
        select HAVE_IDE
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
@@ -24,28 +21,25 @@ config XTENSA
          a home page at <http://xtensa.sourceforge.net/>.
 
 config RWSEM_XCHGADD_ALGORITHM
-       bool
-       default y
+       def_bool y
 
 config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
+       def_bool y
 
 config GENERIC_HWEIGHT
-       bool
-       default y
+       def_bool y
 
 config GENERIC_HARDIRQS
-       bool
-       default y
+       def_bool y
+
+config GENERIC_GPIO
+       def_bool y
 
 config ARCH_HAS_ILOG2_U32
-       bool
-       default n
+       def_bool n
 
 config ARCH_HAS_ILOG2_U64
-       bool
-       default n
+       def_bool n
 
 config NO_IOPORT
        def_bool y
@@ -54,9 +48,18 @@ config HZ
        int
        default 100
 
+config GENERIC_TIME
+       def_bool y
+
 source "init/Kconfig"
 source "kernel/Kconfig.freezer"
 
+config MMU
+       def_bool n
+
+config VARIANT_IRQ_SWITCH
+       def_bool n
+
 menu "Processor type and features"
 
 choice
@@ -65,38 +68,41 @@ choice
 
 config XTENSA_VARIANT_FSF
        bool "fsf - default (not generic) configuration"
+       select MMU
 
 config XTENSA_VARIANT_DC232B
        bool "dc232b - Diamond 232L Standard Core Rev.B (LE)"
+       select MMU
        help
-       This variant refers to Tensilica's Diamond 232L Standard core Rev.B (LE).
-endchoice
+         This variant refers to Tensilica's Diamond 232L Standard core Rev.B (LE).
 
-config MMU
-       bool
-       default y
+config XTENSA_VARIANT_S6000
+       bool "s6000 - Stretch software configurable processor"
+       select VARIANT_IRQ_SWITCH
+       select ARCH_REQUIRE_GPIOLIB
+endchoice
 
 config XTENSA_UNALIGNED_USER
        bool "Unaligned memory access in use space"
-       ---help---
-          The Xtensa architecture currently does not handle unaligned
-          memory accesses in hardware but through an exception handler.
-          Per default, unaligned memory accesses are disabled in user space.
+       help
+         The Xtensa architecture currently does not handle unaligned
+         memory accesses in hardware but through an exception handler.
+         Per default, unaligned memory accesses are disabled in user space.
 
-          Say Y here to enable unaligned memory access in user space.
+         Say Y here to enable unaligned memory access in user space.
 
 config PREEMPT
        bool "Preemptible Kernel"
-       ---help---
-           This option reduces the latency of the kernel when reacting to
-           real-time or interactive events by allowing a low priority process to
-           be preempted even if it is in kernel mode executing a system call.
-           Unfortunately the kernel code has some race conditions if both
-           CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is
-           currently disabled if you are building an SMP kernel.
+       help
+          This option reduces the latency of the kernel when reacting to
+          real-time or interactive events by allowing a low priority process to
+          be preempted even if it is in kernel mode executing a system call.
+          Unfortunately the kernel code has some race conditions if both
+          CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is
+          currently disabled if you are building an SMP kernel.
 
-           Say Y here if you are building a kernel for a desktop, embedded
-           or real-time system.  Say N if you are unsure.
+          Say Y here if you are building a kernel for a desktop, embedded
+          or real-time system.  Say N if you are unsure.
 
 config MATH_EMULATION
        bool "Math emulation"
@@ -105,6 +111,32 @@ config MATH_EMULATION
 
 endmenu
 
+config XTENSA_CALIBRATE_CCOUNT
+       def_bool n
+       help
+         On some platforms (XT2000, for example), the CPU clock rate can
+         vary.  The frequency can be determined, however, by measuring
+         against a well known, fixed frequency, such as an UART oscillator.
+
+config SERIAL_CONSOLE
+       def_bool n
+
+config XTENSA_ISS_NETWORK
+       def_bool n
+
+menu "Bus options"
+
+config PCI
+       bool "PCI support"
+       default y
+       help
+         Find out whether you have a PCI motherboard. PCI is the name of a
+         bus system, i.e. the way the CPU talks to the other stuff inside
+         your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+         VESA. If you have PCI, say Y, otherwise N.
+
+source "drivers/pci/Kconfig"
+
 menu "Platform options"
 
 choice
@@ -113,33 +145,35 @@ choice
 
 config XTENSA_PLATFORM_ISS
        bool "ISS"
+       select XTENSA_CALIBRATE_CCOUNT
+       select SERIAL_CONSOLE
+       select XTENSA_ISS_NETWORK
        help
          ISS is an acronym for Tensilica's Instruction Set Simulator.
 
 config XTENSA_PLATFORM_XT2000
        bool "XT2000"
+       select XTENSA_CALIBRATE_CCOUNT
+       select PCI
        help
          XT2000 is the name of Tensilica's feature-rich emulation platform.
          This hardware is capable of running a full Linux distribution.
 
-endchoice
+config XTENSA_PLATFORM_S6105
+       bool "S6105"
+       select SERIAL_CONSOLE
 
+endchoice
 
-config XTENSA_CALIBRATE_CCOUNT
-       bool "Auto calibration of the CPU clock rate"
-       ---help---
-         On some platforms (XT2000, for example), the CPU clock rate can
-         vary.  The frequency can be determined, however, by measuring
-         against a well known, fixed frequency, such as an UART oscillator.
 
 config XTENSA_CPU_CLOCK
        int "CPU clock rate [MHz]"
        depends on !XTENSA_CALIBRATE_CCOUNT
-       default "16"
+       default 16
 
 config GENERIC_CALIBRATE_DELAY
        bool "Auto calibration of the BogoMIPS value"
-       ---help---
+       help
          The BogoMIPS value can easily be derived from the CPU frequency.
 
 config CMDLINE_BOOL
@@ -156,52 +190,27 @@ config CMDLINE
          time by entering them here. As a minimum, you should specify the
          memory size and the root device (e.g., mem=64M root=/dev/nfs).
 
-config SERIAL_CONSOLE
-       bool
-       depends on XTENSA_PLATFORM_ISS
-       default y
-
-config XTENSA_ISS_NETWORK
-       bool
-       depends on XTENSA_PLATFORM_ISS
-       default y
-
 source "mm/Kconfig"
 
 endmenu
 
-menu "Bus options"
-
-config PCI
-       bool "PCI support" if !XTENSA_PLATFORM_ISS
-       depends on !XTENSA_PLATFORM_ISS
-       default y
+config HOTPLUG
+       bool "Support for hot-pluggable devices"
        help
-         Find out whether you have a PCI motherboard. PCI is the name of a
-         bus system, i.e. the way the CPU talks to the other stuff inside
-         your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-         VESA. If you have PCI, say Y, otherwise N.
+         Say Y here if you want to plug devices into your computer while
+         the system is running, and be able to use them quickly.  In many
+         cases, the devices can likewise be unplugged at any time too.
 
-source "drivers/pci/Kconfig"
+         One well known example of this is PCMCIA- or PC-cards, credit-card
+         size devices such as network cards, modems or hard drives which are
+         plugged into slots found on all modern laptop computers.  Another
+         example, used on modern desktops as well as laptops, is USB.
 
-config HOTPLUG
-
-       bool "Support for hot-pluggable devices"
-       ---help---
-       Say Y here if you want to plug devices into your computer while
-       the system is running, and be able to use them quickly.  In many
-       cases, the devices can likewise be unplugged at any time too.
-
-       One well known example of this is PCMCIA- or PC-cards, credit-card
-       size devices such as network cards, modems or hard drives which are
-       plugged into slots found on all modern laptop computers.  Another
-       example, used on modern desktops as well as laptops, is USB.
-
-       Enable HOTPLUG and build a modular kernel.  Get agent software
-       (from <http://linux-hotplug.sourceforge.net/>) and install it.
-       Then your kernel will automatically call out to a user mode "policy
-       agent" (/sbin/hotplug) to load modules and set up software needed
-       to use devices as you hotplug them.
+         Enable HOTPLUG and build a modular kernel.  Get agent software
+         (from <http://linux-hotplug.sourceforge.net/>) and install it.
+         Then your kernel will automatically call out to a user mode "policy
+         agent" (/sbin/hotplug) to load modules and set up software needed
+         to use devices as you hotplug them.
 
 source "drivers/pcmcia/Kconfig"
 
@@ -213,9 +222,8 @@ menu "Executable file formats"
 
 # only elf supported
 config KCORE_ELF
-        bool
+       def_bool y
         depends on PROC_FS
-        default y
         help
           If you enabled support for /proc file system then the file
           /proc/kcore will contain the kernel core image in ELF format. This
@@ -240,7 +248,7 @@ source "fs/Kconfig"
 menu "Xtensa initrd options"
        depends on BLK_DEV_INITRD
 
-       config EMBEDDED_RAMDISK
+config EMBEDDED_RAMDISK
        bool "Embed root filesystem ramdisk into the kernel"
 
 config EMBEDDED_RAMDISK_IMAGE
index 1da55fe4beff5062cd398fb13b8b25b7d0879410..4caffac3ca2e7d3805bb6d1b8fd11b53bdc544d0 100644 (file)
@@ -15,6 +15,7 @@
 
 variant-$(CONFIG_XTENSA_VARIANT_FSF)           := fsf
 variant-$(CONFIG_XTENSA_VARIANT_DC232B)                := dc232b
+variant-$(CONFIG_XTENSA_VARIANT_S6000)         := s6000
 variant-$(CONFIG_XTENSA_VARIANT_LINUX_CUSTOM)  := custom
 
 VARIANT = $(variant-y)
@@ -24,6 +25,7 @@ export VARIANT
 
 platform-$(CONFIG_XTENSA_PLATFORM_XT2000)      := xt2000
 platform-$(CONFIG_XTENSA_PLATFORM_ISS)         := iss
+platform-$(CONFIG_XTENSA_PLATFORM_S6105)       := s6105
 
 PLATFORM = $(platform-y)
 export PLATFORM
@@ -62,20 +64,23 @@ ifneq ($(VARIANT),)
   endif
 endif
 
-#
+# Only build variant and/or platform if it includes a Makefile
+
+buildvar := $(shell test -a $(srctree)/arch/xtensa/variants/$(VARIANT)/Makefile && echo arch/xtensa/variants/$(VARIANT)/)
+buildplf := $(shell test -a $(srctree)/arch/xtensa/platforms/$(PLATFORM)/Makefile && echo arch/xtensa/platforms/$(PLATFORM)/)
+
+# Find libgcc.a
 
 LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
 head-y         := arch/xtensa/kernel/head.o
 core-y         += arch/xtensa/kernel/ arch/xtensa/mm/
-ifneq ($(PLATFORM),)
-core-y         += arch/xtensa/platforms/$(PLATFORM)/
-endif
+core-y         += $(buildvar) $(buildplf)
+
 libs-y         += arch/xtensa/lib/ $(LIBGCC)
 
 boot           := arch/xtensa/boot
 
-
 all: zImage
 
 bzImage : zImage
diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig
new file mode 100644 (file)
index 0000000..6e1deff
--- /dev/null
@@ -0,0 +1,530 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc7-s6
+# Tue Mar 10 11:09:26 2009
+#
+# CONFIG_FRAME_POINTER is not set
+CONFIG_ZONE_DMA=y
+CONFIG_XTENSA=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_NO_IOPORT=y
+CONFIG_HZ=100
+CONFIG_GENERIC_TIME=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_CLASSIC_RCU is not set
+# CONFIG_TREE_RCU is not set
+CONFIG_PREEMPT_RCU=y
+# CONFIG_RCU_TRACE is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+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"
+# CONFIG_FREEZER is not set
+# CONFIG_MMU is not set
+CONFIG_VARIANT_IRQ_SWITCH=y
+
+#
+# Processor type and features
+#
+# CONFIG_XTENSA_VARIANT_FSF is not set
+# CONFIG_XTENSA_VARIANT_DC232B is not set
+CONFIG_XTENSA_VARIANT_S6000=y
+# CONFIG_XTENSA_UNALIGNED_USER is not set
+CONFIG_PREEMPT=y
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_XTENSA_CALIBRATE_CCOUNT is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_XTENSA_ISS_NETWORK is not set
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# Platform options
+#
+# CONFIG_XTENSA_PLATFORM_ISS is not set
+# CONFIG_XTENSA_PLATFORM_XT2000 is not set
+CONFIG_XTENSA_PLATFORM_S6105=y
+CONFIG_XTENSA_CPU_CLOCK=300
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS1,38400 debug bootmem_debug loglevel=7"
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+
+#
+# Executable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_FLAT=y
+# CONFIG_BINFMT_ZFLAT is not set
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Xtensa initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_DEBUG_NOMMU_REGIONS=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+
+#
+# Tracers
+#
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_DMA=y
index 94c4c53a099eb81cf2c4dbf2292131fb8c746014..8fc1c0c8de073742aaf94428215bad8725f9959f 100644 (file)
@@ -65,13 +65,17 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
 # define __flush_invalidate_dcache_range(p,s)  __invalidate_dcache_range(p,s)
 #endif
 
-#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+#if defined(CONFIG_MMU) && (DCACHE_WAY_SIZE > PAGE_SIZE)
 extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long);
+#else
+static inline void __flush_invalidate_dcache_page_alias(unsigned long virt,
+                                                       unsigned long phys) { }
 #endif
-#if (ICACHE_WAY_SIZE > PAGE_SIZE)
+#if defined(CONFIG_MMU) && (ICACHE_WAY_SIZE > PAGE_SIZE)
 extern void __invalidate_icache_page_alias(unsigned long, unsigned long);
 #else
-# define __invalidate_icache_page_alias(v,p)   do { } while(0)
+static inline void __invalidate_icache_page_alias(unsigned long virt,
+                                               unsigned long phys) { }
 #endif
 
 /*
index e30f3abf48f0a60d889b852088c8493ef8509597..137ca3945b07b55966b65a2ac2e89d0393fe4e8c 100644 (file)
@@ -44,8 +44,9 @@
  *     the value desired).
  */
 
+#ifndef MAX_DMA_ADDRESS
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + XCHAL_KIO_SIZE - 1)
-
+#endif
 
 /* Reserve and release a DMA channel */
 extern int request_dma(unsigned int dmanr, const char * device_id);
diff --git a/arch/xtensa/include/asm/flat.h b/arch/xtensa/include/asm/flat.h
new file mode 100644 (file)
index 0000000..94c44ab
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ASM_XTENSA_FLAT_H
+#define __ASM_XTENSA_FLAT_H
+
+#define flat_argvp_envp_on_stack()                     0
+#define flat_old_ram_flag(flags)                       (flags)
+#define flat_reloc_valid(reloc, size)                  ((reloc) <= (size))
+#define flat_get_addr_from_rp(rp, relval, flags, p)    get_unaligned(rp)
+#define flat_put_addr_at_rp(rp, val, relval    )       put_unaligned(val, rp)
+#define flat_get_relocate_addr(rel)                    (rel)
+#define flat_set_persistent(relval, p)                 0
+
+#endif /* __ASM_XTENSA_FLAT_H */
diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..0763b07
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Generic GPIO API implementation for xtensa.
+ *
+ * Stolen from x86, which is derived from the generic GPIO API for powerpc:
+ *
+ * Copyright (c) 2007-2008  MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * 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.
+ */
+
+#ifndef _ASM_XTENSA_GPIO_H
+#define _ASM_XTENSA_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * Just call gpiolib.
+ */
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+/*
+ * Not implemented, yet.
+ */
+static inline int gpio_to_irq(unsigned int gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* _ASM_XTENSA_GPIO_H */
index 07b7299dab20e3ccb8c6c5740d408cf577d8174f..d04cd3a625fa54906eda4e4339855c19aaecc5f5 100644 (file)
@@ -69,21 +69,28 @@ static inline void * phys_to_virt(unsigned long address)
 
 static inline void *ioremap(unsigned long offset, unsigned long size)
 {
+#ifdef CONFIG_MMU
        if (offset >= XCHAL_KIO_PADDR
            && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
                return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR);
-
        else
                BUG();
+#else
+       return (void *)offset;
+#endif
 }
 
 static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
 {
+#ifdef CONFIG_MMU
        if (offset >= XCHAL_KIO_PADDR
            && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
                return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR);
        else
                BUG();
+#else
+       return (void *)offset;
+#endif
 }
 
 static inline void iounmap(void *addr)
index 1620d1e0e695a038e8f93535471a9b8ce008a89a..dfac82dc52ad2eaea2945f267379bad17deab2ca 100644 (file)
 #include <platform/hardware.h>
 #include <variant/core.h>
 
+#ifdef CONFIG_VARIANT_IRQ_SWITCH
+#include <variant/irq.h>
+#else
+static inline void variant_irq_enable(unsigned int irq) { }
+static inline void variant_irq_disable(unsigned int irq) { }
+#endif
+
 #ifndef PLATFORM_NR_IRQS
 # define PLATFORM_NR_IRQS 0
 #endif
index 44c5bb04c55c32b425e499c5d43348c14a434081..04890d6e233536d1cdef5f17b5d4af530b682270 100644 (file)
 #ifndef _XTENSA_MMU_H
 #define _XTENSA_MMU_H
 
+#ifndef CONFIG_MMU
+#include <asm/nommu.h>
+#else
+
 /* Default "unsigned long" context */
 typedef unsigned long mm_context_t;
 
+#endif /* CONFIG_MMU */
 #endif /* _XTENSA_MMU_H */
index c0fd8e5b4513562ee5d9884108fbb1723ed7cd8d..dbd8731a876aec90c2765df2dd1a1c6d5e2310d0 100644 (file)
 #ifndef _XTENSA_MMU_CONTEXT_H
 #define _XTENSA_MMU_CONTEXT_H
 
+#ifndef CONFIG_MMU
+#include <asm/nommu_context.h>
+#else
+
 #include <linux/stringify.h>
 #include <linux/sched.h>
 
+#include <variant/core.h>
+
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm-generic/mm_hooks.h>
 
-#define XCHAL_MMU_ASID_BITS    8
-
 #if (XCHAL_HAVE_TLBS != 1)
 # error "Linux must have an MMU!"
 #endif
@@ -133,4 +137,5 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 
 }
 
+#endif /* CONFIG_MMU */
 #endif /* _XTENSA_MMU_CONTEXT_H */
diff --git a/arch/xtensa/include/asm/nommu.h b/arch/xtensa/include/asm/nommu.h
new file mode 100644 (file)
index 0000000..dce2c43
--- /dev/null
@@ -0,0 +1,3 @@
+typedef struct {
+       unsigned long end_brk;
+} mm_context_t;
diff --git a/arch/xtensa/include/asm/nommu_context.h b/arch/xtensa/include/asm/nommu_context.h
new file mode 100644 (file)
index 0000000..599e7a2
--- /dev/null
@@ -0,0 +1,25 @@
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       return 0;
+}
+
+static inline void destroy_context(struct mm_struct *mm)
+{
+}
+
+static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+                               struct task_struct *tsk)
+{
+}
+
+static inline void deactivate_mm(struct task_struct *tsk, struct mm_struct *mm)
+{
+}
index 11f7dc2dbec769f4ed5dd4233a6bc787d983556e..17e0c5383b108abb9dac7af627aa00ac1fd343ec 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/processor.h>
 #include <asm/types.h>
 #include <asm/cache.h>
+#include <platform/hardware.h>
 
 /*
  * Fixed TLB translations in the processor.
 #define PAGE_SIZE              (__XTENSA_UL_CONST(1) << PAGE_SHIFT)
 #define PAGE_MASK              (~(PAGE_SIZE-1))
 
+#ifdef CONFIG_MMU
 #define PAGE_OFFSET            XCHAL_KSEG_CACHED_VADDR
 #define MAX_MEM_PFN            XCHAL_KSEG_SIZE
+#else
+#define PAGE_OFFSET            0
+#define MAX_MEM_PFN            (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE)
+#endif
+
 #define PGTABLE_START          0x80000000
 
 /*
@@ -150,9 +157,11 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
  * addresses.
  */
 
+#define ARCH_PFN_OFFSET                (PLATFORM_DEFAULT_MEM_START >> PAGE_SHIFT)
+
 #define __pa(x)                        ((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)                        ((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define pfn_valid(pfn)         ((unsigned long)pfn < max_mapnr)
+#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
 #ifdef CONFIG_DISCONTIGMEM
 # error CONFIG_DISCONTIGMEM not supported
 #endif
@@ -162,8 +171,9 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 
+#ifdef CONFIG_MMU
 #define WANT_PAGE_VIRTUAL
-
+#endif
 
 #endif /* __ASSEMBLY__ */
 
index 8014d96b21f1cfde6c7392ff5219cfaa26e1258b..a138770c358ed1d134fcb0274b93f4eeee515757 100644 (file)
@@ -183,7 +183,15 @@ extern unsigned long empty_zero_page[1024];
 
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 
+#ifdef CONFIG_MMU
 extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)];
+extern void paging_init(void);
+extern void pgtable_cache_init(void);
+#else
+# define swapper_pg_dir NULL
+static inline void paging_init(void) { }
+static inline void pgtable_cache_init(void) { }
+#endif
 
 /*
  * The pmd contains the kernel virtual address of the pte page.
@@ -383,8 +391,6 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 
 #else
 
-extern void paging_init(void);
-
 #define kern_addr_valid(addr)  (1)
 
 extern  void update_mmu_cache(struct vm_area_struct * vma,
@@ -398,9 +404,6 @@ extern  void update_mmu_cache(struct vm_area_struct * vma,
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
                 remap_pfn_range(vma, from, pfn, size, prot)
 
-
-extern void pgtable_cache_init(void);
-
 typedef pte_t *pte_addr_t;
 
 #endif /* !defined (__ASSEMBLY__) */
index e3d5a48ad495fb194a635d429984bcc14c7f4841..7d936e58e9be0a00dee26f90f0c5a0ca36954f29 100644 (file)
@@ -74,16 +74,5 @@ extern int platform_pcibios_fixup (void);
  */
 extern void platform_calibrate_ccount (void);
 
-/*
- * platform_get_rtc_time returns RTC seconds (returns 0 for no error)
- */
-extern int platform_get_rtc_time(time_t*);
-
-/*
- * platform_set_rtc_time set RTC seconds (returns 0 for no error)
- */
-extern int platform_set_rtc_time(time_t);
-
-
 #endif /* _XTENSA_PLATFORM_H */
 
index 07387d3b99f4c0f09cc8d4b6184c8875c4a6405b..0ea4937c0b618d517d68e70f163af7925539dae7 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <variant/core.h>
 #include <asm/coprocessor.h>
+#include <platform/hardware.h>
 
 #include <linux/compiler.h>
 #include <asm/ptrace.h>
@@ -25,6 +26,8 @@
 # error Linux requires the Xtensa Windowed Registers Option.
 #endif
 
+#define ARCH_SLAB_MINALIGN     XCHAL_DATA_WIDTH
+
 /*
  * User space process size: 1 GB.
  * Windowed call ABI requires caller and callee to be located within the same
  * the 1 GB requirement applies to the stack as well.
  */
 
+#ifdef CONFIG_MMU
 #define TASK_SIZE      __XTENSA_UL_CONST(0x40000000)
+#else
+#define TASK_SIZE      (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE)
+#endif
+
 #define STACK_TOP      TASK_SIZE
 #define STACK_TOP_MAX  STACK_TOP
 
index a51d36a27389ff9ebeb213d0707089b82faf421c..80d24c485fd31630d15de4d44823a0c21a8d278e 100644 (file)
@@ -1463,6 +1463,7 @@ ENTRY(_spill_registers)
        callx0  a0              # should not return
 1:     j       1b
 
+#ifdef CONFIG_MMU
 /*
  * We should never get here. Bail out!
  */
@@ -1775,7 +1776,7 @@ ENTRY(fast_store_prohibited)
        bbsi.l  a2, PS_UM_BIT, 1f
        j       _kernel_exception
 1:     j       _user_exception
-
+#endif /* CONFIG_MMU */
 
 /*
  * System Calls.
index 67e69139520bd91cb834dbfc68d591039712d3b7..0817f9db836e3cf582edd26de186e901f7e1d79e 100644 (file)
@@ -53,7 +53,7 @@ _start:       _j      2f
 2:     l32r    a0, 1b
        jx      a0
 
-       .text
+       .section .init.text, "ax"
        .align 4
 _startup:
 
@@ -235,8 +235,9 @@ should_never_return:
  */
        
 .section ".bss.page_aligned", "w"
+#ifdef CONFIG_MMU
 ENTRY(swapper_pg_dir)
        .fill   PAGE_SIZE, 1, 0
+#endif
 ENTRY(empty_zero_page)
        .fill   PAGE_SIZE, 1, 0
-
index f3b66fba5b8f71f0f45700601b9117dd865ae9b9..a36c85edd04588b59129f25eb17dd646a5c5b982 100644 (file)
@@ -132,6 +132,18 @@ static void xtensa_irq_unmask(unsigned int irq)
        set_sr (cached_irq_mask, INTENABLE);
 }
 
+static void xtensa_irq_enable(unsigned int irq)
+{
+       variant_irq_enable(irq);
+       xtensa_irq_unmask(irq);
+}
+
+static void xtensa_irq_disable(unsigned int irq)
+{
+       xtensa_irq_mask(irq);
+       variant_irq_disable(irq);
+}
+
 static void xtensa_irq_ack(unsigned int irq)
 {
        set_sr(1 << irq, INTCLEAR);
@@ -146,6 +158,8 @@ static int xtensa_irq_retrigger(unsigned int irq)
 
 static struct irq_chip xtensa_irq_chip = {
        .name           = "xtensa",
+       .enable         = xtensa_irq_enable,
+       .disable        = xtensa_irq_disable,
        .mask           = xtensa_irq_mask,
        .unmask         = xtensa_irq_unmask,
        .ack            = xtensa_irq_ack,
index 69675f216062b5d00d343050e4fd1c5a22eea84c..1b91a97f1d8401ff9899ed95deae80933e482f7a 100644 (file)
@@ -36,8 +36,6 @@ _F(void, power_off, (void), { while(1); });
 _F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); });
 _F(void, heartbeat, (void), { });
 _F(int,  pcibios_fixup, (void), { return 0; });
-_F(int, get_rtc_time, (time_t* t), { return 0; });
-_F(int, set_rtc_time, (time_t t), { return 0; });
 
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 _F(void, calibrate_ccount, (void),
index 9185597eb6a046b1ccc5f17ad6a9c216a12f0815..031f36685710d087d4b5b7f8426542ea97bc3178 100644 (file)
@@ -172,7 +172,7 @@ void prepare_to_copy(struct task_struct *tsk)
  *       childregs.
  */
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                 struct task_struct * p, struct pt_regs * regs)
 {
index 4ec1633c29414f21f551223f4ea0065c95ccfb88..1e5a034fe01194b200796ea5e2da9d8885eee4fb 100644 (file)
@@ -84,7 +84,13 @@ sysmem_info_t __initdata sysmem;
 int initrd_is_mapped;
 #endif
 
+#ifdef CONFIG_MMU
 extern void init_mmu(void);
+#else
+static inline void init_mmu(void) { }
+#endif
+
+extern void zones_init(void);
 
 /*
  * Boot parameter parsing.
@@ -286,6 +292,7 @@ void __init setup_arch(char **cmdline_p)
 
 
        paging_init();
+       zones_init();
 
 #ifdef CONFIG_VT
 # if defined(CONFIG_VGA_CONSOLE)
index 8df1e842f6d401d060d077246d97d942c2033cad..8848120d291bc7465d9a4fcdf2b07aee7ae9c394 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/errno.h>
 #include <linux/time.h>
-#include <linux/timex.h>
+#include <linux/clocksource.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/timex.h>
 #include <asm/platform.h>
 
-
-DEFINE_SPINLOCK(rtc_lock);
-EXPORT_SYMBOL(rtc_lock);
-
-
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 unsigned long ccount_per_jiffy;                /* per 1/HZ */
 unsigned long nsec_per_ccount;         /* nsec per ccount increment */
 #endif
 
-static long last_rtc_update = 0;
-
-/*
- * Scheduler clock - returns current tim in nanosec units.
- */
-
-unsigned long long sched_clock(void)
+static cycle_t ccount_read(void)
 {
-       return (unsigned long long)jiffies * (1000000000 / HZ);
+       return (cycle_t)get_ccount();
 }
 
+static struct clocksource ccount_clocksource = {
+       .name = "ccount",
+       .rating = 200,
+       .read = ccount_read,
+       .mask = CLOCKSOURCE_MASK(32),
+       /*
+        * With a shift of 22 the lower limit of the cpu clock is
+        * 1MHz, where NSEC_PER_CCOUNT is 1000 or a bit less than
+        * 2^10: Since we have 32 bits and the multiplicator can
+        * already take up as much as 10 bits, this leaves us with
+        * remaining upper 22 bits.
+        */
+       .shift = 22,
+};
+
 static irqreturn_t timer_interrupt(int irq, void *dev_id);
 static struct irqaction timer_irqaction = {
        .handler =      timer_interrupt,
@@ -55,11 +59,11 @@ static struct irqaction timer_irqaction = {
 
 void __init time_init(void)
 {
-       time_t sec_o, sec_n = 0;
+       xtime.tv_nsec = 0;
+       xtime.tv_sec = read_persistent_clock();
 
-       /* The platform must provide a function to calibrate the processor
-        * speed for the CALIBRATE.
-        */
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
 
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
        printk("Calibrating CPU frequency ");
@@ -67,19 +71,10 @@ void __init time_init(void)
        printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ),
                        (int)(ccount_per_jiffy/(10000/HZ))%100);
 #endif
-
-       /* Set time from RTC (if provided) */
-
-       if (platform_get_rtc_time(&sec_o) == 0)
-               while (platform_get_rtc_time(&sec_n))
-                       if (sec_o != sec_n)
-                               break;
-
-       xtime.tv_nsec = 0;
-       last_rtc_update = xtime.tv_sec = sec_n;
-
-       set_normalized_timespec(&wall_to_monotonic,
-               -xtime.tv_sec, -xtime.tv_nsec);
+       ccount_clocksource.mult =
+               clocksource_hz2mult(CCOUNT_PER_JIFFY * HZ,
+                               ccount_clocksource.shift);
+       clocksource_register(&ccount_clocksource);
 
        /* Initialize the linux timer interrupt. */
 
@@ -87,69 +82,6 @@ void __init time_init(void)
        set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
 }
 
-
-int do_settimeofday(struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-       unsigned long delta;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       write_seqlock_irq(&xtime_lock);
-
-       /* This is revolting. We need to set "xtime" correctly. However, the
-        * value in this location is the value at the most recent update of
-        * wall time.  Discover what correction gettimeofday() would have
-        * made, and then undo it!
-        */
-
-       delta = CCOUNT_PER_JIFFY;
-       delta += get_ccount() - get_linux_timer();
-       nsec -= delta * NSEC_PER_CCOUNT;
-
-       wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-       wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-       set_normalized_timespec(&xtime, sec, nsec);
-       set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-       ntp_clear();
-       write_sequnlock_irq(&xtime_lock);
-       return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
-
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-       unsigned long volatile sec, usec, delta, seq;
-
-       do {
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-
-               sec = xtime.tv_sec;
-               usec = (xtime.tv_nsec / NSEC_PER_USEC);
-
-               delta = get_linux_timer() - get_ccount();
-
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       usec += (((unsigned long) CCOUNT_PER_JIFFY - delta)
-                * (unsigned long) NSEC_PER_CCOUNT) / NSEC_PER_USEC;
-
-       for (; usec >= 1000000; sec++, usec -= 1000000)
-               ;
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
 /*
  * The timer interrupt is called HZ times per second.
  */
@@ -178,16 +110,6 @@ again:
                next += CCOUNT_PER_JIFFY;
                set_linux_timer(next);
 
-               if (ntp_synced() &&
-                   xtime.tv_sec - last_rtc_update >= 659 &&
-                   abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ) {
-
-                       if (platform_set_rtc_time(xtime.tv_sec+1) == 0)
-                               last_rtc_update = xtime.tv_sec+1;
-                       else
-                               /* Do it again in 60 s */
-                               last_rtc_update += 60;
-               }
                write_sequnlock(&xtime_lock);
        }
 
@@ -213,4 +135,3 @@ void __cpuinit calibrate_delay(void)
               (loops_per_jiffy/(10000/HZ)) % 100);
 }
 #endif
-
index c44f830b6c7a3fee0e699132ff93edd4f726d94c..9f0b71189e940bccc462c933175c877060ded3c2 100644 (file)
@@ -104,6 +104,7 @@ static dispatch_init_table_t __initdata dispatch_init_table[] = {
 #endif
 { EXCCAUSE_UNALIGNED,          KRNL,      fast_unaligned },
 #endif
+#ifdef CONFIG_MMU
 { EXCCAUSE_ITLB_MISS,          0,         do_page_fault },
 { EXCCAUSE_ITLB_MISS,          USER|KRNL, fast_second_level_miss},
 { EXCCAUSE_ITLB_MULTIHIT,              0,         do_multihit },
@@ -118,6 +119,7 @@ static dispatch_init_table_t __initdata dispatch_init_table[] = {
 { EXCCAUSE_STORE_CACHE_ATTRIBUTE,      USER|KRNL, fast_store_prohibited },
 { EXCCAUSE_STORE_CACHE_ATTRIBUTE,      0,         do_page_fault },
 { EXCCAUSE_LOAD_CACHE_ATTRIBUTE,       0,         do_page_fault },
+#endif /* CONFIG_MMU */
 /* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */
 #if XTENSA_HAVE_COPROCESSOR(0)
 COPROCESSOR(0),
@@ -372,11 +374,10 @@ void show_trace(struct task_struct *task, unsigned long *sp)
        unsigned long a0, a1, pc;
        unsigned long sp_start, sp_end;
 
-       a1 = (unsigned long)sp;
-
-       if (a1 == 0)
-               __asm__ __volatile__ ("mov %0, a1\n" : "=a"(a1));
-
+       if (sp)
+               a1 = (unsigned long)sp;
+       else
+               a1 = task->thread.sp;
 
        sp_start = a1 & ~(THREAD_SIZE-1);
        sp_end = sp_start + THREAD_SIZE;
@@ -418,9 +419,8 @@ void show_stack(struct task_struct *task, unsigned long *sp)
        int i = 0;
        unsigned long *stack;
 
-       if (sp == 0)
-               __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
-
+       if (!sp)
+               sp = (unsigned long *)task->thread.sp;
        stack = sp;
 
        printk("\nStack: ");
index eb2d7bb69ee071352ef9124efb75b7a743d27649..74a7518faf16caebb713c2ede9210d4939d79722 100644 (file)
@@ -309,6 +309,7 @@ ENTRY(_DoubleExceptionVector)
         * All other exceptions are unexpected and thus unrecoverable!
         */
 
+#ifdef CONFIG_MMU
        .extern fast_second_level_miss_double_kernel
 
 .Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
@@ -319,6 +320,9 @@ ENTRY(_DoubleExceptionVector)
        bnez    a3, .Lunrecoverable
 1:     movi    a3, fast_second_level_miss_double_kernel
        jx      a3
+#else
+.equ   .Lksp,  .Lunrecoverable
+#endif
 
        /* Critical! We can't handle this situation. PANIC! */
 
index d506774f4b05062fb57c999d98873538e582e8d9..c1be9a4a740caf3dccc3734adeb7b941411c10e0 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm-generic/vmlinux.lds.h>
 
 #include <variant/core.h>
+#include <platform/hardware.h>
 OUTPUT_ARCH(xtensa)
 ENTRY(_start)
 
@@ -26,7 +27,9 @@ jiffies = jiffies_64 + 4;
 jiffies = jiffies_64;
 #endif
 
+#ifndef KERNELOFFSET
 #define KERNELOFFSET 0xd0001000
+#endif
 
 /* Note: In the following macros, it would be nice to specify only the
    vector name and section kind and construct "sym" and "section" using
index 64e304a2f884e4395fdff94d46da28d717a6c79b..f0b646d2f843feb5945601dbe65966a4a71cfec9 100644 (file)
@@ -2,4 +2,5 @@
 # Makefile for the Linux/Xtensa-specific parts of the memory manager.
 #
 
-obj-y   := init.o fault.o tlb.o misc.o cache.o
+obj-y                  := init.o cache.o misc.o
+obj-$(CONFIG_MMU)      += fault.o mmu.o tlb.o
index 34163cfaaffca3b329fcf3f33fa7e2b4a377928c..427e14fa43c5517d8ed583cd2c0c5f40c6026ce2 100644 (file)
 #include <linux/mm.h>
 #include <linux/slab.h>
 
-#include <asm/pgtable.h>
 #include <asm/bootparam.h>
-#include <asm/mmu_context.h>
-#include <asm/tlb.h>
 #include <asm/page.h>
-#include <asm/pgalloc.h>
-
-
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 /* References to section boundaries */
 
@@ -130,7 +123,8 @@ void __init bootmem_init(void)
 
        /* Find an area to use for the bootmem bitmap. */
 
-       bootmap_size = bootmem_bootmap_pages(max_low_pfn) << PAGE_SHIFT;
+       bootmap_size = bootmem_bootmap_pages(max_low_pfn - min_low_pfn);
+       bootmap_size <<= PAGE_SHIFT;
        bootmap_start = ~0;
 
        for (i=0; i<sysmem.nr_banks; i++)
@@ -145,8 +139,9 @@ void __init bootmem_init(void)
        /* Reserve the bootmem bitmap area */
 
        mem_reserve(bootmap_start, bootmap_start + bootmap_size, 1);
-       bootmap_size = init_bootmem_node(NODE_DATA(0), min_low_pfn,
+       bootmap_size = init_bootmem_node(NODE_DATA(0),
                                         bootmap_start >> PAGE_SHIFT,
+                                        min_low_pfn,
                                         max_low_pfn);
 
        /* Add all remaining memory pieces into the bootmem map */
@@ -158,14 +153,14 @@ void __init bootmem_init(void)
 }
 
 
-void __init paging_init(void)
+void __init zones_init(void)
 {
        unsigned long zones_size[MAX_NR_ZONES];
        int i;
 
        /* All pages are DMA-able, so we put them all in the DMA zone. */
 
-       zones_size[ZONE_DMA] = max_low_pfn;
+       zones_size[ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET;
        for (i = 1; i < MAX_NR_ZONES; i++)
                zones_size[i] = 0;
 
@@ -173,40 +168,7 @@ void __init paging_init(void)
        zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
 #endif
 
-       /* Initialize the kernel's page tables. */
-
-       memset(swapper_pg_dir, 0, PAGE_SIZE);
-
-       free_area_init(zones_size);
-}
-
-/*
- * Flush the mmu and reset associated register to default values.
- */
-
-void __init init_mmu (void)
-{
-       /* Writing zeros to the <t>TLBCFG special registers ensure
-        * that valid values exist in the register.  For existing
-        * PGSZID<w> fields, zero selects the first element of the
-        * page-size array.  For nonexistent PGSZID<w> fields, zero is
-        * the best value to write.  Also, when changing PGSZID<w>
-        * fields, the corresponding TLB must be flushed.
-        */
-       set_itlbcfg_register (0);
-       set_dtlbcfg_register (0);
-       flush_tlb_all ();
-
-       /* Set rasid register to a known value. */
-
-       set_rasid_register (ASID_USER_FIRST);
-
-       /* Set PTEVADDR special register to the start of the page
-        * table, which is in kernel mappable space (ie. not
-        * statically mapped).  This register's value is undefined on
-        * reset.
-        */
-       set_ptevaddr_register (PGTABLE_START);
+       free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL);
 }
 
 /*
@@ -218,8 +180,8 @@ void __init mem_init(void)
        unsigned long codesize, reservedpages, datasize, initsize;
        unsigned long highmemsize, tmp, ram;
 
-       max_mapnr = num_physpages = max_low_pfn;
-       high_memory = (void *) __va(max_mapnr << PAGE_SHIFT);
+       max_mapnr = num_physpages = max_low_pfn - ARCH_PFN_OFFSET;
+       high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
        highmemsize = 0;
 
 #ifdef CONFIG_HIGHMEM
@@ -229,7 +191,7 @@ void __init mem_init(void)
        totalram_pages += free_all_bootmem();
 
        reservedpages = ram = 0;
-       for (tmp = 0; tmp < max_low_pfn; tmp++) {
+       for (tmp = 0; tmp < max_mapnr; tmp++) {
                ram++;
                if (PageReserved(mem_map+tmp))
                        reservedpages++;
@@ -279,23 +241,3 @@ void free_initmem(void)
        printk("Freeing unused kernel memory: %dk freed\n",
               (&__init_end - &__init_begin) >> 10);
 }
-
-struct kmem_cache *pgtable_cache __read_mostly;
-
-static void pgd_ctor(void* addr)
-{
-       pte_t* ptep = (pte_t*)addr;
-       int i;
-
-       for (i = 0; i < 1024; i++, ptep++)
-               pte_clear(NULL, 0, ptep);
-
-}
-
-void __init pgtable_cache_init(void)
-{
-       pgtable_cache = kmem_cache_create("pgd",
-                       PAGE_SIZE, PAGE_SIZE,
-                       SLAB_HWCACHE_ALIGN,
-                       pgd_ctor);
-}
index c885664211d15ffea236ae0fc4fe32c61d7a1155..b048406d87568cb23a5fd14d7dd215dd51f6f6dc 100644 (file)
@@ -84,6 +84,7 @@ ENTRY(copy_page)
 
        retw
 
+#ifdef CONFIG_MMU
 /*
  * If we have to deal with cache aliasing, we use temporary memory mappings
  * to ensure that the source and destination pages have the same color as
@@ -311,6 +312,7 @@ ENTRY(__invalidate_icache_page_alias)
 /* End of special treatment in tlb miss exception */
 
 ENTRY(__tlbtemp_mapping_end)
+#endif /* CONFIG_MMU
 
 /*
  * void __invalidate_icache_page(ulong start)
diff --git a/arch/xtensa/mm/mmu.c b/arch/xtensa/mm/mmu.c
new file mode 100644 (file)
index 0000000..4bb91a9
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * xtensa mmu stuff
+ *
+ * Extracted from init.c
+ */
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/cache.h>
+
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+void __init paging_init(void)
+{
+       memset(swapper_pg_dir, 0, PAGE_SIZE);
+}
+
+/*
+ * Flush the mmu and reset associated register to default values.
+ */
+void __init init_mmu(void)
+{
+       /* Writing zeros to the <t>TLBCFG special registers ensure
+        * that valid values exist in the register.  For existing
+        * PGSZID<w> fields, zero selects the first element of the
+        * page-size array.  For nonexistent PGSZID<w> fields, zero is
+        * the best value to write.  Also, when changing PGSZID<w>
+        * fields, the corresponding TLB must be flushed.
+        */
+       set_itlbcfg_register(0);
+       set_dtlbcfg_register(0);
+       flush_tlb_all();
+
+       /* Set rasid register to a known value. */
+
+       set_rasid_register(ASID_USER_FIRST);
+
+       /* Set PTEVADDR special register to the start of the page
+        * table, which is in kernel mappable space (ie. not
+        * statically mapped).  This register's value is undefined on
+        * reset.
+        */
+       set_ptevaddr_register(PGTABLE_START);
+}
+
+struct kmem_cache *pgtable_cache __read_mostly;
+
+static void pgd_ctor(void *addr)
+{
+       pte_t *ptep = (pte_t *)addr;
+       int i;
+
+       for (i = 0; i < 1024; i++, ptep++)
+               pte_clear(NULL, 0, ptep);
+
+}
+
+void __init pgtable_cache_init(void)
+{
+       pgtable_cache = kmem_cache_create("pgd",
+                       PAGE_SIZE, PAGE_SIZE,
+                       SLAB_HWCACHE_ALIGN,
+                       pgd_ctor);
+}
index 25d46c84eb0836c4933a451c632099ae68759a77..4c559cf7da2d8c13c0a0529f5ae2e458b65257d1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/major.h>
 #include <linux/param.h>
+#include <linux/seq_file.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
 
@@ -176,22 +177,24 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
        /* Stub, once again.. */
 }
 
-static int rs_read_proc(char *page, char **start, off_t off, int count,
-                       int *eof, void *data)
+static int rs_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
-       off_t begin = 0;
-
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-       *eof = 1;
-
-       if (off >= len + begin)
-               return 0;
+       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
+       return 0;
+}
 
-       *start = page + (off - begin);
-       return ((count < begin + len - off) ? count : begin + len - off);
+static int rs_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rs_proc_show, NULL);
 }
 
+static const struct file_operations rs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rs_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 static struct tty_operations serial_ops = {
        .open = rs_open,
@@ -203,7 +206,7 @@ static struct tty_operations serial_ops = {
        .chars_in_buffer = rs_chars_in_buffer,
        .hangup = rs_hangup,
        .wait_until_sent = rs_wait_until_sent,
-       .read_proc = rs_read_proc
+       .proc_fops = &rs_proc_fops,
 };
 
 int __init rs_init(void)
diff --git a/arch/xtensa/platforms/s6105/Makefile b/arch/xtensa/platforms/s6105/Makefile
new file mode 100644 (file)
index 0000000..0be6194
--- /dev/null
@@ -0,0 +1,3 @@
+# Makefile for the Stretch S6105 eval board
+
+obj-y          := setup.o device.o
diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c
new file mode 100644 (file)
index 0000000..78b08be
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * s6105 platform devices
+ *
+ * Copyright (c) 2009 emlix GmbH
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+
+#include <variant/hardware.h>
+
+#define UART_INTNUM            4
+
+static const signed char uart_irq_mappings[] = {
+       S6_INTC_UART(0),
+       S6_INTC_UART(1),
+       -1,
+};
+
+const signed char *platform_irq_mappings[NR_IRQS] = {
+       [UART_INTNUM] = uart_irq_mappings,
+};
+
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .membase = (void *)S6_REG_UART + 0x0000,
+               .mapbase = S6_REG_UART + 0x0000,
+               .irq = UART_INTNUM,
+               .uartclk = S6_SCLK,
+               .regshift = 2,
+               .iotype = SERIAL_IO_MEM,
+               .flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST,
+       },
+       {
+               .membase = (void *)S6_REG_UART + 0x1000,
+               .mapbase = S6_REG_UART + 0x1000,
+               .irq = UART_INTNUM,
+               .uartclk = S6_SCLK,
+               .regshift = 2,
+               .iotype = SERIAL_IO_MEM,
+               .flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST,
+       },
+       { },
+};
+
+static struct platform_device platform_devices[] = {
+       {
+               .name = "serial8250",
+               .id = PLAT8250_DEV_PLATFORM,
+               .dev = {
+                       .platform_data = serial_platform_data,
+               },
+       },
+};
+
+static int __init device_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(platform_devices); i++)
+               platform_device_register(&platform_devices[i]);
+       return 0;
+}
+arch_initcall_sync(device_init);
diff --git a/arch/xtensa/platforms/s6105/include/platform/gpio.h b/arch/xtensa/platforms/s6105/include/platform/gpio.h
new file mode 100644 (file)
index 0000000..fa11aa4
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __ASM_XTENSA_S6105_GPIO_H
+#define __ASM_XTENSA_S6105_GPIO_H
+
+#define GPIO_BP_TEMP_ALARM     0
+#define GPIO_PB_RESET_IN       1
+#define GPIO_EXP_IRQ           2
+#define GPIO_TRIGGER_IRQ       3
+#define GPIO_RTC_IRQ           4
+#define GPIO_PHY_IRQ           5
+#define GPIO_IMAGER_RESET      6
+#define GPIO_SD_IRQ            7
+#define GPIO_MINI_BOOT_INH     8
+#define GPIO_BOARD_RESET       9
+#define GPIO_EXP_PRESENT       10
+#define GPIO_LED1_NGREEN       12
+#define GPIO_LED1_RED          13
+#define GPIO_LED0_NGREEN       14
+#define GPIO_LED0_NRED         15
+#define GPIO_SPI_CS0           16
+#define GPIO_SPI_CS1           17
+#define GPIO_SPI_CS3           19
+#define GPIO_SPI_CS4           20
+#define GPIO_SD_WP             21
+#define GPIO_BP_RESET          22
+#define GPIO_ALARM_OUT         23
+
+#endif /* __ASM_XTENSA_S6105_GPIO_H */
diff --git a/arch/xtensa/platforms/s6105/include/platform/hardware.h b/arch/xtensa/platforms/s6105/include/platform/hardware.h
new file mode 100644 (file)
index 0000000..d628efa
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __XTENSA_S6105_HARDWARE_H
+#define __XTENSA_S6105_HARDWARE_H
+
+#define PLATFORM_DEFAULT_MEM_START     0x40000000
+#define PLATFORM_DEFAULT_MEM_SIZE      0x08000000
+
+#define MAX_DMA_ADDRESS                        0
+
+#define KERNELOFFSET                   (PLATFORM_DEFAULT_MEM_START + 0x1000)
+
+#endif /* __XTENSA_S6105_HARDWARE_H */
diff --git a/arch/xtensa/platforms/s6105/include/platform/serial.h b/arch/xtensa/platforms/s6105/include/platform/serial.h
new file mode 100644 (file)
index 0000000..c8a771e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_XTENSA_S6105_SERIAL_H
+#define __ASM_XTENSA_S6105_SERIAL_H
+
+#include <variant/hardware.h>
+
+#define BASE_BAUD (S6_SCLK / 16)
+
+#endif /* __ASM_XTENSA_S6105_SERIAL_H */
diff --git a/arch/xtensa/platforms/s6105/setup.c b/arch/xtensa/platforms/s6105/setup.c
new file mode 100644 (file)
index 0000000..ae041d5
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * s6105 control routines
+ *
+ * Copyright (c) 2009 emlix GmbH
+ */
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <asm/bootparam.h>
+
+#include <variant/hardware.h>
+#include <platform/gpio.h>
+
+void platform_halt(void)
+{
+       local_irq_disable();
+       while (1)
+               ;
+}
+
+void platform_power_off(void)
+{
+       platform_halt();
+}
+
+void platform_restart(void)
+{
+       platform_halt();
+}
+
+void __init platform_setup(char **cmdline)
+{
+       unsigned long reg;
+
+       reg = readl(S6_REG_GREG1 + S6_GREG1_CLKGATE);
+       reg &= ~(1 << S6_GREG1_BLOCK_SB);
+       writel(reg, S6_REG_GREG1 + S6_GREG1_CLKGATE);
+
+       reg = readl(S6_REG_GREG1 + S6_GREG1_BLOCKENA);
+       reg |= 1 << S6_GREG1_BLOCK_SB;
+       writel(reg, S6_REG_GREG1 + S6_GREG1_BLOCKENA);
+
+       printk(KERN_NOTICE "S6105 on Stretch S6000 - "
+               "Copyright (C) 2009 emlix GmbH <info@emlix.com>\n");
+}
+
+void __init platform_init(bp_tag_t *first)
+{
+       gpio_request(GPIO_LED1_NGREEN, "led1_green");
+       gpio_request(GPIO_LED1_RED, "led1_red");
+       gpio_direction_output(GPIO_LED1_NGREEN, 1);
+}
+
+void platform_heartbeat(void)
+{
+       static unsigned int c;
+
+       if (!(++c & 0x4F))
+               gpio_direction_output(GPIO_LED1_RED, !(c & 0x10));
+}
index 41459ad0776639fccaeb65b40d0db2481733771d..886ef156ded3693ea49d00cf073d5121d17d18cd 100644 (file)
@@ -16,7 +16,6 @@
 #define _XTENSA_XT2000_HARDWARE_H
 
 #include <variant/core.h>
-#include <asm/io.h>
 
 /* 
  * Memory configuration.
diff --git a/arch/xtensa/variants/s6000/Makefile b/arch/xtensa/variants/s6000/Makefile
new file mode 100644 (file)
index 0000000..03b3975
--- /dev/null
@@ -0,0 +1,3 @@
+# s6000 Makefile
+
+obj-y          += irq.o gpio.o
diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c
new file mode 100644 (file)
index 0000000..33a8d95
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * s6000 gpio driver
+ *
+ * Copyright (c) 2009 emlix GmbH
+ * Authors:    Oskar Schirmer <os@emlix.com>
+ *             Johannes Weiner <jw@emlix.com>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <variant/hardware.h>
+
+#define S6_GPIO_DATA           0x000
+#define S6_GPIO_IS             0x404
+#define S6_GPIO_IBE            0x408
+#define S6_GPIO_IEV            0x40C
+#define S6_GPIO_IE             0x410
+#define S6_GPIO_RIS            0x414
+#define S6_GPIO_MIS            0x418
+#define S6_GPIO_IC             0x41C
+#define S6_GPIO_AFSEL          0x420
+#define S6_GPIO_DIR            0x800
+#define S6_GPIO_BANK(nr)       ((nr) * 0x1000)
+#define S6_GPIO_MASK(nr)       (4 << (nr))
+#define S6_GPIO_OFFSET(nr) \
+               (S6_GPIO_BANK((nr) >> 3) + S6_GPIO_MASK((nr) & 7))
+
+static int direction_input(struct gpio_chip *chip, unsigned int off)
+{
+       writeb(0, S6_REG_GPIO + S6_GPIO_DIR + S6_GPIO_OFFSET(off));
+       return 0;
+}
+
+static int get(struct gpio_chip *chip, unsigned int off)
+{
+       return readb(S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off));
+}
+
+static int direction_output(struct gpio_chip *chip, unsigned int off, int val)
+{
+       unsigned rel = S6_GPIO_OFFSET(off);
+       writeb(~0, S6_REG_GPIO + S6_GPIO_DIR + rel);
+       writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + rel);
+       return 0;
+}
+
+static void set(struct gpio_chip *chip, unsigned int off, int val)
+{
+       writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off));
+}
+
+static struct gpio_chip gpiochip = {
+       .owner = THIS_MODULE,
+       .direction_input = direction_input,
+       .get = get,
+       .direction_output = direction_output,
+       .set = set,
+       .base = 0,
+       .ngpio = 24,
+       .can_sleep = 0, /* no blocking io needed */
+       .exported = 0, /* no exporting to userspace */
+};
+
+static int gpio_init(void)
+{
+       return gpiochip_add(&gpiochip);
+}
+device_initcall(gpio_init);
diff --git a/arch/xtensa/variants/s6000/include/variant/core.h b/arch/xtensa/variants/s6000/include/variant/core.h
new file mode 100644 (file)
index 0000000..af00795
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Xtensa processor core configuration information.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1999-2008 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_CONFIGURATION_H
+#define _XTENSA_CORE_CONFIGURATION_H
+
+
+/****************************************************************************
+           Parameters Useful for Any Code, USER or PRIVILEGED
+ ****************************************************************************/
+
+/*
+ *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
+ *  configured, and a value of 0 otherwise.  These macros are always defined.
+ */
+
+
+/*----------------------------------------------------------------------
+                               ISA
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE                  0       /* big-endian byte ordering */
+#define XCHAL_HAVE_WINDOWED            1       /* windowed registers option */
+#define XCHAL_NUM_AREGS                        64      /* num of physical addr regs */
+#define XCHAL_NUM_AREGS_LOG2           6       /* log2(XCHAL_NUM_AREGS) */
+#define XCHAL_MAX_INSTRUCTION_SIZE     8       /* max instr bytes (3..8) */
+#define XCHAL_HAVE_DEBUG               1       /* debug option */
+#define XCHAL_HAVE_DENSITY             1       /* 16-bit instructions */
+#define XCHAL_HAVE_LOOPS               1       /* zero-overhead loops */
+#define XCHAL_HAVE_NSA                 1       /* NSA/NSAU instructions */
+#define XCHAL_HAVE_MINMAX              1       /* MIN/MAX instructions */
+#define XCHAL_HAVE_SEXT                        1       /* SEXT instruction */
+#define XCHAL_HAVE_CLAMPS              1       /* CLAMPS instruction */
+#define XCHAL_HAVE_MUL16               1       /* MUL16S/MUL16U instructions */
+#define XCHAL_HAVE_MUL32               1       /* MULL instruction */
+#define XCHAL_HAVE_MUL32_HIGH          1       /* MULUH/MULSH instructions */
+#define XCHAL_HAVE_DIV32               0       /* QUOS/QUOU/REMS/REMU instructions */
+#define XCHAL_HAVE_L32R                        1       /* L32R instruction */
+#define XCHAL_HAVE_ABSOLUTE_LITERALS   1       /* non-PC-rel (extended) L32R */
+#define XCHAL_HAVE_CONST16             0       /* CONST16 instruction */
+#define XCHAL_HAVE_ADDX                        1       /* ADDX#/SUBX# instructions */
+#define XCHAL_HAVE_WIDE_BRANCHES       0       /* B*.W18 or B*.W15 instr's */
+#define XCHAL_HAVE_PREDICTED_BRANCHES  0       /* B[EQ/EQZ/NE/NEZ]T instr's */
+#define XCHAL_HAVE_CALL4AND12          1       /* (obsolete option) */
+#define XCHAL_HAVE_ABS                 1       /* ABS instruction */
+/*#define XCHAL_HAVE_POPC              0*/     /* POPC instruction */
+/*#define XCHAL_HAVE_CRC               0*/     /* CRC instruction */
+#define XCHAL_HAVE_RELEASE_SYNC                0       /* L32AI/S32RI instructions */
+#define XCHAL_HAVE_S32C1I              0       /* S32C1I instruction */
+#define XCHAL_HAVE_SPECULATION         0       /* speculation */
+#define XCHAL_HAVE_FULL_RESET          0       /* all regs/state reset */
+#define XCHAL_NUM_CONTEXTS             1       /* */
+#define XCHAL_NUM_MISC_REGS            4       /* num of scratch regs (0..4) */
+#define XCHAL_HAVE_TAP_MASTER          0       /* JTAG TAP control instr's */
+#define XCHAL_HAVE_PRID                        0       /* processor ID register */
+#define XCHAL_HAVE_THREADPTR           0       /* THREADPTR register */
+#define XCHAL_HAVE_BOOLEANS            1       /* boolean registers */
+#define XCHAL_HAVE_CP                  1       /* CPENABLE reg (coprocessor) */
+#define XCHAL_CP_MAXCFG                        8       /* max allowed cp id plus one */
+#define XCHAL_HAVE_MAC16               0       /* MAC16 package */
+#define XCHAL_HAVE_VECTORFPU2005       0       /* vector floating-point pkg */
+#define XCHAL_HAVE_FP                  1       /* floating point pkg */
+#define XCHAL_HAVE_VECTRA1             0       /* Vectra I  pkg */
+#define XCHAL_HAVE_VECTRALX            0       /* Vectra LX pkg */
+#define XCHAL_HAVE_HIFI2               0       /* HiFi2 Audio Engine pkg */
+
+
+/*----------------------------------------------------------------------
+                               MISC
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES  8       /* size of write buffer */
+#define XCHAL_INST_FETCH_WIDTH         8       /* instr-fetch width in bytes */
+#define XCHAL_DATA_WIDTH               16      /* data width in bytes */
+/*  In T1050, applies to selected core load and store instructions (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1       /* unaligned loads cause exc. */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION        1       /* unaligned stores cause exc.*/
+
+#define XCHAL_SW_VERSION               701001  /* sw version of this header */
+
+#define XCHAL_CORE_ID                  "stretch_bali"  /* alphanum core name
+                                                  (CoreID) set in the Xtensa
+                                                  Processor Generator */
+
+#define XCHAL_BUILD_UNIQUE_ID          0x000104B9      /* 22-bit sw build ID */
+
+/*
+ *  These definitions describe the hardware targeted by this software.
+ */
+#define XCHAL_HW_CONFIGID0             0xC2F3F9FE      /* ConfigID hi 32 bits*/
+#define XCHAL_HW_CONFIGID1             0x054104B9      /* ConfigID lo 32 bits*/
+#define XCHAL_HW_VERSION_NAME          "LX1.0.2"       /* full version name */
+#define XCHAL_HW_VERSION_MAJOR         2100    /* major ver# of targeted hw */
+#define XCHAL_HW_VERSION_MINOR         2       /* minor ver# of targeted hw */
+#define XCHAL_HW_VERSION               210002  /* major*100+minor */
+#define XCHAL_HW_REL_LX1               1
+#define XCHAL_HW_REL_LX1_0             1
+#define XCHAL_HW_REL_LX1_0_2           1
+#define XCHAL_HW_CONFIGID_RELIABLE     1
+/*  If software targets a *range* of hardware versions, these are the bounds: */
+#define XCHAL_HW_MIN_VERSION_MAJOR     2100    /* major v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION_MINOR     2       /* minor v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION           210002  /* earliest targeted hw */
+#define XCHAL_HW_MAX_VERSION_MAJOR     2100    /* major v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MINOR     2       /* minor v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION           210002  /* latest targeted hw */
+
+
+/*----------------------------------------------------------------------
+                               CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_ICACHE_LINESIZE          16      /* I-cache line size in bytes */
+#define XCHAL_DCACHE_LINESIZE          16      /* D-cache line size in bytes */
+#define XCHAL_ICACHE_LINEWIDTH         4       /* log2(I line size in bytes) */
+#define XCHAL_DCACHE_LINEWIDTH         4       /* log2(D line size in bytes) */
+
+#define XCHAL_ICACHE_SIZE              32768   /* I-cache size in bytes or 0 */
+#define XCHAL_DCACHE_SIZE              32768   /* D-cache size in bytes or 0 */
+
+#define XCHAL_DCACHE_IS_WRITEBACK      1       /* writeback feature */
+
+
+
+
+/****************************************************************************
+    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
+ ****************************************************************************/
+
+
+#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
+
+/*----------------------------------------------------------------------
+                               CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_PIF                 1       /* any outbound PIF present */
+
+/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */
+
+/*  Number of cache sets in log2(lines per way):  */
+#define XCHAL_ICACHE_SETWIDTH          9
+#define XCHAL_DCACHE_SETWIDTH          10
+
+/*  Cache set associativity (number of ways):  */
+#define XCHAL_ICACHE_WAYS              4
+#define XCHAL_DCACHE_WAYS              2
+
+/*  Cache features:  */
+#define XCHAL_ICACHE_LINE_LOCKABLE     1
+#define XCHAL_DCACHE_LINE_LOCKABLE     0
+#define XCHAL_ICACHE_ECC_PARITY                0
+#define XCHAL_DCACHE_ECC_PARITY                0
+
+/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */
+#define XCHAL_CA_BITS                  4
+
+
+/*----------------------------------------------------------------------
+                       INTERNAL I/D RAM/ROMs and XLMI
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM              0       /* number of core instr. ROMs */
+#define XCHAL_NUM_INSTRAM              0       /* number of core instr. RAMs */
+#define XCHAL_NUM_DATAROM              0       /* number of core data ROMs */
+#define XCHAL_NUM_DATARAM              1       /* number of core data RAMs */
+#define XCHAL_NUM_URAM                 0       /* number of core unified RAMs*/
+#define XCHAL_NUM_XLMI                 1       /* number of core XLMI ports */
+
+/*  Data RAM 0:  */
+#define XCHAL_DATARAM0_VADDR           0x3FFF0000
+#define XCHAL_DATARAM0_PADDR           0x3FFF0000
+#define XCHAL_DATARAM0_SIZE            65536
+#define XCHAL_DATARAM0_ECC_PARITY      0
+
+/*  XLMI Port 0:  */
+#define XCHAL_XLMI0_VADDR              0x37F80000
+#define XCHAL_XLMI0_PADDR              0x37F80000
+#define XCHAL_XLMI0_SIZE               262144
+#define XCHAL_XLMI0_ECC_PARITY 0
+
+
+/*----------------------------------------------------------------------
+                       INTERRUPTS and TIMERS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS          1       /* interrupt option */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS  1       /* med/high-pri. interrupts */
+#define XCHAL_HAVE_NMI                 1       /* non-maskable interrupt */
+#define XCHAL_HAVE_CCOUNT              1       /* CCOUNT reg. (timer option) */
+#define XCHAL_NUM_TIMERS               3       /* number of CCOMPAREn regs */
+#define XCHAL_NUM_INTERRUPTS           27      /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2      5       /* ceil(log2(NUM_INTERRUPTS)) */
+#define XCHAL_NUM_EXTINTERRUPTS                20      /* num of external interrupts */
+#define XCHAL_NUM_INTLEVELS            4       /* number of interrupt levels
+                                                  (not including level zero) */
+#define XCHAL_EXCM_LEVEL               1       /* level masked by PS.EXCM */
+       /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
+
+/*  Masks of interrupts at each interrupt level:  */
+#define XCHAL_INTLEVEL1_MASK           0x01F07FFF
+#define XCHAL_INTLEVEL2_MASK           0x02018000
+#define XCHAL_INTLEVEL3_MASK           0x04060000
+#define XCHAL_INTLEVEL4_MASK           0x00000000
+#define XCHAL_INTLEVEL5_MASK           0x00080000
+#define XCHAL_INTLEVEL6_MASK           0x00000000
+#define XCHAL_INTLEVEL7_MASK           0x00000000
+
+/*  Masks of interrupts at each range 1..n of interrupt levels:  */
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK  0x01F07FFF
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK  0x03F1FFFF
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK  0x07F7FFFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK  0x07F7FFFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK  0x07FFFFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK  0x07FFFFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK  0x07FFFFFF
+
+/*  Level of each interrupt:  */
+#define XCHAL_INT0_LEVEL               1
+#define XCHAL_INT1_LEVEL               1
+#define XCHAL_INT2_LEVEL               1
+#define XCHAL_INT3_LEVEL               1
+#define XCHAL_INT4_LEVEL               1
+#define XCHAL_INT5_LEVEL               1
+#define XCHAL_INT6_LEVEL               1
+#define XCHAL_INT7_LEVEL               1
+#define XCHAL_INT8_LEVEL               1
+#define XCHAL_INT9_LEVEL               1
+#define XCHAL_INT10_LEVEL              1
+#define XCHAL_INT11_LEVEL              1
+#define XCHAL_INT12_LEVEL              1
+#define XCHAL_INT13_LEVEL              1
+#define XCHAL_INT14_LEVEL              1
+#define XCHAL_INT15_LEVEL              2
+#define XCHAL_INT16_LEVEL              2
+#define XCHAL_INT17_LEVEL              3
+#define XCHAL_INT18_LEVEL              3
+#define XCHAL_INT19_LEVEL              5
+#define XCHAL_INT20_LEVEL              1
+#define XCHAL_INT21_LEVEL              1
+#define XCHAL_INT22_LEVEL              1
+#define XCHAL_INT23_LEVEL              1
+#define XCHAL_INT24_LEVEL              1
+#define XCHAL_INT25_LEVEL              2
+#define XCHAL_INT26_LEVEL              3
+#define XCHAL_DEBUGLEVEL               4       /* debug interrupt level */
+#define XCHAL_HAVE_DEBUG_EXTERN_INT    1       /* OCD external db interrupt */
+#define XCHAL_NMILEVEL                 5       /* NMI "level" (for use with
+                                                  EXCSAVE/EPS/EPC_n, RFI n) */
+
+/*  Type of each interrupt:  */
+#define XCHAL_INT0_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT7_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT8_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT9_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT10_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT11_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT12_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT13_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT14_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT15_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT16_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT17_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT18_TYPE       XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT19_TYPE       XTHAL_INTTYPE_NMI
+#define XCHAL_INT20_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT21_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT22_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT23_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT24_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT25_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT26_TYPE       XTHAL_INTTYPE_TIMER
+
+/*  Masks of interrupts for each type of interrupt:  */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED        0xF8000000
+#define XCHAL_INTTYPE_MASK_SOFTWARE    0x00F00000
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000000
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL        0x0007FFFF
+#define XCHAL_INTTYPE_MASK_TIMER       0x07000000
+#define XCHAL_INTTYPE_MASK_NMI         0x00080000
+#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000
+
+/*  Interrupt numbers assigned to specific interrupt sources:  */
+#define XCHAL_TIMER0_INTERRUPT         24      /* CCOMPARE0 */
+#define XCHAL_TIMER1_INTERRUPT         25      /* CCOMPARE1 */
+#define XCHAL_TIMER2_INTERRUPT         26      /* CCOMPARE2 */
+#define XCHAL_TIMER3_INTERRUPT         XTHAL_TIMER_UNCONFIGURED
+#define XCHAL_NMI_INTERRUPT            19      /* non-maskable interrupt */
+
+/*  Interrupt numbers for levels at which only one interrupt is configured:  */
+#define XCHAL_INTLEVEL5_NUM            19
+/*  (There are many interrupts each at level(s) 1, 2, 3.)  */
+
+
+/*
+ *  External interrupt vectors/levels.
+ *  These macros describe how Xtensa processor interrupt numbers
+ *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ *  map to external BInterrupt<n> pins, for those interrupts
+ *  configured as external (level-triggered, edge-triggered, or NMI).
+ *  See the Xtensa processor databook for more details.
+ */
+
+/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */
+#define XCHAL_EXTINT0_NUM              0       /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM              1       /* (intlevel 1) */
+#define XCHAL_EXTINT2_NUM              2       /* (intlevel 1) */
+#define XCHAL_EXTINT3_NUM              3       /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM              4       /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM              5       /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM              6       /* (intlevel 1) */
+#define XCHAL_EXTINT7_NUM              7       /* (intlevel 1) */
+#define XCHAL_EXTINT8_NUM              8       /* (intlevel 1) */
+#define XCHAL_EXTINT9_NUM              9       /* (intlevel 1) */
+#define XCHAL_EXTINT10_NUM             10      /* (intlevel 1) */
+#define XCHAL_EXTINT11_NUM             11      /* (intlevel 1) */
+#define XCHAL_EXTINT12_NUM             12      /* (intlevel 1) */
+#define XCHAL_EXTINT13_NUM             13      /* (intlevel 1) */
+#define XCHAL_EXTINT14_NUM             14      /* (intlevel 1) */
+#define XCHAL_EXTINT15_NUM             15      /* (intlevel 2) */
+#define XCHAL_EXTINT16_NUM             16      /* (intlevel 2) */
+#define XCHAL_EXTINT17_NUM             17      /* (intlevel 3) */
+#define XCHAL_EXTINT18_NUM             18      /* (intlevel 3) */
+#define XCHAL_EXTINT19_NUM             19      /* (intlevel 5) */
+
+
+/*----------------------------------------------------------------------
+                       EXCEPTIONS and VECTORS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_XEA_VERSION              2       /* Xtensa Exception Architecture
+                                                  number: 1 == XEA1 (old)
+                                                          2 == XEA2 (new)
+                                                          0 == XEAX (extern) */
+#define XCHAL_HAVE_XEA1                        0       /* Exception Architecture 1 */
+#define XCHAL_HAVE_XEA2                        1       /* Exception Architecture 2 */
+#define XCHAL_HAVE_XEAX                        0       /* External Exception Arch. */
+#define XCHAL_HAVE_EXCEPTIONS          1       /* exception option */
+#define XCHAL_HAVE_MEM_ECC_PARITY      0       /* local memory ECC/parity */
+#define XCHAL_HAVE_VECTOR_SELECT       0       /* relocatable vectors */
+#define XCHAL_HAVE_VECBASE             0       /* relocatable vectors */
+
+#define XCHAL_RESET_VECOFS             0x00000000
+#define XCHAL_RESET_VECTOR_VADDR       0x3FFE03D0
+#define XCHAL_RESET_VECTOR_PADDR       0x3FFE03D0
+#define XCHAL_USER_VECOFS              0x00000000
+#define XCHAL_USER_VECTOR_VADDR                0x40000220
+#define XCHAL_USER_VECTOR_PADDR                0x40000220
+#define XCHAL_KERNEL_VECOFS            0x00000000
+#define XCHAL_KERNEL_VECTOR_VADDR      0x40000200
+#define XCHAL_KERNEL_VECTOR_PADDR      0x40000200
+#define XCHAL_DOUBLEEXC_VECOFS         0x00000000
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR   0x400002A0
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR   0x400002A0
+#define XCHAL_WINDOW_OF4_VECOFS                0x00000000
+#define XCHAL_WINDOW_UF4_VECOFS                0x00000040
+#define XCHAL_WINDOW_OF8_VECOFS                0x00000080
+#define XCHAL_WINDOW_UF8_VECOFS                0x000000C0
+#define XCHAL_WINDOW_OF12_VECOFS       0x00000100
+#define XCHAL_WINDOW_UF12_VECOFS       0x00000140
+#define XCHAL_WINDOW_VECTORS_VADDR     0x40000000
+#define XCHAL_WINDOW_VECTORS_PADDR     0x40000000
+#define XCHAL_INTLEVEL2_VECOFS         0x00000000
+#define XCHAL_INTLEVEL2_VECTOR_VADDR   0x40000240
+#define XCHAL_INTLEVEL2_VECTOR_PADDR   0x40000240
+#define XCHAL_INTLEVEL3_VECOFS         0x00000000
+#define XCHAL_INTLEVEL3_VECTOR_VADDR   0x40000260
+#define XCHAL_INTLEVEL3_VECTOR_PADDR   0x40000260
+#define XCHAL_INTLEVEL4_VECOFS         0x00000000
+#define XCHAL_INTLEVEL4_VECTOR_VADDR   0x40000390
+#define XCHAL_INTLEVEL4_VECTOR_PADDR   0x40000390
+#define XCHAL_DEBUG_VECOFS             XCHAL_INTLEVEL4_VECOFS
+#define XCHAL_DEBUG_VECTOR_VADDR       XCHAL_INTLEVEL4_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR       XCHAL_INTLEVEL4_VECTOR_PADDR
+#define XCHAL_NMI_VECOFS               0x00000000
+#define XCHAL_NMI_VECTOR_VADDR         0x400003B0
+#define XCHAL_NMI_VECTOR_PADDR         0x400003B0
+#define XCHAL_INTLEVEL5_VECOFS         XCHAL_NMI_VECOFS
+#define XCHAL_INTLEVEL5_VECTOR_VADDR   XCHAL_NMI_VECTOR_VADDR
+#define XCHAL_INTLEVEL5_VECTOR_PADDR   XCHAL_NMI_VECTOR_PADDR
+
+
+/*----------------------------------------------------------------------
+                               DEBUG
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_OCD                 1       /* OnChipDebug option */
+#define XCHAL_NUM_IBREAK               2       /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK               2       /* number of DBREAKn regs */
+#define XCHAL_HAVE_OCD_DIR_ARRAY       1       /* faster OCD option */
+
+
+/*----------------------------------------------------------------------
+                               MMU
+  ----------------------------------------------------------------------*/
+
+/*  See core-matmap.h header file for more details.  */
+
+#define XCHAL_HAVE_TLBS                        1       /* inverse of HAVE_CACHEATTR */
+#define XCHAL_HAVE_SPANNING_WAY                1       /* one way maps I+D 4GB vaddr */
+#define XCHAL_HAVE_IDENTITY_MAP                1       /* vaddr == paddr always */
+#define XCHAL_HAVE_CACHEATTR           0       /* CACHEATTR register present */
+#define XCHAL_HAVE_MIMIC_CACHEATTR     1       /* region protection */
+#define XCHAL_HAVE_XLT_CACHEATTR       0       /* region prot. w/translation */
+#define XCHAL_HAVE_PTP_MMU             0       /* full MMU (with page table
+                                                  [autorefill] and protection)
+                                                  usable for an MMU-based OS */
+/*  If none of the above last 4 are set, it's a custom TLB configuration.  */
+
+#define XCHAL_MMU_ASID_BITS            0       /* number of bits in ASIDs */
+#define XCHAL_MMU_RINGS                        1       /* number of rings (1..4) */
+#define XCHAL_MMU_RING_BITS            0       /* num of bits in RING field */
+
+#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
+
+
+#endif /* _XTENSA_CORE_CONFIGURATION_H */
+
diff --git a/arch/xtensa/variants/s6000/include/variant/hardware.h b/arch/xtensa/variants/s6000/include/variant/hardware.h
new file mode 100644 (file)
index 0000000..5d9ba09
--- /dev/null
@@ -0,0 +1,259 @@
+#ifndef __XTENSA_S6000_HARDWARE_H
+#define __XTENSA_S6000_HARDWARE_H
+
+#define S6_SCLK                        1843200
+
+#define S6_MEM_REG              0x20000000
+#define S6_MEM_EFI              0x33F00000
+#define S6_MEM_PCIE_DATARAM1    0x34000000
+#define S6_MEM_XLMI             0x37F80000
+#define S6_MEM_PIF_DATARAM1     0x37FFC000
+#define S6_MEM_GMAC             0x38000000
+#define S6_MEM_I2S              0x3A000000
+#define S6_MEM_EGIB             0x3C000000
+#define S6_MEM_PCIE_CFG         0x3E000000
+#define S6_MEM_PIF_DATARAM      0x3FFE0000
+#define S6_MEM_XLMI_DATARAM     0x3FFF0000
+#define S6_MEM_DDR              0x40000000
+#define S6_MEM_PCIE_APER        0xC0000000
+#define S6_MEM_AUX              0xF0000000
+
+/* Device addresses */
+
+#define S6_REG_SCB              S6_MEM_REG
+#define S6_REG_NB               (S6_REG_SCB + 0x10000)
+#define S6_REG_LMSDMA           (S6_REG_SCB + 0x20000)
+#define S6_REG_NI               (S6_REG_SCB + 0x30000)
+#define S6_REG_NIDMA            (S6_REG_SCB + 0x40000)
+#define S6_REG_NS               (S6_REG_SCB + 0x50000)
+#define S6_REG_DDR              (S6_REG_SCB + 0x60000)
+#define S6_REG_GREG1            (S6_REG_SCB + 0x70000)
+#define S6_REG_DP               (S6_REG_SCB + 0x80000)
+#define S6_REG_DPDMA            (S6_REG_SCB + 0x90000)
+#define S6_REG_EGIB             (S6_REG_SCB + 0xA0000)
+#define S6_REG_PCIE             (S6_REG_SCB + 0xB0000)
+#define S6_REG_I2S              (S6_REG_SCB + 0xC0000)
+#define S6_REG_GMAC             (S6_REG_SCB + 0xD0000)
+#define S6_REG_HIFDMA           (S6_REG_SCB + 0xE0000)
+#define S6_REG_GREG2            (S6_REG_SCB + 0xF0000)
+
+#define S6_REG_APB              S6_REG_SCB
+#define S6_REG_UART             (S6_REG_APB + 0x0000)
+#define S6_REG_INTC             (S6_REG_APB + 0x2000)
+#define S6_REG_SPI              (S6_REG_APB + 0x3000)
+#define S6_REG_I2C              (S6_REG_APB + 0x4000)
+#define S6_REG_GPIO             (S6_REG_APB + 0x8000)
+
+/* Global register block */
+
+#define S6_GREG1_PLL_LOCKCLEAR 0x000
+#define S6_GREG1_PLL_LOCK_SYS          0
+#define S6_GREG1_PLL_LOCK_IO           1
+#define S6_GREG1_PLL_LOCK_AIM          2
+#define S6_GREG1_PLL_LOCK_DP0          3
+#define S6_GREG1_PLL_LOCK_DP2          4
+#define S6_GREG1_PLL_LOCK_DDR          5
+#define S6_GREG1_PLL_LOCKSTAT  0x004
+#define S6_GREG1_PLL_LOCKSTAT_CURLOCK  0
+#define S6_GREG1_PLL_LOCKSTAT_EVERUNLCK        8
+#define S6_GREG1_PLLSEL                0x010
+#define S6_GREG1_PLLSEL_AIM            0
+#define S6_GREG1_PLLSEL_AIM_DDR2               0
+#define S6_GREG1_PLLSEL_AIM_300MHZ             1
+#define S6_GREG1_PLLSEL_AIM_240MHZ             2
+#define S6_GREG1_PLLSEL_AIM_200MHZ             3
+#define S6_GREG1_PLLSEL_AIM_150MHZ             4
+#define S6_GREG1_PLLSEL_AIM_120MHZ             5
+#define S6_GREG1_PLLSEL_AIM_40MHZ              6
+#define S6_GREG1_PLLSEL_AIM_PLLAIMREF          7
+#define S6_GREG1_PLLSEL_AIM_MASK               7
+#define S6_GREG1_PLLSEL_DDR            8
+#define S6_GREG1_PLLSEL_DDR_HS                 0
+#define S6_GREG1_PLLSEL_DDR_333MHZ             1
+#define S6_GREG1_PLLSEL_DDR_250MHZ             2
+#define S6_GREG1_PLLSEL_DDR_200MHZ             3
+#define S6_GREG1_PLLSEL_DDR_167MHZ             4
+#define S6_GREG1_PLLSEL_DDR_100MHZ             5
+#define S6_GREG1_PLLSEL_DDR_33MHZ              6
+#define S6_GREG1_PLLSEL_DDR_PLLIOREF           7
+#define S6_GREG1_PLLSEL_DDR_MASK               7
+#define S6_GREG1_PLLSEL_GMAC           16
+#define S6_GREG1_PLLSEL_GMAC_125MHZ            0
+#define S6_GREG1_PLLSEL_GMAC_25MHZ             1
+#define S6_GREG1_PLLSEL_GMAC_2500KHZ           2
+#define S6_GREG1_PLLSEL_GMAC_EXTERN            3
+#define S6_GREG1_PLLSEL_GMAC_MASK              3
+#define S6_GREG1_PLLSEL_GMII           18
+#define S6_GREG1_PLLSEL_GMII_111MHZ            0
+#define S6_GREG1_PLLSEL_GMII_IOREF             1
+#define S6_GREG1_PLLSEL_GMII_NONE              2
+#define S6_GREG1_PLLSEL_GMII_125MHZ            3
+#define S6_GREG1_PLLSEL_GMII_MASK              3
+#define S6_GREG1_SYSUNLOCKCNT  0x020
+#define S6_GREG1_IOUNLOCKCNT   0x024
+#define S6_GREG1_AIMUNLOCKCNT  0x028
+#define S6_GREG1_DP0UNLOCKCNT  0x02C
+#define S6_GREG1_DP2UNLOCKCNT  0x030
+#define S6_GREG1_DDRUNLOCKCNT  0x034
+#define S6_GREG1_CLKBAL0       0x040
+#define S6_GREG1_CLKBAL0_LSGB          0
+#define S6_GREG1_CLKBAL0_LSPX          8
+#define S6_GREG1_CLKBAL0_MEMDO         16
+#define S6_GREG1_CLKBAL0_HSXT1         24
+#define S6_GREG1_CLKBAL1       0x044
+#define S6_GREG1_CLKBAL1_HSISEF                0
+#define S6_GREG1_CLKBAL1_HSNI          8
+#define S6_GREG1_CLKBAL1_HSNS          16
+#define S6_GREG1_CLKBAL1_HSISEFCFG     24
+#define S6_GREG1_CLKBAL2       0x048
+#define S6_GREG1_CLKBAL2_LSNB          0
+#define S6_GREG1_CLKBAL2_LSSB          8
+#define S6_GREG1_CLKBAL2_LSREST                24
+#define S6_GREG1_CLKBAL3       0x04C
+#define S6_GREG1_CLKBAL3_ISEFXAD       0
+#define S6_GREG1_CLKBAL3_ISEFLMS       8
+#define S6_GREG1_CLKBAL3_ISEFISEF      16
+#define S6_GREG1_CLKBAL3_DDRDD         24
+#define S6_GREG1_CLKBAL4       0x050
+#define S6_GREG1_CLKBAL4_DDRDP         0
+#define S6_GREG1_CLKBAL4_DDRDO         8
+#define S6_GREG1_CLKBAL4_DDRNB         16
+#define S6_GREG1_CLKBAL4_DDRLMS                24
+#define S6_GREG1_BLOCKENA      0x100
+#define S6_GREG1_BLOCK_DDR             0
+#define S6_GREG1_BLOCK_DP              1
+#define S6_GREG1_BLOCK_NSNI            2
+#define S6_GREG1_BLOCK_PCIE            3
+#define S6_GREG1_BLOCK_GMAC            4
+#define S6_GREG1_BLOCK_I2S             5
+#define S6_GREG1_BLOCK_EGIB            6
+#define S6_GREG1_BLOCK_SB              7
+#define S6_GREG1_BLOCK_XT1             8
+#define S6_GREG1_CLKGATE       0x104
+#define S6_GREG1_BGATE_AIMNORTH                9
+#define S6_GREG1_BGATE_AIMEAST         10
+#define S6_GREG1_BGATE_AIMWEST         11
+#define S6_GREG1_BGATE_AIMSOUTH                12
+#define S6_GREG1_CHIPRES       0x108
+#define S6_GREG1_CHIPRES_SOFTRES       0
+#define S6_GREG1_CHIPRES_LOSTLOCK      1
+#define S6_GREG1_RESETCAUSE    0x10C
+#define S6_GREG1_RESETCAUSE_RESETN     0
+#define S6_GREG1_RESETCAUSE_GLOBAL     1
+#define S6_GREG1_RESETCAUSE_WDOGTIMER  2
+#define S6_GREG1_RESETCAUSE_SWCHIP     3
+#define S6_GREG1_RESETCAUSE_PLLSYSLOSS 4
+#define S6_GREG1_RESETCAUSE_PCIE       5
+#define S6_GREG1_RESETCAUSE_CREATEDGLOB        6
+#define S6_GREG1_REFCLOCKCNT   0x110
+#define S6_GREG1_RESETTIMER    0x114
+#define S6_GREG1_NMITIMER      0x118
+#define S6_GREG1_GLOBAL_TIMER  0x11C
+#define S6_GREG1_TIMER0                0x180
+#define S6_GREG1_TIMER1                0x184
+#define S6_GREG1_UARTCLOCKSEL  0x204
+#define S6_GREG1_CHIPVERSPACKG 0x208
+#define S6_GREG1_CHIPVERSPACKG_CHIPVID 0
+#define S6_GREG1_CHIPVERSPACKG_PACKSEL 8
+#define S6_GREG1_ONDIETERMCTRL 0x20C
+#define S6_GREG1_ONDIETERMCTRL_WEST    0
+#define S6_GREG1_ONDIETERMCTRL_NORTH   2
+#define S6_GREG1_ONDIETERMCTRL_EAST    4
+#define S6_GREG1_ONDIETERMCTRL_SOUTH   6
+#define S6_GREG1_ONDIETERMCTRL_NONE            0
+#define S6_GREG1_ONDIETERMCTRL_75OHM           2
+#define S6_GREG1_ONDIETERMCTRL_MASK            3
+#define S6_GREG1_BOOT_CFG0     0x210
+#define S6_GREG1_BOOT_CFG0_AIMSTRONG   1
+#define S6_GREG1_BOOT_CFG0_MINIBOOTDL  2
+#define S6_GREG1_BOOT_CFG0_OCDGPIO8SET 5
+#define S6_GREG1_BOOT_CFG0_OCDGPIOENA  6
+#define S6_GREG1_BOOT_CFG0_DOWNSTREAM  7
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV   8
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_300MHZ    1
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_240MHZ    2
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_200MHZ    3
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_150MHZ    4
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_120MHZ    5
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_40MHZ     6
+#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_MASK      7
+#define S6_GREG1_BOOT_CFG0_BALHSLMS    12
+#define S6_GREG1_BOOT_CFG0_BALHSNB     18
+#define S6_GREG1_BOOT_CFG0_BALHSXAD    24
+#define S6_GREG1_BOOT_CFG1     0x214
+#define S6_GREG1_BOOT_CFG1_PCIE1LANE   1
+#define S6_GREG1_BOOT_CFG1_MPLLPRESCALE        2
+#define S6_GREG1_BOOT_CFG1_MPLLNCY     4
+#define S6_GREG1_BOOT_CFG1_MPLLNCY5    9
+#define S6_GREG1_BOOT_CFG1_BALHSREST   14
+#define S6_GREG1_BOOT_CFG1_BALHSPSMEMS 20
+#define S6_GREG1_BOOT_CFG1_BALLSGI     26
+#define S6_GREG1_BOOT_CFG2     0x218
+#define S6_GREG1_BOOT_CFG2_PEID                0
+#define S6_GREG1_BOOT_CFG3     0x21C
+#define S6_GREG1_DRAMBUSYHOLDOF        0x220
+#define S6_GREG1_DRAMBUSYHOLDOF_XT0    0
+#define S6_GREG1_DRAMBUSYHOLDOF_XT1    4
+#define S6_GREG1_DRAMBUSYHOLDOF_XT_MASK                7
+#define S6_GREG1_PCIEBAR1SIZE  0x224
+#define S6_GREG1_PCIEBAR2SIZE  0x228
+#define S6_GREG1_PCIEVENDOR    0x22C
+#define S6_GREG1_PCIEDEVICE    0x230
+#define S6_GREG1_PCIEREV       0x234
+#define S6_GREG1_PCIECLASS     0x238
+#define S6_GREG1_XT1DCACHEMISS 0x240
+#define S6_GREG1_XT1ICACHEMISS 0x244
+#define S6_GREG1_HWSEMAPHORE(n)        (0x400 + 4 * (n))
+#define S6_GREG1_HWSEMAPHORE_NB                16
+
+/* peripheral interrupt numbers */
+
+#define S6_INTC_GPIO(n)                        (n)             /* 0..3 */
+#define S6_INTC_I2C                    4
+#define S6_INTC_SPI                    5
+#define S6_INTC_NB_ERR                 6
+#define S6_INTC_DMA_LMSERR             7
+#define S6_INTC_DMA_LMSLOWWMRK(n)      (8 + (n))       /* 0..11 */
+#define S6_INTC_DMA_LMSPENDCNT(n)      (20 + (n))      /* 0..11 */
+#define S6_INTC_DMA HOSTLOWWMRK(n)     (32 + (n))      /* 0..6 */
+#define S6_INTC_DMA_HOSTPENDCNT(n)     (39 + (n))      /* 0..6 */
+#define S6_INTC_DMA_HOSTERR            46
+#define S6_INTC_UART(n)                        (47 + (n))      /* 0..1 */
+#define S6_INTC_XAD                    49
+#define S6_INTC_NI_ERR                 50
+#define S6_INTC_NI_INFIFOFULL          51
+#define S6_INTC_DMA_NIERR              52
+#define S6_INTC_DMA_NILOWWMRK(n)       (53 + (n))      /* 0..3 */
+#define S6_INTC_DMA_NIPENDCNT(n)       (57 + (n))      /* 0..3 */
+#define S6_INTC_DDR                    61
+#define S6_INTC_NS_ERR                 62
+#define S6_INTC_EFI_CFGERR             63
+#define S6_INTC_EFI_ISEFTEST           64
+#define S6_INTC_EFI_WRITEERR           65
+#define S6_INTC_NMI_TIMER              66
+#define S6_INTC_PLLLOCK_SYS            67
+#define S6_INTC_PLLLOCK_IO             68
+#define S6_INTC_PLLLOCK_AIM            69
+#define S6_INTC_PLLLOCK_DP0            70
+#define S6_INTC_PLLLOCK_DP2            71
+#define S6_INTC_I2S_ERR                        72
+#define S6_INTC_GMAC_STAT              73
+#define S6_INTC_GMAC_ERR               74
+#define S6_INTC_GIB_ERR                        75
+#define S6_INTC_PCIE_ERR               76
+#define S6_INTC_PCIE_MSI(n)            (77 + (n))      /* 0..3 */
+#define S6_INTC_PCIE_INTA              81
+#define S6_INTC_PCIE_INTB              82
+#define S6_INTC_PCIE_INTC              83
+#define S6_INTC_PCIE_INTD              84
+#define S6_INTC_SW(n)                  (85 + (n))      /* 0..9 */
+#define S6_INTC_SW_ENABLE(n)           (85 + 256 + (n))
+#define S6_INTC_DMA_DP_ERR             95
+#define S6_INTC_DMA_DPLOWWMRK(n)       (96 + (n))      /* 0..3 */
+#define S6_INTC_DMA_DPPENDCNT(n)       (100 + (n))     /* 0..3 */
+#define S6_INTC_DMA_DPTERMCNT(n)       (104 + (n))     /* 0..3 */
+#define S6_INTC_TIMER0                 108
+#define S6_INTC_TIMER1                 109
+#define S6_INTC_DMA_HOSTTERMCNT(n)     (110 + (n))     /* 0..6 */
+
+#endif /* __XTENSA_S6000_HARDWARE_H */
diff --git a/arch/xtensa/variants/s6000/include/variant/irq.h b/arch/xtensa/variants/s6000/include/variant/irq.h
new file mode 100644 (file)
index 0000000..fa031cb
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __XTENSA_S6000_IRQ_H
+#define __XTENSA_S6000_IRQ_H
+
+#define NO_IRQ         (-1)
+
+extern void variant_irq_enable(unsigned int irq);
+extern void variant_irq_disable(unsigned int irq);
+
+#endif /* __XTENSA_S6000_IRQ_H */
diff --git a/arch/xtensa/variants/s6000/include/variant/tie-asm.h b/arch/xtensa/variants/s6000/include/variant/tie-asm.h
new file mode 100644 (file)
index 0000000..f02d0a3
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * This header file contains assembly-language definitions (assembly
+ * macros, etc.) for this specific Xtensa processor's TIE extensions
+ * and options.  It is customized to this Xtensa processor configuration.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2008 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_TIE_ASM_H
+#define _XTENSA_CORE_TIE_ASM_H
+
+/*  Selection parameter values for save-area save/restore macros:  */
+/*  Option vs. TIE:  */
+#define XTHAL_SAS_TIE  0x0001  /* custom extension or coprocessor */
+#define XTHAL_SAS_OPT  0x0002  /* optional (and not a coprocessor) */
+/*  Whether used automatically by compiler:  */
+#define XTHAL_SAS_NOCC 0x0004  /* not used by compiler w/o special opts/code */
+#define XTHAL_SAS_CC   0x0008  /* used by compiler without special opts/code */
+/*  ABI handling across function calls:  */
+#define XTHAL_SAS_CALR 0x0010  /* caller-saved */
+#define XTHAL_SAS_CALE 0x0020  /* callee-saved */
+#define XTHAL_SAS_GLOB 0x0040  /* global across function calls (in thread) */
+/*  Misc  */
+#define XTHAL_SAS_ALL  0xFFFF  /* include all default NCP contents */
+
+
+
+/* Macro to save all non-coprocessor (extra) custom TIE and optional state
+ * (not including zero-overhead loop registers).
+ * Save area ptr (clobbered):  ptr  (16 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_NCP_NUM_ATMPS needed)
+ */
+       .macro xchal_ncp_store  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+       xchal_sa_start  \continue, \ofs
+       .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
+       xchal_sa_align  \ptr, 0, 1024-4, 4, 4
+       rsr     \at1, BR                // boolean option
+       s32i    \at1, \ptr, .Lxchal_ofs_ + 0
+       .set    .Lxchal_ofs_, .Lxchal_ofs_ + 4
+       .endif
+       .endm   // xchal_ncp_store
+
+/* Macro to save all non-coprocessor (extra) custom TIE and optional state
+ * (not including zero-overhead loop registers).
+ * Save area ptr (clobbered):  ptr  (16 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_NCP_NUM_ATMPS needed)
+ */
+       .macro xchal_ncp_load  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+       xchal_sa_start  \continue, \ofs
+       .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
+       xchal_sa_align  \ptr, 0, 1024-4, 4, 4
+       l32i    \at1, \ptr, .Lxchal_ofs_ + 0
+       wsr     \at1, BR                // boolean option
+       .set    .Lxchal_ofs_, .Lxchal_ofs_ + 4
+       .endif
+       .endm   // xchal_ncp_load
+
+
+
+#define XCHAL_NCP_NUM_ATMPS    1
+
+
+
+/* Macro to save the state of TIE coprocessor FPU.
+ * Save area ptr (clobbered):  ptr  (16 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_CP0_NUM_ATMPS needed)
+ */
+#define xchal_cp_FPU_store     xchal_cp0_store
+/* #define xchal_cp_FPU_store_a2       xchal_cp0_store a2 a3 a4 a5 a6 */
+       .macro  xchal_cp0_store  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+       xchal_sa_start \continue, \ofs
+       .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
+       xchal_sa_align  \ptr, 0, 0, 1, 16
+       rur232  \at1            // FCR
+       s32i    \at1, \ptr, 0
+       rur233  \at1            // FSR
+       s32i    \at1, \ptr, 4
+       SSI f0, \ptr,  8
+       SSI f1, \ptr,  12
+       SSI f2, \ptr,  16
+       SSI f3, \ptr,  20
+       SSI f4, \ptr,  24
+       SSI f5, \ptr,  28
+       SSI f6, \ptr,  32
+       SSI f7, \ptr,  36
+       SSI f8, \ptr,  40
+       SSI f9, \ptr,  44
+       SSI f10, \ptr,  48
+       SSI f11, \ptr,  52
+       SSI f12, \ptr,  56
+       SSI f13, \ptr,  60
+       SSI f14, \ptr,  64
+       SSI f15, \ptr,  68
+       .set    .Lxchal_ofs_, .Lxchal_ofs_ + 72
+       .endif
+       .endm   // xchal_cp0_store
+
+/* Macro to restore the state of TIE coprocessor FPU.
+ * Save area ptr (clobbered):  ptr  (16 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_CP0_NUM_ATMPS needed)
+ */
+#define xchal_cp_FPU_load      xchal_cp0_load
+/* #define xchal_cp_FPU_load_a2        xchal_cp0_load a2 a3 a4 a5 a6 */
+       .macro  xchal_cp0_load  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+       xchal_sa_start \continue, \ofs
+       .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
+       xchal_sa_align  \ptr, 0, 0, 1, 16
+       l32i    \at1, \ptr, 0
+       wur232  \at1            // FCR
+       l32i    \at1, \ptr, 4
+       wur233  \at1            // FSR
+       LSI f0, \ptr,  8
+       LSI f1, \ptr,  12
+       LSI f2, \ptr,  16
+       LSI f3, \ptr,  20
+       LSI f4, \ptr,  24
+       LSI f5, \ptr,  28
+       LSI f6, \ptr,  32
+       LSI f7, \ptr,  36
+       LSI f8, \ptr,  40
+       LSI f9, \ptr,  44
+       LSI f10, \ptr,  48
+       LSI f11, \ptr,  52
+       LSI f12, \ptr,  56
+       LSI f13, \ptr,  60
+       LSI f14, \ptr,  64
+       LSI f15, \ptr,  68
+       .set    .Lxchal_ofs_, .Lxchal_ofs_ + 72
+       .endif
+       .endm   // xchal_cp0_load
+
+#define XCHAL_CP0_NUM_ATMPS    1
+
+/* Macro to save the state of TIE coprocessor XAD.
+ * Save area ptr (clobbered):  ptr  (16 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_CP6_NUM_ATMPS needed)
+ */
+#define xchal_cp_XAD_store     xchal_cp6_store
+/* #define xchal_cp_XAD_store_a2       xchal_cp6_store a2 a3 a4 a5 a6 */
+       .macro  xchal_cp6_store  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+       xchal_sa_start \continue, \ofs
+       .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
+       xchal_sa_align  \ptr, 0, 0, 1, 16
+       rur0    \at1            // LDCBHI
+       s32i    \at1, \ptr, 0
+       rur1    \at1            // LDCBLO
+       s32i    \at1, \ptr, 4
+       rur2    \at1            // STCBHI
+       s32i    \at1, \ptr, 8
+       rur3    \at1            // STCBLO
+       s32i    \at1, \ptr, 12
+       rur8    \at1            // LDBRBASE
+       s32i    \at1, \ptr, 16
+       rur9    \at1            // LDBROFF
+       s32i    \at1, \ptr, 20
+       rur10   \at1            // LDBRINC
+       s32i    \at1, \ptr, 24
+       rur11   \at1            // STBRBASE
+       s32i    \at1, \ptr, 28
+       rur12   \at1            // STBROFF
+       s32i    \at1, \ptr, 32
+       rur13   \at1            // STBRINC
+       s32i    \at1, \ptr, 36
+       rur24   \at1            // SCRATCH0
+       s32i    \at1, \ptr, 40
+       rur25   \at1            // SCRATCH1
+       s32i    \at1, \ptr, 44
+       rur26   \at1            // SCRATCH2
+       s32i    \at1, \ptr, 48
+       rur27   \at1            // SCRATCH3
+       s32i    \at1, \ptr, 52
+       WRAS128I wra0, \ptr,  64
+       WRAS128I wra1, \ptr,  80
+       WRAS128I wra2, \ptr,  96
+       WRAS128I wra3, \ptr,  112
+       WRAS128I wra4, \ptr,  128
+       WRAS128I wra5, \ptr,  144
+       WRAS128I wra6, \ptr,  160
+       WRAS128I wra7, \ptr,  176
+       WRAS128I wra8, \ptr,  192
+       WRAS128I wra9, \ptr,  208
+       WRAS128I wra10, \ptr,  224
+       WRAS128I wra11, \ptr,  240
+       WRAS128I wra12, \ptr,  256
+       WRAS128I wra13, \ptr,  272
+       WRAS128I wra14, \ptr,  288
+       WRAS128I wra15, \ptr,  304
+       WRBS128I wrb0, \ptr,  320
+       WRBS128I wrb1, \ptr,  336
+       WRBS128I wrb2, \ptr,  352
+       WRBS128I wrb3, \ptr,  368
+       WRBS128I wrb4, \ptr,  384
+       WRBS128I wrb5, \ptr,  400
+       WRBS128I wrb6, \ptr,  416
+       WRBS128I wrb7, \ptr,  432
+       WRBS128I wrb8, \ptr,  448
+       WRBS128I wrb9, \ptr,  464
+       WRBS128I wrb10, \ptr,  480
+       WRBS128I wrb11, \ptr,  496
+       WRBS128I wrb12, \ptr,  512
+       WRBS128I wrb13, \ptr,  528
+       WRBS128I wrb14, \ptr,  544
+       WRBS128I wrb15, \ptr,  560
+       .set    .Lxchal_ofs_, .Lxchal_ofs_ + 576
+       .endif
+       .endm   // xchal_cp6_store
+
+/* Macro to restore the state of TIE coprocessor XAD.
+ * Save area ptr (clobbered):  ptr  (16 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_CP6_NUM_ATMPS needed)
+ */
+#define xchal_cp_XAD_load      xchal_cp6_load
+/* #define xchal_cp_XAD_load_a2        xchal_cp6_load a2 a3 a4 a5 a6 */
+       .macro  xchal_cp6_load  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+       xchal_sa_start \continue, \ofs
+       .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
+       xchal_sa_align  \ptr, 0, 0, 1, 16
+       l32i    \at1, \ptr, 0
+       wur0    \at1            // LDCBHI
+       l32i    \at1, \ptr, 4
+       wur1    \at1            // LDCBLO
+       l32i    \at1, \ptr, 8
+       wur2    \at1            // STCBHI
+       l32i    \at1, \ptr, 12
+       wur3    \at1            // STCBLO
+       l32i    \at1, \ptr, 16
+       wur8    \at1            // LDBRBASE
+       l32i    \at1, \ptr, 20
+       wur9    \at1            // LDBROFF
+       l32i    \at1, \ptr, 24
+       wur10   \at1            // LDBRINC
+       l32i    \at1, \ptr, 28
+       wur11   \at1            // STBRBASE
+       l32i    \at1, \ptr, 32
+       wur12   \at1            // STBROFF
+       l32i    \at1, \ptr, 36
+       wur13   \at1            // STBRINC
+       l32i    \at1, \ptr, 40
+       wur24   \at1            // SCRATCH0
+       l32i    \at1, \ptr, 44
+       wur25   \at1            // SCRATCH1
+       l32i    \at1, \ptr, 48
+       wur26   \at1            // SCRATCH2
+       l32i    \at1, \ptr, 52
+       wur27   \at1            // SCRATCH3
+       WRBL128I wrb0, \ptr,  320
+       WRBL128I wrb1, \ptr,  336
+       WRBL128I wrb2, \ptr,  352
+       WRBL128I wrb3, \ptr,  368
+       WRBL128I wrb4, \ptr,  384
+       WRBL128I wrb5, \ptr,  400
+       WRBL128I wrb6, \ptr,  416
+       WRBL128I wrb7, \ptr,  432
+       WRBL128I wrb8, \ptr,  448
+       WRBL128I wrb9, \ptr,  464
+       WRBL128I wrb10, \ptr,  480
+       WRBL128I wrb11, \ptr,  496
+       WRBL128I wrb12, \ptr,  512
+       WRBL128I wrb13, \ptr,  528
+       WRBL128I wrb14, \ptr,  544
+       WRBL128I wrb15, \ptr,  560
+       WRAL128I wra0, \ptr,  64
+       WRAL128I wra1, \ptr,  80
+       WRAL128I wra2, \ptr,  96
+       WRAL128I wra3, \ptr,  112
+       WRAL128I wra4, \ptr,  128
+       WRAL128I wra5, \ptr,  144
+       WRAL128I wra6, \ptr,  160
+       WRAL128I wra7, \ptr,  176
+       WRAL128I wra8, \ptr,  192
+       WRAL128I wra9, \ptr,  208
+       WRAL128I wra10, \ptr,  224
+       WRAL128I wra11, \ptr,  240
+       WRAL128I wra12, \ptr,  256
+       WRAL128I wra13, \ptr,  272
+       WRAL128I wra14, \ptr,  288
+       WRAL128I wra15, \ptr,  304
+       .set    .Lxchal_ofs_, .Lxchal_ofs_ + 576
+       .endif
+       .endm   // xchal_cp6_load
+
+#define XCHAL_CP6_NUM_ATMPS    1
+#define XCHAL_SA_NUM_ATMPS     1
+
+       /*  Empty macros for unconfigured coprocessors:  */
+       .macro xchal_cp1_store  p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp1_load   p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp2_store  p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp2_load   p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp3_store  p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp3_load   p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp4_store  p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp4_load   p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp5_store  p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp5_load   p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp7_store  p a b c d continue=0 ofs=-1 select=-1 ; .endm
+       .macro xchal_cp7_load   p a b c d continue=0 ofs=-1 select=-1 ; .endm
+
+#endif /*_XTENSA_CORE_TIE_ASM_H*/
+
diff --git a/arch/xtensa/variants/s6000/include/variant/tie.h b/arch/xtensa/variants/s6000/include/variant/tie.h
new file mode 100644 (file)
index 0000000..be7ea84
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * This header file describes this specific Xtensa processor's TIE extensions
+ * that extend basic Xtensa core functionality.  It is customized to this
+ * Xtensa processor configuration.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2008 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_TIE_H
+#define _XTENSA_CORE_TIE_H
+
+#define XCHAL_CP_NUM                   2       /* number of coprocessors */
+#define XCHAL_CP_MAX                   7       /* max CP ID + 1 (0 if none) */
+#define XCHAL_CP_MASK                  0x41    /* bitmask of all CPs by ID */
+#define XCHAL_CP_PORT_MASK             0x00    /* bitmask of only port CPs */
+
+/*  Basic parameters of each coprocessor:  */
+#define XCHAL_CP0_NAME                 "FPU"
+#define XCHAL_CP0_IDENT                        FPU
+#define XCHAL_CP0_SA_SIZE              72      /* size of state save area */
+#define XCHAL_CP0_SA_ALIGN             4       /* min alignment of save area */
+#define XCHAL_CP_ID_FPU                        0       /* coprocessor ID (0..7) */
+#define XCHAL_CP6_NAME                 "XAD"
+#define XCHAL_CP6_IDENT                        XAD
+#define XCHAL_CP6_SA_SIZE              576     /* size of state save area */
+#define XCHAL_CP6_SA_ALIGN             16      /* min alignment of save area */
+#define XCHAL_CP_ID_XAD                        6       /* coprocessor ID (0..7) */
+
+/*  Filler info for unassigned coprocessors, to simplify arrays etc:  */
+#define XCHAL_CP1_SA_SIZE              0
+#define XCHAL_CP1_SA_ALIGN             1
+#define XCHAL_CP2_SA_SIZE              0
+#define XCHAL_CP2_SA_ALIGN             1
+#define XCHAL_CP3_SA_SIZE              0
+#define XCHAL_CP3_SA_ALIGN             1
+#define XCHAL_CP4_SA_SIZE              0
+#define XCHAL_CP4_SA_ALIGN             1
+#define XCHAL_CP5_SA_SIZE              0
+#define XCHAL_CP5_SA_ALIGN             1
+#define XCHAL_CP7_SA_SIZE              0
+#define XCHAL_CP7_SA_ALIGN             1
+
+/*  Save area for non-coprocessor optional and custom (TIE) state:  */
+#define XCHAL_NCP_SA_SIZE              4
+#define XCHAL_NCP_SA_ALIGN             4
+
+/*  Total save area for optional and custom state (NCP + CPn):  */
+#define XCHAL_TOTAL_SA_SIZE            672     /* with 16-byte align padding */
+#define XCHAL_TOTAL_SA_ALIGN           16      /* actual minimum alignment */
+
+/*
+ * Detailed contents of save areas.
+ * NOTE:  caller must define the XCHAL_SA_REG macro (not defined here)
+ * before expanding the XCHAL_xxx_SA_LIST() macros.
+ *
+ * XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize,
+ *             dbnum,base,regnum,bitsz,gapsz,reset,x...)
+ *
+ *     s = passed from XCHAL_*_LIST(s), eg. to select how to expand
+ *     ccused = set if used by compiler without special options or code
+ *     abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global)
+ *     kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg)
+ *     opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg)
+ *     name = lowercase reg name (no quotes)
+ *     galign = group byte alignment (power of 2) (galign >= align)
+ *     align = register byte alignment (power of 2)
+ *     asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz)
+ *       (not including any pad bytes required to galign this or next reg)
+ *     dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>)
+ *     base = reg shortname w/o index (or sr=special, ur=TIE user reg)
+ *     regnum = reg index in regfile, or special/TIE-user reg number
+ *     bitsz = number of significant bits (regfile width, or ur/sr mask bits)
+ *     gapsz = intervening bits, if bitsz bits not stored contiguously
+ *     (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize)
+ *     reset = register reset value (or 0 if undefined at reset)
+ *     x = reserved for future use (0 until then)
+ *
+ *  To filter out certain registers, e.g. to expand only the non-global
+ *  registers used by the compiler, you can do something like this:
+ *
+ *  #define XCHAL_SA_REG(s,ccused,p...)        SELCC##ccused(p)
+ *  #define SELCC0(p...)
+ *  #define SELCC1(abikind,p...)       SELAK##abikind(p)
+ *  #define SELAK0(p...)               REG(p)
+ *  #define SELAK1(p...)               REG(p)
+ *  #define SELAK2(p...)
+ *  #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \
+ *             ...what you want to expand...
+ */
+
+#define XCHAL_NCP_SA_NUM       1
+#define XCHAL_NCP_SA_LIST(s)   \
+ XCHAL_SA_REG(s,0,0,0,1,             br, 4, 4, 4,0x0204,  sr,4  , 16,0,0,0)
+
+#define XCHAL_CP0_SA_NUM       18
+#define XCHAL_CP0_SA_LIST(s)   \
+ XCHAL_SA_REG(s,0,0,1,0,            fcr, 4, 4, 4,0x03E8,  ur,232, 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,            fsr, 4, 4, 4,0x03E9,  ur,233, 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f0, 4, 4, 4,0x0030,   f,0  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f1, 4, 4, 4,0x0031,   f,1  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f2, 4, 4, 4,0x0032,   f,2  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f3, 4, 4, 4,0x0033,   f,3  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f4, 4, 4, 4,0x0034,   f,4  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f5, 4, 4, 4,0x0035,   f,5  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f6, 4, 4, 4,0x0036,   f,6  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f7, 4, 4, 4,0x0037,   f,7  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f8, 4, 4, 4,0x0038,   f,8  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,             f9, 4, 4, 4,0x0039,   f,9  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,            f10, 4, 4, 4,0x003A,   f,10 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,            f11, 4, 4, 4,0x003B,   f,11 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,            f12, 4, 4, 4,0x003C,   f,12 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,            f13, 4, 4, 4,0x003D,   f,13 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,            f14, 4, 4, 4,0x003E,   f,14 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,            f15, 4, 4, 4,0x003F,   f,15 , 32,0,0,0)
+
+#define XCHAL_CP1_SA_NUM       0
+#define XCHAL_CP1_SA_LIST(s)   /* empty */
+
+#define XCHAL_CP2_SA_NUM       0
+#define XCHAL_CP2_SA_LIST(s)   /* empty */
+
+#define XCHAL_CP3_SA_NUM       0
+#define XCHAL_CP3_SA_LIST(s)   /* empty */
+
+#define XCHAL_CP4_SA_NUM       0
+#define XCHAL_CP4_SA_LIST(s)   /* empty */
+
+#define XCHAL_CP5_SA_NUM       0
+#define XCHAL_CP5_SA_LIST(s)   /* empty */
+
+#define XCHAL_CP6_SA_NUM       46
+#define XCHAL_CP6_SA_LIST(s)   \
+ XCHAL_SA_REG(s,0,0,1,0,         ldcbhi,16, 4, 4,0x0300,  ur,0  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,         ldcblo, 4, 4, 4,0x0301,  ur,1  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,         stcbhi, 4, 4, 4,0x0302,  ur,2  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,         stcblo, 4, 4, 4,0x0303,  ur,3  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,       ldbrbase, 4, 4, 4,0x0308,  ur,8  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,        ldbroff, 4, 4, 4,0x0309,  ur,9  , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,        ldbrinc, 4, 4, 4,0x030A,  ur,10 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,       stbrbase, 4, 4, 4,0x030B,  ur,11 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,        stbroff, 4, 4, 4,0x030C,  ur,12 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,        stbrinc, 4, 4, 4,0x030D,  ur,13 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,       scratch0, 4, 4, 4,0x0318,  ur,24 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,       scratch1, 4, 4, 4,0x0319,  ur,25 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,       scratch2, 4, 4, 4,0x031A,  ur,26 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,1,0,       scratch3, 4, 4, 4,0x031B,  ur,27 , 32,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra0,16,16,16,0x1010, wra,0  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra1,16,16,16,0x1011, wra,1  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra2,16,16,16,0x1012, wra,2  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra3,16,16,16,0x1013, wra,3  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra4,16,16,16,0x1014, wra,4  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra5,16,16,16,0x1015, wra,5  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra6,16,16,16,0x1016, wra,6  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra7,16,16,16,0x1017, wra,7  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra8,16,16,16,0x1018, wra,8  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wra9,16,16,16,0x1019, wra,9  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wra10,16,16,16,0x101A, wra,10 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wra11,16,16,16,0x101B, wra,11 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wra12,16,16,16,0x101C, wra,12 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wra13,16,16,16,0x101D, wra,13 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wra14,16,16,16,0x101E, wra,14 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wra15,16,16,16,0x101F, wra,15 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb0,16,16,16,0x1020, wrb,0  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb1,16,16,16,0x1021, wrb,1  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb2,16,16,16,0x1022, wrb,2  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb3,16,16,16,0x1023, wrb,3  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb4,16,16,16,0x1024, wrb,4  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb5,16,16,16,0x1025, wrb,5  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb6,16,16,16,0x1026, wrb,6  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb7,16,16,16,0x1027, wrb,7  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb8,16,16,16,0x1028, wrb,8  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,           wrb9,16,16,16,0x1029, wrb,9  ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wrb10,16,16,16,0x102A, wrb,10 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wrb11,16,16,16,0x102B, wrb,11 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wrb12,16,16,16,0x102C, wrb,12 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wrb13,16,16,16,0x102D, wrb,13 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wrb14,16,16,16,0x102E, wrb,14 ,128,0,0,0) \
+ XCHAL_SA_REG(s,0,0,2,0,          wrb15,16,16,16,0x102F, wrb,15 ,128,0,0,0)
+
+#define XCHAL_CP7_SA_NUM       0
+#define XCHAL_CP7_SA_LIST(s)   /* empty */
+
+/* Byte length of instruction from its first nibble (op0 field), per FLIX.  */
+#define XCHAL_OP0_FORMAT_LENGTHS       3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8
+
+#endif /*_XTENSA_CORE_TIE_H*/
+
diff --git a/arch/xtensa/variants/s6000/irq.c b/arch/xtensa/variants/s6000/irq.c
new file mode 100644 (file)
index 0000000..6651e32
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * s6000 irq crossbar
+ *
+ * Copyright (c) 2009 emlix GmbH
+ * Authors:    Johannes Weiner <jw@emlix.com>
+ *             Oskar Schirmer <os@emlix.com>
+ */
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <variant/hardware.h>
+
+/* S6_REG_INTC */
+#define INTC_STATUS    0x000
+#define INTC_RAW       0x010
+#define INTC_STATUS_AG 0x100
+#define INTC_CFG(n)    (0x200 + 4 * (n))
+
+/*
+ * The s6000 has a crossbar that multiplexes interrupt output lines
+ * from the peripherals to input lines on the xtensa core.
+ *
+ * We leave the mapping decisions to the platform as it depends on the
+ * actually connected peripherals which distribution makes sense.
+ */
+extern const signed char *platform_irq_mappings[NR_IRQS];
+
+static unsigned long scp_to_intc_enable[] = {
+#define        TO_INTC_ENABLE(n)       (((n) << 1) + 1)
+       TO_INTC_ENABLE(0),
+       TO_INTC_ENABLE(1),
+       TO_INTC_ENABLE(2),
+       TO_INTC_ENABLE(3),
+       TO_INTC_ENABLE(4),
+       TO_INTC_ENABLE(5),
+       TO_INTC_ENABLE(6),
+       TO_INTC_ENABLE(7),
+       TO_INTC_ENABLE(8),
+       TO_INTC_ENABLE(9),
+       TO_INTC_ENABLE(10),
+       TO_INTC_ENABLE(11),
+       TO_INTC_ENABLE(12),
+       -1,
+       -1,
+       TO_INTC_ENABLE(13),
+       -1,
+       TO_INTC_ENABLE(14),
+       -1,
+       TO_INTC_ENABLE(15),
+#undef TO_INTC_ENABLE
+};
+
+static void irq_set(unsigned int irq, int enable)
+{
+       unsigned long en;
+       const signed char *m = platform_irq_mappings[irq];
+
+       if (!m)
+               return;
+       en = enable ? scp_to_intc_enable[irq] : 0;
+       while (*m >= 0) {
+               writel(en, S6_REG_INTC + INTC_CFG(*m));
+               m++;
+       }
+}
+
+void variant_irq_enable(unsigned int irq)
+{
+       irq_set(irq, 1);
+}
+
+void variant_irq_disable(unsigned int irq)
+{
+       irq_set(irq, 0);
+}
index ce0efc6b26dc54cfabf225d4a78265ef401a9a24..ee9c21602228e0dcb1b6ab8adf6909dae4adc2fd 100644 (file)
@@ -64,7 +64,7 @@ static int raise_blk_irq(int cpu, struct request *rq)
                data->info = rq;
                data->flags = 0;
 
-               __smp_call_function_single(cpu, data);
+               __smp_call_function_single(cpu, data, 0);
                return 0;
        }
 
index f21147f3626a628c2fb78e1e5448a0361f9a630d..06eb6cc09fef97714d12ebf8859e5e712d798df5 100644 (file)
@@ -30,7 +30,7 @@
 #ifdef CONFIG_DMA_ENGINE
 static int __init async_tx_init(void)
 {
-       dmaengine_get();
+       async_dmaengine_get();
 
        printk(KERN_INFO "async_tx: api initialized (async)\n");
 
@@ -39,7 +39,7 @@ static int __init async_tx_init(void)
 
 static void __exit async_tx_exit(void)
 {
-       dmaengine_put();
+       async_dmaengine_put();
 }
 
 /**
@@ -56,7 +56,7 @@ __async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
        if (depend_tx &&
            dma_has_cap(tx_type, depend_tx->chan->device->cap_mask))
                return depend_tx->chan;
-       return dma_find_channel(tx_type);
+       return async_dma_find_channel(tx_type);
 }
 EXPORT_SYMBOL_GPL(__async_tx_find_channel);
 #else
index 595b78672b36ad90e27cf50ed28126bb43970fb5..95fe2c8d6c516ea0325b9287df8775adb542cee7 100644 (file)
 #include <linux/raid/xor.h>
 #include <linux/async_tx.h>
 
-/* do_async_xor - dma map the pages and perform the xor with an engine.
- *     This routine is marked __always_inline so it can be compiled away
- *     when CONFIG_DMA_ENGINE=n
- */
-static __always_inline struct dma_async_tx_descriptor *
+/* do_async_xor - dma map the pages and perform the xor with an engine */
+static __async_inline struct dma_async_tx_descriptor *
 do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list,
             unsigned int offset, int src_cnt, size_t len,
             enum async_tx_flags flags,
index 7a659733f94a4e1087fabcfc8d5e48fd6c5c4521..2ccc8b0076ce36ed7d67ff6202e44e90076d7ee2 100644 (file)
@@ -77,6 +77,9 @@ static int shash_update_unaligned(struct shash_desc *desc, const u8 *data,
        u8 buf[shash_align_buffer_size(unaligned_len, alignmask)]
                __attribute__ ((aligned));
 
+       if (unaligned_len > len)
+               unaligned_len = len;
+
        memcpy(buf, data, unaligned_len);
 
        return shash->update(desc, buf, unaligned_len) ?:
index b2e6db075e4993eac4fcffb9004b82ee4a0bca71..996b6ee57d9e3fb3ff48251ea9ee01d405b648ad 100644 (file)
@@ -18,8 +18,8 @@
 
 #define BH_TRACE 0
 #include <linux/module.h>
-#include <linux/raid/md.h>
 #include <linux/raid/xor.h>
+#include <linux/jiffies.h>
 #include <asm/xor.h>
 
 /* The xor routines to use.  */
index 9b917dac77322b4aa397549aa4874ed0c4ad8dab..88e42abf5d881b8bf443ecc4f58e3b4e76b3ecd3 100644 (file)
@@ -191,7 +191,6 @@ static int acpi_ac_add_fs(struct acpi_device *device)
                                                     acpi_ac_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        /* 'state' [R] */
index 69cbc57c2d1cd248e7431bb40661e9ea139efbb7..3bcb5bfc45d3366645bfdf6a417d6c140e30107d 100644 (file)
@@ -760,7 +760,6 @@ static int acpi_battery_add_fs(struct acpi_device *device)
                                                     acpi_battery_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
index 171fd914f43533f46bf417dd4d4a7b6936fc6e50..c2f06069dcd40d614a20c0a5e3a2883d47535a9a 100644 (file)
@@ -200,12 +200,10 @@ static int acpi_button_add_fs(struct acpi_device *device)
 
        if (!entry)
                return -ENODEV;
-       entry->owner = THIS_MODULE;
 
        acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
        if (!acpi_device_dir(device))
                return -ENODEV;
-       acpi_device_dir(device)->owner = THIS_MODULE;
 
        /* 'info' [R] */
        entry = proc_create_data(ACPI_BUTTON_FILE_INFO,
@@ -522,7 +520,6 @@ static int __init acpi_button_init(void)
        acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
        if (!acpi_button_dir)
                return -ENODEV;
-       acpi_button_dir->owner = THIS_MODULE;
        result = acpi_bus_register_driver(&acpi_button_driver);
        if (result < 0) {
                remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
index eaaee1660bdf41ec490696b812b2c17869daffe9..8a02944bf92d687e4b1cf5c3e79b8efce59c9d6a 100644 (file)
@@ -193,7 +193,6 @@ static int acpi_fan_add_fs(struct acpi_device *device)
                                                     acpi_fan_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        /* 'status' [R/W] */
@@ -347,7 +346,6 @@ static int __init acpi_fan_init(void)
        acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
        if (!acpi_fan_dir)
                return -ENODEV;
-       acpi_fan_dir->owner = THIS_MODULE;
 #endif
 
        result = acpi_bus_register_driver(&acpi_fan_driver);
index 5b38a026d1220113aec9c88cbb08f325537012d3..196f97d00956aa379b95b8fbe8e5a6cb6ddd10eb 100644 (file)
@@ -66,11 +66,18 @@ struct acpi_pci_root {
        struct acpi_device * device;
        struct acpi_pci_id id;
        struct pci_bus *bus;
+
+       u32 osc_support_set;    /* _OSC state of support bits */
+       u32 osc_control_set;    /* _OSC state of control bits */
+       u32 osc_control_qry;    /* the latest _OSC query result */
+
+       u32 osc_queried:1;      /* has _OSC control been queried? */
 };
 
 static LIST_HEAD(acpi_pci_roots);
 
 static struct acpi_pci_driver *sub_driver;
+static DEFINE_MUTEX(osc_lock);
 
 int acpi_pci_register_driver(struct acpi_pci_driver *driver)
 {
@@ -185,6 +192,175 @@ static void acpi_pci_bridge_scan(struct acpi_device *device)
                }
 }
 
+static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40,
+                         0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
+
+static acpi_status acpi_pci_run_osc(acpi_handle handle,
+                                   const u32 *capbuf, u32 *retval)
+{
+       acpi_status status;
+       struct acpi_object_list input;
+       union acpi_object in_params[4];
+       struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *out_obj;
+       u32 errors;
+
+       /* Setting up input parameters */
+       input.count = 4;
+       input.pointer = in_params;
+       in_params[0].type               = ACPI_TYPE_BUFFER;
+       in_params[0].buffer.length      = 16;
+       in_params[0].buffer.pointer     = OSC_UUID;
+       in_params[1].type               = ACPI_TYPE_INTEGER;
+       in_params[1].integer.value      = 1;
+       in_params[2].type               = ACPI_TYPE_INTEGER;
+       in_params[2].integer.value      = 3;
+       in_params[3].type               = ACPI_TYPE_BUFFER;
+       in_params[3].buffer.length      = 12;
+       in_params[3].buffer.pointer     = (u8 *)capbuf;
+
+       status = acpi_evaluate_object(handle, "_OSC", &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       if (!output.length)
+               return AE_NULL_OBJECT;
+
+       out_obj = output.pointer;
+       if (out_obj->type != ACPI_TYPE_BUFFER) {
+               printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
+               status = AE_TYPE;
+               goto out_kfree;
+       }
+       /* Need to ignore the bit0 in result code */
+       errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
+       if (errors) {
+               if (errors & OSC_REQUEST_ERROR)
+                       printk(KERN_DEBUG "_OSC request failed\n");
+               if (errors & OSC_INVALID_UUID_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid UUID\n");
+               if (errors & OSC_INVALID_REVISION_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid revision\n");
+               if (errors & OSC_CAPABILITIES_MASK_ERROR) {
+                       if (capbuf[OSC_QUERY_TYPE] & OSC_QUERY_ENABLE)
+                               goto out_success;
+                       printk(KERN_DEBUG
+                              "Firmware did not grant requested _OSC control\n");
+                       status = AE_SUPPORT;
+                       goto out_kfree;
+               }
+               status = AE_ERROR;
+               goto out_kfree;
+       }
+out_success:
+       *retval = *((u32 *)(out_obj->buffer.pointer + 8));
+       status = AE_OK;
+
+out_kfree:
+       kfree(output.pointer);
+       return status;
+}
+
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+{
+       acpi_status status;
+       u32 support_set, result, capbuf[3];
+
+       /* do _OSC query for all possible controls */
+       support_set = root->osc_support_set | (flags & OSC_SUPPORT_MASKS);
+       capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+       capbuf[OSC_SUPPORT_TYPE] = support_set;
+       capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
+
+       status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
+       if (ACPI_SUCCESS(status)) {
+               root->osc_support_set = support_set;
+               root->osc_control_qry = result;
+               root->osc_queried = 1;
+       }
+       return status;
+}
+
+static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
+{
+       acpi_status status;
+       acpi_handle tmp;
+
+       status = acpi_get_handle(root->device->handle, "_OSC", &tmp);
+       if (ACPI_FAILURE(status))
+               return status;
+       mutex_lock(&osc_lock);
+       status = acpi_pci_query_osc(root, flags);
+       mutex_unlock(&osc_lock);
+       return status;
+}
+
+static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
+{
+       struct acpi_pci_root *root;
+       list_for_each_entry(root, &acpi_pci_roots, node) {
+               if (root->device->handle == handle)
+                       return root;
+       }
+       return NULL;
+}
+
+/**
+ * acpi_pci_osc_control_set - commit requested control to Firmware
+ * @handle: acpi_handle for the target ACPI object
+ * @flags: driver's requested control bits
+ *
+ * Attempt to take control from Firmware on requested control bits.
+ **/
+acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
+{
+       acpi_status status;
+       u32 control_req, result, capbuf[3];
+       acpi_handle tmp;
+       struct acpi_pci_root *root;
+
+       status = acpi_get_handle(handle, "_OSC", &tmp);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       control_req = (flags & OSC_CONTROL_MASKS);
+       if (!control_req)
+               return AE_TYPE;
+
+       root = acpi_pci_find_root(handle);
+       if (!root)
+               return AE_NOT_EXIST;
+
+       mutex_lock(&osc_lock);
+       /* No need to evaluate _OSC if the control was already granted. */
+       if ((root->osc_control_set & control_req) == control_req)
+               goto out;
+
+       /* Need to query controls first before requesting them */
+       if (!root->osc_queried) {
+               status = acpi_pci_query_osc(root, root->osc_support_set);
+               if (ACPI_FAILURE(status))
+                       goto out;
+       }
+       if ((root->osc_control_qry & control_req) != control_req) {
+               printk(KERN_DEBUG
+                      "Firmware did not grant requested _OSC control\n");
+               status = AE_SUPPORT;
+               goto out;
+       }
+
+       capbuf[OSC_QUERY_TYPE] = 0;
+       capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
+       capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
+       status = acpi_pci_run_osc(handle, capbuf, &result);
+       if (ACPI_SUCCESS(status))
+               root->osc_control_set = result;
+out:
+       mutex_unlock(&osc_lock);
+       return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
        int result = 0;
@@ -217,7 +393,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
         * PCI domains, so we indicate this in _OSC support capabilities.
         */
        flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
-       pci_acpi_osc_support(device->handle, flags);
+       acpi_pci_osc_support(root, flags);
 
        /* 
         * Segment
@@ -353,7 +529,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        if (pci_msi_enabled())
                flags |= OSC_MSI_SUPPORT;
        if (flags != base_flags)
-               pci_acpi_osc_support(device->handle, flags);
+               acpi_pci_osc_support(root, flags);
 
       end:
        if (result) {
index 0cc2fd31e3765f7c9b945460345533dfebf1424b..fa2f7422d23de1e2bec5ee3702fa15e2a5ca284c 100644 (file)
@@ -359,7 +359,6 @@ static int acpi_processor_add_fs(struct acpi_device *device)
                if (!acpi_device_dir(device))
                        return -ENODEV;
        }
-       acpi_device_dir(device)->owner = THIS_MODULE;
 
        /* 'info' [R] */
        entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO,
@@ -1137,7 +1136,6 @@ static int __init acpi_processor_init(void)
        acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
        if (!acpi_processor_dir)
                return -ENOMEM;
-       acpi_processor_dir->owner = THIS_MODULE;
 
        /*
         * Check whether the system is DMI table. If yes, OSPM
index 6050ce4818731fd2bcf8c6891d5a343414d0133a..59afd52ccc121aace5b3d47b56442d718901a090 100644 (file)
@@ -488,7 +488,6 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
                if (!*dir) {
                        return -ENODEV;
                }
-               (*dir)->owner = THIS_MODULE;
        }
 
        /* 'info' [R] */
index 99e6f1f8ea457677e1b989c711e37e1b339e60c3..1ba9d61ea69a01289e9d25db201c387cf22fe55d 100644 (file)
@@ -367,7 +367,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                /*
                 * Treat freezing temperatures as invalid as well; some
                 * BIOSes return really low values and cause reboots at startup.
-                * Below zero (Celcius) values clearly aren't right for sure..
+                * Below zero (Celsius) values clearly aren't right for sure..
                 * ... so lets discard those as invalid.
                 */
                if (ACPI_FAILURE(status) ||
@@ -1506,7 +1506,6 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
                                                     acpi_thermal_dir);
                if (!acpi_device_dir(device))
                        return -ENODEV;
-               acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
        /* 'state' [R] */
@@ -1875,7 +1874,6 @@ static int __init acpi_thermal_init(void)
        acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
        if (!acpi_thermal_dir)
                return -ENODEV;
-       acpi_thermal_dir->owner = THIS_MODULE;
 
        result = acpi_bus_register_driver(&acpi_thermal_driver);
        if (result < 0) {
index bb5ed059114aa296e826b91f8b35083ccc773028..67cc36dc9b82fe94b7430628076191e3a6246894 100644 (file)
@@ -1125,8 +1125,6 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
        if (!device_dir)
                return -ENOMEM;
 
-       device_dir->owner = THIS_MODULE;
-
        /* 'info' [R] */
        entry = proc_create_data("info", S_IRUGO, device_dir,
                        &acpi_video_device_info_fops, acpi_driver_data(device));
@@ -1403,8 +1401,6 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
        if (!device_dir)
                return -ENOMEM;
 
-       device_dir->owner = THIS_MODULE;
-
        /* 'info' [R] */
        entry = proc_create_data("info", S_IRUGO, device_dir,
                                 &acpi_video_bus_info_fops,
@@ -2131,7 +2127,6 @@ static int __init acpi_video_init(void)
        acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
        if (!acpi_video_dir)
                return -ENODEV;
-       acpi_video_dir->owner = THIS_MODULE;
 
        result = acpi_bus_register_driver(&acpi_video_bus);
        if (result < 0) {
index 0bcf264646702465795ba7e31e7dce1e014b87ae..9120717c0701398a21db009b7b0b48dc95267763 100644 (file)
@@ -86,7 +86,7 @@ config ATA_SFF
 
          For users with exclusively modern controllers like AHCI,
          Silicon Image 3124, or Marvell 6440, you may choose to
-         disable this uneeded SFF support.
+         disable this unneeded SFF support.
 
          If unsure, say Y.
 
index 14b9d5f4c203d28d3bcc639e6f1f8580d77093f0..c07e725ea93db3ffdffb933917b0be456911b724 100644 (file)
@@ -6,7 +6,6 @@
 #
 
 menuconfig AUXDISPLAY
-       depends on PARPORT
        bool "Auxiliary Display support"
        ---help---
          Say Y here to get to see options for auxiliary display drivers.
@@ -14,7 +13,7 @@ menuconfig AUXDISPLAY
 
          If you say N, all options in this submenu will be skipped and disabled.
 
-if AUXDISPLAY && PARPORT
+if AUXDISPLAY
 
 config KS0108
        tristate "KS0108 LCD Controller"
index 5b257a57bc57ae60e369950b60126f3d43f43e04..e62a4ccea54d0c4a3dc6dcd84eb107e557bcb54c 100644 (file)
@@ -119,7 +119,7 @@ static ssize_t print_cpus_map(char *buf, const struct cpumask *map)
 #define        print_cpus_func(type) \
 static ssize_t print_cpus_##type(struct sysdev_class *class, char *buf)        \
 {                                                                      \
-       return print_cpus_map(buf, &cpu_##type##_map);                  \
+       return print_cpus_map(buf, cpu_##type##_mask);                  \
 }                                                                      \
 static struct sysdev_class_attribute attr_##type##_map =               \
        _SYSDEV_CLASS_ATTR(type, 0444, print_cpus_##type, NULL)
index c2d1eed903767484304b1f3208c27719b5ec3195..9f0e672f4be84ff35489b8f5e8724898ec3d9f12 100644 (file)
@@ -98,3 +98,10 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
        return iommu_ops->iova_to_phys(domain, iova);
 }
 EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
+
+int iommu_domain_has_cap(struct iommu_domain *domain,
+                        unsigned long cap)
+{
+       return iommu_ops->domain_has_cap(domain, cap);
+}
+EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
index e255341682c88d4a0955f1151595c1334e005dd5..69b4ddb7de3b8c00d59a34fd16af5dc789e7b109 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pm.h>
 #include <linux/resume-trace.h>
 #include <linux/rwsem.h>
+#include <linux/interrupt.h>
 
 #include "../base.h"
 #include "power.h"
@@ -349,7 +350,8 @@ static int resume_device_noirq(struct device *dev, pm_message_t state)
  *     Execute the appropriate "noirq resume" callback for all devices marked
  *     as DPM_OFF_IRQ.
  *
- *     Must be called with interrupts disabled and only one CPU running.
+ *     Must be called under dpm_list_mtx.  Device drivers should not receive
+ *     interrupts while it's being executed.
  */
 static void dpm_power_up(pm_message_t state)
 {
@@ -370,14 +372,13 @@ static void dpm_power_up(pm_message_t state)
  *     device_power_up - Turn on all devices that need special attention.
  *     @state: PM transition of the system being carried out.
  *
- *     Power on system devices, then devices that required we shut them down
- *     with interrupts disabled.
- *
- *     Must be called with interrupts disabled.
+ *     Call the "early" resume handlers and enable device drivers to receive
+ *     interrupts.
  */
 void device_power_up(pm_message_t state)
 {
        dpm_power_up(state);
+       resume_device_irqs();
 }
 EXPORT_SYMBOL_GPL(device_power_up);
 
@@ -602,16 +603,17 @@ static int suspend_device_noirq(struct device *dev, pm_message_t state)
  *     device_power_down - Shut down special devices.
  *     @state: PM transition of the system being carried out.
  *
- *     Power down devices that require interrupts to be disabled.
- *     Then power down system devices.
+ *     Prevent device drivers from receiving interrupts and call the "late"
+ *     suspend handlers.
  *
- *     Must be called with interrupts disabled and only one CPU running.
+ *     Must be called under dpm_list_mtx.
  */
 int device_power_down(pm_message_t state)
 {
        struct device *dev;
        int error = 0;
 
+       suspend_device_irqs();
        list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
                error = suspend_device_noirq(dev, state);
                if (error) {
@@ -621,7 +623,7 @@ int device_power_down(pm_message_t state)
                dev->power.status = DPM_OFF_IRQ;
        }
        if (error)
-               dpm_power_up(resume_event(state));
+               device_power_up(resume_event(state));
        return error;
 }
 EXPORT_SYMBOL_GPL(device_power_down);
index cbd36cf59a0f2e2af74ddc9255f64380299a6666..3236b434b964c04078d6dfda2d4364e70fafb11b 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pm.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <linux/interrupt.h>
 
 #include "base.h"
 
@@ -299,7 +300,7 @@ void sysdev_unregister(struct sys_device *sysdev)
  *     and the class driver.
  *
  *     Note: The list is iterated in reverse order, so that we shut down
- *     child devices before we shut down thier parents. The list ordering
+ *     child devices before we shut down their parents. The list ordering
  *     is guaranteed by virtue of the fact that child devices are registered
  *     after their parents.
  */
@@ -369,6 +370,13 @@ int sysdev_suspend(pm_message_t state)
        struct sysdev_driver *drv, *err_drv;
        int ret;
 
+       pr_debug("Checking wake-up interrupts\n");
+
+       /* Return error code if there are any wake-up interrupts pending */
+       ret = check_wakeup_irqs();
+       if (ret)
+               return ret;
+
        pr_debug("Suspending System Devices\n");
 
        list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
index 45c5a33daf498d623e9749bd75e8f4bf94a9e49e..31693bc24444f3541c74dfccc9c9c384edf8fd5a 100644 (file)
@@ -4,6 +4,7 @@
  * Filesystem request handling methods
  */
 
+#include <linux/ata.h>
 #include <linux/hdreg.h>
 #include <linux/blkdev.h>
 #include <linux/skbuff.h>
@@ -267,7 +268,7 @@ aoecmd_ata_rw(struct aoedev *d)
                writebit = 0;
        }
 
-       ah->cmdstat = WIN_READ | writebit | extbit;
+       ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit;
 
        /* mark all tracking fields and load out */
        buf->nframesout += 1;
@@ -362,10 +363,10 @@ resend(struct aoedev *d, struct aoetgt *t, struct frame *f)
        switch (ah->cmdstat) {
        default:
                break;
-       case WIN_READ:
-       case WIN_READ_EXT:
-       case WIN_WRITE:
-       case WIN_WRITE_EXT:
+       case ATA_CMD_PIO_READ:
+       case ATA_CMD_PIO_READ_EXT:
+       case ATA_CMD_PIO_WRITE:
+       case ATA_CMD_PIO_WRITE_EXT:
                put_lba(ah, f->lba);
 
                n = f->bcnt;
@@ -812,8 +813,8 @@ aoecmd_ata_rsp(struct sk_buff *skb)
                        d->htgt = NULL;
                n = ahout->scnt << 9;
                switch (ahout->cmdstat) {
-               case WIN_READ:
-               case WIN_READ_EXT:
+               case ATA_CMD_PIO_READ:
+               case ATA_CMD_PIO_READ_EXT:
                        if (skb->len - sizeof *hin - sizeof *ahin < n) {
                                printk(KERN_ERR
                                        "aoe: %s.  skb->len=%d need=%ld\n",
@@ -823,8 +824,8 @@ aoecmd_ata_rsp(struct sk_buff *skb)
                                return;
                        }
                        memcpy(f->bufaddr, ahin+1, n);
-               case WIN_WRITE:
-               case WIN_WRITE_EXT:
+               case ATA_CMD_PIO_WRITE:
+               case ATA_CMD_PIO_WRITE_EXT:
                        ifp = getif(t, skb->dev);
                        if (ifp) {
                                ifp->lost = 0;
@@ -838,7 +839,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
                                goto xmit;
                        }
                        break;
-               case WIN_IDENTIFY:
+               case ATA_CMD_ID_ATA:
                        if (skb->len - sizeof *hin - sizeof *ahin < 512) {
                                printk(KERN_INFO
                                        "aoe: runt data size in ataid.  skb->len=%d\n",
@@ -914,7 +915,7 @@ aoecmd_ata_id(struct aoedev *d)
 
        /* set up ata header */
        ah->scnt = 1;
-       ah->cmdstat = WIN_IDENTIFY;
+       ah->cmdstat = ATA_CMD_ID_ATA;
        ah->lba3 = 0xa0;
 
        skb->dev = t->ifp->nd;
index c2c95e614506761a98ace446e02219203e5530dd..1300df6f1642a9a84fb345c22f9f88850cd1fe29 100644 (file)
@@ -177,6 +177,7 @@ static int print_unex = 1;
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
 #include <linux/buffer_head.h> /* for invalidate_buffers() */
 #include <linux/mutex.h>
 
@@ -4597,6 +4598,13 @@ MODULE_AUTHOR("Alain L. Knaff");
 MODULE_SUPPORTED_DEVICE("fd");
 MODULE_LICENSE("GPL");
 
+/* This doesn't actually get used other than for module information */
+static const struct pnp_device_id floppy_pnpids[] = {
+       { "PNP0700", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
+
 #else
 
 __setup("floppy=", floppy_setup);
index 482c0c4b964f31c39a6fe5f3d95b6768776b4393..3c11f062a18cff77c25ab4f9f3159eb7218a4391 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/ata.h>
 #include <linux/hdreg.h>
 
+#define HD_IRQ 14
+
 #define REALLY_SLOW_IO
 #include <asm/system.h>
 #include <asm/io.h>
index 2621ed2ce6d299c186391ddfb19635fc3470bf73..40b17d3b55a1b2559b0f69cd2f507dae5e243bd1 100644 (file)
@@ -1192,6 +1192,30 @@ loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) {
        return err;
 }
 
+static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
+{
+       int err;
+       sector_t sec;
+       loff_t sz;
+
+       err = -ENXIO;
+       if (unlikely(lo->lo_state != Lo_bound))
+               goto out;
+       err = figure_loop_size(lo);
+       if (unlikely(err))
+               goto out;
+       sec = get_capacity(lo->lo_disk);
+       /* the width of sector_t may be narrow for bit-shift */
+       sz = sec;
+       sz <<= 9;
+       mutex_lock(&bdev->bd_mutex);
+       bd_set_size(bdev, sz);
+       mutex_unlock(&bdev->bd_mutex);
+
+ out:
+       return err;
+}
+
 static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        unsigned int cmd, unsigned long arg)
 {
@@ -1224,6 +1248,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        case LOOP_GET_STATUS64:
                err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
                break;
+       case LOOP_SET_CAPACITY:
+               err = -EPERM;
+               if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+                       err = loop_set_capacity(lo, bdev);
+               break;
        default:
                err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
        }
@@ -1371,6 +1400,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
                        lo, (struct compat_loop_info __user *) arg);
                mutex_unlock(&lo->lo_ctl_mutex);
                break;
+       case LOOP_SET_CAPACITY:
        case LOOP_CLR_FD:
        case LOOP_GET_STATUS64:
        case LOOP_SET_STATUS64:
index 8299e2d3b61163b2d2d82bb8b00ea4495e3000f9..4d6de4f15ccb34dd4039ed4bf3e53b5993751958 100644 (file)
@@ -4,7 +4,7 @@
  * Note that you can not swap over this thing, yet. Seems to work but
  * deadlocks sometimes - you can not swap over TCP in general.
  * 
- * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
+ * Copyright 1997-2000, 2008 Pavel Machek <pavel@suse.cz>
  * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
  *
  * This file is released under GPLv2 or later.
@@ -276,7 +276,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
        return 0;
 
 error_out:
-       return 1;
+       return -EIO;
 }
 
 static struct request *nbd_find_request(struct nbd_device *lo,
@@ -467,9 +467,7 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req)
                mutex_unlock(&lo->tx_lock);
                printk(KERN_ERR "%s: Attempted send on closed socket\n",
                       lo->disk->disk_name);
-               req->errors++;
-               nbd_end_request(req);
-               return;
+               goto error_out;
        }
 
        lo->active_req = req;
@@ -531,7 +529,7 @@ static int nbd_thread(void *data)
  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
  */
 
-static void do_nbd_request(struct request_queue * q)
+static void do_nbd_request(struct request_queue *q)
 {
        struct request *req;
        
@@ -568,27 +566,17 @@ static void do_nbd_request(struct request_queue * q)
        }
 }
 
-static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
-                    unsigned int cmd, unsigned long arg)
-{
-       struct nbd_device *lo = bdev->bd_disk->private_data;
-       struct file *file;
-       int error;
-       struct request sreq ;
-       struct task_struct *thread;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       BUG_ON(lo->magic != LO_MAGIC);
-
-       /* Anyone capable of this syscall can do *real bad* things */
-       dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
-                       lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+/* Must be called with tx_lock held */
 
+static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
+                      unsigned int cmd, unsigned long arg)
+{
        switch (cmd) {
-       case NBD_DISCONNECT:
+       case NBD_DISCONNECT: {
+               struct request sreq;
+
                printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
+
                blk_rq_init(NULL, &sreq);
                sreq.cmd_type = REQ_TYPE_SPECIAL;
                nbd_cmd(&sreq) = NBD_CMD_DISC;
@@ -599,29 +587,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                 */
                sreq.sector = 0;
                sreq.nr_sectors = 0;
-                if (!lo->sock)
+               if (!lo->sock)
                        return -EINVAL;
-               mutex_lock(&lo->tx_lock);
-                nbd_send_req(lo, &sreq);
-               mutex_unlock(&lo->tx_lock);
+               nbd_send_req(lo, &sreq);
                 return 0;
+       }
  
-       case NBD_CLEAR_SOCK:
-               error = 0;
-               mutex_lock(&lo->tx_lock);
+       case NBD_CLEAR_SOCK: {
+               struct file *file;
+
                lo->sock = NULL;
-               mutex_unlock(&lo->tx_lock);
                file = lo->file;
                lo->file = NULL;
                nbd_clear_que(lo);
                BUG_ON(!list_empty(&lo->queue_head));
                if (file)
                        fput(file);
-               return error;
-       case NBD_SET_SOCK:
+               return 0;
+       }
+
+       case NBD_SET_SOCK: {
+               struct file *file;
                if (lo->file)
                        return -EBUSY;
-               error = -EINVAL;
                file = fget(arg);
                if (file) {
                        struct inode *inode = file->f_path.dentry->d_inode;
@@ -630,12 +618,14 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                                lo->sock = SOCKET_I(inode);
                                if (max_part > 0)
                                        bdev->bd_invalidated = 1;
-                               error = 0;
+                               return 0;
                        } else {
                                fput(file);
                        }
                }
-               return error;
+               return -EINVAL;
+       }
+
        case NBD_SET_BLKSIZE:
                lo->blksize = arg;
                lo->bytesize &= ~(lo->blksize-1);
@@ -643,35 +633,50 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                set_blocksize(bdev, lo->blksize);
                set_capacity(lo->disk, lo->bytesize >> 9);
                return 0;
+
        case NBD_SET_SIZE:
                lo->bytesize = arg & ~(lo->blksize-1);
                bdev->bd_inode->i_size = lo->bytesize;
                set_blocksize(bdev, lo->blksize);
                set_capacity(lo->disk, lo->bytesize >> 9);
                return 0;
+
        case NBD_SET_TIMEOUT:
                lo->xmit_timeout = arg * HZ;
                return 0;
+
        case NBD_SET_SIZE_BLOCKS:
                lo->bytesize = ((u64) arg) * lo->blksize;
                bdev->bd_inode->i_size = lo->bytesize;
                set_blocksize(bdev, lo->blksize);
                set_capacity(lo->disk, lo->bytesize >> 9);
                return 0;
-       case NBD_DO_IT:
+
+       case NBD_DO_IT: {
+               struct task_struct *thread;
+               struct file *file;
+               int error;
+
                if (lo->pid)
                        return -EBUSY;
                if (!lo->file)
                        return -EINVAL;
+
+               mutex_unlock(&lo->tx_lock);
+
                thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
-               if (IS_ERR(thread))
+               if (IS_ERR(thread)) {
+                       mutex_lock(&lo->tx_lock);
                        return PTR_ERR(thread);
+               }
                wake_up_process(thread);
                error = nbd_do_it(lo);
                kthread_stop(thread);
+
+               mutex_lock(&lo->tx_lock);
                if (error)
                        return error;
-               sock_shutdown(lo, 1);
+               sock_shutdown(lo, 0);
                file = lo->file;
                lo->file = NULL;
                nbd_clear_que(lo);
@@ -684,6 +689,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                if (max_part > 0)
                        ioctl_by_bdev(bdev, BLKRRPART, 0);
                return lo->harderror;
+       }
+
        case NBD_CLEAR_QUE:
                /*
                 * This is for compatibility only.  The queue is always cleared
@@ -691,6 +698,7 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                 */
                BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
                return 0;
+
        case NBD_PRINT_DEBUG:
                printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",
                        bdev->bd_disk->disk_name,
@@ -698,7 +706,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                        &lo->queue_head);
                return 0;
        }
-       return -EINVAL;
+       return -ENOTTY;
+}
+
+static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
+                    unsigned int cmd, unsigned long arg)
+{
+       struct nbd_device *lo = bdev->bd_disk->private_data;
+       int error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       BUG_ON(lo->magic != LO_MAGIC);
+
+       /* Anyone capable of this syscall can do *real bad* things */
+       dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
+                       lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+
+       mutex_lock(&lo->tx_lock);
+       error = __nbd_ioctl(bdev, lo, cmd, arg);
+       mutex_unlock(&lo->tx_lock);
+
+       return error;
 }
 
 static struct block_device_operations nbd_fops =
index 393ed6760d783c155a2a0846d8de03c505167057..8eddef373a9197d9db8834d5ba15d1f743b85ee2 100644 (file)
@@ -551,8 +551,6 @@ static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
                dev_warn(&dev->core, "failed to create /proc entry\n");
                return;
        }
-
-       pde->owner = THIS_MODULE;
        pde->data = priv;
 }
 
index 119be3442f28f7f2c979fd2c5ee64c1967ff16f8..6cccdc3f5220ce58b46bb0a0f2714bb537c5dc6b 100644 (file)
@@ -89,6 +89,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
+#include <linux/ata.h>
 #include <linux/hdreg.h>
 #include <linux/platform_device.h>
 #if defined(CONFIG_OF)
@@ -208,7 +209,7 @@ struct ace_device {
        struct gendisk *gd;
 
        /* Inserted CF card parameters */
-       struct hd_driveid cf_id;
+       u16 cf_id[ATA_ID_WORDS];
 };
 
 static int ace_major;
@@ -402,21 +403,14 @@ static void ace_dump_regs(struct ace_device *ace)
                 ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT));
 }
 
-void ace_fix_driveid(struct hd_driveid *id)
+void ace_fix_driveid(u16 *id)
 {
 #if defined(__BIG_ENDIAN)
-       u16 *buf = (void *)id;
        int i;
 
        /* All half words have wrong byte order; swap the bytes */
-       for (i = 0; i < sizeof(struct hd_driveid); i += 2, buf++)
-               *buf = le16_to_cpu(*buf);
-
-       /* Some of the data values are 32bit; swap the half words  */
-       id->lba_capacity = ((id->lba_capacity >> 16) & 0x0000FFFF) |
-           ((id->lba_capacity << 16) & 0xFFFF0000);
-       id->spg = ((id->spg >> 16) & 0x0000FFFF) |
-           ((id->spg << 16) & 0xFFFF0000);
+       for (i = 0; i < ATA_ID_WORDS; i++, id++)
+               *id = le16_to_cpu(*id);
 #endif
 }
 
@@ -614,7 +608,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
                break;
 
        case ACE_FSM_STATE_IDENTIFY_COMPLETE:
-               ace_fix_driveid(&ace->cf_id);
+               ace_fix_driveid(&ace->cf_id[0]);
                ace_dump_mem(&ace->cf_id, 512); /* Debug: Dump out disk ID */
 
                if (ace->data_result) {
@@ -627,9 +621,10 @@ static void ace_fsm_dostate(struct ace_device *ace)
                        ace->media_change = 0;
 
                        /* Record disk parameters */
-                       set_capacity(ace->gd, ace->cf_id.lba_capacity);
+                       set_capacity(ace->gd,
+                               ata_id_u32(&ace->cf_id, ATA_ID_LBA_CAPACITY));
                        dev_info(ace->dev, "capacity: %i sectors\n",
-                                ace->cf_id.lba_capacity);
+                               ata_id_u32(&ace->cf_id, ATA_ID_LBA_CAPACITY));
                }
 
                /* We're done, drop to IDLE state and notify waiters */
@@ -928,12 +923,13 @@ static int ace_release(struct gendisk *disk, fmode_t mode)
 static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
        struct ace_device *ace = bdev->bd_disk->private_data;
+       u16 *cf_id = &ace->cf_id[0];
 
        dev_dbg(ace->dev, "ace_getgeo()\n");
 
-       geo->heads = ace->cf_id.heads;
-       geo->sectors = ace->cf_id.sectors;
-       geo->cylinders = ace->cf_id.cyls;
+       geo->heads      = cf_id[ATA_ID_HEADS];
+       geo->sectors    = cf_id[ATA_ID_SECTORS];
+       geo->cylinders  = cf_id[ATA_ID_CYLS];
 
        return 0;
 }
index a58869ea8513826d32af82688c661b50fdd90071..fd3ebd1be570f98062ae3761bf6a51d3b1145427 100644 (file)
@@ -79,6 +79,7 @@ static char *serial_version = "4.30";
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
@@ -1825,14 +1826,13 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct serial_state *state)
+static inline void line_info(struct seq_file *m, struct serial_state *state)
 {
        struct async_struct *info = state->info, scr_info;
        char    stat_buf[30], control, status;
-       int     ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%d: uart:amiga_builtin",state->line);
+       seq_printf(m, "%d: uart:amiga_builtin",state->line);
 
        /*
         * Figure out the current RS-232 lines
@@ -1864,55 +1864,49 @@ static inline int line_info(char *buf, struct serial_state *state)
                strcat(stat_buf, "|CD");
 
        if (info->quot) {
-               ret += sprintf(buf+ret, " baud:%d",
-                              state->baud_base / info->quot);
+               seq_printf(m, " baud:%d", state->baud_base / info->quot);
        }
 
-       ret += sprintf(buf+ret, " tx:%d rx:%d",
-                     state->icount.tx, state->icount.rx);
+       seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx);
 
        if (state->icount.frame)
-               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+               seq_printf(m, " fe:%d", state->icount.frame);
 
        if (state->icount.parity)
-               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+               seq_printf(m, " pe:%d", state->icount.parity);
 
        if (state->icount.brk)
-               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
+               seq_printf(m, " brk:%d", state->icount.brk);
 
        if (state->icount.overrun)
-               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+               seq_printf(m, " oe:%d", state->icount.overrun);
 
        /*
         * Last thing is the RS-232 status lines
         */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-       return ret;
+       seq_printf(m, " %s\n", stat_buf+1);
 }
 
-static int rs_read_proc(char *page, char **start, off_t off, int count,
-                       int *eof, void *data)
+static int rs_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
-
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-       l = line_info(page + len, &rs_table[0]);
-       len += l;
-       if (len+begin > off+count)
-         goto done;
-       if (len+begin < off) {
-         begin += len;
-         len = 0;
-       }
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
+       line_info(m, &rs_table[0]);
+       return 0;
 }
 
+static int rs_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rs_proc_show, NULL);
+}
+
+static const struct file_operations rs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rs_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * ---------------------------------------------------------------------
  * rs_init() and friends
@@ -1951,9 +1945,9 @@ static const struct tty_operations serial_ops = {
        .break_ctl = rs_break,
        .send_xchar = rs_send_xchar,
        .wait_until_sent = rs_wait_until_sent,
-       .read_proc = rs_read_proc,
        .tiocmget = rs_tiocmget,
        .tiocmset = rs_tiocmset,
+       .proc_fops = &rs_proc_fops,
 };
 
 /*
index f6094ae0ef334f622ec80f48bd559cae243ebcae..140ea10ecb886e276c8a6ba53d112cdf06d96499 100644 (file)
@@ -140,7 +140,7 @@ static int bsr_open(struct inode * inode, struct file * filp)
        return 0;
 }
 
-const static struct file_operations bsr_fops = {
+static const struct file_operations bsr_fops = {
        .owner = THIS_MODULE,
        .mmap  = bsr_mmap,
        .open  = bsr_open,
index 6a59f72a9c2157697de1a3228a19296e1fc89fb2..272db0e2b491188103f8658ed77e02671004f782 100644 (file)
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 static void cy_throttle(struct tty_struct *tty);
 static void cy_send_xchar(struct tty_struct *tty, char ch);
@@ -868,8 +869,6 @@ static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
 static unsigned detect_isa_irq(void __iomem *);
 #endif                         /* CONFIG_ISA */
 
-static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *);
-
 #ifndef CONFIG_CYZ_INTR
 static void cyz_poll(unsigned long);
 
@@ -5216,31 +5215,22 @@ static struct pci_driver cy_pci_driver = {
 };
 #endif
 
-static int
-cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
-               int *eof, void *data)
+static int cyclades_proc_show(struct seq_file *m, void *v)
 {
        struct cyclades_port *info;
        unsigned int i, j;
-       int len = 0;
-       off_t begin = 0;
-       off_t pos = 0;
-       int size;
        __u32 cur_jifs = jiffies;
 
-       size = sprintf(buf, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
+       seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
                        "IdleIn  Overruns  Ldisc\n");
 
-       pos += size;
-       len += size;
-
        /* Output one line for each known port */
        for (i = 0; i < NR_CARDS; i++)
                for (j = 0; j < cy_card[i].nports; j++) {
                        info = &cy_card[i].ports[j];
 
                        if (info->port.count)
-                               size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+                               seq_printf(m, "%3d %8lu %10lu %8lu "
                                        "%10lu %8lu %9lu %6ld\n", info->line,
                                        (cur_jifs - info->idle_stats.in_use) /
                                        HZ, info->idle_stats.xmit_bytes,
@@ -5251,30 +5241,26 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
                                        /* FIXME: double check locking */
                                        (long)info->port.tty->ldisc.ops->num);
                        else
-                               size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+                               seq_printf(m, "%3d %8lu %10lu %8lu "
                                        "%10lu %8lu %9lu %6ld\n",
                                        info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
-                       len += size;
-                       pos = begin + len;
-
-                       if (pos < offset) {
-                               len = 0;
-                               begin = pos;
-                       }
-                       if (pos > offset + length)
-                               goto done;
                }
-       *eof = 1;
-done:
-       *start = buf + (offset - begin);        /* Start of wanted data */
-       len -= (offset - begin);        /* Start slop */
-       if (len > length)
-               len = length;   /* Ending slop */
-       if (len < 0)
-               len = 0;
-       return len;
+       return 0;
+}
+
+static int cyclades_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, cyclades_proc_show, NULL);
 }
 
+static const struct file_operations cyclades_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = cyclades_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /* The serial driver boot-time initialization code!
     Hardware I/O ports are mapped to character special devices on a
     first found, first allocated manner.  That is, this code searches
@@ -5311,9 +5297,9 @@ static const struct tty_operations cy_ops = {
        .hangup = cy_hangup,
        .break_ctl = cy_break,
        .wait_until_sent = cy_wait_until_sent,
-       .read_proc = cyclades_get_proc_info,
        .tiocmget = cy_tiocmget,
        .tiocmset = cy_tiocmset,
+       .proc_fops = &cyclades_proc_fops,
 };
 
 static int __init cy_init(void)
index 32b8bbf5003e17678a996e50ccb2c9b38d018886..50dfa3bc71cee00de3eeb20858416ce4a4941bfd 100644 (file)
@@ -713,7 +713,7 @@ static struct ctl_table_header *sysctl_header;
  */
 #define        TICK_CALIBRATE  (1000UL)
 
-static unsigned long hpet_calibrate(struct hpets *hpetp)
+static unsigned long __hpet_calibrate(struct hpets *hpetp)
 {
        struct hpet_timer __iomem *timer = NULL;
        unsigned long t, m, count, i, flags, start;
@@ -750,6 +750,26 @@ static unsigned long hpet_calibrate(struct hpets *hpetp)
        return (m - start) / i;
 }
 
+static unsigned long hpet_calibrate(struct hpets *hpetp)
+{
+       unsigned long ret = -1;
+       unsigned long tmp;
+
+       /*
+        * Try to calibrate until return value becomes stable small value.
+        * If SMI interruption occurs in calibration loop, the return value
+        * will be big. This avoids its impact.
+        */
+       for ( ; ; ) {
+               tmp = __hpet_calibrate(hpetp);
+               if (ret <= tmp)
+                       break;
+               ret = tmp;
+       }
+
+       return ret;
+}
+
 int hpet_alloc(struct hpet_data *hdp)
 {
        u64 cap, mcfg;
index 10ad41be5897ec53ab27623d0677aa31ed714365..dcd352ad0e7f1e1378c654efd3266c56bf403604 100644 (file)
@@ -90,10 +90,30 @@ static struct hwrng timeriomem_rng_ops = {
 
 static int __init timeriomem_rng_probe(struct platform_device *pdev)
 {
+       struct resource *res, *mem;
        int ret;
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!res)
+               return -ENOENT;
+
+       mem = request_mem_region(res->start, res->end - res->start + 1,
+                                pdev->name);
+       if (mem == NULL)
+               return -EBUSY;
+
+       dev_set_drvdata(&pdev->dev, mem);
+
        timeriomem_rng_data = pdev->dev.platform_data;
 
+       timeriomem_rng_data->address = ioremap(res->start,
+                                               res->end - res->start + 1);
+       if (!timeriomem_rng_data->address) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
        if (timeriomem_rng_data->period != 0
                && usecs_to_jiffies(timeriomem_rng_data->period) > 0) {
                timeriomem_rng_timer.expires = jiffies;
@@ -104,23 +124,34 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev)
        timeriomem_rng_data->present = 1;
 
        ret = hwrng_register(&timeriomem_rng_ops);
-       if (ret) {
-               dev_err(&pdev->dev, "problem registering\n");
-               return ret;
-       }
+       if (ret)
+               goto err_register;
 
        dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
                        timeriomem_rng_data->address,
                        timeriomem_rng_data->period);
 
        return 0;
+
+err_register:
+       dev_err(&pdev->dev, "problem registering\n");
+       iounmap(timeriomem_rng_data->address);
+err_ioremap:
+       release_resource(mem);
+
+       return ret;
 }
 
 static int __devexit timeriomem_rng_remove(struct platform_device *pdev)
 {
+       struct resource *mem = dev_get_drvdata(&pdev->dev);
+
        del_timer_sync(&timeriomem_rng_timer);
        hwrng_unregister(&timeriomem_rng_ops);
 
+       iounmap(timeriomem_rng_data->address);
+       release_resource(mem);
+
        return 0;
 }
 
index 70e0ebc30bd08d5b9e034b2b22c341475c761252..afd9247cf082d15e2cb6f1e8273c72fba9317ba5 100644 (file)
 #include <linux/seq_file.h>
 
 static const struct file_operations ip2mem_proc_fops;
-static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
+static const struct file_operations ip2_proc_fops;
 
 /********************/
 /* Type Definitions */
@@ -446,9 +446,9 @@ static const struct tty_operations ip2_ops = {
        .stop            = ip2_stop,
        .start           = ip2_start,
        .hangup          = ip2_hangup,
-       .read_proc       = ip2_read_proc,
        .tiocmget        = ip2_tiocmget,
        .tiocmset        = ip2_tiocmset,
+       .proc_fops       = &ip2_proc_fops,
 };
 
 /******************************************************************************/
@@ -3029,19 +3029,17 @@ static const struct file_operations ip2mem_proc_fops = {
  * different sources including ip2mkdev.c and a couple of other drivers.
  * The bugs are all mine.  :-) =mhw=
  */
-static int ip2_read_proc(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
+static int ip2_proc_show(struct seq_file *m, void *v)
 {
        int     i, j, box;
-       int     len = 0;
        int     boxes = 0;
        int     ports = 0;
        int     tports = 0;
-       off_t   begin = 0;
        i2eBordStrPtr  pB;
+       char *sep;
 
-       len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion );
-       len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
+       seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion);
+       seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
                        IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
                        IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
 
@@ -3053,7 +3051,8 @@ static int ip2_read_proc(char *page, char **start, off_t off,
                        switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) 
                        {
                        case POR_ID_FIIEX:
-                               len += sprintf( page+len, "Board %d: EX ports=", i );
+                               seq_printf(m, "Board %d: EX ports=", i);
+                               sep = "";
                                for( box = 0; box < ABS_MAX_BOXES; ++box )
                                {
                                        ports = 0;
@@ -3065,79 +3064,74 @@ static int ip2_read_proc(char *page, char **start, off_t off,
                                                        ++ports;
                                                }
                                        }
-                                       len += sprintf( page+len, "%d,", ports );
+                                       seq_printf(m, "%s%d", sep, ports);
+                                       sep = ",";
                                        tports += ports;
                                }
-
-                               --len;  /* Backup over that last comma */
-
-                               len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 );
+                               seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8);
                                break;
 
                        case POR_ID_II_4:
-                               len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i );
+                               seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i);
                                tports = ports = 4;
                                break;
 
                        case POR_ID_II_8:
-                               len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i );
+                               seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i);
                                tports = ports = 8;
                                break;
 
                        case POR_ID_II_8R:
-                               len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i );
+                               seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i);
                                tports = ports = 8;
                                break;
 
                        default:
-                               len += sprintf(page+len, "Board %d: unknown", i );
+                               seq_printf(m, "Board %d: unknown", i);
                                /* Don't try and probe for minor numbers */
                                tports = ports = 0;
                        }
 
                } else {
                        /* Don't try and probe for minor numbers */
-                       len += sprintf(page+len, "Board %d: vacant", i );
+                       seq_printf(m, "Board %d: vacant", i);
                        tports = ports = 0;
                }
 
                if( tports ) {
-                       len += sprintf(page+len, " minors=" );
-
+                       seq_puts(m, " minors=");
+                       sep = "";
                        for ( box = 0; box < ABS_MAX_BOXES; ++box )
                        {
                                for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
                                {
                                        if ( pB->i2eChannelMap[box] & (1 << j) )
                                        {
-                                               len += sprintf (page+len,"%d,",
+                                               seq_printf(m, "%s%d", sep,
                                                        j + ABS_BIGGEST_BOX *
                                                        (box+i*ABS_MAX_BOXES));
+                                               sep = ",";
                                        }
                                }
                        }
-
-                       page[ len - 1 ] = '\n'; /* Overwrite that last comma */
-               } else {
-                       len += sprintf (page+len,"\n" );
-               }
-
-               if (len+begin > off+count)
-                       break;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
                }
+               seq_putc(m, '\n');
        }
+       return 0;
+ }
 
-       if (i >= IP2_MAX_BOARDS)
-               *eof = 1;
-       if (off >= len+begin)
-               return 0;
+static int ip2_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ip2_proc_show, NULL);
+}
 
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
- }
+static const struct file_operations ip2_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ip2_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
  
 /******************************************************************************/
 /* Function:   ip2trace()                                                     */
index 7a88dfd4427b136c6e034b06d4f6e6e3a416cd39..e93fc8d22fb2b839413dacd50fda823c060f7989 100644 (file)
@@ -1944,7 +1944,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
 
 int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
                            read_proc_t *read_proc,
-                           void *data, struct module *owner)
+                           void *data)
 {
        int                    rv = 0;
 #ifdef CONFIG_PROC_FS
@@ -1970,7 +1970,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
        } else {
                file->data = data;
                file->read_proc = read_proc;
-               file->owner = owner;
 
                mutex_lock(&smi->proc_entry_lock);
                /* Stick it on the list. */
@@ -1993,23 +1992,21 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
        smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
        if (!smi->proc_dir)
                rv = -ENOMEM;
-       else
-               smi->proc_dir->owner = THIS_MODULE;
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "stats",
                                             stat_file_read_proc,
-                                            smi, THIS_MODULE);
+                                            smi);
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "ipmb",
                                             ipmb_file_read_proc,
-                                            smi, THIS_MODULE);
+                                            smi);
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "version",
                                             version_file_read_proc,
-                                            smi, THIS_MODULE);
+                                            smi);
 #endif /* CONFIG_PROC_FS */
 
        return rv;
@@ -4265,7 +4262,6 @@ static int ipmi_init_msghandler(void)
            return -ENOMEM;
        }
 
-       proc_ipmi_root->owner = THIS_MODULE;
 #endif /* CONFIG_PROC_FS */
 
        setup_timer(&ipmi_timer, ipmi_timeout, 0);
index 3000135f2ead3bcd98cd505b7fa89f11d0d2ab5e..e58ea4cd55ce02a101f282dd5977be4417b41bf4 100644 (file)
@@ -2899,7 +2899,7 @@ static int try_smi_init(struct smi_info *new_smi)
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
                                     type_file_read_proc,
-                                    new_smi, THIS_MODULE);
+                                    new_smi);
        if (rv) {
                printk(KERN_ERR
                       "ipmi_si: Unable to create proc entry: %d\n",
@@ -2909,7 +2909,7 @@ static int try_smi_init(struct smi_info *new_smi)
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
                                     stat_file_read_proc,
-                                    new_smi, THIS_MODULE);
+                                    new_smi);
        if (rv) {
                printk(KERN_ERR
                       "ipmi_si: Unable to create proc entry: %d\n",
@@ -2919,7 +2919,7 @@ static int try_smi_init(struct smi_info *new_smi)
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
                                     param_read_proc,
-                                    new_smi, THIS_MODULE);
+                                    new_smi);
        if (rv) {
                printk(KERN_ERR
                       "ipmi_si: Unable to create proc entry: %d\n",
index 5c3dc6b8411c88d62ec800f082678dc6f66ec3d8..fff19f7e29d25eac8c7cfbb4903638107dd8561c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/seq_file.h>
 #include <linux/cdk.h>
 #include <linux/comstats.h>
 #include <linux/istallion.h>
@@ -613,7 +614,6 @@ static int  stli_breakctl(struct tty_struct *tty, int state);
 static void    stli_waituntilsent(struct tty_struct *tty, int timeout);
 static void    stli_sendxchar(struct tty_struct *tty, char ch);
 static void    stli_hangup(struct tty_struct *tty);
-static int     stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos);
 
 static int     stli_brdinit(struct stlibrd *brdp);
 static int     stli_startbrd(struct stlibrd *brdp);
@@ -1893,20 +1893,10 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
        stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
 }
 
-/*****************************************************************************/
-
-#define        MAXLINE         80
-
-/*
- *     Format info for a specified port. The line is deliberately limited
- *     to 80 characters. (If it is too long it will be truncated, if too
- *     short then padded with spaces).
- */
-
-static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos)
+static void stli_portinfo(struct seq_file *m, struct stlibrd *brdp, struct stliport *portp, int portnr)
 {
-       char *sp, *uart;
-       int rc, cnt;
+       char *uart;
+       int rc;
 
        rc = stli_portcmdstats(NULL, portp);
 
@@ -1918,44 +1908,50 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
                default:uart = "CD1400"; break;
                }
        }
-
-       sp = pos;
-       sp += sprintf(sp, "%d: uart:%s ", portnr, uart);
+       seq_printf(m, "%d: uart:%s ", portnr, uart);
 
        if ((brdp->state & BST_STARTED) && (rc >= 0)) {
-               sp += sprintf(sp, "tx:%d rx:%d", (int) stli_comstats.txtotal,
+               char sep;
+
+               seq_printf(m, "tx:%d rx:%d", (int) stli_comstats.txtotal,
                        (int) stli_comstats.rxtotal);
 
                if (stli_comstats.rxframing)
-                       sp += sprintf(sp, " fe:%d",
+                       seq_printf(m, " fe:%d",
                                (int) stli_comstats.rxframing);
                if (stli_comstats.rxparity)
-                       sp += sprintf(sp, " pe:%d",
+                       seq_printf(m, " pe:%d",
                                (int) stli_comstats.rxparity);
                if (stli_comstats.rxbreaks)
-                       sp += sprintf(sp, " brk:%d",
+                       seq_printf(m, " brk:%d",
                                (int) stli_comstats.rxbreaks);
                if (stli_comstats.rxoverrun)
-                       sp += sprintf(sp, " oe:%d",
+                       seq_printf(m, " oe:%d",
                                (int) stli_comstats.rxoverrun);
 
-               cnt = sprintf(sp, "%s%s%s%s%s ",
-                       (stli_comstats.signals & TIOCM_RTS) ? "|RTS" : "",
-                       (stli_comstats.signals & TIOCM_CTS) ? "|CTS" : "",
-                       (stli_comstats.signals & TIOCM_DTR) ? "|DTR" : "",
-                       (stli_comstats.signals & TIOCM_CD) ? "|DCD" : "",
-                       (stli_comstats.signals & TIOCM_DSR) ? "|DSR" : "");
-               *sp = ' ';
-               sp += cnt;
+               sep = ' ';
+               if (stli_comstats.signals & TIOCM_RTS) {
+                       seq_printf(m, "%c%s", sep, "RTS");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_CTS) {
+                       seq_printf(m, "%c%s", sep, "CTS");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_DTR) {
+                       seq_printf(m, "%c%s", sep, "DTR");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_CD) {
+                       seq_printf(m, "%c%s", sep, "DCD");
+                       sep = '|';
+               }
+               if (stli_comstats.signals & TIOCM_DSR) {
+                       seq_printf(m, "%c%s", sep, "DSR");
+                       sep = '|';
+               }
        }
-
-       for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
-               *sp++ = ' ';
-       if (cnt >= MAXLINE)
-               pos[(MAXLINE - 2)] = '+';
-       pos[(MAXLINE - 1)] = '\n';
-
-       return(MAXLINE);
+       seq_putc(m, '\n');
 }
 
 /*****************************************************************************/
@@ -1964,26 +1960,15 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
  *     Port info, read from the /proc file system.
  */
 
-static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int stli_proc_show(struct seq_file *m, void *v)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
        unsigned int brdnr, portnr, totalport;
-       int curoff, maxoff;
-       char *pos;
 
-       pos = page;
        totalport = 0;
-       curoff = 0;
-
-       if (off == 0) {
-               pos += sprintf(pos, "%s: version %s", stli_drvtitle,
-                       stli_drvversion);
-               while (pos < (page + MAXLINE - 1))
-                       *pos++ = ' ';
-               *pos++ = '\n';
-       }
-       curoff =  MAXLINE;
+
+       seq_printf(m, "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
 /*
  *     We scan through for each board, panel and port. The offset is
@@ -1996,33 +1981,31 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
                if (brdp->state == 0)
                        continue;
 
-               maxoff = curoff + (brdp->nrports * MAXLINE);
-               if (off >= maxoff) {
-                       curoff = maxoff;
-                       continue;
-               }
-
                totalport = brdnr * STL_MAXPORTS;
                for (portnr = 0; (portnr < brdp->nrports); portnr++,
                    totalport++) {
                        portp = brdp->ports[portnr];
                        if (portp == NULL)
                                continue;
-                       if (off >= (curoff += MAXLINE))
-                               continue;
-                       if ((pos - page + MAXLINE) > count)
-                               goto stli_readdone;
-                       pos += stli_portinfo(brdp, portp, totalport, pos);
+                       stli_portinfo(m, brdp, portp, totalport);
                }
        }
+       return 0;
+}
 
-       *eof = 1;
-
-stli_readdone:
-       *start = page;
-       return(pos - page);
+static int stli_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stli_proc_show, NULL);
 }
 
+static const struct file_operations stli_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = stli_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*****************************************************************************/
 
 /*
@@ -4427,9 +4410,9 @@ static const struct tty_operations stli_ops = {
        .break_ctl = stli_breakctl,
        .wait_until_sent = stli_waituntilsent,
        .send_xchar = stli_sendxchar,
-       .read_proc = stli_readproc,
        .tiocmget = stli_tiocmget,
        .tiocmset = stli_tiocmset,
+       .proc_fops = &stli_proc_fops,
 };
 
 static const struct tty_port_operations stli_port_ops = {
index 5608a1e5a3b3416fa44e44e504c9a2817d1c3c2c..19d79fc54461c592111fbce5d0e68e395e10dcd4 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
@@ -2619,13 +2620,12 @@ cleanup:
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, MGSLPC_INFO *info)
+static inline void line_info(struct seq_file *m, MGSLPC_INFO *info)
 {
        char    stat_buf[30];
-       int     ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%s:io:%04X irq:%d",
+       seq_printf(m, "%s:io:%04X irq:%d",
                      info->device_name, info->io_base, info->irq_level);
 
        /* output current serial signal states */
@@ -2649,75 +2649,70 @@ static inline int line_info(char *buf, MGSLPC_INFO *info)
                strcat(stat_buf, "|RI");
 
        if (info->params.mode == MGSL_MODE_HDLC) {
-               ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d",
+               seq_printf(m, " HDLC txok:%d rxok:%d",
                              info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d",
+               seq_printf(m, " ASYNC tx:%d rx:%d",
                              info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
 
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
 
-       ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
                       info->tx_active,info->bh_requested,info->bh_running,
                       info->pending_bh);
-
-       return ret;
 }
 
 /* Called to print information about devices
  */
-static int mgslpc_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
+static int mgslpc_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        MGSLPC_INFO *info;
 
-       len += sprintf(page, "synclink driver:%s\n", driver_version);
+       seq_printf(m, "synclink driver:%s\n", driver_version);
 
        info = mgslpc_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+static int mgslpc_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mgslpc_proc_show, NULL);
 }
 
+static const struct file_operations mgslpc_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mgslpc_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int rx_alloc_buffers(MGSLPC_INFO *info)
 {
        /* each buffer has header and data */
@@ -2861,13 +2856,13 @@ static const struct tty_operations mgslpc_ops = {
        .send_xchar = mgslpc_send_xchar,
        .break_ctl = mgslpc_break,
        .wait_until_sent = mgslpc_wait_until_sent,
-       .read_proc = mgslpc_read_proc,
        .set_termios = mgslpc_set_termios,
        .stop = tx_pause,
        .start = tx_release,
        .hangup = mgslpc_hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &mgslpc_proc_fops,
 };
 
 static void synclink_cs_cleanup(void)
index 7c43ae782b26e385e1b0c96efacd7e82846b794b..f824ef8a9273d7d46e63b113fa83ea03249f95e1 100644 (file)
@@ -1488,7 +1488,8 @@ static void rekey_seq_generator(struct work_struct *work)
        keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS;
        smp_wmb();
        ip_cnt++;
-       schedule_delayed_work(&rekey_work, REKEY_INTERVAL);
+       schedule_delayed_work(&rekey_work,
+                             round_jiffies_relative(REKEY_INTERVAL));
 }
 
 static inline struct keydata *get_keyptr(void)
index e1e0dd89ac9aa309e2f92c9183618948b09b6900..2ad813a801dc391cc8bca62a4cc847b16ea0d4d1 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/seq_file.h>
 #include <linux/cd1400.h>
 #include <linux/sc26198.h>
 #include <linux/comstats.h>
@@ -1379,52 +1380,47 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
                stl_putchar(tty, ch);
 }
 
-/*****************************************************************************/
-
-#define        MAXLINE         80
-
-/*
- *     Format info for a specified port. The line is deliberately limited
- *     to 80 characters. (If it is too long it will be truncated, if too
- *     short then padded with spaces).
- */
-
-static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
+static void stl_portinfo(struct seq_file *m, struct stlport *portp, int portnr)
 {
-       char    *sp;
-       int     sigs, cnt;
+       int     sigs;
+       char sep;
 
-       sp = pos;
-       sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d",
+       seq_printf(m, "%d: uart:%s tx:%d rx:%d",
                portnr, (portp->hwid == 1) ? "SC26198" : "CD1400",
                (int) portp->stats.txtotal, (int) portp->stats.rxtotal);
 
        if (portp->stats.rxframing)
-               sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing);
+               seq_printf(m, " fe:%d", (int) portp->stats.rxframing);
        if (portp->stats.rxparity)
-               sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity);
+               seq_printf(m, " pe:%d", (int) portp->stats.rxparity);
        if (portp->stats.rxbreaks)
-               sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks);
+               seq_printf(m, " brk:%d", (int) portp->stats.rxbreaks);
        if (portp->stats.rxoverrun)
-               sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun);
+               seq_printf(m, " oe:%d", (int) portp->stats.rxoverrun);
 
        sigs = stl_getsignals(portp);
-       cnt = sprintf(sp, "%s%s%s%s%s ",
-               (sigs & TIOCM_RTS) ? "|RTS" : "",
-               (sigs & TIOCM_CTS) ? "|CTS" : "",
-               (sigs & TIOCM_DTR) ? "|DTR" : "",
-               (sigs & TIOCM_CD) ? "|DCD" : "",
-               (sigs & TIOCM_DSR) ? "|DSR" : "");
-       *sp = ' ';
-       sp += cnt;
-
-       for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++)
-               *sp++ = ' ';
-       if (cnt >= MAXLINE)
-               pos[(MAXLINE - 2)] = '+';
-       pos[(MAXLINE - 1)] = '\n';
-
-       return MAXLINE;
+       sep = ' ';
+       if (sigs & TIOCM_RTS) {
+               seq_printf(m, "%c%s", sep, "RTS");
+               sep = '|';
+       }
+       if (sigs & TIOCM_CTS) {
+               seq_printf(m, "%c%s", sep, "CTS");
+               sep = '|';
+       }
+       if (sigs & TIOCM_DTR) {
+               seq_printf(m, "%c%s", sep, "DTR");
+               sep = '|';
+       }
+       if (sigs & TIOCM_CD) {
+               seq_printf(m, "%c%s", sep, "DCD");
+               sep = '|';
+       }
+       if (sigs & TIOCM_DSR) {
+               seq_printf(m, "%c%s", sep, "DSR");
+               sep = '|';
+       }
+       seq_putc(m, '\n');
 }
 
 /*****************************************************************************/
@@ -1433,30 +1429,17 @@ static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
  *     Port info, read from the /proc file system.
  */
 
-static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int stl_proc_show(struct seq_file *m, void *v)
 {
        struct stlbrd   *brdp;
        struct stlpanel *panelp;
        struct stlport  *portp;
        unsigned int    brdnr, panelnr, portnr;
-       int             totalport, curoff, maxoff;
-       char            *pos;
+       int             totalport;
 
-       pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p,"
-               "data=%p\n", page, start, off, count, eof, data);
-
-       pos = page;
        totalport = 0;
-       curoff = 0;
-
-       if (off == 0) {
-               pos += sprintf(pos, "%s: version %s", stl_drvtitle,
-                       stl_drvversion);
-               while (pos < (page + MAXLINE - 1))
-                       *pos++ = ' ';
-               *pos++ = '\n';
-       }
-       curoff =  MAXLINE;
+
+       seq_printf(m, "%s: version %s\n", stl_drvtitle, stl_drvversion);
 
 /*
  *     We scan through for each board, panel and port. The offset is
@@ -1469,46 +1452,37 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof
                if (brdp->state == 0)
                        continue;
 
-               maxoff = curoff + (brdp->nrports * MAXLINE);
-               if (off >= maxoff) {
-                       curoff = maxoff;
-                       continue;
-               }
-
                totalport = brdnr * STL_MAXPORTS;
                for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) {
                        panelp = brdp->panels[panelnr];
                        if (panelp == NULL)
                                continue;
 
-                       maxoff = curoff + (panelp->nrports * MAXLINE);
-                       if (off >= maxoff) {
-                               curoff = maxoff;
-                               totalport += panelp->nrports;
-                               continue;
-                       }
-
                        for (portnr = 0; portnr < panelp->nrports; portnr++,
                            totalport++) {
                                portp = panelp->ports[portnr];
                                if (portp == NULL)
                                        continue;
-                               if (off >= (curoff += MAXLINE))
-                                       continue;
-                               if ((pos - page + MAXLINE) > count)
-                                       goto stl_readdone;
-                               pos += stl_portinfo(portp, totalport, pos);
+                               stl_portinfo(m, portp, totalport);
                        }
                }
        }
+       return 0;
+}
 
-       *eof = 1;
-
-stl_readdone:
-       *start = page;
-       return pos - page;
+static int stl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stl_proc_show, NULL);
 }
 
+static const struct file_operations stl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = stl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*****************************************************************************/
 
 /*
@@ -2566,9 +2540,9 @@ static const struct tty_operations stl_ops = {
        .break_ctl = stl_breakctl,
        .wait_until_sent = stl_waituntilsent,
        .send_xchar = stl_sendxchar,
-       .read_proc = stl_readproc,
        .tiocmget = stl_tiocmget,
        .tiocmset = stl_tiocmset,
+       .proc_fops = &stl_proc_fops,
 };
 
 static const struct tty_port_operations stl_port_ops = {
index 0057a8f58cb1261c71b48db67f1562d74282ee59..afd0b26ca05681210edd0cc0f22b01497eea3e37 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -3459,18 +3460,17 @@ cleanup:
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct mgsl_struct *info)
+static inline void line_info(struct seq_file *m, struct mgsl_struct *info)
 {
        char    stat_buf[30];
-       int     ret;
        unsigned long flags;
 
        if (info->bus_type == MGSL_BUS_TYPE_PCI) {
-               ret = sprintf(buf, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X",
+               seq_printf(m, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X",
                        info->device_name, info->io_base, info->irq_level,
                        info->phys_memory_base, info->phys_lcr_base);
        } else {
-               ret = sprintf(buf, "%s:(E)ISA io:%04X irq:%d dma:%d",
+               seq_printf(m, "%s:(E)ISA io:%04X irq:%d dma:%d",
                        info->device_name, info->io_base, 
                        info->irq_level, info->dma_level);
        }
@@ -3497,37 +3497,37 @@ static inline int line_info(char *buf, struct mgsl_struct *info)
 
        if (info->params.mode == MGSL_MODE_HDLC ||
            info->params.mode == MGSL_MODE_RAW ) {
-               ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d",
+               seq_printf(m, " HDLC txok:%d rxok:%d",
                              info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);   
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d",
+               seq_printf(m, " ASYNC tx:%d rx:%d",
                              info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);   
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
        
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
        
-       ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
         info->tx_active,info->bh_requested,info->bh_running,
         info->pending_bh);
         
@@ -3544,60 +3544,40 @@ static inline int line_info(char *buf, struct mgsl_struct *info)
        u16 Tmr = usc_InReg( info, TMR );
        u16 Tccr = usc_InReg( info, TCCR );
        u16 Ccar = inw( info->io_base + CCAR );
-       ret += sprintf(buf+ret, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n"
+       seq_printf(m, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n"
                         "ricr=%04X icr =%04X dccr=%04X tmr=%04X tccr=%04X ccar=%04X\n",
                        Tcsr,Tdmr,Ticr,Rscr,Rdmr,Ricr,Icr,Dccr,Tmr,Tccr,Ccar );
        }
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
-       
-       return ret;
-       
-}      /* end of line_info() */
+}
 
-/* mgsl_read_proc()
- * 
- * Called to print information about devices
- * 
- * Arguments:
- *     page    page of memory to hold returned info
- *     start   
- *     off
- *     count
- *     eof
- *     data
- *     
- * Return Value:
- */
-static int mgsl_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
+/* Called to print information about devices */
+static int mgsl_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        struct mgsl_struct *info;
        
-       len += sprintf(page, "synclink driver:%s\n", driver_version);
+       seq_printf(m, "synclink driver:%s\n", driver_version);
        
        info = mgsl_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
-       
-}      /* end of mgsl_read_proc() */
+static int mgsl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mgsl_proc_show, NULL);
+}
+
+static const struct file_operations mgsl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mgsl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /* mgsl_allocate_dma_buffers()
  * 
@@ -4335,13 +4315,13 @@ static const struct tty_operations mgsl_ops = {
        .send_xchar = mgsl_send_xchar,
        .break_ctl = mgsl_break,
        .wait_until_sent = mgsl_wait_until_sent,
-       .read_proc = mgsl_read_proc,
        .set_termios = mgsl_set_termios,
        .stop = mgsl_stop,
        .start = mgsl_start,
        .hangup = mgsl_hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &mgsl_proc_fops,
 };
 
 /*
index efb3dc928a43a7b6fe26bcfc551511f84d601772..5e256494686a8413734db27db5b9826069e36847 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
@@ -154,7 +155,6 @@ static void tx_hold(struct tty_struct *tty);
 static void tx_release(struct tty_struct *tty);
 
 static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
 static int  chars_in_buffer(struct tty_struct *tty);
 static void throttle(struct tty_struct * tty);
 static void unthrottle(struct tty_struct * tty);
@@ -298,6 +298,7 @@ struct slgt_info {
 
        unsigned int rbuf_fill_level;
        unsigned int if_mode;
+       unsigned int base_clock;
 
        /* device status */
 
@@ -1156,22 +1157,26 @@ static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *ne
                return -EFAULT;
 
        spin_lock(&info->lock);
-       info->params.mode            = tmp_params.mode;
-       info->params.loopback        = tmp_params.loopback;
-       info->params.flags           = tmp_params.flags;
-       info->params.encoding        = tmp_params.encoding;
-       info->params.clock_speed     = tmp_params.clock_speed;
-       info->params.addr_filter     = tmp_params.addr_filter;
-       info->params.crc_type        = tmp_params.crc_type;
-       info->params.preamble_length = tmp_params.preamble_length;
-       info->params.preamble        = tmp_params.preamble;
-       info->params.data_rate       = tmp_params.data_rate;
-       info->params.data_bits       = tmp_params.data_bits;
-       info->params.stop_bits       = tmp_params.stop_bits;
-       info->params.parity          = tmp_params.parity;
+       if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) {
+               info->base_clock = tmp_params.clock_speed;
+       } else {
+               info->params.mode            = tmp_params.mode;
+               info->params.loopback        = tmp_params.loopback;
+               info->params.flags           = tmp_params.flags;
+               info->params.encoding        = tmp_params.encoding;
+               info->params.clock_speed     = tmp_params.clock_speed;
+               info->params.addr_filter     = tmp_params.addr_filter;
+               info->params.crc_type        = tmp_params.crc_type;
+               info->params.preamble_length = tmp_params.preamble_length;
+               info->params.preamble        = tmp_params.preamble;
+               info->params.data_rate       = tmp_params.data_rate;
+               info->params.data_bits       = tmp_params.data_bits;
+               info->params.stop_bits       = tmp_params.stop_bits;
+               info->params.parity          = tmp_params.parity;
+       }
        spin_unlock(&info->lock);
 
-       change_params(info);
+       program_hw(info);
 
        return 0;
 }
@@ -1229,13 +1234,12 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
 /*
  * proc fs support
  */
-static inline int line_info(char *buf, struct slgt_info *info)
+static inline void line_info(struct seq_file *m, struct slgt_info *info)
 {
        char stat_buf[30];
-       int ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
+       seq_printf(m, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
                      info->device_name, info->phys_reg_addr,
                      info->irq_level, info->max_frame_size);
 
@@ -1260,75 +1264,70 @@ static inline int line_info(char *buf, struct slgt_info *info)
                strcat(stat_buf, "|RI");
 
        if (info->params.mode != MGSL_MODE_ASYNC) {
-               ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+               seq_printf(m, "\tHDLC txok:%d rxok:%d",
                               info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+               seq_printf(m, "\tASYNC tx:%d rx:%d",
                               info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
 
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
 
-       ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
                       info->tx_active,info->bh_requested,info->bh_running,
                       info->pending_bh);
-
-       return ret;
 }
 
 /* Called to print information about devices
  */
-static int read_proc(char *page, char **start, off_t off, int count,
-                    int *eof, void *data)
+static int synclink_gt_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        struct slgt_info *info;
 
-       len += sprintf(page, "synclink_gt driver\n");
+       seq_puts(m, "synclink_gt driver\n");
 
        info = slgt_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+static int synclink_gt_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, synclink_gt_proc_show, NULL);
 }
 
+static const struct file_operations synclink_gt_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = synclink_gt_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * return count of bytes in transmit buffer
  */
@@ -2565,10 +2564,13 @@ static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params)
                return -EFAULT;
 
        spin_lock_irqsave(&info->lock, flags);
-       memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
+       if (tmp_params.mode == MGSL_MODE_BASE_CLOCK)
+               info->base_clock = tmp_params.clock_speed;
+       else
+               memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
        spin_unlock_irqrestore(&info->lock, flags);
 
-       change_params(info);
+       program_hw(info);
 
        return 0;
 }
@@ -3438,6 +3440,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
+               info->base_clock = 14745600;
                info->rbuf_fill_level = DMABUFSIZE;
                info->port.close_delay = 5*HZ/10;
                info->port.closing_wait = 30*HZ;
@@ -3562,13 +3565,13 @@ static const struct tty_operations ops = {
        .send_xchar = send_xchar,
        .break_ctl = set_break,
        .wait_until_sent = wait_until_sent,
-       .read_proc = read_proc,
        .set_termios = set_termios,
        .stop = tx_hold,
        .start = tx_release,
        .hangup = hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &synclink_gt_proc_fops,
 };
 
 static void slgt_cleanup(void)
@@ -3785,7 +3788,7 @@ static void enable_loopback(struct slgt_info *info)
 static void set_rate(struct slgt_info *info, u32 rate)
 {
        unsigned int div;
-       static unsigned int osc = 14745600;
+       unsigned int osc = info->base_clock;
 
        /* div = osc/rate - 1
         *
@@ -4089,18 +4092,27 @@ static void async_mode(struct slgt_info *info)
         * 06  CTS      IRQ enable
         * 05  DCD      IRQ enable
         * 04  RI       IRQ enable
-        * 03  reserved, must be zero
+        * 03  0=16x sampling, 1=8x sampling
         * 02  1=txd->rxd internal loopback enable
         * 01  reserved, must be zero
         * 00  1=master IRQ enable
         */
        val = BIT15 + BIT14 + BIT0;
+       /* JCR[8] : 1 = x8 async mode feature available */
+       if ((rd_reg32(info, JCR) & BIT8) && info->params.data_rate &&
+           ((info->base_clock < (info->params.data_rate * 16)) ||
+            (info->base_clock % (info->params.data_rate * 16)))) {
+               /* use 8x sampling */
+               val |= BIT3;
+               set_rate(info, info->params.data_rate * 8);
+       } else {
+               /* use 16x sampling */
+               set_rate(info, info->params.data_rate * 16);
+       }
        wr_reg16(info, SCR, val);
 
        slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER);
 
-       set_rate(info, info->params.data_rate * 16);
-
        if (info->params.loopback)
                enable_loopback(info);
 }
index 8eb6c89a980ec1cb674eef7fe83e42142ea4d5cf..26de60efe4b247162c3be863bb3a3c66d86d6c49 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
@@ -520,7 +521,6 @@ static void tx_hold(struct tty_struct *tty);
 static void tx_release(struct tty_struct *tty);
 
 static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
 static int  chars_in_buffer(struct tty_struct *tty);
 static void throttle(struct tty_struct * tty);
 static void unthrottle(struct tty_struct * tty);
@@ -1354,13 +1354,12 @@ static int ioctl(struct tty_struct *tty, struct file *file,
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, SLMP_INFO *info)
+static inline void line_info(struct seq_file *m, SLMP_INFO *info)
 {
        char    stat_buf[30];
-       int     ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n"
+       seq_printf(m, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n"
                       "\tIRQ=%d MaxFrameSize=%u\n",
                info->device_name,
                info->phys_sca_base,
@@ -1391,75 +1390,70 @@ static inline int line_info(char *buf, SLMP_INFO *info)
                strcat(stat_buf, "|RI");
 
        if (info->params.mode == MGSL_MODE_HDLC) {
-               ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+               seq_printf(m, "\tHDLC txok:%d rxok:%d",
                              info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxlong:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+               seq_printf(m, "\tASYNC tx:%d rx:%d",
                              info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
 
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
 
-       ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
         info->tx_active,info->bh_requested,info->bh_running,
         info->pending_bh);
-
-       return ret;
 }
 
 /* Called to print information about devices
  */
-static int read_proc(char *page, char **start, off_t off, int count,
-             int *eof, void *data)
+static int synclinkmp_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        SLMP_INFO *info;
 
-       len += sprintf(page, "synclinkmp driver:%s\n", driver_version);
+       seq_printf(m, "synclinkmp driver:%s\n", driver_version);
 
        info = synclinkmp_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+static int synclinkmp_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, synclinkmp_proc_show, NULL);
 }
 
+static const struct file_operations synclinkmp_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = synclinkmp_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /* Return the count of bytes in transmit buffer
  */
 static int chars_in_buffer(struct tty_struct *tty)
@@ -3905,13 +3899,13 @@ static const struct tty_operations ops = {
        .send_xchar = send_xchar,
        .break_ctl = set_break,
        .wait_until_sent = wait_until_sent,
-       .read_proc = read_proc,
        .set_termios = set_termios,
        .stop = tx_hold,
        .start = tx_release,
        .hangup = hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &synclinkmp_proc_fops,
 };
 
 
index 33a9351c896dfbaff7dbf9afb5515d998bbb943e..ebea9b2c30a583737a0e7800122217ff4eaf273c 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/vt_kern.h>
 #include <linux/workqueue.h>
 #include <linux/kexec.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/hrtimer.h>
 #include <linux/oom.h>
 
@@ -346,6 +346,19 @@ static struct sysrq_key_op sysrq_moom_op = {
        .enable_mask    = SYSRQ_ENABLE_SIGNAL,
 };
 
+#ifdef CONFIG_BLOCK
+static void sysrq_handle_thaw(int key, struct tty_struct *tty)
+{
+       emergency_thaw_all();
+}
+static struct sysrq_key_op sysrq_thaw_op = {
+       .handler        = sysrq_handle_thaw,
+       .help_msg       = "thaw-filesystems(J)",
+       .action_msg     = "Emergency Thaw of all frozen filesystems",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+#endif
+
 static void sysrq_handle_kill(int key, struct tty_struct *tty)
 {
        send_sig_all(SIGKILL);
@@ -396,9 +409,13 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
        &sysrq_moom_op,                 /* f */
        /* g: May be registered by ppc for kgdb */
        NULL,                           /* g */
-       NULL,                           /* h */
+       NULL,                           /* h - reserved for help */
        &sysrq_kill_op,                 /* i */
+#ifdef CONFIG_BLOCK
+       &sysrq_thaw_op,                 /* j */
+#else
        NULL,                           /* j */
+#endif
        &sysrq_SAK_op,                  /* k */
 #ifdef CONFIG_SMP
        &sysrq_showallcpus_op,          /* l */
index 34ab6d798f819ebf2a62ad56f0abdfec1addd8d2..55ba6f142883f6de16cc0460b540bbc64b932738 100644 (file)
@@ -10,8 +10,6 @@
  */
 
 #include <linux/audit.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
 #include <linux/tty.h>
 
 struct tty_audit_buf {
index 224f271d8cbe06868d69ce415339efa30f110d55..66b99a2049e373cacca62d54d1d689daed2417e2 100644 (file)
@@ -464,7 +464,7 @@ void tty_wakeup(struct tty_struct *tty)
                        tty_ldisc_deref(ld);
                }
        }
-       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
 }
 
 EXPORT_SYMBOL_GPL(tty_wakeup);
@@ -587,8 +587,8 @@ static void do_tty_hangup(struct work_struct *work)
         * FIXME: Once we trust the LDISC code better we can wait here for
         * ldisc completion and fix the driver call race
         */
-       wake_up_interruptible(&tty->write_wait);
-       wake_up_interruptible(&tty->read_wait);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
        /*
         * Shutdown the current line discipline, and reset it to
         * N_TTY.
@@ -879,7 +879,7 @@ void stop_tty(struct tty_struct *tty)
        if (tty->link && tty->link->packet) {
                tty->ctrl_status &= ~TIOCPKT_START;
                tty->ctrl_status |= TIOCPKT_STOP;
-               wake_up_interruptible(&tty->link->read_wait);
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
        }
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
        if (tty->ops->stop)
@@ -913,7 +913,7 @@ void start_tty(struct tty_struct *tty)
        if (tty->link && tty->link->packet) {
                tty->ctrl_status &= ~TIOCPKT_STOP;
                tty->ctrl_status |= TIOCPKT_START;
-               wake_up_interruptible(&tty->link->read_wait);
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
        }
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
        if (tty->ops->start)
@@ -970,7 +970,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
 void tty_write_unlock(struct tty_struct *tty)
 {
        mutex_unlock(&tty->atomic_write_lock);
-       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
 }
 
 int tty_write_lock(struct tty_struct *tty, int ndelay)
@@ -1623,21 +1623,21 @@ void tty_release_dev(struct file *filp)
 
                if (tty_closing) {
                        if (waitqueue_active(&tty->read_wait)) {
-                               wake_up(&tty->read_wait);
+                               wake_up_poll(&tty->read_wait, POLLIN);
                                do_sleep++;
                        }
                        if (waitqueue_active(&tty->write_wait)) {
-                               wake_up(&tty->write_wait);
+                               wake_up_poll(&tty->write_wait, POLLOUT);
                                do_sleep++;
                        }
                }
                if (o_tty_closing) {
                        if (waitqueue_active(&o_tty->read_wait)) {
-                               wake_up(&o_tty->read_wait);
+                               wake_up_poll(&o_tty->read_wait, POLLIN);
                                do_sleep++;
                        }
                        if (waitqueue_active(&o_tty->write_wait)) {
-                               wake_up(&o_tty->write_wait);
+                               wake_up_poll(&o_tty->write_wait, POLLOUT);
                                do_sleep++;
                        }
                }
@@ -1758,7 +1758,7 @@ static int __tty_open(struct inode *inode, struct file *filp)
        struct tty_driver *driver;
        int index;
        dev_t device = inode->i_rdev;
-       unsigned short saved_flags = filp->f_flags;
+       unsigned saved_flags = filp->f_flags;
 
        nonseekable_open(inode, filp);
 
@@ -2681,7 +2681,7 @@ void __do_SAK(struct tty_struct *tty)
        /* Kill the entire session */
        do_each_pid_task(session, PIDTYPE_SID, p) {
                printk(KERN_NOTICE "SAK: killed process %d"
-                       " (%s): task_session_nr(p)==tty->session\n",
+                       " (%s): task_session(p)==tty->session\n",
                        task_pid_nr(p), p->comm);
                send_sig(SIGKILL, p, 1);
        } while_each_pid_task(session, PIDTYPE_SID, p);
@@ -2691,7 +2691,7 @@ void __do_SAK(struct tty_struct *tty)
        do_each_thread(g, p) {
                if (p->signal->tty == tty) {
                        printk(KERN_NOTICE "SAK: killed process %d"
-                           " (%s): task_session_nr(p)==tty->session\n",
+                           " (%s): task_session(p)==tty->session\n",
                            task_pid_nr(p), p->comm);
                        send_sig(SIGKILL, p, 1);
                        continue;
index 7a84b406a9522d633f6eab84ada8134319b2aeac..f78f5b0127a88501ec0b21cf9d42c517209ad933 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/tty_flip.h>
 #include <linux/devpts_fs.h>
 #include <linux/file.h>
-#include <linux/fdtable.h>
 #include <linux/console.h>
 #include <linux/timer.h>
 #include <linux/ctype.h>
index 0c79fe7f15673563257fe6a3a01a0c451f6dd997..4d85402a9e4a0990d2db5afdfac0c66376b1af09 100644 (file)
@@ -1882,7 +1882,7 @@ static void hifn_clear_rings(struct hifn_device *dev, int error)
 
 static void hifn_work(struct work_struct *work)
 {
-       struct delayed_work *dw = container_of(work, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(work);
        struct hifn_device *dev = container_of(dw, struct hifn_device, work);
        unsigned long flags;
        int reset = 0;
index d9e751be8c5fb120e5f0d06ef27684c8f33fa549..af9761ccf9f132a6414aacec926251b06c8b64c6 100644 (file)
@@ -101,6 +101,7 @@ struct buffer_desc {
        u32 phys_addr;
        u32 __reserved[4];
        struct buffer_desc *next;
+       enum dma_data_direction dir;
 };
 
 struct crypt_ctl {
@@ -132,14 +133,10 @@ struct crypt_ctl {
 struct ablk_ctx {
        struct buffer_desc *src;
        struct buffer_desc *dst;
-       unsigned src_nents;
-       unsigned dst_nents;
 };
 
 struct aead_ctx {
        struct buffer_desc *buffer;
-       unsigned short assoc_nents;
-       unsigned short src_nents;
        struct scatterlist ivlist;
        /* used when the hmac is not on one sg entry */
        u8 *hmac_virt;
@@ -312,7 +309,7 @@ static struct crypt_ctl *get_crypt_desc_emerg(void)
        }
 }
 
-static void free_buf_chain(struct buffer_desc *buf, u32 phys)
+static void free_buf_chain(struct device *dev, struct buffer_desc *buf,u32 phys)
 {
        while (buf) {
                struct buffer_desc *buf1;
@@ -320,6 +317,7 @@ static void free_buf_chain(struct buffer_desc *buf, u32 phys)
 
                buf1 = buf->next;
                phys1 = buf->phys_next;
+               dma_unmap_single(dev, buf->phys_next, buf->buf_len, buf->dir);
                dma_pool_free(buffer_pool, buf, phys);
                buf = buf1;
                phys = phys1;
@@ -348,7 +346,6 @@ static void one_packet(dma_addr_t phys)
        struct crypt_ctl *crypt;
        struct ixp_ctx *ctx;
        int failed;
-       enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
 
        failed = phys & 0x1 ? -EBADMSG : 0;
        phys &= ~0x3;
@@ -358,13 +355,8 @@ static void one_packet(dma_addr_t phys)
        case CTL_FLAG_PERFORM_AEAD: {
                struct aead_request *req = crypt->data.aead_req;
                struct aead_ctx *req_ctx = aead_request_ctx(req);
-               dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents,
-                               DMA_TO_DEVICE);
-               dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
-               dma_unmap_sg(dev, req->src, req_ctx->src_nents,
-                               DMA_BIDIRECTIONAL);
 
-               free_buf_chain(req_ctx->buffer, crypt->src_buf);
+               free_buf_chain(dev, req_ctx->buffer, crypt->src_buf);
                if (req_ctx->hmac_virt) {
                        finish_scattered_hmac(crypt);
                }
@@ -374,16 +366,11 @@ static void one_packet(dma_addr_t phys)
        case CTL_FLAG_PERFORM_ABLK: {
                struct ablkcipher_request *req = crypt->data.ablk_req;
                struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req);
-               int nents;
+
                if (req_ctx->dst) {
-                       nents = req_ctx->dst_nents;
-                       dma_unmap_sg(dev, req->dst, nents, DMA_FROM_DEVICE);
-                       free_buf_chain(req_ctx->dst, crypt->dst_buf);
-                       src_direction = DMA_TO_DEVICE;
+                       free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
                }
-               nents = req_ctx->src_nents;
-               dma_unmap_sg(dev, req->src, nents, src_direction);
-               free_buf_chain(req_ctx->src, crypt->src_buf);
+               free_buf_chain(dev, req_ctx->src, crypt->src_buf);
                req->base.complete(&req->base, failed);
                break;
        }
@@ -750,56 +737,35 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
        return 0;
 }
 
-static int count_sg(struct scatterlist *sg, int nbytes)
+static struct buffer_desc *chainup_buffers(struct device *dev,
+               struct scatterlist *sg, unsigned nbytes,
+               struct buffer_desc *buf, gfp_t flags,
+               enum dma_data_direction dir)
 {
-       int i;
-       for (i = 0; nbytes > 0; i++, sg = sg_next(sg))
-               nbytes -= sg->length;
-       return i;
-}
-
-static struct buffer_desc *chainup_buffers(struct scatterlist *sg,
-                       unsigned nbytes, struct buffer_desc *buf, gfp_t flags)
-{
-       int nents = 0;
-
-       while (nbytes > 0) {
+       for (;nbytes > 0; sg = scatterwalk_sg_next(sg)) {
+               unsigned len = min(nbytes, sg->length);
                struct buffer_desc *next_buf;
                u32 next_buf_phys;
-               unsigned len = min(nbytes, sg_dma_len(sg));
+               void *ptr;
 
-               nents++;
                nbytes -= len;
-               if (!buf->phys_addr) {
-                       buf->phys_addr = sg_dma_address(sg);
-                       buf->buf_len = len;
-                       buf->next = NULL;
-                       buf->phys_next = 0;
-                       goto next;
-               }
-               /* Two consecutive chunks on one page may be handled by the old
-                * buffer descriptor, increased by the length of the new one
-                */
-               if (sg_dma_address(sg) == buf->phys_addr + buf->buf_len) {
-                       buf->buf_len += len;
-                       goto next;
-               }
+               ptr = page_address(sg_page(sg)) + sg->offset;
                next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys);
-               if (!next_buf)
-                       return NULL;
+               if (!next_buf) {
+                       buf = NULL;
+                       break;
+               }
+               sg_dma_address(sg) = dma_map_single(dev, ptr, len, dir);
                buf->next = next_buf;
                buf->phys_next = next_buf_phys;
-
                buf = next_buf;
-               buf->next = NULL;
-               buf->phys_next = 0;
+
                buf->phys_addr = sg_dma_address(sg);
                buf->buf_len = len;
-next:
-               if (nbytes > 0) {
-                       sg = sg_next(sg);
-               }
+               buf->dir = dir;
        }
+       buf->next = NULL;
+       buf->phys_next = 0;
        return buf;
 }
 
@@ -860,12 +826,12 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
        struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
        struct ixp_ctx *ctx = crypto_ablkcipher_ctx(tfm);
        unsigned ivsize = crypto_ablkcipher_ivsize(tfm);
-       int ret = -ENOMEM;
        struct ix_sa_dir *dir;
        struct crypt_ctl *crypt;
-       unsigned int nbytes = req->nbytes, nents;
+       unsigned int nbytes = req->nbytes;
        enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
        struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req);
+       struct buffer_desc src_hook;
        gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
                                GFP_KERNEL : GFP_ATOMIC;
 
@@ -878,7 +844,7 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
 
        crypt = get_crypt_desc();
        if (!crypt)
-               return ret;
+               return -ENOMEM;
 
        crypt->data.ablk_req = req;
        crypt->crypto_ctx = dir->npe_ctx_phys;
@@ -891,53 +857,41 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
        BUG_ON(ivsize && !req->info);
        memcpy(crypt->iv, req->info, ivsize);
        if (req->src != req->dst) {
+               struct buffer_desc dst_hook;
                crypt->mode |= NPE_OP_NOT_IN_PLACE;
-               nents = count_sg(req->dst, nbytes);
                /* This was never tested by Intel
                 * for more than one dst buffer, I think. */
-               BUG_ON(nents != 1);
-               req_ctx->dst_nents = nents;
-               dma_map_sg(dev, req->dst, nents, DMA_FROM_DEVICE);
-               req_ctx->dst = dma_pool_alloc(buffer_pool, flags,&crypt->dst_buf);
-               if (!req_ctx->dst)
-                       goto unmap_sg_dest;
-               req_ctx->dst->phys_addr = 0;
-               if (!chainup_buffers(req->dst, nbytes, req_ctx->dst, flags))
+               BUG_ON(req->dst->length < nbytes);
+               req_ctx->dst = NULL;
+               if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
+                                       flags, DMA_FROM_DEVICE))
                        goto free_buf_dest;
                src_direction = DMA_TO_DEVICE;
+               req_ctx->dst = dst_hook.next;
+               crypt->dst_buf = dst_hook.phys_next;
        } else {
                req_ctx->dst = NULL;
-               req_ctx->dst_nents = 0;
        }
-       nents = count_sg(req->src, nbytes);
-       req_ctx->src_nents = nents;
-       dma_map_sg(dev, req->src, nents, src_direction);
-
-       req_ctx->src = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf);
-       if (!req_ctx->src)
-               goto unmap_sg_src;
-       req_ctx->src->phys_addr = 0;
-       if (!chainup_buffers(req->src, nbytes, req_ctx->src, flags))
+       req_ctx->src = NULL;
+       if (!chainup_buffers(dev, req->src, nbytes, &src_hook,
+                               flags, src_direction))
                goto free_buf_src;
 
+       req_ctx->src = src_hook.next;
+       crypt->src_buf = src_hook.phys_next;
        crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK;
        qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
        BUG_ON(qmgr_stat_overflow(SEND_QID));
        return -EINPROGRESS;
 
 free_buf_src:
-       free_buf_chain(req_ctx->src, crypt->src_buf);
-unmap_sg_src:
-       dma_unmap_sg(dev, req->src, req_ctx->src_nents, src_direction);
+       free_buf_chain(dev, req_ctx->src, crypt->src_buf);
 free_buf_dest:
        if (req->src != req->dst) {
-               free_buf_chain(req_ctx->dst, crypt->dst_buf);
-unmap_sg_dest:
-               dma_unmap_sg(dev, req->src, req_ctx->dst_nents,
-                       DMA_FROM_DEVICE);
+               free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
        }
        crypt->ctl_flags = CTL_FLAG_UNUSED;
-       return ret;
+       return -ENOMEM;
 }
 
 static int ablk_encrypt(struct ablkcipher_request *req)
@@ -985,7 +939,7 @@ static int hmac_inconsistent(struct scatterlist *sg, unsigned start,
                        break;
 
                offset += sg->length;
-               sg = sg_next(sg);
+               sg = scatterwalk_sg_next(sg);
        }
        return (start + nbytes > offset + sg->length);
 }
@@ -997,11 +951,10 @@ static int aead_perform(struct aead_request *req, int encrypt,
        struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
        unsigned ivsize = crypto_aead_ivsize(tfm);
        unsigned authsize = crypto_aead_authsize(tfm);
-       int ret = -ENOMEM;
        struct ix_sa_dir *dir;
        struct crypt_ctl *crypt;
-       unsigned int cryptlen, nents;
-       struct buffer_desc *buf;
+       unsigned int cryptlen;
+       struct buffer_desc *buf, src_hook;
        struct aead_ctx *req_ctx = aead_request_ctx(req);
        gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
                                GFP_KERNEL : GFP_ATOMIC;
@@ -1022,7 +975,7 @@ static int aead_perform(struct aead_request *req, int encrypt,
        }
        crypt = get_crypt_desc();
        if (!crypt)
-               return ret;
+               return -ENOMEM;
 
        crypt->data.aead_req = req;
        crypt->crypto_ctx = dir->npe_ctx_phys;
@@ -1041,31 +994,27 @@ static int aead_perform(struct aead_request *req, int encrypt,
                BUG(); /* -ENOTSUP because of my lazyness */
        }
 
-       req_ctx->buffer = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf);
-       if (!req_ctx->buffer)
-               goto out;
-       req_ctx->buffer->phys_addr = 0;
        /* ASSOC data */
-       nents = count_sg(req->assoc, req->assoclen);
-       req_ctx->assoc_nents = nents;
-       dma_map_sg(dev, req->assoc, nents, DMA_TO_DEVICE);
-       buf = chainup_buffers(req->assoc, req->assoclen, req_ctx->buffer,flags);
+       buf = chainup_buffers(dev, req->assoc, req->assoclen, &src_hook,
+               flags, DMA_TO_DEVICE);
+       req_ctx->buffer = src_hook.next;
+       crypt->src_buf = src_hook.phys_next;
        if (!buf)
-               goto unmap_sg_assoc;
+               goto out;
        /* IV */
        sg_init_table(&req_ctx->ivlist, 1);
        sg_set_buf(&req_ctx->ivlist, iv, ivsize);
-       dma_map_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
-       buf = chainup_buffers(&req_ctx->ivlist, ivsize, buf, flags);
+       buf = chainup_buffers(dev, &req_ctx->ivlist, ivsize, buf, flags,
+                       DMA_BIDIRECTIONAL);
        if (!buf)
-               goto unmap_sg_iv;
+               goto free_chain;
        if (unlikely(hmac_inconsistent(req->src, cryptlen, authsize))) {
                /* The 12 hmac bytes are scattered,
                 * we need to copy them into a safe buffer */
                req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags,
                                &crypt->icv_rev_aes);
                if (unlikely(!req_ctx->hmac_virt))
-                       goto unmap_sg_iv;
+                       goto free_chain;
                if (!encrypt) {
                        scatterwalk_map_and_copy(req_ctx->hmac_virt,
                                req->src, cryptlen, authsize, 0);
@@ -1075,33 +1024,28 @@ static int aead_perform(struct aead_request *req, int encrypt,
                req_ctx->hmac_virt = NULL;
        }
        /* Crypt */
-       nents = count_sg(req->src, cryptlen + authsize);
-       req_ctx->src_nents = nents;
-       dma_map_sg(dev, req->src, nents, DMA_BIDIRECTIONAL);
-       buf = chainup_buffers(req->src, cryptlen + authsize, buf, flags);
+       buf = chainup_buffers(dev, req->src, cryptlen + authsize, buf, flags,
+                       DMA_BIDIRECTIONAL);
        if (!buf)
-               goto unmap_sg_src;
+               goto free_hmac_virt;
        if (!req_ctx->hmac_virt) {
                crypt->icv_rev_aes = buf->phys_addr + buf->buf_len - authsize;
        }
+
        crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD;
        qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
        BUG_ON(qmgr_stat_overflow(SEND_QID));
        return -EINPROGRESS;
-unmap_sg_src:
-       dma_unmap_sg(dev, req->src, req_ctx->src_nents, DMA_BIDIRECTIONAL);
+free_hmac_virt:
        if (req_ctx->hmac_virt) {
                dma_pool_free(buffer_pool, req_ctx->hmac_virt,
                                crypt->icv_rev_aes);
        }
-unmap_sg_iv:
-       dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
-unmap_sg_assoc:
-       dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents, DMA_TO_DEVICE);
-       free_buf_chain(req_ctx->buffer, crypt->src_buf);
+free_chain:
+       free_buf_chain(dev, req_ctx->buffer, crypt->src_buf);
 out:
        crypt->ctl_flags = CTL_FLAG_UNUSED;
-       return ret;
+       return -ENOMEM;
 }
 
 static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
index 48ea59e796722cea45e2421830355f349c22c939..3b3c01b6f1ee34333d0f57f558f25560f76b2d44 100644 (file)
@@ -98,6 +98,17 @@ config NET_DMA
          Say Y here if you enabled INTEL_IOATDMA or FSL_DMA, otherwise
          say N.
 
+config ASYNC_TX_DMA
+       bool "Async_tx: Offload support for the async_tx api"
+       depends on DMA_ENGINE
+       help
+         This allows the async_tx api to take advantage of offload engines for
+         memcpy, memset, xor, and raid6 p+q operations.  If your platform has
+         a dma engine that can perform raid operations and you have enabled
+         MD_RAID456 say Y.
+
+         If unsure, say N.
+
 config DMATEST
        tristate "DMA Test client"
        depends on DMA_ENGINE
index 280a9d263eb3c4271d1cff6e55448cae0a93b387..92438e9dacc35887bd2d8b493ea3d93ac3bc20f7 100644 (file)
@@ -507,6 +507,7 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v
                         * published in the general-purpose allocator
                         */
                        dma_cap_set(DMA_PRIVATE, device->cap_mask);
+                       device->privatecnt++;
                        err = dma_chan_get(chan);
 
                        if (err == -ENODEV) {
@@ -518,6 +519,8 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v
                                       dma_chan_name(chan), err);
                        else
                                break;
+                       if (--device->privatecnt == 0)
+                               dma_cap_clear(DMA_PRIVATE, device->cap_mask);
                        chan->private = NULL;
                        chan = NULL;
                }
@@ -537,6 +540,9 @@ void dma_release_channel(struct dma_chan *chan)
        WARN_ONCE(chan->client_count != 1,
                  "chan reference count %d != 1\n", chan->client_count);
        dma_chan_put(chan);
+       /* drop PRIVATE cap enabled by __dma_request_channel() */
+       if (--chan->device->privatecnt == 0)
+               dma_cap_clear(DMA_PRIVATE, chan->device->cap_mask);
        chan->private = NULL;
        mutex_unlock(&dma_list_mutex);
 }
@@ -602,6 +608,24 @@ void dmaengine_put(void)
 }
 EXPORT_SYMBOL(dmaengine_put);
 
+static int get_dma_id(struct dma_device *device)
+{
+       int rc;
+
+ idr_retry:
+       if (!idr_pre_get(&dma_idr, GFP_KERNEL))
+               return -ENOMEM;
+       mutex_lock(&dma_list_mutex);
+       rc = idr_get_new(&dma_idr, NULL, &device->dev_id);
+       mutex_unlock(&dma_list_mutex);
+       if (rc == -EAGAIN)
+               goto idr_retry;
+       else if (rc != 0)
+               return rc;
+
+       return 0;
+}
+
 /**
  * dma_async_device_register - registers DMA devices found
  * @device: &dma_device
@@ -640,27 +664,25 @@ int dma_async_device_register(struct dma_device *device)
        idr_ref = kmalloc(sizeof(*idr_ref), GFP_KERNEL);
        if (!idr_ref)
                return -ENOMEM;
-       atomic_set(idr_ref, 0);
- idr_retry:
-       if (!idr_pre_get(&dma_idr, GFP_KERNEL))
-               return -ENOMEM;
-       mutex_lock(&dma_list_mutex);
-       rc = idr_get_new(&dma_idr, NULL, &device->dev_id);
-       mutex_unlock(&dma_list_mutex);
-       if (rc == -EAGAIN)
-               goto idr_retry;
-       else if (rc != 0)
+       rc = get_dma_id(device);
+       if (rc != 0) {
+               kfree(idr_ref);
                return rc;
+       }
+
+       atomic_set(idr_ref, 0);
 
        /* represent channels in sysfs. Probably want devs too */
        list_for_each_entry(chan, &device->channels, device_node) {
+               rc = -ENOMEM;
                chan->local = alloc_percpu(typeof(*chan->local));
                if (chan->local == NULL)
-                       continue;
+                       goto err_out;
                chan->dev = kzalloc(sizeof(*chan->dev), GFP_KERNEL);
                if (chan->dev == NULL) {
                        free_percpu(chan->local);
-                       continue;
+                       chan->local = NULL;
+                       goto err_out;
                }
 
                chan->chan_id = chancnt++;
@@ -677,6 +699,8 @@ int dma_async_device_register(struct dma_device *device)
                if (rc) {
                        free_percpu(chan->local);
                        chan->local = NULL;
+                       kfree(chan->dev);
+                       atomic_dec(idr_ref);
                        goto err_out;
                }
                chan->client_count = 0;
@@ -701,12 +725,23 @@ int dma_async_device_register(struct dma_device *device)
                        }
                }
        list_add_tail_rcu(&device->global_node, &dma_device_list);
+       if (dma_has_cap(DMA_PRIVATE, device->cap_mask))
+               device->privatecnt++;   /* Always private */
        dma_channel_rebalance();
        mutex_unlock(&dma_list_mutex);
 
        return 0;
 
 err_out:
+       /* if we never registered a channel just release the idr */
+       if (atomic_read(idr_ref) == 0) {
+               mutex_lock(&dma_list_mutex);
+               idr_remove(&dma_idr, device->dev_id);
+               mutex_unlock(&dma_list_mutex);
+               kfree(idr_ref);
+               return rc;
+       }
+
        list_for_each_entry(chan, &device->channels, device_node) {
                if (chan->local == NULL)
                        continue;
@@ -893,6 +928,7 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
 {
        tx->chan = chan;
        spin_lock_init(&tx->lock);
+       INIT_LIST_HEAD(&tx->tx_list);
 }
 EXPORT_SYMBOL(dma_async_tx_descriptor_init);
 
index e190d8b30700c40858fceb83afa05f49d9ce8d2e..a27c0fb1bc11f17b6b8c56bdc383aee5a710b051 100644 (file)
@@ -38,6 +38,11 @@ module_param(max_channels, uint, S_IRUGO);
 MODULE_PARM_DESC(max_channels,
                "Maximum number of channels to use (default: all)");
 
+static unsigned int xor_sources = 3;
+module_param(xor_sources, uint, S_IRUGO);
+MODULE_PARM_DESC(xor_sources,
+               "Number of xor source buffers (default: 3)");
+
 /*
  * Initialization patterns. All bytes in the source buffer has bit 7
  * set, all bytes in the destination buffer has bit 7 cleared.
@@ -59,8 +64,9 @@ struct dmatest_thread {
        struct list_head        node;
        struct task_struct      *task;
        struct dma_chan         *chan;
-       u8                      *srcbuf;
-       u8                      *dstbuf;
+       u8                      **srcs;
+       u8                      **dsts;
+       enum dma_transaction_type type;
 };
 
 struct dmatest_chan {
@@ -98,30 +104,37 @@ static unsigned long dmatest_random(void)
        return buf;
 }
 
-static void dmatest_init_srcbuf(u8 *buf, unsigned int start, unsigned int len)
+static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len)
 {
        unsigned int i;
-
-       for (i = 0; i < start; i++)
-               buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
-       for ( ; i < start + len; i++)
-               buf[i] = PATTERN_SRC | PATTERN_COPY
-                       | (~i & PATTERN_COUNT_MASK);;
-       for ( ; i < test_buf_size; i++)
-               buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
+       u8 *buf;
+
+       for (; (buf = *bufs); bufs++) {
+               for (i = 0; i < start; i++)
+                       buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
+               for ( ; i < start + len; i++)
+                       buf[i] = PATTERN_SRC | PATTERN_COPY
+                               | (~i & PATTERN_COUNT_MASK);;
+               for ( ; i < test_buf_size; i++)
+                       buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
+               buf++;
+       }
 }
 
-static void dmatest_init_dstbuf(u8 *buf, unsigned int start, unsigned int len)
+static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len)
 {
        unsigned int i;
-
-       for (i = 0; i < start; i++)
-               buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
-       for ( ; i < start + len; i++)
-               buf[i] = PATTERN_DST | PATTERN_OVERWRITE
-                       | (~i & PATTERN_COUNT_MASK);
-       for ( ; i < test_buf_size; i++)
-               buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
+       u8 *buf;
+
+       for (; (buf = *bufs); bufs++) {
+               for (i = 0; i < start; i++)
+                       buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
+               for ( ; i < start + len; i++)
+                       buf[i] = PATTERN_DST | PATTERN_OVERWRITE
+                               | (~i & PATTERN_COUNT_MASK);
+               for ( ; i < test_buf_size; i++)
+                       buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
+       }
 }
 
 static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index,
@@ -150,23 +163,30 @@ static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index,
                                thread_name, index, expected, actual);
 }
 
-static unsigned int dmatest_verify(u8 *buf, unsigned int start,
+static unsigned int dmatest_verify(u8 **bufs, unsigned int start,
                unsigned int end, unsigned int counter, u8 pattern,
                bool is_srcbuf)
 {
        unsigned int i;
        unsigned int error_count = 0;
        u8 actual;
-
-       for (i = start; i < end; i++) {
-               actual = buf[i];
-               if (actual != (pattern | (~counter & PATTERN_COUNT_MASK))) {
-                       if (error_count < 32)
-                               dmatest_mismatch(actual, pattern, i, counter,
-                                               is_srcbuf);
-                       error_count++;
+       u8 expected;
+       u8 *buf;
+       unsigned int counter_orig = counter;
+
+       for (; (buf = *bufs); bufs++) {
+               counter = counter_orig;
+               for (i = start; i < end; i++) {
+                       actual = buf[i];
+                       expected = pattern | (~counter & PATTERN_COUNT_MASK);
+                       if (actual != expected) {
+                               if (error_count < 32)
+                                       dmatest_mismatch(actual, pattern, i,
+                                                        counter, is_srcbuf);
+                               error_count++;
+                       }
+                       counter++;
                }
-               counter++;
        }
 
        if (error_count > 32)
@@ -176,12 +196,17 @@ static unsigned int dmatest_verify(u8 *buf, unsigned int start,
        return error_count;
 }
 
+static void dmatest_callback(void *completion)
+{
+       complete(completion);
+}
+
 /*
  * This function repeatedly tests DMA transfers of various lengths and
- * offsets until it is told to exit by kthread_stop(). There may be
- * multiple threads running this function in parallel for a single
- * channel, and there may be multiple channels being tested in
- * parallel.
+ * offsets for a given operation type until it is told to exit by
+ * kthread_stop(). There may be multiple threads running this function
+ * in parallel for a single channel, and there may be multiple channels
+ * being tested in parallel.
  *
  * Before each test, the source and destination buffer is initialized
  * with a known pattern. This pattern is different depending on
@@ -201,25 +226,57 @@ static int dmatest_func(void *data)
        unsigned int            total_tests = 0;
        dma_cookie_t            cookie;
        enum dma_status         status;
+       enum dma_ctrl_flags     flags;
        int                     ret;
+       int                     src_cnt;
+       int                     dst_cnt;
+       int                     i;
 
        thread_name = current->comm;
 
        ret = -ENOMEM;
-       thread->srcbuf = kmalloc(test_buf_size, GFP_KERNEL);
-       if (!thread->srcbuf)
-               goto err_srcbuf;
-       thread->dstbuf = kmalloc(test_buf_size, GFP_KERNEL);
-       if (!thread->dstbuf)
-               goto err_dstbuf;
 
        smp_rmb();
        chan = thread->chan;
+       if (thread->type == DMA_MEMCPY)
+               src_cnt = dst_cnt = 1;
+       else if (thread->type == DMA_XOR) {
+               src_cnt = xor_sources | 1; /* force odd to ensure dst = src */
+               dst_cnt = 1;
+       } else
+               goto err_srcs;
+
+       thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL);
+       if (!thread->srcs)
+               goto err_srcs;
+       for (i = 0; i < src_cnt; i++) {
+               thread->srcs[i] = kmalloc(test_buf_size, GFP_KERNEL);
+               if (!thread->srcs[i])
+                       goto err_srcbuf;
+       }
+       thread->srcs[i] = NULL;
+
+       thread->dsts = kcalloc(dst_cnt+1, sizeof(u8 *), GFP_KERNEL);
+       if (!thread->dsts)
+               goto err_dsts;
+       for (i = 0; i < dst_cnt; i++) {
+               thread->dsts[i] = kmalloc(test_buf_size, GFP_KERNEL);
+               if (!thread->dsts[i])
+                       goto err_dstbuf;
+       }
+       thread->dsts[i] = NULL;
+
+       set_user_nice(current, 10);
+
+       flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT;
 
        while (!kthread_should_stop()) {
                struct dma_device *dev = chan->device;
-               struct dma_async_tx_descriptor *tx;
-               dma_addr_t dma_src, dma_dest;
+               struct dma_async_tx_descriptor *tx = NULL;
+               dma_addr_t dma_srcs[src_cnt];
+               dma_addr_t dma_dsts[dst_cnt];
+               struct completion cmp;
+               unsigned long tmo = msecs_to_jiffies(3000);
 
                total_tests++;
 
@@ -227,22 +284,41 @@ static int dmatest_func(void *data)
                src_off = dmatest_random() % (test_buf_size - len + 1);
                dst_off = dmatest_random() % (test_buf_size - len + 1);
 
-               dmatest_init_srcbuf(thread->srcbuf, src_off, len);
-               dmatest_init_dstbuf(thread->dstbuf, dst_off, len);
+               dmatest_init_srcs(thread->srcs, src_off, len);
+               dmatest_init_dsts(thread->dsts, dst_off, len);
 
-               dma_src = dma_map_single(dev->dev, thread->srcbuf + src_off,
-                               len, DMA_TO_DEVICE);
+               for (i = 0; i < src_cnt; i++) {
+                       u8 *buf = thread->srcs[i] + src_off;
+
+                       dma_srcs[i] = dma_map_single(dev->dev, buf, len,
+                                                    DMA_TO_DEVICE);
+               }
                /* map with DMA_BIDIRECTIONAL to force writeback/invalidate */
-               dma_dest = dma_map_single(dev->dev, thread->dstbuf,
-                               test_buf_size, DMA_BIDIRECTIONAL);
+               for (i = 0; i < dst_cnt; i++) {
+                       dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i],
+                                                    test_buf_size,
+                                                    DMA_BIDIRECTIONAL);
+               }
+
+               if (thread->type == DMA_MEMCPY)
+                       tx = dev->device_prep_dma_memcpy(chan,
+                                                        dma_dsts[0] + dst_off,
+                                                        dma_srcs[0], len,
+                                                        flags);
+               else if (thread->type == DMA_XOR)
+                       tx = dev->device_prep_dma_xor(chan,
+                                                     dma_dsts[0] + dst_off,
+                                                     dma_srcs, xor_sources,
+                                                     len, flags);
 
-               tx = dev->device_prep_dma_memcpy(chan, dma_dest + dst_off,
-                               dma_src, len,
-                               DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP);
                if (!tx) {
-                       dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
-                       dma_unmap_single(dev->dev, dma_dest,
-                                       test_buf_size, DMA_BIDIRECTIONAL);
+                       for (i = 0; i < src_cnt; i++)
+                               dma_unmap_single(dev->dev, dma_srcs[i], len,
+                                                DMA_TO_DEVICE);
+                       for (i = 0; i < dst_cnt; i++)
+                               dma_unmap_single(dev->dev, dma_dsts[i],
+                                                test_buf_size,
+                                                DMA_BIDIRECTIONAL);
                        pr_warning("%s: #%u: prep error with src_off=0x%x "
                                        "dst_off=0x%x len=0x%x\n",
                                        thread_name, total_tests - 1,
@@ -251,7 +327,10 @@ static int dmatest_func(void *data)
                        failed_tests++;
                        continue;
                }
-               tx->callback = NULL;
+
+               init_completion(&cmp);
+               tx->callback = dmatest_callback;
+               tx->callback_param = &cmp;
                cookie = tx->tx_submit(tx);
 
                if (dma_submit_error(cookie)) {
@@ -263,44 +342,50 @@ static int dmatest_func(void *data)
                        failed_tests++;
                        continue;
                }
-               dma_async_memcpy_issue_pending(chan);
+               dma_async_issue_pending(chan);
 
-               do {
-                       msleep(1);
-                       status = dma_async_memcpy_complete(
-                                       chan, cookie, NULL, NULL);
-               } while (status == DMA_IN_PROGRESS);
+               tmo = wait_for_completion_timeout(&cmp, tmo);
+               status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
 
-               if (status == DMA_ERROR) {
-                       pr_warning("%s: #%u: error during copy\n",
-                                       thread_name, total_tests - 1);
+               if (tmo == 0) {
+                       pr_warning("%s: #%u: test timed out\n",
+                                  thread_name, total_tests - 1);
+                       failed_tests++;
+                       continue;
+               } else if (status != DMA_SUCCESS) {
+                       pr_warning("%s: #%u: got completion callback,"
+                                  " but status is \'%s\'\n",
+                                  thread_name, total_tests - 1,
+                                  status == DMA_ERROR ? "error" : "in progress");
                        failed_tests++;
                        continue;
                }
+
                /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */
-               dma_unmap_single(dev->dev, dma_dest,
-                               test_buf_size, DMA_BIDIRECTIONAL);
+               for (i = 0; i < dst_cnt; i++)
+                       dma_unmap_single(dev->dev, dma_dsts[i], test_buf_size,
+                                        DMA_BIDIRECTIONAL);
 
                error_count = 0;
 
                pr_debug("%s: verifying source buffer...\n", thread_name);
-               error_count += dmatest_verify(thread->srcbuf, 0, src_off,
+               error_count += dmatest_verify(thread->srcs, 0, src_off,
                                0, PATTERN_SRC, true);
-               error_count += dmatest_verify(thread->srcbuf, src_off,
+               error_count += dmatest_verify(thread->srcs, src_off,
                                src_off + len, src_off,
                                PATTERN_SRC | PATTERN_COPY, true);
-               error_count += dmatest_verify(thread->srcbuf, src_off + len,
+               error_count += dmatest_verify(thread->srcs, src_off + len,
                                test_buf_size, src_off + len,
                                PATTERN_SRC, true);
 
                pr_debug("%s: verifying dest buffer...\n",
                                thread->task->comm);
-               error_count += dmatest_verify(thread->dstbuf, 0, dst_off,
+               error_count += dmatest_verify(thread->dsts, 0, dst_off,
                                0, PATTERN_DST, false);
-               error_count += dmatest_verify(thread->dstbuf, dst_off,
+               error_count += dmatest_verify(thread->dsts, dst_off,
                                dst_off + len, src_off,
                                PATTERN_SRC | PATTERN_COPY, false);
-               error_count += dmatest_verify(thread->dstbuf, dst_off + len,
+               error_count += dmatest_verify(thread->dsts, dst_off + len,
                                test_buf_size, dst_off + len,
                                PATTERN_DST, false);
 
@@ -319,10 +404,16 @@ static int dmatest_func(void *data)
        }
 
        ret = 0;
-       kfree(thread->dstbuf);
+       for (i = 0; thread->dsts[i]; i++)
+               kfree(thread->dsts[i]);
 err_dstbuf:
-       kfree(thread->srcbuf);
+       kfree(thread->dsts);
+err_dsts:
+       for (i = 0; thread->srcs[i]; i++)
+               kfree(thread->srcs[i]);
 err_srcbuf:
+       kfree(thread->srcs);
+err_srcs:
        pr_notice("%s: terminating after %u tests, %u failures (status %d)\n",
                        thread_name, total_tests, failed_tests, ret);
        return ret;
@@ -344,35 +435,36 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc)
        kfree(dtc);
 }
 
-static int dmatest_add_channel(struct dma_chan *chan)
+static int dmatest_add_threads(struct dmatest_chan *dtc, enum dma_transaction_type type)
 {
-       struct dmatest_chan     *dtc;
-       struct dmatest_thread   *thread;
-       unsigned int            i;
-
-       dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
-       if (!dtc) {
-               pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan));
-               return -ENOMEM;
-       }
+       struct dmatest_thread *thread;
+       struct dma_chan *chan = dtc->chan;
+       char *op;
+       unsigned int i;
 
-       dtc->chan = chan;
-       INIT_LIST_HEAD(&dtc->threads);
+       if (type == DMA_MEMCPY)
+               op = "copy";
+       else if (type == DMA_XOR)
+               op = "xor";
+       else
+               return -EINVAL;
 
        for (i = 0; i < threads_per_chan; i++) {
                thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL);
                if (!thread) {
-                       pr_warning("dmatest: No memory for %s-test%u\n",
-                                  dma_chan_name(chan), i);
+                       pr_warning("dmatest: No memory for %s-%s%u\n",
+                                  dma_chan_name(chan), op, i);
+
                        break;
                }
                thread->chan = dtc->chan;
+               thread->type = type;
                smp_wmb();
-               thread->task = kthread_run(dmatest_func, thread, "%s-test%u",
-                               dma_chan_name(chan), i);
+               thread->task = kthread_run(dmatest_func, thread, "%s-%s%u",
+                               dma_chan_name(chan), op, i);
                if (IS_ERR(thread->task)) {
-                       pr_warning("dmatest: Failed to run thread %s-test%u\n",
-                                       dma_chan_name(chan), i);
+                       pr_warning("dmatest: Failed to run thread %s-%s%u\n",
+                                       dma_chan_name(chan), op, i);
                        kfree(thread);
                        break;
                }
@@ -382,7 +474,36 @@ static int dmatest_add_channel(struct dma_chan *chan)
                list_add_tail(&thread->node, &dtc->threads);
        }
 
-       pr_info("dmatest: Started %u threads using %s\n", i, dma_chan_name(chan));
+       return i;
+}
+
+static int dmatest_add_channel(struct dma_chan *chan)
+{
+       struct dmatest_chan     *dtc;
+       struct dma_device       *dma_dev = chan->device;
+       unsigned int            thread_count = 0;
+       unsigned int            cnt;
+
+       dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
+       if (!dtc) {
+               pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan));
+               return -ENOMEM;
+       }
+
+       dtc->chan = chan;
+       INIT_LIST_HEAD(&dtc->threads);
+
+       if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
+               cnt = dmatest_add_threads(dtc, DMA_MEMCPY);
+               thread_count += cnt > 0 ?: 0;
+       }
+       if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
+               cnt = dmatest_add_threads(dtc, DMA_XOR);
+               thread_count += cnt > 0 ?: 0;
+       }
+
+       pr_info("dmatest: Started %u threads using %s\n",
+               thread_count, dma_chan_name(chan));
 
        list_add_tail(&dtc->node, &dmatest_channels);
        nr_channels++;
index 20ad3d26bec2d5330ac40bd8b437475009e0d8f0..98c9a847bf51c27a8671cd3947690458e0896746 100644 (file)
@@ -363,6 +363,82 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
        dwc_descriptor_complete(dwc, bad_desc);
 }
 
+/* --------------------- Cyclic DMA API extensions -------------------- */
+
+inline dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan)
+{
+       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+       return channel_readl(dwc, SAR);
+}
+EXPORT_SYMBOL(dw_dma_get_src_addr);
+
+inline dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan)
+{
+       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+       return channel_readl(dwc, DAR);
+}
+EXPORT_SYMBOL(dw_dma_get_dst_addr);
+
+/* called with dwc->lock held and all DMAC interrupts disabled */
+static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
+               u32 status_block, u32 status_err, u32 status_xfer)
+{
+       if (status_block & dwc->mask) {
+               void (*callback)(void *param);
+               void *callback_param;
+
+               dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n",
+                               channel_readl(dwc, LLP));
+               dma_writel(dw, CLEAR.BLOCK, dwc->mask);
+
+               callback = dwc->cdesc->period_callback;
+               callback_param = dwc->cdesc->period_callback_param;
+               if (callback) {
+                       spin_unlock(&dwc->lock);
+                       callback(callback_param);
+                       spin_lock(&dwc->lock);
+               }
+       }
+
+       /*
+        * Error and transfer complete are highly unlikely, and will most
+        * likely be due to a configuration error by the user.
+        */
+       if (unlikely(status_err & dwc->mask) ||
+                       unlikely(status_xfer & dwc->mask)) {
+               int i;
+
+               dev_err(chan2dev(&dwc->chan), "cyclic DMA unexpected %s "
+                               "interrupt, stopping DMA transfer\n",
+                               status_xfer ? "xfer" : "error");
+               dev_err(chan2dev(&dwc->chan),
+                       "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
+                       channel_readl(dwc, SAR),
+                       channel_readl(dwc, DAR),
+                       channel_readl(dwc, LLP),
+                       channel_readl(dwc, CTL_HI),
+                       channel_readl(dwc, CTL_LO));
+
+               channel_clear_bit(dw, CH_EN, dwc->mask);
+               while (dma_readl(dw, CH_EN) & dwc->mask)
+                       cpu_relax();
+
+               /* make sure DMA does not restart by loading a new list */
+               channel_writel(dwc, LLP, 0);
+               channel_writel(dwc, CTL_LO, 0);
+               channel_writel(dwc, CTL_HI, 0);
+
+               dma_writel(dw, CLEAR.BLOCK, dwc->mask);
+               dma_writel(dw, CLEAR.ERROR, dwc->mask);
+               dma_writel(dw, CLEAR.XFER, dwc->mask);
+
+               for (i = 0; i < dwc->cdesc->periods; i++)
+                       dwc_dump_lli(dwc, &dwc->cdesc->desc[i]->lli);
+       }
+}
+
+/* ------------------------------------------------------------------------- */
+
 static void dw_dma_tasklet(unsigned long data)
 {
        struct dw_dma *dw = (struct dw_dma *)data;
@@ -382,7 +458,10 @@ static void dw_dma_tasklet(unsigned long data)
        for (i = 0; i < dw->dma.chancnt; i++) {
                dwc = &dw->chan[i];
                spin_lock(&dwc->lock);
-               if (status_err & (1 << i))
+               if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
+                       dwc_handle_cyclic(dw, dwc, status_block, status_err,
+                                       status_xfer);
+               else if (status_err & (1 << i))
                        dwc_handle_error(dw, dwc);
                else if ((status_block | status_xfer) & (1 << i))
                        dwc_scan_descriptors(dw, dwc);
@@ -826,7 +905,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
                dma_async_tx_descriptor_init(&desc->txd, chan);
                desc->txd.tx_submit = dwc_tx_submit;
                desc->txd.flags = DMA_CTRL_ACK;
-               INIT_LIST_HEAD(&desc->txd.tx_list);
                desc->txd.phys = dma_map_single(chan2parent(chan), &desc->lli,
                                sizeof(desc->lli), DMA_TO_DEVICE);
                dwc_desc_put(dwc, desc);
@@ -884,6 +962,257 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        dev_vdbg(chan2dev(chan), "free_chan_resources done\n");
 }
 
+/* --------------------- Cyclic DMA API extensions -------------------- */
+
+/**
+ * dw_dma_cyclic_start - start the cyclic DMA transfer
+ * @chan: the DMA channel to start
+ *
+ * Must be called with soft interrupts disabled. Returns zero on success or
+ * -errno on failure.
+ */
+int dw_dma_cyclic_start(struct dma_chan *chan)
+{
+       struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
+       struct dw_dma           *dw = to_dw_dma(dwc->chan.device);
+
+       if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) {
+               dev_err(chan2dev(&dwc->chan), "missing prep for cyclic DMA\n");
+               return -ENODEV;
+       }
+
+       spin_lock(&dwc->lock);
+
+       /* assert channel is idle */
+       if (dma_readl(dw, CH_EN) & dwc->mask) {
+               dev_err(chan2dev(&dwc->chan),
+                       "BUG: Attempted to start non-idle channel\n");
+               dev_err(chan2dev(&dwc->chan),
+                       "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
+                       channel_readl(dwc, SAR),
+                       channel_readl(dwc, DAR),
+                       channel_readl(dwc, LLP),
+                       channel_readl(dwc, CTL_HI),
+                       channel_readl(dwc, CTL_LO));
+               spin_unlock(&dwc->lock);
+               return -EBUSY;
+       }
+
+       dma_writel(dw, CLEAR.BLOCK, dwc->mask);
+       dma_writel(dw, CLEAR.ERROR, dwc->mask);
+       dma_writel(dw, CLEAR.XFER, dwc->mask);
+
+       /* setup DMAC channel registers */
+       channel_writel(dwc, LLP, dwc->cdesc->desc[0]->txd.phys);
+       channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
+       channel_writel(dwc, CTL_HI, 0);
+
+       channel_set_bit(dw, CH_EN, dwc->mask);
+
+       spin_unlock(&dwc->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(dw_dma_cyclic_start);
+
+/**
+ * dw_dma_cyclic_stop - stop the cyclic DMA transfer
+ * @chan: the DMA channel to stop
+ *
+ * Must be called with soft interrupts disabled.
+ */
+void dw_dma_cyclic_stop(struct dma_chan *chan)
+{
+       struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
+       struct dw_dma           *dw = to_dw_dma(dwc->chan.device);
+
+       spin_lock(&dwc->lock);
+
+       channel_clear_bit(dw, CH_EN, dwc->mask);
+       while (dma_readl(dw, CH_EN) & dwc->mask)
+               cpu_relax();
+
+       spin_unlock(&dwc->lock);
+}
+EXPORT_SYMBOL(dw_dma_cyclic_stop);
+
+/**
+ * dw_dma_cyclic_prep - prepare the cyclic DMA transfer
+ * @chan: the DMA channel to prepare
+ * @buf_addr: physical DMA address where the buffer starts
+ * @buf_len: total number of bytes for the entire buffer
+ * @period_len: number of bytes for each period
+ * @direction: transfer direction, to or from device
+ *
+ * Must be called before trying to start the transfer. Returns a valid struct
+ * dw_cyclic_desc if successful or an ERR_PTR(-errno) if not successful.
+ */
+struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
+               dma_addr_t buf_addr, size_t buf_len, size_t period_len,
+               enum dma_data_direction direction)
+{
+       struct dw_dma_chan              *dwc = to_dw_dma_chan(chan);
+       struct dw_cyclic_desc           *cdesc;
+       struct dw_cyclic_desc           *retval = NULL;
+       struct dw_desc                  *desc;
+       struct dw_desc                  *last = NULL;
+       struct dw_dma_slave             *dws = chan->private;
+       unsigned long                   was_cyclic;
+       unsigned int                    reg_width;
+       unsigned int                    periods;
+       unsigned int                    i;
+
+       spin_lock_bh(&dwc->lock);
+       if (!list_empty(&dwc->queue) || !list_empty(&dwc->active_list)) {
+               spin_unlock_bh(&dwc->lock);
+               dev_dbg(chan2dev(&dwc->chan),
+                               "queue and/or active list are not empty\n");
+               return ERR_PTR(-EBUSY);
+       }
+
+       was_cyclic = test_and_set_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
+       spin_unlock_bh(&dwc->lock);
+       if (was_cyclic) {
+               dev_dbg(chan2dev(&dwc->chan),
+                               "channel already prepared for cyclic DMA\n");
+               return ERR_PTR(-EBUSY);
+       }
+
+       retval = ERR_PTR(-EINVAL);
+       reg_width = dws->reg_width;
+       periods = buf_len / period_len;
+
+       /* Check for too big/unaligned periods and unaligned DMA buffer. */
+       if (period_len > (DWC_MAX_COUNT << reg_width))
+               goto out_err;
+       if (unlikely(period_len & ((1 << reg_width) - 1)))
+               goto out_err;
+       if (unlikely(buf_addr & ((1 << reg_width) - 1)))
+               goto out_err;
+       if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE))))
+               goto out_err;
+
+       retval = ERR_PTR(-ENOMEM);
+
+       if (periods > NR_DESCS_PER_CHANNEL)
+               goto out_err;
+
+       cdesc = kzalloc(sizeof(struct dw_cyclic_desc), GFP_KERNEL);
+       if (!cdesc)
+               goto out_err;
+
+       cdesc->desc = kzalloc(sizeof(struct dw_desc *) * periods, GFP_KERNEL);
+       if (!cdesc->desc)
+               goto out_err_alloc;
+
+       for (i = 0; i < periods; i++) {
+               desc = dwc_desc_get(dwc);
+               if (!desc)
+                       goto out_err_desc_get;
+
+               switch (direction) {
+               case DMA_TO_DEVICE:
+                       desc->lli.dar = dws->tx_reg;
+                       desc->lli.sar = buf_addr + (period_len * i);
+                       desc->lli.ctllo = (DWC_DEFAULT_CTLLO
+                                       | DWC_CTLL_DST_WIDTH(reg_width)
+                                       | DWC_CTLL_SRC_WIDTH(reg_width)
+                                       | DWC_CTLL_DST_FIX
+                                       | DWC_CTLL_SRC_INC
+                                       | DWC_CTLL_FC_M2P
+                                       | DWC_CTLL_INT_EN);
+                       break;
+               case DMA_FROM_DEVICE:
+                       desc->lli.dar = buf_addr + (period_len * i);
+                       desc->lli.sar = dws->rx_reg;
+                       desc->lli.ctllo = (DWC_DEFAULT_CTLLO
+                                       | DWC_CTLL_SRC_WIDTH(reg_width)
+                                       | DWC_CTLL_DST_WIDTH(reg_width)
+                                       | DWC_CTLL_DST_INC
+                                       | DWC_CTLL_SRC_FIX
+                                       | DWC_CTLL_FC_P2M
+                                       | DWC_CTLL_INT_EN);
+                       break;
+               default:
+                       break;
+               }
+
+               desc->lli.ctlhi = (period_len >> reg_width);
+               cdesc->desc[i] = desc;
+
+               if (last) {
+                       last->lli.llp = desc->txd.phys;
+                       dma_sync_single_for_device(chan2parent(chan),
+                                       last->txd.phys, sizeof(last->lli),
+                                       DMA_TO_DEVICE);
+               }
+
+               last = desc;
+       }
+
+       /* lets make a cyclic list */
+       last->lli.llp = cdesc->desc[0]->txd.phys;
+       dma_sync_single_for_device(chan2parent(chan), last->txd.phys,
+                       sizeof(last->lli), DMA_TO_DEVICE);
+
+       dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%08x len %zu "
+                       "period %zu periods %d\n", buf_addr, buf_len,
+                       period_len, periods);
+
+       cdesc->periods = periods;
+       dwc->cdesc = cdesc;
+
+       return cdesc;
+
+out_err_desc_get:
+       while (i--)
+               dwc_desc_put(dwc, cdesc->desc[i]);
+out_err_alloc:
+       kfree(cdesc);
+out_err:
+       clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
+       return (struct dw_cyclic_desc *)retval;
+}
+EXPORT_SYMBOL(dw_dma_cyclic_prep);
+
+/**
+ * dw_dma_cyclic_free - free a prepared cyclic DMA transfer
+ * @chan: the DMA channel to free
+ */
+void dw_dma_cyclic_free(struct dma_chan *chan)
+{
+       struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
+       struct dw_dma           *dw = to_dw_dma(dwc->chan.device);
+       struct dw_cyclic_desc   *cdesc = dwc->cdesc;
+       int                     i;
+
+       dev_dbg(chan2dev(&dwc->chan), "cyclic free\n");
+
+       if (!cdesc)
+               return;
+
+       spin_lock_bh(&dwc->lock);
+
+       channel_clear_bit(dw, CH_EN, dwc->mask);
+       while (dma_readl(dw, CH_EN) & dwc->mask)
+               cpu_relax();
+
+       dma_writel(dw, CLEAR.BLOCK, dwc->mask);
+       dma_writel(dw, CLEAR.ERROR, dwc->mask);
+       dma_writel(dw, CLEAR.XFER, dwc->mask);
+
+       spin_unlock_bh(&dwc->lock);
+
+       for (i = 0; i < cdesc->periods; i++)
+               dwc_desc_put(dwc, cdesc->desc[i]);
+
+       kfree(cdesc->desc);
+       kfree(cdesc);
+
+       clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
+}
+EXPORT_SYMBOL(dw_dma_cyclic_free);
+
 /*----------------------------------------------------------------------*/
 
 static void dw_dma_off(struct dw_dma *dw)
index b252b202c5cf1888f65149d3e22deee3d9cfeef0..13a580767031a3aac04046ffd563ef1d83f053b0 100644 (file)
@@ -126,6 +126,10 @@ struct dw_dma_regs {
 
 #define DW_REGLEN              0x400
 
+enum dw_dmac_flags {
+       DW_DMA_IS_CYCLIC = 0,
+};
+
 struct dw_dma_chan {
        struct dma_chan         chan;
        void __iomem            *ch_regs;
@@ -134,10 +138,12 @@ struct dw_dma_chan {
        spinlock_t              lock;
 
        /* these other elements are all protected by lock */
+       unsigned long           flags;
        dma_cookie_t            completed;
        struct list_head        active_list;
        struct list_head        queue;
        struct list_head        free_list;
+       struct dw_cyclic_desc   *cdesc;
 
        unsigned int            descs_allocated;
 };
@@ -158,7 +164,6 @@ static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
        return container_of(chan, struct dw_dma_chan, chan);
 }
 
-
 struct dw_dma {
        struct dma_device       dma;
        void __iomem            *regs;
index 86d6da47f558765736149344b2c595b13a289f3f..da8a8ed9e411008d68e14820444695176caa9318 100644 (file)
@@ -354,7 +354,6 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
                dma_async_tx_descriptor_init(&desc_sw->async_tx,
                                                &fsl_chan->common);
                desc_sw->async_tx.tx_submit = fsl_dma_tx_submit;
-               INIT_LIST_HEAD(&desc_sw->async_tx.tx_list);
                desc_sw->async_tx.phys = pdesc;
        }
 
index 5905cd36bcd23b43b86dcc532a1a70cc5ce5ce58..e4fc33c1c32f89fc99711ca2c759f15e79eeaa62 100644 (file)
@@ -693,7 +693,6 @@ static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
                desc_sw->async_tx.tx_submit = ioat2_tx_submit;
                break;
        }
-       INIT_LIST_HEAD(&desc_sw->async_tx.tx_list);
 
        desc_sw->hw = desc;
        desc_sw->async_tx.phys = phys;
index 16adbe61cfb2cd60efd1a01246be3f9c9f4eac43..2f052265122f62e2681bbdb0dfbbd558cef24713 100644 (file)
@@ -498,7 +498,6 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
                slot->async_tx.tx_submit = iop_adma_tx_submit;
                INIT_LIST_HEAD(&slot->chain_node);
                INIT_LIST_HEAD(&slot->slot_node);
-               INIT_LIST_HEAD(&slot->async_tx.tx_list);
                hw_desc = (char *) iop_chan->device->dma_desc_pool;
                slot->async_tx.phys =
                        (dma_addr_t) &hw_desc[idx * IOP_ADMA_SLOT_SIZE];
index da781d1078951f9164dcf5c1da1706f376b1a21d..e202a6ce55735bf3d6fdb456f718fade1301ba32 100644 (file)
@@ -28,6 +28,9 @@
 #define FS_VF_IN_VALID 0x00000002
 #define FS_ENC_IN_VALID        0x00000001
 
+static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan,
+                              bool wait_for_stop);
+
 /*
  * There can be only one, we could allocate it dynamically, but then we'd have
  * to add an extra parameter to some functions, and use something as ugly as
@@ -107,7 +110,7 @@ static uint32_t bytes_per_pixel(enum pixel_fmt fmt)
        }
 }
 
-/* Enable / disable direct write to memory by the Camera Sensor Interface */
+/* Enable direct write to memory by the Camera Sensor Interface */
 static void ipu_ic_enable_task(struct ipu *ipu, enum ipu_channel channel)
 {
        uint32_t ic_conf, mask;
@@ -126,6 +129,7 @@ static void ipu_ic_enable_task(struct ipu *ipu, enum ipu_channel channel)
        idmac_write_icreg(ipu, ic_conf, IC_CONF);
 }
 
+/* Called under spin_lock_irqsave(&ipu_data.lock) */
 static void ipu_ic_disable_task(struct ipu *ipu, enum ipu_channel channel)
 {
        uint32_t ic_conf, mask;
@@ -422,7 +426,7 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
                break;
        default:
                dev_err(ipu_data.dev,
-                       "mxc ipu: unimplemented pixel format %d\n", pixel_fmt);
+                       "mx3 ipu: unimplemented pixel format %d\n", pixel_fmt);
                break;
        }
 
@@ -433,20 +437,20 @@ static void ipu_ch_param_set_burst_size(union chan_param_mem *params,
                                        uint16_t burst_pixels)
 {
        params->pp.npb = burst_pixels - 1;
-};
+}
 
 static void ipu_ch_param_set_buffer(union chan_param_mem *params,
                                    dma_addr_t buf0, dma_addr_t buf1)
 {
        params->pp.eba0 = buf0;
        params->pp.eba1 = buf1;
-};
+}
 
 static void ipu_ch_param_set_rotation(union chan_param_mem *params,
                                      enum ipu_rotate_mode rotate)
 {
        params->pp.bam = rotate;
-};
+}
 
 static void ipu_write_param_mem(uint32_t addr, uint32_t *data,
                                uint32_t num_words)
@@ -571,7 +575,7 @@ static uint32_t dma_param_addr(uint32_t dma_ch)
 {
        /* Channel Parameter Memory */
        return 0x10000 | (dma_ch << 4);
-};
+}
 
 static void ipu_channel_set_priority(struct ipu *ipu, enum ipu_channel channel,
                                     bool prio)
@@ -611,7 +615,8 @@ static uint32_t ipu_channel_conf_mask(enum ipu_channel channel)
 
 /**
  * ipu_enable_channel() - enable an IPU channel.
- * @channel:   channel ID.
+ * @idmac:     IPU DMAC context.
+ * @ichan:     IDMAC channel.
  * @return:    0 on success or negative error code on failure.
  */
 static int ipu_enable_channel(struct idmac *idmac, struct idmac_channel *ichan)
@@ -649,7 +654,7 @@ static int ipu_enable_channel(struct idmac *idmac, struct idmac_channel *ichan)
 
 /**
  * ipu_init_channel_buffer() - initialize a buffer for logical IPU channel.
- * @channel:   channel ID.
+ * @ichan:     IDMAC channel.
  * @pixel_fmt: pixel format of buffer. Pixel format is a FOURCC ASCII code.
  * @width:     width of buffer in pixels.
  * @height:    height of buffer in pixels.
@@ -687,7 +692,7 @@ static int ipu_init_channel_buffer(struct idmac_channel *ichan,
        }
 
        /* IC channel's stride must be a multiple of 8 pixels */
-       if ((channel <= 13) && (stride % 8)) {
+       if ((channel <= IDMAC_IC_13) && (stride % 8)) {
                dev_err(ipu->dev, "Stride must be 8 pixel multiple\n");
                return -EINVAL;
        }
@@ -752,7 +757,7 @@ static void ipu_select_buffer(enum ipu_channel channel, int buffer_n)
 
 /**
  * ipu_update_channel_buffer() - update physical address of a channel buffer.
- * @channel:   channel ID.
+ * @ichan:     IDMAC channel.
  * @buffer_n:  buffer number to update.
  *             0 or 1 are the only valid values.
  * @phyaddr:   buffer physical address.
@@ -760,9 +765,10 @@ static void ipu_select_buffer(enum ipu_channel channel, int buffer_n)
  *              function will fail if the buffer is set to ready.
  */
 /* Called under spin_lock(_irqsave)(&ichan->lock) */
-static int ipu_update_channel_buffer(enum ipu_channel channel,
+static int ipu_update_channel_buffer(struct idmac_channel *ichan,
                                     int buffer_n, dma_addr_t phyaddr)
 {
+       enum ipu_channel channel = ichan->dma_chan.chan_id;
        uint32_t reg;
        unsigned long flags;
 
@@ -771,8 +777,8 @@ static int ipu_update_channel_buffer(enum ipu_channel channel,
        if (buffer_n == 0) {
                reg = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY);
                if (reg & (1UL << channel)) {
-                       spin_unlock_irqrestore(&ipu_data.lock, flags);
-                       return -EACCES;
+                       ipu_ic_disable_task(&ipu_data, channel);
+                       ichan->status = IPU_CHANNEL_READY;
                }
 
                /* 44.3.3.1.9 - Row Number 1 (WORD1, offset 0) */
@@ -782,8 +788,8 @@ static int ipu_update_channel_buffer(enum ipu_channel channel,
        } else {
                reg = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY);
                if (reg & (1UL << channel)) {
-                       spin_unlock_irqrestore(&ipu_data.lock, flags);
-                       return -EACCES;
+                       ipu_ic_disable_task(&ipu_data, channel);
+                       ichan->status = IPU_CHANNEL_READY;
                }
 
                /* Check if double-buffering is already enabled */
@@ -804,6 +810,39 @@ static int ipu_update_channel_buffer(enum ipu_channel channel,
        return 0;
 }
 
+/* Called under spin_lock_irqsave(&ichan->lock) */
+static int ipu_submit_buffer(struct idmac_channel *ichan,
+       struct idmac_tx_desc *desc, struct scatterlist *sg, int buf_idx)
+{
+       unsigned int chan_id = ichan->dma_chan.chan_id;
+       struct device *dev = &ichan->dma_chan.dev->device;
+       int ret;
+
+       if (async_tx_test_ack(&desc->txd))
+               return -EINTR;
+
+       /*
+        * On first invocation this shouldn't be necessary, the call to
+        * ipu_init_channel_buffer() above will set addresses for us, so we
+        * could make it conditional on status >= IPU_CHANNEL_ENABLED, but
+        * doing it again shouldn't hurt either.
+        */
+       ret = ipu_update_channel_buffer(ichan, buf_idx,
+                                       sg_dma_address(sg));
+
+       if (ret < 0) {
+               dev_err(dev, "Updating sg %p on channel 0x%x buffer %d failed!\n",
+                       sg, chan_id, buf_idx);
+               return ret;
+       }
+
+       ipu_select_buffer(chan_id, buf_idx);
+       dev_dbg(dev, "Updated sg %p on channel 0x%x buffer %d\n",
+               sg, chan_id, buf_idx);
+
+       return 0;
+}
+
 /* Called under spin_lock_irqsave(&ichan->lock) */
 static int ipu_submit_channel_buffers(struct idmac_channel *ichan,
                                      struct idmac_tx_desc *desc)
@@ -815,20 +854,10 @@ static int ipu_submit_channel_buffers(struct idmac_channel *ichan,
                if (!ichan->sg[i]) {
                        ichan->sg[i] = sg;
 
-                       /*
-                        * On first invocation this shouldn't be necessary, the
-                        * call to ipu_init_channel_buffer() above will set
-                        * addresses for us, so we could make it conditional
-                        * on status >= IPU_CHANNEL_ENABLED, but doing it again
-                        * shouldn't hurt either.
-                        */
-                       ret = ipu_update_channel_buffer(ichan->dma_chan.chan_id, i,
-                                                       sg_dma_address(sg));
+                       ret = ipu_submit_buffer(ichan, desc, sg, i);
                        if (ret < 0)
                                return ret;
 
-                       ipu_select_buffer(ichan->dma_chan.chan_id, i);
-
                        sg = sg_next(sg);
                }
        }
@@ -842,19 +871,22 @@ static dma_cookie_t idmac_tx_submit(struct dma_async_tx_descriptor *tx)
        struct idmac_channel *ichan = to_idmac_chan(tx->chan);
        struct idmac *idmac = to_idmac(tx->chan->device);
        struct ipu *ipu = to_ipu(idmac);
+       struct device *dev = &ichan->dma_chan.dev->device;
        dma_cookie_t cookie;
        unsigned long flags;
+       int ret;
 
        /* Sanity check */
        if (!list_empty(&desc->list)) {
                /* The descriptor doesn't belong to client */
-               dev_err(&ichan->dma_chan.dev->device,
-                       "Descriptor %p not prepared!\n", tx);
+               dev_err(dev, "Descriptor %p not prepared!\n", tx);
                return -EBUSY;
        }
 
        mutex_lock(&ichan->chan_mutex);
 
+       async_tx_clear_ack(tx);
+
        if (ichan->status < IPU_CHANNEL_READY) {
                struct idmac_video_param *video = &ichan->params.video;
                /*
@@ -878,16 +910,7 @@ static dma_cookie_t idmac_tx_submit(struct dma_async_tx_descriptor *tx)
                        goto out;
        }
 
-       /* ipu->lock can be taken under ichan->lock, but not v.v. */
-       spin_lock_irqsave(&ichan->lock, flags);
-
-       /* submit_buffers() atomically verifies and fills empty sg slots */
-       cookie = ipu_submit_channel_buffers(ichan, desc);
-
-       spin_unlock_irqrestore(&ichan->lock, flags);
-
-       if (cookie < 0)
-               goto out;
+       dev_dbg(dev, "Submitting sg %p\n", &desc->sg[0]);
 
        cookie = ichan->dma_chan.cookie;
 
@@ -897,24 +920,40 @@ static dma_cookie_t idmac_tx_submit(struct dma_async_tx_descriptor *tx)
        /* from dmaengine.h: "last cookie value returned to client" */
        ichan->dma_chan.cookie = cookie;
        tx->cookie = cookie;
+
+       /* ipu->lock can be taken under ichan->lock, but not v.v. */
        spin_lock_irqsave(&ichan->lock, flags);
+
        list_add_tail(&desc->list, &ichan->queue);
+       /* submit_buffers() atomically verifies and fills empty sg slots */
+       ret = ipu_submit_channel_buffers(ichan, desc);
+
        spin_unlock_irqrestore(&ichan->lock, flags);
 
+       if (ret < 0) {
+               cookie = ret;
+               goto dequeue;
+       }
+
        if (ichan->status < IPU_CHANNEL_ENABLED) {
-               int ret = ipu_enable_channel(idmac, ichan);
+               ret = ipu_enable_channel(idmac, ichan);
                if (ret < 0) {
                        cookie = ret;
-                       spin_lock_irqsave(&ichan->lock, flags);
-                       list_del_init(&desc->list);
-                       spin_unlock_irqrestore(&ichan->lock, flags);
-                       tx->cookie = cookie;
-                       ichan->dma_chan.cookie = cookie;
+                       goto dequeue;
                }
        }
 
        dump_idmac_reg(ipu);
 
+dequeue:
+       if (cookie < 0) {
+               spin_lock_irqsave(&ichan->lock, flags);
+               list_del_init(&desc->list);
+               spin_unlock_irqrestore(&ichan->lock, flags);
+               tx->cookie = cookie;
+               ichan->dma_chan.cookie = cookie;
+       }
+
 out:
        mutex_unlock(&ichan->chan_mutex);
 
@@ -944,8 +983,6 @@ static int idmac_desc_alloc(struct idmac_channel *ichan, int n)
                memset(txd, 0, sizeof(*txd));
                dma_async_tx_descriptor_init(txd, &ichan->dma_chan);
                txd->tx_submit          = idmac_tx_submit;
-               txd->chan               = &ichan->dma_chan;
-               INIT_LIST_HEAD(&txd->tx_list);
 
                list_add(&desc->list, &ichan->free_list);
 
@@ -1161,6 +1198,24 @@ static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan,
        return 0;
 }
 
+static struct scatterlist *idmac_sg_next(struct idmac_channel *ichan,
+       struct idmac_tx_desc **desc, struct scatterlist *sg)
+{
+       struct scatterlist *sgnew = sg ? sg_next(sg) : NULL;
+
+       if (sgnew)
+               /* next sg-element in this list */
+               return sgnew;
+
+       if ((*desc)->list.next == &ichan->queue)
+               /* No more descriptors on the queue */
+               return NULL;
+
+       /* Fetch next descriptor */
+       *desc = list_entry((*desc)->list.next, struct idmac_tx_desc, list);
+       return (*desc)->sg;
+}
+
 /*
  * We have several possibilities here:
  * current BUF         next BUF
@@ -1176,23 +1231,46 @@ static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan,
 static irqreturn_t idmac_interrupt(int irq, void *dev_id)
 {
        struct idmac_channel *ichan = dev_id;
+       struct device *dev = &ichan->dma_chan.dev->device;
        unsigned int chan_id = ichan->dma_chan.chan_id;
        struct scatterlist **sg, *sgnext, *sgnew = NULL;
        /* Next transfer descriptor */
-       struct idmac_tx_desc *desc = NULL, *descnew;
+       struct idmac_tx_desc *desc, *descnew;
        dma_async_tx_callback callback;
        void *callback_param;
        bool done = false;
-       u32     ready0 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY),
-               ready1 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY),
-               curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF);
+       u32 ready0, ready1, curbuf, err;
+       unsigned long flags;
 
        /* IDMAC has cleared the respective BUFx_RDY bit, we manage the buffer */
 
-       pr_debug("IDMAC irq %d\n", irq);
+       dev_dbg(dev, "IDMAC irq %d, buf %d\n", irq, ichan->active_buffer);
+
+       spin_lock_irqsave(&ipu_data.lock, flags);
+
+       ready0  = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY);
+       ready1  = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY);
+       curbuf  = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF);
+       err     = idmac_read_ipureg(&ipu_data, IPU_INT_STAT_4);
+
+       if (err & (1 << chan_id)) {
+               idmac_write_ipureg(&ipu_data, 1 << chan_id, IPU_INT_STAT_4);
+               spin_unlock_irqrestore(&ipu_data.lock, flags);
+               /*
+                * Doing this
+                * ichan->sg[0] = ichan->sg[1] = NULL;
+                * you can force channel re-enable on the next tx_submit(), but
+                * this is dirty - think about descriptors with multiple
+                * sg elements.
+                */
+               dev_warn(dev, "NFB4EOF on channel %d, ready %x, %x, cur %x\n",
+                        chan_id, ready0, ready1, curbuf);
+               return IRQ_HANDLED;
+       }
+       spin_unlock_irqrestore(&ipu_data.lock, flags);
+
        /* Other interrupts do not interfere with this channel */
        spin_lock(&ichan->lock);
-
        if (unlikely(chan_id != IDMAC_SDC_0 && chan_id != IDMAC_SDC_1 &&
                     ((curbuf >> chan_id) & 1) == ichan->active_buffer)) {
                int i = 100;
@@ -1207,19 +1285,23 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
 
                if (!i) {
                        spin_unlock(&ichan->lock);
-                       dev_dbg(ichan->dma_chan.device->dev,
+                       dev_dbg(dev,
                                "IRQ on active buffer on channel %x, active "
                                "%d, ready %x, %x, current %x!\n", chan_id,
                                ichan->active_buffer, ready0, ready1, curbuf);
                        return IRQ_NONE;
-               }
+               } else
+                       dev_dbg(dev,
+                               "Buffer deactivated on channel %x, active "
+                               "%d, ready %x, %x, current %x, rest %d!\n", chan_id,
+                               ichan->active_buffer, ready0, ready1, curbuf, i);
        }
 
        if (unlikely((ichan->active_buffer && (ready1 >> chan_id) & 1) ||
                     (!ichan->active_buffer && (ready0 >> chan_id) & 1)
                     )) {
                spin_unlock(&ichan->lock);
-               dev_dbg(ichan->dma_chan.device->dev,
+               dev_dbg(dev,
                        "IRQ with active buffer still ready on channel %x, "
                        "active %d, ready %x, %x!\n", chan_id,
                        ichan->active_buffer, ready0, ready1);
@@ -1227,8 +1309,9 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
        }
 
        if (unlikely(list_empty(&ichan->queue))) {
+               ichan->sg[ichan->active_buffer] = NULL;
                spin_unlock(&ichan->lock);
-               dev_err(ichan->dma_chan.device->dev,
+               dev_err(dev,
                        "IRQ without queued buffers on channel %x, active %d, "
                        "ready %x, %x!\n", chan_id,
                        ichan->active_buffer, ready0, ready1);
@@ -1243,40 +1326,44 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
        sg = &ichan->sg[ichan->active_buffer];
        sgnext = ichan->sg[!ichan->active_buffer];
 
+       if (!*sg) {
+               spin_unlock(&ichan->lock);
+               return IRQ_HANDLED;
+       }
+
+       desc = list_entry(ichan->queue.next, struct idmac_tx_desc, list);
+       descnew = desc;
+
+       dev_dbg(dev, "IDMAC irq %d, dma 0x%08x, next dma 0x%08x, current %d, curbuf 0x%08x\n",
+               irq, sg_dma_address(*sg), sgnext ? sg_dma_address(sgnext) : 0, ichan->active_buffer, curbuf);
+
+       /* Find the descriptor of sgnext */
+       sgnew = idmac_sg_next(ichan, &descnew, *sg);
+       if (sgnext != sgnew)
+               dev_err(dev, "Submitted buffer %p, next buffer %p\n", sgnext, sgnew);
+
        /*
         * if sgnext == NULL sg must be the last element in a scatterlist and
         * queue must be empty
         */
        if (unlikely(!sgnext)) {
-               if (unlikely(sg_next(*sg))) {
-                       dev_err(ichan->dma_chan.device->dev,
-                               "Broken buffer-update locking on channel %x!\n",
-                               chan_id);
-                       /* We'll let the user catch up */
+               if (!WARN_ON(sg_next(*sg)))
+                       dev_dbg(dev, "Underrun on channel %x\n", chan_id);
+               ichan->sg[!ichan->active_buffer] = sgnew;
+
+               if (unlikely(sgnew)) {
+                       ipu_submit_buffer(ichan, descnew, sgnew, !ichan->active_buffer);
                } else {
-                       /* Underrun */
+                       spin_lock_irqsave(&ipu_data.lock, flags);
                        ipu_ic_disable_task(&ipu_data, chan_id);
-                       dev_dbg(ichan->dma_chan.device->dev,
-                               "Underrun on channel %x\n", chan_id);
+                       spin_unlock_irqrestore(&ipu_data.lock, flags);
                        ichan->status = IPU_CHANNEL_READY;
                        /* Continue to check for complete descriptor */
                }
        }
 
-       desc = list_entry(ichan->queue.next, struct idmac_tx_desc, list);
-
-       /* First calculate and submit the next sg element */
-       if (likely(sgnext))
-               sgnew = sg_next(sgnext);
-
-       if (unlikely(!sgnew)) {
-               /* Start a new scatterlist, if any queued */
-               if (likely(desc->list.next != &ichan->queue)) {
-                       descnew = list_entry(desc->list.next,
-                                            struct idmac_tx_desc, list);
-                       sgnew = &descnew->sg[0];
-               }
-       }
+       /* Calculate and submit the next sg element */
+       sgnew = idmac_sg_next(ichan, &descnew, sgnew);
 
        if (unlikely(!sg_next(*sg)) || !sgnext) {
                /*
@@ -1289,17 +1376,13 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
 
        *sg = sgnew;
 
-       if (likely(sgnew)) {
-               int ret;
-
-               ret = ipu_update_channel_buffer(chan_id, ichan->active_buffer,
-                                               sg_dma_address(*sg));
-               if (ret < 0)
-                       dev_err(ichan->dma_chan.device->dev,
-                               "Failed to update buffer on channel %x buffer %d!\n",
-                               chan_id, ichan->active_buffer);
-               else
-                       ipu_select_buffer(chan_id, ichan->active_buffer);
+       if (likely(sgnew) &&
+           ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) {
+               callback = desc->txd.callback;
+               callback_param = desc->txd.callback_param;
+               spin_unlock(&ichan->lock);
+               callback(callback_param);
+               spin_lock(&ichan->lock);
        }
 
        /* Flip the active buffer - even if update above failed */
@@ -1327,13 +1410,20 @@ static void ipu_gc_tasklet(unsigned long arg)
                struct idmac_channel *ichan = ipu->channel + i;
                struct idmac_tx_desc *desc;
                unsigned long flags;
-               int j;
+               struct scatterlist *sg;
+               int j, k;
 
                for (j = 0; j < ichan->n_tx_desc; j++) {
                        desc = ichan->desc + j;
                        spin_lock_irqsave(&ichan->lock, flags);
                        if (async_tx_test_ack(&desc->txd)) {
                                list_move(&desc->list, &ichan->free_list);
+                               for_each_sg(desc->sg, sg, desc->sg_len, k) {
+                                       if (ichan->sg[0] == sg)
+                                               ichan->sg[0] = NULL;
+                                       else if (ichan->sg[1] == sg)
+                                               ichan->sg[1] = NULL;
+                               }
                                async_tx_clear_ack(&desc->txd);
                        }
                        spin_unlock_irqrestore(&ichan->lock, flags);
@@ -1341,13 +1431,7 @@ static void ipu_gc_tasklet(unsigned long arg)
        }
 }
 
-/*
- * At the time .device_alloc_chan_resources() method is called, we cannot know,
- * whether the client will accept the channel. Thus we must only check, if we
- * can satisfy client's request but the only real criterion to verify, whether
- * the client has accepted our offer is the client_count. That's why we have to
- * perform the rest of our allocation tasks on the first call to this function.
- */
+/* Allocate and initialise a transfer descriptor. */
 static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan,
                struct scatterlist *sgl, unsigned int sg_len,
                enum dma_data_direction direction, unsigned long tx_flags)
@@ -1358,8 +1442,8 @@ static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan
        unsigned long flags;
 
        /* We only can handle these three channels so far */
-       if (ichan->dma_chan.chan_id != IDMAC_SDC_0 && ichan->dma_chan.chan_id != IDMAC_SDC_1 &&
-           ichan->dma_chan.chan_id != IDMAC_IC_7)
+       if (chan->chan_id != IDMAC_SDC_0 && chan->chan_id != IDMAC_SDC_1 &&
+           chan->chan_id != IDMAC_IC_7)
                return NULL;
 
        if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE) {
@@ -1400,7 +1484,7 @@ static void idmac_issue_pending(struct dma_chan *chan)
 
        /* This is not always needed, but doesn't hurt either */
        spin_lock_irqsave(&ipu->lock, flags);
-       ipu_select_buffer(ichan->dma_chan.chan_id, ichan->active_buffer);
+       ipu_select_buffer(chan->chan_id, ichan->active_buffer);
        spin_unlock_irqrestore(&ipu->lock, flags);
 
        /*
@@ -1432,8 +1516,7 @@ static void __idmac_terminate_all(struct dma_chan *chan)
                        struct idmac_tx_desc *desc = ichan->desc + i;
                        if (list_empty(&desc->list))
                                /* Descriptor was prepared, but not submitted */
-                               list_add(&desc->list,
-                                        &ichan->free_list);
+                               list_add(&desc->list, &ichan->free_list);
 
                        async_tx_clear_ack(&desc->txd);
                }
@@ -1458,6 +1541,28 @@ static void idmac_terminate_all(struct dma_chan *chan)
        mutex_unlock(&ichan->chan_mutex);
 }
 
+#ifdef DEBUG
+static irqreturn_t ic_sof_irq(int irq, void *dev_id)
+{
+       struct idmac_channel *ichan = dev_id;
+       printk(KERN_DEBUG "Got SOF IRQ %d on Channel %d\n",
+              irq, ichan->dma_chan.chan_id);
+       disable_irq(irq);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ic_eof_irq(int irq, void *dev_id)
+{
+       struct idmac_channel *ichan = dev_id;
+       printk(KERN_DEBUG "Got EOF IRQ %d on Channel %d\n",
+              irq, ichan->dma_chan.chan_id);
+       disable_irq(irq);
+       return IRQ_HANDLED;
+}
+
+static int ic_sof = -EINVAL, ic_eof = -EINVAL;
+#endif
+
 static int idmac_alloc_chan_resources(struct dma_chan *chan)
 {
        struct idmac_channel *ichan = to_idmac_chan(chan);
@@ -1471,31 +1576,49 @@ static int idmac_alloc_chan_resources(struct dma_chan *chan)
        chan->cookie            = 1;
        ichan->completed        = -ENXIO;
 
-       ret = ipu_irq_map(ichan->dma_chan.chan_id);
+       ret = ipu_irq_map(chan->chan_id);
        if (ret < 0)
                goto eimap;
 
        ichan->eof_irq = ret;
+
+       /*
+        * Important to first disable the channel, because maybe someone
+        * used it before us, e.g., the bootloader
+        */
+       ipu_disable_channel(idmac, ichan, true);
+
+       ret = ipu_init_channel(idmac, ichan);
+       if (ret < 0)
+               goto eichan;
+
        ret = request_irq(ichan->eof_irq, idmac_interrupt, 0,
                          ichan->eof_name, ichan);
        if (ret < 0)
                goto erirq;
 
-       ret = ipu_init_channel(idmac, ichan);
-       if (ret < 0)
-               goto eichan;
+#ifdef DEBUG
+       if (chan->chan_id == IDMAC_IC_7) {
+               ic_sof = ipu_irq_map(69);
+               if (ic_sof > 0)
+                       request_irq(ic_sof, ic_sof_irq, 0, "IC SOF", ichan);
+               ic_eof = ipu_irq_map(70);
+               if (ic_eof > 0)
+                       request_irq(ic_eof, ic_eof_irq, 0, "IC EOF", ichan);
+       }
+#endif
 
        ichan->status = IPU_CHANNEL_INITIALIZED;
 
-       dev_dbg(&ichan->dma_chan.dev->device, "Found channel 0x%x, irq %d\n",
-               ichan->dma_chan.chan_id, ichan->eof_irq);
+       dev_dbg(&chan->dev->device, "Found channel 0x%x, irq %d\n",
+               chan->chan_id, ichan->eof_irq);
 
        return ret;
 
-eichan:
-       free_irq(ichan->eof_irq, ichan);
 erirq:
-       ipu_irq_unmap(ichan->dma_chan.chan_id);
+       ipu_uninit_channel(idmac, ichan);
+eichan:
+       ipu_irq_unmap(chan->chan_id);
 eimap:
        return ret;
 }
@@ -1510,8 +1633,22 @@ static void idmac_free_chan_resources(struct dma_chan *chan)
        __idmac_terminate_all(chan);
 
        if (ichan->status > IPU_CHANNEL_FREE) {
+#ifdef DEBUG
+               if (chan->chan_id == IDMAC_IC_7) {
+                       if (ic_sof > 0) {
+                               free_irq(ic_sof, ichan);
+                               ipu_irq_unmap(69);
+                               ic_sof = -EINVAL;
+                       }
+                       if (ic_eof > 0) {
+                               free_irq(ic_eof, ichan);
+                               ipu_irq_unmap(70);
+                               ic_eof = -EINVAL;
+                       }
+               }
+#endif
                free_irq(ichan->eof_irq, ichan);
-               ipu_irq_unmap(ichan->dma_chan.chan_id);
+               ipu_irq_unmap(chan->chan_id);
        }
 
        ichan->status = IPU_CHANNEL_FREE;
@@ -1573,7 +1710,7 @@ static int __init ipu_idmac_init(struct ipu *ipu)
                dma_chan->device        = &idmac->dma;
                dma_chan->cookie        = 1;
                dma_chan->chan_id       = i;
-               list_add_tail(&ichan->dma_chan.device_node, &dma->channels);
+               list_add_tail(&dma_chan->device_node, &dma->channels);
        }
 
        idmac_write_icreg(ipu, 0x00000070, IDMAC_CONF);
@@ -1581,7 +1718,7 @@ static int __init ipu_idmac_init(struct ipu *ipu)
        return dma_async_device_register(&idmac->dma);
 }
 
-static void ipu_idmac_exit(struct ipu *ipu)
+static void __exit ipu_idmac_exit(struct ipu *ipu)
 {
        int i;
        struct idmac *idmac = &ipu->idmac;
@@ -1600,7 +1737,7 @@ static void ipu_idmac_exit(struct ipu *ipu)
  * IPU common probe / remove
  */
 
-static int ipu_probe(struct platform_device *pdev)
+static int __init ipu_probe(struct platform_device *pdev)
 {
        struct ipu_platform_data *pdata = pdev->dev.platform_data;
        struct resource *mem_ipu, *mem_ic;
@@ -1700,7 +1837,7 @@ err_noirq:
        return ret;
 }
 
-static int ipu_remove(struct platform_device *pdev)
+static int __exit ipu_remove(struct platform_device *pdev)
 {
        struct ipu *ipu = platform_get_drvdata(pdev);
 
@@ -1725,7 +1862,7 @@ static struct platform_driver ipu_platform_driver = {
                .name   = "ipu-core",
                .owner  = THIS_MODULE,
        },
-       .remove         = ipu_remove,
+       .remove         = __exit_p(ipu_remove),
 };
 
 static int __init ipu_init(void)
index 83f532cc767f7db111ed6f6e3cbb0640ebbb6871..dd8ebc75b667ad0089a1152fe7dd416a8ad786f6 100644 (file)
@@ -352,7 +352,7 @@ static struct irq_chip ipu_irq_chip = {
 };
 
 /* Install the IRQ handler */
-int ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev)
+int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev)
 {
        struct ipu_platform_data *pdata = dev->dev.platform_data;
        unsigned int irq, irq_base, i;
index cb7f26fb9f188ce594081069bd61c6e99c957930..ddab94f512247d600a1488a44d27a832f8ee9d3c 100644 (file)
@@ -632,7 +632,6 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
                slot->async_tx.tx_submit = mv_xor_tx_submit;
                INIT_LIST_HEAD(&slot->chain_node);
                INIT_LIST_HEAD(&slot->slot_node);
-               INIT_LIST_HEAD(&slot->async_tx.tx_list);
                hw_desc = (char *) mv_chan->device->dma_desc_pool;
                slot->async_tx.phys =
                        (dma_addr_t) &hw_desc[idx * MV_XOR_SLOT_SIZE];
index eee47fd16d79866899f7438fcdaea321a524d1f8..e5f5c5a8ba6c9bf61616a01afde3bbfe22ac25c1 100644 (file)
@@ -1,13 +1,12 @@
 #
 #      EDAC Kconfig
-#      Copyright (c) 2003 Linux Networx
+#      Copyright (c) 2008 Doug Thompson www.softwarebitmaker.com
 #      Licensed and distributed under the GPL
 #
 
 menuconfig EDAC
-       bool "EDAC - error detection and reporting (EXPERIMENTAL)"
+       bool "EDAC - error detection and reporting"
        depends on HAS_IOMEM
-       depends on EXPERIMENTAL
        depends on X86 || PPC
        help
          EDAC is designed to report errors in the core system.
@@ -40,6 +39,14 @@ config EDAC_DEBUG
          there're four debug levels (x=0,1,2,3 from low to high).
          Usually you should select 'N'.
 
+config EDAC_DEBUG_VERBOSE
+       bool "More verbose debugging"
+       depends on EDAC_DEBUG
+       help
+         This option makes debugging information more verbose.
+         Source file name and line number where debugging message
+         printed will be added to debugging message.
+
 config EDAC_MM_EDAC
        tristate "Main Memory EDAC (Error Detection And Correction) reporting"
        default y
@@ -174,4 +181,27 @@ config EDAC_CELL
          Cell Broadband Engine internal memory controller
          on platform without a hypervisor
 
+config EDAC_PPC4XX
+       tristate "PPC4xx IBM DDR2 Memory Controller"
+       depends on EDAC_MM_EDAC && 4xx
+       help
+         This enables support for EDAC on the ECC memory used
+         with the IBM DDR2 memory controller found in various
+         PowerPC 4xx embedded processors such as the 405EX[r],
+         440SP, 440SPe, 460EX, 460GT and 460SX.
+
+config EDAC_AMD8131
+       tristate "AMD8131 HyperTransport PCI-X Tunnel"
+       depends on EDAC_MM_EDAC && PCI
+       help
+         Support for error detection and correction on the
+         AMD8131 HyperTransport PCI-X Tunnel chip.
+
+config EDAC_AMD8111
+       tristate "AMD8111 HyperTransport I/O Hub"
+       depends on EDAC_MM_EDAC && PCI
+       help
+         Support for error detection and correction on the
+         AMD8111 HyperTransport I/O Hub chip.
+
 endif # EDAC
index b75196927de37901424bf58a6c009702ef7f1850..a5fdcf02f591d586a33c37bd1d9337798d99bd42 100644 (file)
@@ -34,4 +34,4 @@ obj-$(CONFIG_EDAC_PASEMI)             += pasemi_edac.o
 obj-$(CONFIG_EDAC_MPC85XX)             += mpc85xx_edac.o
 obj-$(CONFIG_EDAC_MV64X60)             += mv64x60_edac.o
 obj-$(CONFIG_EDAC_CELL)                        += cell_edac.o
-
+obj-$(CONFIG_EDAC_PPC4XX)              += ppc4xx_edac.o
diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c
new file mode 100644 (file)
index 0000000..6146921
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This 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
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/edac.h>
+#include <linux/pci_ids.h>
+#include <asm/io.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "amd8111_edac.h"
+
+#define AMD8111_EDAC_REVISION  " Ver: 1.0.0 " __DATE__
+#define AMD8111_EDAC_MOD_STR   "amd8111_edac"
+
+#define PCI_DEVICE_ID_AMD_8111_PCI     0x7460
+static int edac_dev_idx;
+
+enum amd8111_edac_devs {
+       LPC_BRIDGE = 0,
+};
+
+enum amd8111_edac_pcis {
+       PCI_BRIDGE = 0,
+};
+
+/* Wrapper functions for accessing PCI configuration space */
+static int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
+{
+       int ret;
+
+       ret = pci_read_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Read Error at 0x%x\n", reg);
+
+       return ret;
+}
+
+static void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8)
+{
+       int ret;
+
+       ret = pci_read_config_byte(dev, reg, val8);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Read Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
+{
+       int ret;
+
+       ret = pci_write_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Write Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8)
+{
+       int ret;
+
+       ret = pci_write_config_byte(dev, reg, val8);
+       if (ret != 0)
+               printk(KERN_ERR AMD8111_EDAC_MOD_STR
+                       " PCI Access Write Error at 0x%x\n", reg);
+}
+
+/*
+ * device-specific methods for amd8111 PCI Bridge Controller
+ *
+ * Error Reporting and Handling for amd8111 chipset could be found
+ * in its datasheet 3.1.2 section, P37
+ */
+static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)
+{
+       u32 val32;
+       struct pci_dev *dev = pci_info->dev;
+
+       /* First clear error detection flags on the host interface */
+
+       /* Clear SSE/SMA/STA flags in the global status register*/
+       edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+       if (val32 & PCI_STSCMD_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+       /* Clear CRC and Link Fail flags in HT Link Control reg */
+       edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+       if (val32 & HT_LINK_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+       /* Second clear all fault on the secondary interface */
+
+       /* Clear error flags in the memory-base limit reg. */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+       /* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */
+       edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+       if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK)
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+
+       /* Last enable error detections */
+       if (edac_op_state == EDAC_OPSTATE_POLL) {
+               /* Enable System Error reporting in global status register */
+               edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+               val32 |= PCI_STSCMD_SERREN;
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+               /* Enable CRC Sync flood packets to HyperTransport Link */
+               edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+               val32 |= HT_LINK_CRCFEN;
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+               /* Enable SSE reporting etc in Interrupt control reg */
+               edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+               val32 |= PCI_INTBRG_CTRL_POLL_MASK;
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+       }
+}
+
+static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info)
+{
+       u32 val32;
+       struct pci_dev *dev = pci_info->dev;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL) {
+               /* Disable System Error reporting */
+               edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+               val32 &= ~PCI_STSCMD_SERREN;
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+               /* Disable CRC flood packets */
+               edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+               val32 &= ~HT_LINK_CRCFEN;
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+               /* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */
+               edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+               val32 &= ~PCI_INTBRG_CTRL_POLL_MASK;
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+       }
+}
+
+static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev)
+{
+       struct amd8111_pci_info *pci_info = edac_dev->pvt_info;
+       struct pci_dev *dev = pci_info->dev;
+       u32 val32;
+
+       /* Check out PCI Bridge Status and Command Register */
+       edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+       if (val32 & PCI_STSCMD_CLEAR_MASK) {
+               printk(KERN_INFO "Error(s) in PCI bridge status and command"
+                       "register on device %s\n", pci_info->ctl_name);
+               printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n",
+                       (val32 & PCI_STSCMD_SSE) != 0,
+                       (val32 & PCI_STSCMD_RMA) != 0,
+                       (val32 & PCI_STSCMD_RTA) != 0);
+
+               val32 |= PCI_STSCMD_CLEAR_MASK;
+               edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check out HyperTransport Link Control Register */
+       edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+       if (val32 & HT_LINK_LKFAIL) {
+               printk(KERN_INFO "Error(s) in hypertransport link control"
+                       "register on device %s\n", pci_info->ctl_name);
+               printk(KERN_INFO "LKFAIL: %d\n",
+                       (val32 & HT_LINK_LKFAIL) != 0);
+
+               val32 |= HT_LINK_LKFAIL;
+               edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check out PCI Interrupt and Bridge Control Register */
+       edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+       if (val32 & PCI_INTBRG_CTRL_DTSTAT) {
+               printk(KERN_INFO "Error(s) in PCI interrupt and bridge control"
+                       "register on device %s\n", pci_info->ctl_name);
+               printk(KERN_INFO "DTSTAT: %d\n",
+                       (val32 & PCI_INTBRG_CTRL_DTSTAT) != 0);
+
+               val32 |= PCI_INTBRG_CTRL_DTSTAT;
+               edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check out PCI Bridge Memory Base-Limit Register */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_CLEAR_MASK) {
+               printk(KERN_INFO
+                       "Error(s) in mem limit register on %s device\n",
+                       pci_info->ctl_name);
+               printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
+                       "RTA: %d, STA: %d, MDPE: %d\n",
+                       (val32 & MEM_LIMIT_DPE)  != 0,
+                       (val32 & MEM_LIMIT_RSE)  != 0,
+                       (val32 & MEM_LIMIT_RMA)  != 0,
+                       (val32 & MEM_LIMIT_RTA)  != 0,
+                       (val32 & MEM_LIMIT_STA)  != 0,
+                       (val32 & MEM_LIMIT_MDPE) != 0);
+
+               val32 |= MEM_LIMIT_CLEAR_MASK;
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+}
+
+static struct resource *legacy_io_res;
+static int at_compat_reg_broken;
+#define LEGACY_NR_PORTS        1
+
+/* device-specific methods for amd8111 LPC Bridge device */
+static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info)
+{
+       u8 val8;
+       struct pci_dev *dev = dev_info->dev;
+
+       /* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */
+       legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS,
+                                       AMD8111_EDAC_MOD_STR);
+       if (!legacy_io_res)
+               printk(KERN_INFO "%s: failed to request legacy I/O region "
+                       "start %d, len %d\n", __func__,
+                       REG_AT_COMPAT, LEGACY_NR_PORTS);
+       else {
+               val8 = __do_inb(REG_AT_COMPAT);
+               if (val8 == 0xff) { /* buggy port */
+                       printk(KERN_INFO "%s: port %d is buggy, not supported"
+                               " by hardware?\n", __func__, REG_AT_COMPAT);
+                       at_compat_reg_broken = 1;
+                       release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
+                       legacy_io_res = NULL;
+               } else {
+                       u8 out8 = 0;
+                       if (val8 & AT_COMPAT_SERR)
+                               out8 = AT_COMPAT_CLRSERR;
+                       if (val8 & AT_COMPAT_IOCHK)
+                               out8 |= AT_COMPAT_CLRIOCHK;
+                       if (out8 > 0)
+                               __do_outb(out8, REG_AT_COMPAT);
+               }
+       }
+
+       /* Second clear error flags on LPC bridge */
+       edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+       if (val8 & IO_CTRL_1_CLEAR_MASK)
+               edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+}
+
+static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info)
+{
+       if (legacy_io_res)
+               release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
+}
+
+static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev)
+{
+       struct amd8111_dev_info *dev_info = edac_dev->pvt_info;
+       struct pci_dev *dev = dev_info->dev;
+       u8 val8;
+
+       edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+       if (val8 & IO_CTRL_1_CLEAR_MASK) {
+               printk(KERN_INFO
+                       "Error(s) in IO control register on %s device\n",
+                       dev_info->ctl_name);
+               printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n",
+                       (val8 & IO_CTRL_1_LPC_ERR) != 0,
+                       (val8 & IO_CTRL_1_PW2LPC) != 0);
+
+               val8 |= IO_CTRL_1_CLEAR_MASK;
+               edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+
+               edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+       }
+
+       if (at_compat_reg_broken == 0) {
+               u8 out8 = 0;
+               val8 = __do_inb(REG_AT_COMPAT);
+               if (val8 & AT_COMPAT_SERR)
+                       out8 = AT_COMPAT_CLRSERR;
+               if (val8 & AT_COMPAT_IOCHK)
+                       out8 |= AT_COMPAT_CLRIOCHK;
+               if (out8 > 0) {
+                       __do_outb(out8, REG_AT_COMPAT);
+                       edac_device_handle_ue(edac_dev, 0, 0,
+                                               edac_dev->ctl_name);
+               }
+       }
+}
+
+/* General devices represented by edac_device_ctl_info */
+static struct amd8111_dev_info amd8111_devices[] = {
+       [LPC_BRIDGE] = {
+               .err_dev = PCI_DEVICE_ID_AMD_8111_LPC,
+               .ctl_name = "lpc",
+               .init = amd8111_lpc_bridge_init,
+               .exit = amd8111_lpc_bridge_exit,
+               .check = amd8111_lpc_bridge_check,
+       },
+       {0},
+};
+
+/* PCI controllers represented by edac_pci_ctl_info */
+static struct amd8111_pci_info amd8111_pcis[] = {
+       [PCI_BRIDGE] = {
+               .err_dev = PCI_DEVICE_ID_AMD_8111_PCI,
+               .ctl_name = "AMD8111_PCI_Controller",
+               .init = amd8111_pci_bridge_init,
+               .exit = amd8111_pci_bridge_exit,
+               .check = amd8111_pci_bridge_check,
+       },
+       {0},
+};
+
+static int amd8111_dev_probe(struct pci_dev *dev,
+                               const struct pci_device_id *id)
+{
+       struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
+
+       dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                       dev_info->err_dev, NULL);
+
+       if (!dev_info->dev) {
+               printk(KERN_ERR "EDAC device not found:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, dev_info->err_dev,
+                       dev_info->ctl_name);
+               return -ENODEV;
+       }
+
+       if (pci_enable_device(dev_info->dev)) {
+               pci_dev_put(dev_info->dev);
+               printk(KERN_ERR "failed to enable:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, dev_info->err_dev,
+                       dev_info->ctl_name);
+               return -ENODEV;
+       }
+
+       /*
+        * we do not allocate extra private structure for
+        * edac_device_ctl_info, but make use of existing
+        * one instead.
+       */
+       dev_info->edac_idx = edac_dev_idx++;
+       dev_info->edac_dev =
+               edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
+                                          NULL, 0, 0,
+                                          NULL, 0, dev_info->edac_idx);
+       if (!dev_info->edac_dev)
+               return -ENOMEM;
+
+       dev_info->edac_dev->pvt_info = dev_info;
+       dev_info->edac_dev->dev = &dev_info->dev->dev;
+       dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
+       dev_info->edac_dev->ctl_name = dev_info->ctl_name;
+       dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               dev_info->edac_dev->edac_check = dev_info->check;
+
+       if (dev_info->init)
+               dev_info->init(dev_info);
+
+       if (edac_device_add_device(dev_info->edac_dev) > 0) {
+               printk(KERN_ERR "failed to add edac_dev for %s\n",
+                       dev_info->ctl_name);
+               edac_device_free_ctl_info(dev_info->edac_dev);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "added one edac_dev on AMD8111 "
+               "vendor %x, device %x, name %s\n",
+               PCI_VENDOR_ID_AMD, dev_info->err_dev,
+               dev_info->ctl_name);
+
+       return 0;
+}
+
+static void amd8111_dev_remove(struct pci_dev *dev)
+{
+       struct amd8111_dev_info *dev_info;
+
+       for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++)
+               if (dev_info->dev->device == dev->device)
+                       break;
+
+       if (!dev_info->err_dev) /* should never happen */
+               return;
+
+       if (dev_info->edac_dev) {
+               edac_device_del_device(dev_info->edac_dev->dev);
+               edac_device_free_ctl_info(dev_info->edac_dev);
+       }
+
+       if (dev_info->exit)
+               dev_info->exit(dev_info);
+
+       pci_dev_put(dev_info->dev);
+}
+
+static int amd8111_pci_probe(struct pci_dev *dev,
+                               const struct pci_device_id *id)
+{
+       struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
+
+       pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                       pci_info->err_dev, NULL);
+
+       if (!pci_info->dev) {
+               printk(KERN_ERR "EDAC device not found:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, pci_info->err_dev,
+                       pci_info->ctl_name);
+               return -ENODEV;
+       }
+
+       if (pci_enable_device(pci_info->dev)) {
+               pci_dev_put(pci_info->dev);
+               printk(KERN_ERR "failed to enable:"
+                       "vendor %x, device %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, pci_info->err_dev,
+                       pci_info->ctl_name);
+               return -ENODEV;
+       }
+
+       /*
+        * we do not allocate extra private structure for
+        * edac_pci_ctl_info, but make use of existing
+        * one instead.
+       */
+       pci_info->edac_idx = edac_pci_alloc_index();
+       pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
+       if (!pci_info->edac_dev)
+               return -ENOMEM;
+
+       pci_info->edac_dev->pvt_info = pci_info;
+       pci_info->edac_dev->dev = &pci_info->dev->dev;
+       pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
+       pci_info->edac_dev->ctl_name = pci_info->ctl_name;
+       pci_info->edac_dev->dev_name = pci_info->dev->dev.bus_id;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               pci_info->edac_dev->edac_check = pci_info->check;
+
+       if (pci_info->init)
+               pci_info->init(pci_info);
+
+       if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
+               printk(KERN_ERR "failed to add edac_pci for %s\n",
+                       pci_info->ctl_name);
+               edac_pci_free_ctl_info(pci_info->edac_dev);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "added one edac_pci on AMD8111 "
+               "vendor %x, device %x, name %s\n",
+               PCI_VENDOR_ID_AMD, pci_info->err_dev,
+               pci_info->ctl_name);
+
+       return 0;
+}
+
+static void amd8111_pci_remove(struct pci_dev *dev)
+{
+       struct amd8111_pci_info *pci_info;
+
+       for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++)
+               if (pci_info->dev->device == dev->device)
+                       break;
+
+       if (!pci_info->err_dev) /* should never happen */
+               return;
+
+       if (pci_info->edac_dev) {
+               edac_pci_del_device(pci_info->edac_dev->dev);
+               edac_pci_free_ctl_info(pci_info->edac_dev);
+       }
+
+       if (pci_info->exit)
+               pci_info->exit(pci_info);
+
+       pci_dev_put(pci_info->dev);
+}
+
+/* PCI Device ID talbe for general EDAC device */
+static const struct pci_device_id amd8111_edac_dev_tbl[] = {
+       {
+       PCI_VEND_DEV(AMD, 8111_LPC),
+       .subvendor = PCI_ANY_ID,
+       .subdevice = PCI_ANY_ID,
+       .class = 0,
+       .class_mask = 0,
+       .driver_data = LPC_BRIDGE,
+       },
+       {
+       0,
+       }                       /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl);
+
+static struct pci_driver amd8111_edac_dev_driver = {
+       .name = "AMD8111_EDAC_DEV",
+       .probe = amd8111_dev_probe,
+       .remove = amd8111_dev_remove,
+       .id_table = amd8111_edac_dev_tbl,
+};
+
+/* PCI Device ID table for EDAC PCI controller */
+static const struct pci_device_id amd8111_edac_pci_tbl[] = {
+       {
+       PCI_VEND_DEV(AMD, 8111_PCI),
+       .subvendor = PCI_ANY_ID,
+       .subdevice = PCI_ANY_ID,
+       .class = 0,
+       .class_mask = 0,
+       .driver_data = PCI_BRIDGE,
+       },
+       {
+       0,
+       }                       /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl);
+
+static struct pci_driver amd8111_edac_pci_driver = {
+       .name = "AMD8111_EDAC_PCI",
+       .probe = amd8111_pci_probe,
+       .remove = amd8111_pci_remove,
+       .id_table = amd8111_edac_pci_tbl,
+};
+
+static int __init amd8111_edac_init(void)
+{
+       int val;
+
+       printk(KERN_INFO "AMD8111 EDAC driver " AMD8111_EDAC_REVISION "\n");
+       printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
+
+       /* Only POLL mode supported so far */
+       edac_op_state = EDAC_OPSTATE_POLL;
+
+       val = pci_register_driver(&amd8111_edac_dev_driver);
+       val |= pci_register_driver(&amd8111_edac_pci_driver);
+
+       return val;
+}
+
+static void __exit amd8111_edac_exit(void)
+{
+       pci_unregister_driver(&amd8111_edac_pci_driver);
+       pci_unregister_driver(&amd8111_edac_dev_driver);
+}
+
+
+module_init(amd8111_edac_init);
+module_exit(amd8111_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n");
+MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module");
diff --git a/drivers/edac/amd8111_edac.h b/drivers/edac/amd8111_edac.h
new file mode 100644 (file)
index 0000000..3579433
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * amd8111_edac.h, EDAC defs for AMD8111 hypertransport chip
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This 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
+ */
+
+#ifndef _AMD8111_EDAC_H_
+#define _AMD8111_EDAC_H_
+
+/************************************************************
+ *     PCI Bridge Status and Command Register, DevA:0x04
+ ************************************************************/
+#define REG_PCI_STSCMD 0x04
+enum pci_stscmd_bits {
+       PCI_STSCMD_SSE          = BIT(30),
+       PCI_STSCMD_RMA          = BIT(29),
+       PCI_STSCMD_RTA          = BIT(28),
+       PCI_STSCMD_SERREN       = BIT(8),
+       PCI_STSCMD_CLEAR_MASK   = (PCI_STSCMD_SSE |
+                                  PCI_STSCMD_RMA |
+                                  PCI_STSCMD_RTA)
+};
+
+/************************************************************
+ *     PCI Bridge Memory Base-Limit Register, DevA:0x1c
+ ************************************************************/
+#define REG_MEM_LIM     0x1c
+enum mem_limit_bits {
+       MEM_LIMIT_DPE   = BIT(31),
+       MEM_LIMIT_RSE   = BIT(30),
+       MEM_LIMIT_RMA   = BIT(29),
+       MEM_LIMIT_RTA   = BIT(28),
+       MEM_LIMIT_STA   = BIT(27),
+       MEM_LIMIT_MDPE  = BIT(24),
+       MEM_LIMIT_CLEAR_MASK  = (MEM_LIMIT_DPE |
+                                MEM_LIMIT_RSE |
+                                MEM_LIMIT_RMA |
+                                MEM_LIMIT_RTA |
+                                MEM_LIMIT_STA |
+                                MEM_LIMIT_MDPE)
+};
+
+/************************************************************
+ *     HyperTransport Link Control Register, DevA:0xc4
+ ************************************************************/
+#define REG_HT_LINK    0xc4
+enum ht_link_bits {
+       HT_LINK_LKFAIL  = BIT(4),
+       HT_LINK_CRCFEN  = BIT(1),
+       HT_LINK_CLEAR_MASK = (HT_LINK_LKFAIL)
+};
+
+/************************************************************
+ *     PCI Bridge Interrupt and Bridge Control, DevA:0x3c
+ ************************************************************/
+#define REG_PCI_INTBRG_CTRL    0x3c
+enum pci_intbrg_ctrl_bits {
+       PCI_INTBRG_CTRL_DTSERREN        = BIT(27),
+       PCI_INTBRG_CTRL_DTSTAT          = BIT(26),
+       PCI_INTBRG_CTRL_MARSP           = BIT(21),
+       PCI_INTBRG_CTRL_SERREN          = BIT(17),
+       PCI_INTBRG_CTRL_PEREN           = BIT(16),
+       PCI_INTBRG_CTRL_CLEAR_MASK      = (PCI_INTBRG_CTRL_DTSTAT),
+       PCI_INTBRG_CTRL_POLL_MASK       = (PCI_INTBRG_CTRL_DTSERREN |
+                                          PCI_INTBRG_CTRL_MARSP |
+                                          PCI_INTBRG_CTRL_SERREN)
+};
+
+/************************************************************
+ *             I/O Control 1 Register, DevB:0x40
+ ************************************************************/
+#define REG_IO_CTRL_1 0x40
+enum io_ctrl_1_bits {
+       IO_CTRL_1_NMIONERR      = BIT(7),
+       IO_CTRL_1_LPC_ERR       = BIT(6),
+       IO_CTRL_1_PW2LPC        = BIT(1),
+       IO_CTRL_1_CLEAR_MASK    = (IO_CTRL_1_LPC_ERR | IO_CTRL_1_PW2LPC)
+};
+
+/************************************************************
+ *             Legacy I/O Space Registers
+ ************************************************************/
+#define REG_AT_COMPAT 0x61
+enum at_compat_bits {
+       AT_COMPAT_SERR          = BIT(7),
+       AT_COMPAT_IOCHK         = BIT(6),
+       AT_COMPAT_CLRIOCHK      = BIT(3),
+       AT_COMPAT_CLRSERR       = BIT(2),
+};
+
+struct amd8111_dev_info {
+       u16 err_dev;    /* PCI Device ID */
+       struct pci_dev *dev;
+       int edac_idx;   /* device index */
+       char *ctl_name;
+       struct edac_device_ctl_info *edac_dev;
+       void (*init)(struct amd8111_dev_info *dev_info);
+       void (*exit)(struct amd8111_dev_info *dev_info);
+       void (*check)(struct edac_device_ctl_info *edac_dev);
+};
+
+struct amd8111_pci_info {
+       u16 err_dev;    /* PCI Device ID */
+       struct pci_dev *dev;
+       int edac_idx;   /* pci index */
+       const char *ctl_name;
+       struct edac_pci_ctl_info *edac_dev;
+       void (*init)(struct amd8111_pci_info *dev_info);
+       void (*exit)(struct amd8111_pci_info *dev_info);
+       void (*check)(struct edac_pci_ctl_info *edac_dev);
+};
+
+#endif /* _AMD8111_EDAC_H_ */
diff --git a/drivers/edac/amd8131_edac.c b/drivers/edac/amd8131_edac.c
new file mode 100644 (file)
index 0000000..c083b31
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * amd8131_edac.c, AMD8131 hypertransport chip EDAC kernel module
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This 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
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/edac.h>
+#include <linux/pci_ids.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "amd8131_edac.h"
+
+#define AMD8131_EDAC_REVISION  " Ver: 1.0.0 " __DATE__
+#define AMD8131_EDAC_MOD_STR   "amd8131_edac"
+
+/* Wrapper functions for accessing PCI configuration space */
+static void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
+{
+       int ret;
+
+       ret = pci_read_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8131_EDAC_MOD_STR
+                       " PCI Access Read Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
+{
+       int ret;
+
+       ret = pci_write_config_dword(dev, reg, val32);
+       if (ret != 0)
+               printk(KERN_ERR AMD8131_EDAC_MOD_STR
+                       " PCI Access Write Error at 0x%x\n", reg);
+}
+
+static char * const bridge_str[] = {
+       [NORTH_A] = "NORTH A",
+       [NORTH_B] = "NORTH B",
+       [SOUTH_A] = "SOUTH A",
+       [SOUTH_B] = "SOUTH B",
+       [NO_BRIDGE] = "NO BRIDGE",
+};
+
+/* Support up to two AMD8131 chipsets on a platform */
+static struct amd8131_dev_info amd8131_devices[] = {
+       {
+       .inst = NORTH_A,
+       .devfn = DEVFN_PCIX_BRIDGE_NORTH_A,
+       .ctl_name = "AMD8131_PCIX_NORTH_A",
+       },
+       {
+       .inst = NORTH_B,
+       .devfn = DEVFN_PCIX_BRIDGE_NORTH_B,
+       .ctl_name = "AMD8131_PCIX_NORTH_B",
+       },
+       {
+       .inst = SOUTH_A,
+       .devfn = DEVFN_PCIX_BRIDGE_SOUTH_A,
+       .ctl_name = "AMD8131_PCIX_SOUTH_A",
+       },
+       {
+       .inst = SOUTH_B,
+       .devfn = DEVFN_PCIX_BRIDGE_SOUTH_B,
+       .ctl_name = "AMD8131_PCIX_SOUTH_B",
+       },
+       {.inst = NO_BRIDGE,},
+};
+
+static void amd8131_pcix_init(struct amd8131_dev_info *dev_info)
+{
+       u32 val32;
+       struct pci_dev *dev = dev_info->dev;
+
+       /* First clear error detection flags */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_MASK)
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+       /* Clear Discard Timer Timedout flag */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       if (val32 & INT_CTLR_DTS)
+               edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+       /* Clear CRC Error flag on link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       if (val32 & LNK_CTRL_CRCERR_A)
+               edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+       /* Clear CRC Error flag on link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       if (val32 & LNK_CTRL_CRCERR_B)
+               edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+       /*
+        * Then enable all error detections.
+        *
+        * Setup Discard Timer Sync Flood Enable,
+        * System Error Enable and Parity Error Enable.
+        */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       val32 |= INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE;
+       edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+       /* Enable overall SERR Error detection */
+       edac_pci_read_dword(dev, REG_STS_CMD, &val32);
+       val32 |= STS_CMD_SERREN;
+       edac_pci_write_dword(dev, REG_STS_CMD, val32);
+
+       /* Setup CRC Flood Enable for link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       val32 |= LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+       /* Setup CRC Flood Enable for link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       val32 |= LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+}
+
+static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info)
+{
+       u32 val32;
+       struct pci_dev *dev = dev_info->dev;
+
+       /* Disable SERR, PERR and DTSE Error detection */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       val32 &= ~(INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE);
+       edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+       /* Disable overall System Error detection */
+       edac_pci_read_dword(dev, REG_STS_CMD, &val32);
+       val32 &= ~STS_CMD_SERREN;
+       edac_pci_write_dword(dev, REG_STS_CMD, val32);
+
+       /* Disable CRC Sync Flood on link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       val32 &= ~LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+       /* Disable CRC Sync Flood on link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       val32 &= ~LNK_CTRL_CRCFEN;
+       edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+}
+
+static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev)
+{
+       struct amd8131_dev_info *dev_info = edac_dev->pvt_info;
+       struct pci_dev *dev = dev_info->dev;
+       u32 val32;
+
+       /* Check PCI-X Bridge Memory Base-Limit Register for errors */
+       edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+       if (val32 & MEM_LIMIT_MASK) {
+               printk(KERN_INFO "Error(s) in mem limit register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
+                       "RTA: %d, STA: %d, MDPE: %d\n",
+                       val32 & MEM_LIMIT_DPE,
+                       val32 & MEM_LIMIT_RSE,
+                       val32 & MEM_LIMIT_RMA,
+                       val32 & MEM_LIMIT_RTA,
+                       val32 & MEM_LIMIT_STA,
+                       val32 & MEM_LIMIT_MDPE);
+
+               val32 |= MEM_LIMIT_MASK;
+               edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check if Discard Timer timed out */
+       edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+       if (val32 & INT_CTLR_DTS) {
+               printk(KERN_INFO "Error(s) in interrupt and control register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "DTS: %d\n", val32 & INT_CTLR_DTS);
+
+               val32 |= INT_CTLR_DTS;
+               edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check if CRC error happens on link side A */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+       if (val32 & LNK_CTRL_CRCERR_A) {
+               printk(KERN_INFO "Error(s) in link conf and control register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_A);
+
+               val32 |= LNK_CTRL_CRCERR_A;
+               edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+
+       /* Check if CRC error happens on link side B */
+       edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+       if (val32 & LNK_CTRL_CRCERR_B) {
+               printk(KERN_INFO "Error(s) in link conf and control register "
+                       "on %s bridge\n", dev_info->ctl_name);
+               printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_B);
+
+               val32 |= LNK_CTRL_CRCERR_B;
+               edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+               edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+       }
+}
+
+static struct amd8131_info amd8131_chipset = {
+       .err_dev = PCI_DEVICE_ID_AMD_8131_APIC,
+       .devices = amd8131_devices,
+       .init = amd8131_pcix_init,
+       .exit = amd8131_pcix_exit,
+       .check = amd8131_pcix_check,
+};
+
+/*
+ * There are 4 PCIX Bridges on ATCA-6101 that share the same PCI Device ID,
+ * so amd8131_probe() would be called by kernel 4 times, with different
+ * address of pci_dev for each of them each time.
+ */
+static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct amd8131_dev_info *dev_info;
+
+       for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
+               dev_info++)
+               if (dev_info->devfn == dev->devfn)
+                       break;
+
+       if (dev_info->inst == NO_BRIDGE) /* should never happen */
+               return -ENODEV;
+
+       /*
+        * We can't call pci_get_device() as we are used to do because
+        * there are 4 of them but pci_dev_get() instead.
+        */
+       dev_info->dev = pci_dev_get(dev);
+
+       if (pci_enable_device(dev_info->dev)) {
+               pci_dev_put(dev_info->dev);
+               printk(KERN_ERR "failed to enable:"
+                       "vendor %x, device %x, devfn %x, name %s\n",
+                       PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
+                       dev_info->devfn, dev_info->ctl_name);
+               return -ENODEV;
+       }
+
+       /*
+        * we do not allocate extra private structure for
+        * edac_pci_ctl_info, but make use of existing
+        * one instead.
+        */
+       dev_info->edac_idx = edac_pci_alloc_index();
+       dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name);
+       if (!dev_info->edac_dev)
+               return -ENOMEM;
+
+       dev_info->edac_dev->pvt_info = dev_info;
+       dev_info->edac_dev->dev = &dev_info->dev->dev;
+       dev_info->edac_dev->mod_name = AMD8131_EDAC_MOD_STR;
+       dev_info->edac_dev->ctl_name = dev_info->ctl_name;
+       dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               dev_info->edac_dev->edac_check = amd8131_chipset.check;
+
+       if (amd8131_chipset.init)
+               amd8131_chipset.init(dev_info);
+
+       if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) {
+               printk(KERN_ERR "failed edac_pci_add_device() for %s\n",
+                       dev_info->ctl_name);
+               edac_pci_free_ctl_info(dev_info->edac_dev);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "added one device on AMD8131 "
+               "vendor %x, device %x, devfn %x, name %s\n",
+               PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
+               dev_info->devfn, dev_info->ctl_name);
+
+       return 0;
+}
+
+static void amd8131_remove(struct pci_dev *dev)
+{
+       struct amd8131_dev_info *dev_info;
+
+       for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
+               dev_info++)
+               if (dev_info->devfn == dev->devfn)
+                       break;
+
+       if (dev_info->inst == NO_BRIDGE) /* should never happen */
+               return;
+
+       if (dev_info->edac_dev) {
+               edac_pci_del_device(dev_info->edac_dev->dev);
+               edac_pci_free_ctl_info(dev_info->edac_dev);
+       }
+
+       if (amd8131_chipset.exit)
+               amd8131_chipset.exit(dev_info);
+
+       pci_dev_put(dev_info->dev);
+}
+
+static const struct pci_device_id amd8131_edac_pci_tbl[] = {
+       {
+       PCI_VEND_DEV(AMD, 8131_BRIDGE),
+       .subvendor = PCI_ANY_ID,
+       .subdevice = PCI_ANY_ID,
+       .class = 0,
+       .class_mask = 0,
+       .driver_data = 0,
+       },
+       {
+       0,
+       }                       /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl);
+
+static struct pci_driver amd8131_edac_driver = {
+       .name = AMD8131_EDAC_MOD_STR,
+       .probe = amd8131_probe,
+       .remove = amd8131_remove,
+       .id_table = amd8131_edac_pci_tbl,
+};
+
+static int __init amd8131_edac_init(void)
+{
+       printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n");
+       printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
+
+       /* Only POLL mode supported so far */
+       edac_op_state = EDAC_OPSTATE_POLL;
+
+       return pci_register_driver(&amd8131_edac_driver);
+}
+
+static void __exit amd8131_edac_exit(void)
+{
+       pci_unregister_driver(&amd8131_edac_driver);
+}
+
+module_init(amd8131_edac_init);
+module_exit(amd8131_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n");
+MODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module");
diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h
new file mode 100644 (file)
index 0000000..60e0d1c
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * amd8131_edac.h, EDAC defs for AMD8131 hypertransport chip
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:    Cao Qingtao <qingtao.cao@windriver.com>
+ *             Benjamin Walsh <benjamin.walsh@windriver.com>
+ *             Hu Yongqi <yongqi.hu@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This 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
+ */
+
+#ifndef _AMD8131_EDAC_H_
+#define _AMD8131_EDAC_H_
+
+#define DEVFN_PCIX_BRIDGE_NORTH_A      8
+#define DEVFN_PCIX_BRIDGE_NORTH_B      16
+#define DEVFN_PCIX_BRIDGE_SOUTH_A      24
+#define DEVFN_PCIX_BRIDGE_SOUTH_B      32
+
+/************************************************************
+ *     PCI-X Bridge Status and Command Register, DevA:0x04
+ ************************************************************/
+#define REG_STS_CMD    0x04
+enum sts_cmd_bits {
+       STS_CMD_SSE     = BIT(30),
+       STS_CMD_SERREN  = BIT(8)
+};
+
+/************************************************************
+ *     PCI-X Bridge Interrupt and Bridge Control Register,
+ ************************************************************/
+#define REG_INT_CTLR   0x3c
+enum int_ctlr_bits {
+       INT_CTLR_DTSE   = BIT(27),
+       INT_CTLR_DTS    = BIT(26),
+       INT_CTLR_SERR   = BIT(17),
+       INT_CTLR_PERR   = BIT(16)
+};
+
+/************************************************************
+ *     PCI-X Bridge Memory Base-Limit Register, DevA:0x1C
+ ************************************************************/
+#define REG_MEM_LIM    0x1c
+enum mem_limit_bits {
+       MEM_LIMIT_DPE   = BIT(31),
+       MEM_LIMIT_RSE   = BIT(30),
+       MEM_LIMIT_RMA   = BIT(29),
+       MEM_LIMIT_RTA   = BIT(28),
+       MEM_LIMIT_STA   = BIT(27),
+       MEM_LIMIT_MDPE  = BIT(24),
+       MEM_LIMIT_MASK  = MEM_LIMIT_DPE|MEM_LIMIT_RSE|MEM_LIMIT_RMA|
+                               MEM_LIMIT_RTA|MEM_LIMIT_STA|MEM_LIMIT_MDPE
+};
+
+/************************************************************
+ *     Link Configuration And Control Register, side A
+ ************************************************************/
+#define REG_LNK_CTRL_A 0xc4
+
+/************************************************************
+ *     Link Configuration And Control Register, side B
+ ************************************************************/
+#define REG_LNK_CTRL_B  0xc8
+
+enum lnk_ctrl_bits {
+       LNK_CTRL_CRCERR_A       = BIT(9),
+       LNK_CTRL_CRCERR_B       = BIT(8),
+       LNK_CTRL_CRCFEN         = BIT(1)
+};
+
+enum pcix_bridge_inst {
+       NORTH_A = 0,
+       NORTH_B = 1,
+       SOUTH_A = 2,
+       SOUTH_B = 3,
+       NO_BRIDGE = 4
+};
+
+struct amd8131_dev_info {
+       int devfn;
+       enum pcix_bridge_inst inst;
+       struct pci_dev *dev;
+       int edac_idx;   /* pci device index */
+       char *ctl_name;
+       struct edac_pci_ctl_info *edac_dev;
+};
+
+/*
+ * AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC
+ * Controler, and ATCA-6101 has two AMD8131 chipsets, so there are
+ * four PCIX Bridges on ATCA-6101 altogether.
+ *
+ * These PCIX Bridges share the same PCI Device ID and are all of
+ * Function Zero, they could be discrimated by their pci_dev->devfn.
+ * They share the same set of init/check/exit methods, and their
+ * private structures are collected in the devices[] array.
+ */
+struct amd8131_info {
+       u16 err_dev;    /* PCI Device ID for AMD8131 APIC*/
+       struct amd8131_dev_info *devices;
+       void (*init)(struct amd8131_dev_info *dev_info);
+       void (*exit)(struct amd8131_dev_info *dev_info);
+       void (*check)(struct edac_pci_ctl_info *edac_dev);
+};
+
+#endif /* _AMD8131_EDAC_H_ */
+
index 4b55ec607a88f622bf6e81e24aad7812a401d76a..28f2c3f959b5a3b0776c9993cf92f6bc9dcc4a96 100644 (file)
 #define edac_printk(level, prefix, fmt, arg...) \
        printk(level "EDAC " prefix ": " fmt, ##arg)
 
+#define edac_printk_verbose(level, prefix, fmt, arg...) \
+       printk(level "EDAC " prefix ": " "in %s, line at %d: " fmt,     \
+              __FILE__, __LINE__, ##arg)
+
 #define edac_mc_printk(mci, level, fmt, arg...) \
        printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
 
 #ifdef CONFIG_EDAC_DEBUG
 extern int edac_debug_level;
 
+#ifndef CONFIG_EDAC_DEBUG_VERBOSE
 #define edac_debug_printk(level, fmt, arg...)                            \
        do {                                                             \
                if (level <= edac_debug_level)                           \
                        edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \
-       } while(0)
+       } while (0)
+#else  /* CONFIG_EDAC_DEBUG_VERBOSE */
+#define edac_debug_printk(level, fmt, arg...)                            \
+       do {                                                             \
+               if (level <= edac_debug_level)                           \
+                       edac_printk_verbose(KERN_DEBUG, EDAC_DEBUG, fmt, \
+                                           ##arg);                     \
+       } while (0)
+#endif
 
 #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
 #define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
@@ -831,6 +844,7 @@ extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
 extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
                                unsigned long value);
 
+extern int edac_pci_alloc_index(void);
 extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
 extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);
 
index 5d3c8083a40ebdee27dd34fb260038fcca01ad53..5b150aea703a3fb89b8fb0af40d3f29f5dd01a58 100644 (file)
@@ -30,6 +30,7 @@
 
 static DEFINE_MUTEX(edac_pci_ctls_mutex);
 static LIST_HEAD(edac_pci_list);
+static atomic_t pci_indexes = ATOMIC_INIT(0);
 
 /*
  * edac_pci_alloc_ctl_info
@@ -317,6 +318,19 @@ void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
 }
 EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
 
+/*
+ * edac_pci_alloc_index: Allocate a unique PCI index number
+ *
+ * Return:
+ *      allocated index number
+ *
+ */
+int edac_pci_alloc_index(void)
+{
+       return atomic_inc_return(&pci_indexes) - 1;
+}
+EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
+
 /*
  * edac_pci_add_device: Insert the 'edac_dev' structure into the
  * edac_pci global list and create sysfs entries associated with
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
new file mode 100644 (file)
index 0000000..11f2172
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ *   Grant Erickson <gerickson@nuovations.com>
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/types.h>
+
+#include <asm/dcr.h>
+
+#include "edac_core.h"
+#include "ppc4xx_edac.h"
+
+/*
+ * This file implements a driver for monitoring and handling events
+ * associated with the IMB DDR2 ECC controller found in the AMCC/IBM
+ * 405EX[r], 440SP, 440SPe, 460EX, 460GT and 460SX.
+ *
+ * As realized in the 405EX[r], this controller features:
+ *
+ *   - Support for registered- and non-registered DDR1 and DDR2 memory.
+ *   - 32-bit or 16-bit memory interface with optional ECC.
+ *
+ *     o ECC support includes:
+ *
+ *       - 4-bit SEC/DED
+ *       - Aligned-nibble error detect
+ *       - Bypass mode
+ *
+ *   - Two (2) memory banks/ranks.
+ *   - Up to 1 GiB per bank/rank in 32-bit mode and up to 512 MiB per
+ *     bank/rank in 16-bit mode.
+ *
+ * As realized in the 440SP and 440SPe, this controller changes/adds:
+ *
+ *   - 64-bit or 32-bit memory interface with optional ECC.
+ *
+ *     o ECC support includes:
+ *
+ *       - 8-bit SEC/DED
+ *       - Aligned-nibble error detect
+ *       - Bypass mode
+ *
+ *   - Up to 4 GiB per bank/rank in 64-bit mode and up to 2 GiB
+ *     per bank/rank in 32-bit mode.
+ *
+ * As realized in the 460EX and 460GT, this controller changes/adds:
+ *
+ *   - 64-bit or 32-bit memory interface with optional ECC.
+ *
+ *     o ECC support includes:
+ *
+ *       - 8-bit SEC/DED
+ *       - Aligned-nibble error detect
+ *       - Bypass mode
+ *
+ *   - Four (4) memory banks/ranks.
+ *   - Up to 16 GiB per bank/rank in 64-bit mode and up to 8 GiB
+ *     per bank/rank in 32-bit mode.
+ *
+ * At present, this driver has ONLY been tested against the controller
+ * realization in the 405EX[r] on the AMCC Kilauea and Haleakala
+ * boards (256 MiB w/o ECC memory soldered onto the board) and a
+ * proprietary board based on those designs (128 MiB ECC memory, also
+ * soldered onto the board).
+ *
+ * Dynamic feature detection and handling needs to be added for the
+ * other realizations of this controller listed above.
+ *
+ * Eventually, this driver will likely be adapted to the above variant
+ * realizations of this controller as well as broken apart to handle
+ * the other known ECC-capable controllers prevalent in other 4xx
+ * processors:
+ *
+ *   - IBM SDRAM (405GP, 405CR and 405EP) "ibm,sdram-4xx"
+ *   - IBM DDR1 (440GP, 440GX, 440EP and 440GR) "ibm,sdram-4xx-ddr"
+ *   - Denali DDR1/DDR2 (440EPX and 440GRX) "denali,sdram-4xx-ddr2"
+ *
+ * For this controller, unfortunately, correctable errors report
+ * nothing more than the beat/cycle and byte/lane the correction
+ * occurred on and the check bit group that covered the error.
+ *
+ * In contrast, uncorrectable errors also report the failing address,
+ * the bus master and the transaction direction (i.e. read or write)
+ *
+ * Regardless of whether the error is a CE or a UE, we report the
+ * following pieces of information in the driver-unique message to the
+ * EDAC subsystem:
+ *
+ *   - Device tree path
+ *   - Bank(s)
+ *   - Check bit error group
+ *   - Beat(s)/lane(s)
+ */
+
+/* Preprocessor Definitions */
+
+#define EDAC_OPSTATE_INT_STR           "interrupt"
+#define EDAC_OPSTATE_POLL_STR          "polled"
+#define EDAC_OPSTATE_UNKNOWN_STR       "unknown"
+
+#define PPC4XX_EDAC_MODULE_NAME                "ppc4xx_edac"
+#define PPC4XX_EDAC_MODULE_REVISION    "v1.0.0 " __DATE__
+
+#define PPC4XX_EDAC_MESSAGE_SIZE       256
+
+/*
+ * Kernel logging without an EDAC instance
+ */
+#define ppc4xx_edac_printk(level, fmt, arg...) \
+       edac_printk(level, "PPC4xx MC", fmt, ##arg)
+
+/*
+ * Kernel logging with an EDAC instance
+ */
+#define ppc4xx_edac_mc_printk(level, mci, fmt, arg...) \
+       edac_mc_chipset_printk(mci, level, "PPC4xx", fmt, ##arg)
+
+/*
+ * Macros to convert bank configuration size enumerations into MiB and
+ * page values.
+ */
+#define SDRAM_MBCF_SZ_MiB_MIN          4
+#define SDRAM_MBCF_SZ_TO_MiB(n)                (SDRAM_MBCF_SZ_MiB_MIN \
+                                        << (SDRAM_MBCF_SZ_DECODE(n)))
+#define SDRAM_MBCF_SZ_TO_PAGES(n)      (SDRAM_MBCF_SZ_MiB_MIN \
+                                        << (20 - PAGE_SHIFT + \
+                                            SDRAM_MBCF_SZ_DECODE(n)))
+
+/*
+ * The ibm,sdram-4xx-ddr2 Device Control Registers (DCRs) are
+ * indirectly acccessed and have a base and length defined by the
+ * device tree. The base can be anything; however, we expect the
+ * length to be precisely two registers, the first for the address
+ * window and the second for the data window.
+ */
+#define SDRAM_DCR_RESOURCE_LEN         2
+#define SDRAM_DCR_ADDR_OFFSET          0
+#define SDRAM_DCR_DATA_OFFSET          1
+
+/*
+ * Device tree interrupt indices
+ */
+#define INTMAP_ECCDED_INDEX            0       /* Double-bit Error Detect */
+#define INTMAP_ECCSEC_INDEX            1       /* Single-bit Error Correct */
+
+/* Type Definitions */
+
+/*
+ * PPC4xx SDRAM memory controller private instance data
+ */
+struct ppc4xx_edac_pdata {
+       dcr_host_t dcr_host;    /* Indirect DCR address/data window mapping */
+       struct {
+               int sec;        /* Single-bit correctable error IRQ assigned */
+               int ded;        /* Double-bit detectable error IRQ assigned */
+       } irqs;
+};
+
+/*
+ * Various status data gathered and manipulated when checking and
+ * reporting ECC status.
+ */
+struct ppc4xx_ecc_status {
+       u32 ecces;
+       u32 besr;
+       u32 bearh;
+       u32 bearl;
+       u32 wmirq;
+};
+
+/* Function Prototypes */
+
+static int ppc4xx_edac_probe(struct of_device *device,
+                            const struct of_device_id *device_id);
+static int ppc4xx_edac_remove(struct of_device *device);
+
+/* Global Variables */
+
+/*
+ * Device tree node type and compatible tuples this driver can match
+ * on.
+ */
+static struct of_device_id ppc4xx_edac_match[] = {
+       {
+               .compatible     = "ibm,sdram-4xx-ddr2"
+       },
+       { }
+};
+
+static struct of_platform_driver ppc4xx_edac_driver = {
+       .match_table            = ppc4xx_edac_match,
+       .probe                  = ppc4xx_edac_probe,
+       .remove                 = ppc4xx_edac_remove,
+       .driver                 = {
+               .owner  = THIS_MODULE,
+               .name   = PPC4XX_EDAC_MODULE_NAME
+       }
+};
+
+/*
+ * TODO: The row and channel parameters likely need to be dynamically
+ * set based on the aforementioned variant controller realizations.
+ */
+static const unsigned ppc4xx_edac_nr_csrows = 2;
+static const unsigned ppc4xx_edac_nr_chans = 1;
+
+/*
+ * Strings associated with PLB master IDs capable of being posted in
+ * SDRAM_BESR or SDRAM_WMIRQ on uncorrectable ECC errors.
+ */
+static const char * const ppc4xx_plb_masters[9] = {
+       [SDRAM_PLB_M0ID_ICU]    = "ICU",
+       [SDRAM_PLB_M0ID_PCIE0]  = "PCI-E 0",
+       [SDRAM_PLB_M0ID_PCIE1]  = "PCI-E 1",
+       [SDRAM_PLB_M0ID_DMA]    = "DMA",
+       [SDRAM_PLB_M0ID_DCU]    = "DCU",
+       [SDRAM_PLB_M0ID_OPB]    = "OPB",
+       [SDRAM_PLB_M0ID_MAL]    = "MAL",
+       [SDRAM_PLB_M0ID_SEC]    = "SEC",
+       [SDRAM_PLB_M0ID_AHB]    = "AHB"
+};
+
+/**
+ * mfsdram - read and return controller register data
+ * @dcr_host: A pointer to the DCR mapping.
+ * @idcr_n: The indirect DCR register to read.
+ *
+ * This routine reads and returns the data associated with the
+ * controller's specified indirect DCR register.
+ *
+ * Returns the read data.
+ */
+static inline u32
+mfsdram(const dcr_host_t *dcr_host, unsigned int idcr_n)
+{
+       return __mfdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET,
+                       dcr_host->base + SDRAM_DCR_DATA_OFFSET,
+                       idcr_n);
+}
+
+/**
+ * mtsdram - write controller register data
+ * @dcr_host: A pointer to the DCR mapping.
+ * @idcr_n: The indirect DCR register to write.
+ * @value: The data to write.
+ *
+ * This routine writes the provided data to the controller's specified
+ * indirect DCR register.
+ */
+static inline void
+mtsdram(const dcr_host_t *dcr_host, unsigned int idcr_n, u32 value)
+{
+       return __mtdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET,
+                       dcr_host->base + SDRAM_DCR_DATA_OFFSET,
+                       idcr_n,
+                       value);
+}
+
+/**
+ * ppc4xx_edac_check_bank_error - check a bank for an ECC bank error
+ * @status: A pointer to the ECC status structure to check for an
+ *          ECC bank error.
+ * @bank: The bank to check for an ECC error.
+ *
+ * This routine determines whether the specified bank has an ECC
+ * error.
+ *
+ * Returns true if the specified bank has an ECC error; otherwise,
+ * false.
+ */
+static bool
+ppc4xx_edac_check_bank_error(const struct ppc4xx_ecc_status *status,
+                            unsigned int bank)
+{
+       switch (bank) {
+       case 0:
+               return status->ecces & SDRAM_ECCES_BK0ER;
+       case 1:
+               return status->ecces & SDRAM_ECCES_BK1ER;
+       default:
+               return false;
+       }
+}
+
+/**
+ * ppc4xx_edac_generate_bank_message - generate interpretted bank status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the bank message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS[BKNER]
+ * field of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_bank_message(const struct mem_ctl_info *mci,
+                                 const struct ppc4xx_ecc_status *status,
+                                 char *buffer,
+                                 size_t size)
+{
+       int n, total = 0;
+       unsigned int row, rows;
+
+       n = snprintf(buffer, size, "%s: Banks: ", mci->dev_name);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       for (rows = 0, row = 0; row < mci->nr_csrows; row++) {
+               if (ppc4xx_edac_check_bank_error(status, row)) {
+                       n = snprintf(buffer, size, "%s%u",
+                                       (rows++ ? ", " : ""), row);
+
+                       if (n < 0 || n >= size)
+                               goto fail;
+
+                       buffer += n;
+                       size -= n;
+                       total += n;
+               }
+       }
+
+       n = snprintf(buffer, size, "%s; ", rows ? "" : "None");
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+ fail:
+       return total;
+}
+
+/**
+ * ppc4xx_edac_generate_checkbit_message - generate interpretted checkbit message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the checkbit message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS[CKBER]
+ * field of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_checkbit_message(const struct mem_ctl_info *mci,
+                                     const struct ppc4xx_ecc_status *status,
+                                     char *buffer,
+                                     size_t size)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       const char *ckber = NULL;
+
+       switch (status->ecces & SDRAM_ECCES_CKBER_MASK) {
+       case SDRAM_ECCES_CKBER_NONE:
+               ckber = "None";
+               break;
+       case SDRAM_ECCES_CKBER_32_ECC_0_3:
+               ckber = "ECC0:3";
+               break;
+       case SDRAM_ECCES_CKBER_32_ECC_4_8:
+               switch (mfsdram(&pdata->dcr_host, SDRAM_MCOPT1) &
+                       SDRAM_MCOPT1_WDTH_MASK) {
+               case SDRAM_MCOPT1_WDTH_16:
+                       ckber = "ECC0:3";
+                       break;
+               case SDRAM_MCOPT1_WDTH_32:
+                       ckber = "ECC4:8";
+                       break;
+               default:
+                       ckber = "Unknown";
+                       break;
+               }
+               break;
+       case SDRAM_ECCES_CKBER_32_ECC_0_8:
+               ckber = "ECC0:8";
+               break;
+       default:
+               ckber = "Unknown";
+               break;
+       }
+
+       return snprintf(buffer, size, "Checkbit Error: %s", ckber);
+}
+
+/**
+ * ppc4xx_edac_generate_lane_message - generate interpretted byte lane message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the byte lane message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS[BNCE]
+ * field of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_lane_message(const struct mem_ctl_info *mci,
+                                 const struct ppc4xx_ecc_status *status,
+                                 char *buffer,
+                                 size_t size)
+{
+       int n, total = 0;
+       unsigned int lane, lanes;
+       const unsigned int first_lane = 0;
+       const unsigned int lane_count = 16;
+
+       n = snprintf(buffer, size, "; Byte Lane Errors: ");
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       for (lanes = 0, lane = first_lane; lane < lane_count; lane++) {
+               if ((status->ecces & SDRAM_ECCES_BNCE_ENCODE(lane)) != 0) {
+                       n = snprintf(buffer, size,
+                                    "%s%u",
+                                    (lanes++ ? ", " : ""), lane);
+
+                       if (n < 0 || n >= size)
+                               goto fail;
+
+                       buffer += n;
+                       size -= n;
+                       total += n;
+               }
+       }
+
+       n = snprintf(buffer, size, "%s; ", lanes ? "" : "None");
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+ fail:
+       return total;
+}
+
+/**
+ * ppc4xx_edac_generate_ecc_message - generate interpretted ECC status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the ECCES message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the ECCESS register of
+ * the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_ecc_message(const struct mem_ctl_info *mci,
+                                const struct ppc4xx_ecc_status *status,
+                                char *buffer,
+                                size_t size)
+{
+       int n, total = 0;
+
+       n = ppc4xx_edac_generate_bank_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       n = ppc4xx_edac_generate_checkbit_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+       n = ppc4xx_edac_generate_lane_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               goto fail;
+
+       buffer += n;
+       size -= n;
+       total += n;
+
+ fail:
+       return total;
+}
+
+/**
+ * ppc4xx_edac_generate_plb_message - generate interpretted PLB status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the PLB message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the portion of the
+ * driver-unique report message associated with the PLB-related BESR
+ * and/or WMIRQ registers of the specified ECC status.
+ *
+ * Returns the number of characters generated on success; otherwise, <
+ * 0 on error.
+ */
+static int
+ppc4xx_edac_generate_plb_message(const struct mem_ctl_info *mci,
+                                const struct ppc4xx_ecc_status *status,
+                                char *buffer,
+                                size_t size)
+{
+       unsigned int master;
+       bool read;
+
+       if ((status->besr & SDRAM_BESR_MASK) == 0)
+               return 0;
+
+       if ((status->besr & SDRAM_BESR_M0ET_MASK) == SDRAM_BESR_M0ET_NONE)
+               return 0;
+
+       read = ((status->besr & SDRAM_BESR_M0RW_MASK) == SDRAM_BESR_M0RW_READ);
+
+       master = SDRAM_BESR_M0ID_DECODE(status->besr);
+
+       return snprintf(buffer, size,
+                       "%s error w/ PLB master %u \"%s\"; ",
+                       (read ? "Read" : "Write"),
+                       master,
+                       (((master >= SDRAM_PLB_M0ID_FIRST) &&
+                         (master <= SDRAM_PLB_M0ID_LAST)) ?
+                        ppc4xx_plb_masters[master] : "UNKNOWN"));
+}
+
+/**
+ * ppc4xx_edac_generate_message - generate interpretted status message
+ * @mci: A pointer to the EDAC memory controller instance associated
+ *       with the driver-unique message being generated.
+ * @status: A pointer to the ECC status structure to generate the
+ *          message from.
+ * @buffer: A pointer to the buffer in which to generate the
+ *          message.
+ * @size: The size, in bytes, of space available in buffer.
+ *
+ * This routine generates to the provided buffer the driver-unique
+ * EDAC report message from the specified ECC status.
+ */
+static void
+ppc4xx_edac_generate_message(const struct mem_ctl_info *mci,
+                            const struct ppc4xx_ecc_status *status,
+                            char *buffer,
+                            size_t size)
+{
+       int n;
+
+       if (buffer == NULL || size == 0)
+               return;
+
+       n = ppc4xx_edac_generate_ecc_message(mci, status, buffer, size);
+
+       if (n < 0 || n >= size)
+               return;
+
+       buffer += n;
+       size -= n;
+
+       ppc4xx_edac_generate_plb_message(mci, status, buffer, size);
+}
+
+#ifdef DEBUG
+/**
+ * ppc4xx_ecc_dump_status - dump controller ECC status registers
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the status being dumped.
+ * @status: A pointer to the ECC status structure to generate the
+ *          dump from.
+ *
+ * This routine dumps to the kernel log buffer the raw and
+ * interpretted specified ECC status.
+ */
+static void
+ppc4xx_ecc_dump_status(const struct mem_ctl_info *mci,
+                      const struct ppc4xx_ecc_status *status)
+{
+       char message[PPC4XX_EDAC_MESSAGE_SIZE];
+
+       ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
+
+       ppc4xx_edac_mc_printk(KERN_INFO, mci,
+                             "\n"
+                             "\tECCES: 0x%08x\n"
+                             "\tWMIRQ: 0x%08x\n"
+                             "\tBESR:  0x%08x\n"
+                             "\tBEAR:  0x%08x%08x\n"
+                             "\t%s\n",
+                             status->ecces,
+                             status->wmirq,
+                             status->besr,
+                             status->bearh,
+                             status->bearl,
+                             message);
+}
+#endif /* DEBUG */
+
+/**
+ * ppc4xx_ecc_get_status - get controller ECC status
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the status being retrieved.
+ * @status: A pointer to the ECC status structure to populate the
+ *          ECC status with.
+ *
+ * This routine reads and masks, as appropriate, all the relevant
+ * status registers that deal with ibm,sdram-4xx-ddr2 ECC errors.
+ * While we read all of them, for correctable errors, we only expect
+ * to deal with ECCES. For uncorrectable errors, we expect to deal
+ * with all of them.
+ */
+static void
+ppc4xx_ecc_get_status(const struct mem_ctl_info *mci,
+                     struct ppc4xx_ecc_status *status)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       const dcr_host_t *dcr_host = &pdata->dcr_host;
+
+       status->ecces = mfsdram(dcr_host, SDRAM_ECCES) & SDRAM_ECCES_MASK;
+       status->wmirq = mfsdram(dcr_host, SDRAM_WMIRQ) & SDRAM_WMIRQ_MASK;
+       status->besr  = mfsdram(dcr_host, SDRAM_BESR)  & SDRAM_BESR_MASK;
+       status->bearl = mfsdram(dcr_host, SDRAM_BEARL);
+       status->bearh = mfsdram(dcr_host, SDRAM_BEARH);
+}
+
+/**
+ * ppc4xx_ecc_clear_status - clear controller ECC status
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the status being cleared.
+ * @status: A pointer to the ECC status structure containing the
+ *          values to write to clear the ECC status.
+ *
+ * This routine clears--by writing the masked (as appropriate) status
+ * values back to--the status registers that deal with
+ * ibm,sdram-4xx-ddr2 ECC errors.
+ */
+static void
+ppc4xx_ecc_clear_status(const struct mem_ctl_info *mci,
+                       const struct ppc4xx_ecc_status *status)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       const dcr_host_t *dcr_host = &pdata->dcr_host;
+
+       mtsdram(dcr_host, SDRAM_ECCES,  status->ecces & SDRAM_ECCES_MASK);
+       mtsdram(dcr_host, SDRAM_WMIRQ,  status->wmirq & SDRAM_WMIRQ_MASK);
+       mtsdram(dcr_host, SDRAM_BESR,   status->besr & SDRAM_BESR_MASK);
+       mtsdram(dcr_host, SDRAM_BEARL,  0);
+       mtsdram(dcr_host, SDRAM_BEARH,  0);
+}
+
+/**
+ * ppc4xx_edac_handle_ce - handle controller correctable ECC error (CE)
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the correctable error being handled and reported.
+ * @status: A pointer to the ECC status structure associated with
+ *          the correctable error being handled and reported.
+ *
+ * This routine handles an ibm,sdram-4xx-ddr2 controller ECC
+ * correctable error. Per the aforementioned discussion, there's not
+ * enough status available to use the full EDAC correctable error
+ * interface, so we just pass driver-unique message to the "no info"
+ * interface.
+ */
+static void
+ppc4xx_edac_handle_ce(struct mem_ctl_info *mci,
+                     const struct ppc4xx_ecc_status *status)
+{
+       int row;
+       char message[PPC4XX_EDAC_MESSAGE_SIZE];
+
+       ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
+
+       for (row = 0; row < mci->nr_csrows; row++)
+               if (ppc4xx_edac_check_bank_error(status, row))
+                       edac_mc_handle_ce_no_info(mci, message);
+}
+
+/**
+ * ppc4xx_edac_handle_ue - handle controller uncorrectable ECC error (UE)
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the uncorrectable error being handled and
+ *       reported.
+ * @status: A pointer to the ECC status structure associated with
+ *          the uncorrectable error being handled and reported.
+ *
+ * This routine handles an ibm,sdram-4xx-ddr2 controller ECC
+ * uncorrectable error.
+ */
+static void
+ppc4xx_edac_handle_ue(struct mem_ctl_info *mci,
+                     const struct ppc4xx_ecc_status *status)
+{
+       const u64 bear = ((u64)status->bearh << 32 | status->bearl);
+       const unsigned long page = bear >> PAGE_SHIFT;
+       const unsigned long offset = bear & ~PAGE_MASK;
+       int row;
+       char message[PPC4XX_EDAC_MESSAGE_SIZE];
+
+       ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
+
+       for (row = 0; row < mci->nr_csrows; row++)
+               if (ppc4xx_edac_check_bank_error(status, row))
+                       edac_mc_handle_ue(mci, page, offset, row, message);
+}
+
+/**
+ * ppc4xx_edac_check - check controller for ECC errors
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the ibm,sdram-4xx-ddr2 controller being
+ *       checked.
+ *
+ * This routine is used to check and post ECC errors and is called by
+ * both the EDAC polling thread and this driver's CE and UE interrupt
+ * handler.
+ */
+static void
+ppc4xx_edac_check(struct mem_ctl_info *mci)
+{
+#ifdef DEBUG
+       static unsigned int count;
+#endif
+       struct ppc4xx_ecc_status status;
+
+       ppc4xx_ecc_get_status(mci, &status);
+
+#ifdef DEBUG
+       if (count++ % 30 == 0)
+               ppc4xx_ecc_dump_status(mci, &status);
+#endif
+
+       if (status.ecces & SDRAM_ECCES_UE)
+               ppc4xx_edac_handle_ue(mci, &status);
+
+       if (status.ecces & SDRAM_ECCES_CE)
+               ppc4xx_edac_handle_ce(mci, &status);
+
+       ppc4xx_ecc_clear_status(mci, &status);
+}
+
+/**
+ * ppc4xx_edac_isr - SEC (CE) and DED (UE) interrupt service routine
+ * @irq:    The virtual interrupt number being serviced.
+ * @dev_id: A pointer to the EDAC memory controller instance
+ *          associated with the interrupt being handled.
+ *
+ * This routine implements the interrupt handler for both correctable
+ * (CE) and uncorrectable (UE) ECC errors for the ibm,sdram-4xx-ddr2
+ * controller. It simply calls through to the same routine used during
+ * polling to check, report and clear the ECC status.
+ *
+ * Unconditionally returns IRQ_HANDLED.
+ */
+static irqreturn_t
+ppc4xx_edac_isr(int irq, void *dev_id)
+{
+       struct mem_ctl_info *mci = dev_id;
+
+       ppc4xx_edac_check(mci);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * ppc4xx_edac_get_dtype - return the controller memory width
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which the width
+ *          is derived.
+ *
+ * This routine returns the EDAC device type width appropriate for the
+ * current controller configuration.
+ *
+ * TODO: This needs to be conditioned dynamically through feature
+ * flags or some such when other controller variants are supported as
+ * the 405EX[r] is 16-/32-bit and the others are 32-/64-bit with the
+ * 16- and 64-bit field definition/value/enumeration (b1) overloaded
+ * among them.
+ *
+ * Returns a device type width enumeration.
+ */
+static enum dev_type __devinit
+ppc4xx_edac_get_dtype(u32 mcopt1)
+{
+       switch (mcopt1 & SDRAM_MCOPT1_WDTH_MASK) {
+       case SDRAM_MCOPT1_WDTH_16:
+               return DEV_X2;
+       case SDRAM_MCOPT1_WDTH_32:
+               return DEV_X4;
+       default:
+               return DEV_UNKNOWN;
+       }
+}
+
+/**
+ * ppc4xx_edac_get_mtype - return controller memory type
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which the memory type
+ *          is derived.
+ *
+ * This routine returns the EDAC memory type appropriate for the
+ * current controller configuration.
+ *
+ * Returns a memory type enumeration.
+ */
+static enum mem_type __devinit
+ppc4xx_edac_get_mtype(u32 mcopt1)
+{
+       bool rden = ((mcopt1 & SDRAM_MCOPT1_RDEN_MASK) == SDRAM_MCOPT1_RDEN);
+
+       switch (mcopt1 & SDRAM_MCOPT1_DDR_TYPE_MASK) {
+       case SDRAM_MCOPT1_DDR2_TYPE:
+               return rden ? MEM_RDDR2 : MEM_DDR2;
+       case SDRAM_MCOPT1_DDR1_TYPE:
+               return rden ? MEM_RDDR : MEM_DDR;
+       default:
+               return MEM_UNKNOWN;
+       }
+}
+
+/**
+ * ppc4xx_edac_init_csrows - intialize driver instance rows
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the ibm,sdram-4xx-ddr2 controller for which
+ *       the csrows (i.e. banks/ranks) are being initialized.
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which bank width
+ *          and memory typ information is derived.
+ *
+ * This routine intializes the virtual "chip select rows" associated
+ * with the EDAC memory controller instance. An ibm,sdram-4xx-ddr2
+ * controller bank/rank is mapped to a row.
+ *
+ * Returns 0 if OK; otherwise, -EINVAL if the memory bank size
+ * configuration cannot be determined.
+ */
+static int __devinit
+ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
+{
+       const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       int status = 0;
+       enum mem_type mtype;
+       enum dev_type dtype;
+       enum edac_type edac_mode;
+       int row;
+       u32 mbxcf, size;
+       static u32 ppc4xx_last_page;
+
+       /* Establish the memory type and width */
+
+       mtype = ppc4xx_edac_get_mtype(mcopt1);
+       dtype = ppc4xx_edac_get_dtype(mcopt1);
+
+       /* Establish EDAC mode */
+
+       if (mci->edac_cap & EDAC_FLAG_SECDED)
+               edac_mode = EDAC_SECDED;
+       else if (mci->edac_cap & EDAC_FLAG_EC)
+               edac_mode = EDAC_EC;
+       else
+               edac_mode = EDAC_NONE;
+
+       /*
+        * Initialize each chip select row structure which correspond
+        * 1:1 with a controller bank/rank.
+        */
+
+       for (row = 0; row < mci->nr_csrows; row++) {
+               struct csrow_info *csi = &mci->csrows[row];
+
+               /*
+                * Get the configuration settings for this
+                * row/bank/rank and skip disabled banks.
+                */
+
+               mbxcf = mfsdram(&pdata->dcr_host, SDRAM_MBXCF(row));
+
+               if ((mbxcf & SDRAM_MBCF_BE_MASK) != SDRAM_MBCF_BE_ENABLE)
+                       continue;
+
+               /* Map the bank configuration size setting to pages. */
+
+               size = mbxcf & SDRAM_MBCF_SZ_MASK;
+
+               switch (size) {
+               case SDRAM_MBCF_SZ_4MB:
+               case SDRAM_MBCF_SZ_8MB:
+               case SDRAM_MBCF_SZ_16MB:
+               case SDRAM_MBCF_SZ_32MB:
+               case SDRAM_MBCF_SZ_64MB:
+               case SDRAM_MBCF_SZ_128MB:
+               case SDRAM_MBCF_SZ_256MB:
+               case SDRAM_MBCF_SZ_512MB:
+               case SDRAM_MBCF_SZ_1GB:
+               case SDRAM_MBCF_SZ_2GB:
+               case SDRAM_MBCF_SZ_4GB:
+               case SDRAM_MBCF_SZ_8GB:
+                       csi->nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size);
+                       break;
+               default:
+                       ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                             "Unrecognized memory bank %d "
+                                             "size 0x%08x\n",
+                                             row, SDRAM_MBCF_SZ_DECODE(size));
+                       status = -EINVAL;
+                       goto done;
+               }
+
+               csi->first_page = ppc4xx_last_page;
+               csi->last_page  = csi->first_page + csi->nr_pages - 1;
+               csi->page_mask  = 0;
+
+               /*
+                * It's unclear exactly what grain should be set to
+                * here. The SDRAM_ECCES register allows resolution of
+                * an error down to a nibble which would potentially
+                * argue for a grain of '1' byte, even though we only
+                * know the associated address for uncorrectable
+                * errors. This value is not used at present for
+                * anything other than error reporting so getting it
+                * wrong should be of little consequence. Other
+                * possible values would be the PLB width (16), the
+                * page size (PAGE_SIZE) or the memory width (2 or 4).
+                */
+
+               csi->grain      = 1;
+
+               csi->mtype      = mtype;
+               csi->dtype      = dtype;
+
+               csi->edac_mode  = edac_mode;
+
+               ppc4xx_last_page += csi->nr_pages;
+       }
+
+ done:
+       return status;
+}
+
+/**
+ * ppc4xx_edac_mc_init - intialize driver instance
+ * @mci: A pointer to the EDAC memory controller instance being
+ *       initialized.
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller this EDAC instance is bound to.
+ * @match: A pointer to the OpenFirmware device tree match
+ *         information associated with the controller this EDAC instance
+ *         is bound to.
+ * @dcr_host: A pointer to the DCR data containing the DCR mapping
+ *            for this controller instance.
+ * @mcopt1: The 32-bit Memory Controller Option 1 register value
+ *          currently set for the controller, from which ECC capabilities
+ *          and scrub mode are derived.
+ *
+ * This routine performs initialization of the EDAC memory controller
+ * instance and related driver-private data associated with the
+ * ibm,sdram-4xx-ddr2 memory controller the instance is bound to.
+ *
+ * Returns 0 if OK; otherwise, < 0 on error.
+ */
+static int __devinit
+ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
+                   struct of_device *op,
+                   const struct of_device_id *match,
+                   const dcr_host_t *dcr_host,
+                   u32 mcopt1)
+{
+       int status = 0;
+       const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
+       struct ppc4xx_edac_pdata *pdata = NULL;
+       const struct device_node *np = op->node;
+
+       if (match == NULL)
+               return -EINVAL;
+
+       /* Initial driver pointers and private data */
+
+       mci->dev                = &op->dev;
+
+       dev_set_drvdata(mci->dev, mci);
+
+       pdata                   = mci->pvt_info;
+
+       pdata->dcr_host         = *dcr_host;
+       pdata->irqs.sec         = NO_IRQ;
+       pdata->irqs.ded         = NO_IRQ;
+
+       /* Initialize controller capabilities and configuration */
+
+       mci->mtype_cap          = (MEM_FLAG_DDR | MEM_FLAG_RDDR |
+                                  MEM_FLAG_DDR2 | MEM_FLAG_RDDR2);
+
+       mci->edac_ctl_cap       = (EDAC_FLAG_NONE |
+                                  EDAC_FLAG_EC |
+                                  EDAC_FLAG_SECDED);
+
+       mci->scrub_cap          = SCRUB_NONE;
+       mci->scrub_mode         = SCRUB_NONE;
+
+       /*
+        * Update the actual capabilites based on the MCOPT1[MCHK]
+        * settings. Scrubbing is only useful if reporting is enabled.
+        */
+
+       switch (memcheck) {
+       case SDRAM_MCOPT1_MCHK_CHK:
+               mci->edac_cap   = EDAC_FLAG_EC;
+               break;
+       case SDRAM_MCOPT1_MCHK_CHK_REP:
+               mci->edac_cap   = (EDAC_FLAG_EC | EDAC_FLAG_SECDED);
+               mci->scrub_mode = SCRUB_SW_SRC;
+               break;
+       default:
+               mci->edac_cap   = EDAC_FLAG_NONE;
+               break;
+       }
+
+       /* Initialize strings */
+
+       mci->mod_name           = PPC4XX_EDAC_MODULE_NAME;
+       mci->mod_ver            = PPC4XX_EDAC_MODULE_REVISION;
+       mci->ctl_name           = match->compatible,
+       mci->dev_name           = np->full_name;
+
+       /* Initialize callbacks */
+
+       mci->edac_check         = ppc4xx_edac_check;
+       mci->ctl_page_to_phys   = NULL;
+
+       /* Initialize chip select rows */
+
+       status = ppc4xx_edac_init_csrows(mci, mcopt1);
+
+       if (status)
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Failed to initialize rows!\n");
+
+       return status;
+}
+
+/**
+ * ppc4xx_edac_register_irq - setup and register controller interrupts
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller this EDAC instance is bound to.
+ * @mci: A pointer to the EDAC memory controller instance
+ *       associated with the ibm,sdram-4xx-ddr2 controller for which
+ *       interrupts are being registered.
+ *
+ * This routine parses the correctable (CE) and uncorrectable error (UE)
+ * interrupts from the device tree node and maps and assigns them to
+ * the associated EDAC memory controller instance.
+ *
+ * Returns 0 if OK; otherwise, -ENODEV if the interrupts could not be
+ * mapped and assigned.
+ */
+static int __devinit
+ppc4xx_edac_register_irq(struct of_device *op, struct mem_ctl_info *mci)
+{
+       int status = 0;
+       int ded_irq, sec_irq;
+       struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+       struct device_node *np = op->node;
+
+       ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX);
+       sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX);
+
+       if (ded_irq == NO_IRQ || sec_irq == NO_IRQ) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Unable to map interrupts.\n");
+               status = -ENODEV;
+               goto fail;
+       }
+
+       status = request_irq(ded_irq,
+                            ppc4xx_edac_isr,
+                            IRQF_DISABLED,
+                            "[EDAC] MC ECCDED",
+                            mci);
+
+       if (status < 0) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Unable to request irq %d for ECC DED",
+                                     ded_irq);
+               status = -ENODEV;
+               goto fail1;
+       }
+
+       status = request_irq(sec_irq,
+                            ppc4xx_edac_isr,
+                            IRQF_DISABLED,
+                            "[EDAC] MC ECCSEC",
+                            mci);
+
+       if (status < 0) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Unable to request irq %d for ECC SEC",
+                                     sec_irq);
+               status = -ENODEV;
+               goto fail2;
+       }
+
+       ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCDED irq is %d\n", ded_irq);
+       ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCSEC irq is %d\n", sec_irq);
+
+       pdata->irqs.ded = ded_irq;
+       pdata->irqs.sec = sec_irq;
+
+       return 0;
+
+ fail2:
+       free_irq(sec_irq, mci);
+
+ fail1:
+       free_irq(ded_irq, mci);
+
+ fail:
+       return status;
+}
+
+/**
+ * ppc4xx_edac_map_dcrs - locate and map controller registers
+ * @np: A pointer to the device tree node containing the DCR
+ *      resources to map.
+ * @dcr_host: A pointer to the DCR data to populate with the
+ *            DCR mapping.
+ *
+ * This routine attempts to locate in the device tree and map the DCR
+ * register resources associated with the controller's indirect DCR
+ * address and data windows.
+ *
+ * Returns 0 if the DCRs were successfully mapped; otherwise, < 0 on
+ * error.
+ */
+static int __devinit
+ppc4xx_edac_map_dcrs(const struct device_node *np, dcr_host_t *dcr_host)
+{
+       unsigned int dcr_base, dcr_len;
+
+       if (np == NULL || dcr_host == NULL)
+               return -EINVAL;
+
+       /* Get the DCR resource extent and sanity check the values. */
+
+       dcr_base = dcr_resource_start(np, 0);
+       dcr_len = dcr_resource_len(np, 0);
+
+       if (dcr_base == 0 || dcr_len == 0) {
+               ppc4xx_edac_printk(KERN_ERR,
+                                  "Failed to obtain DCR property.\n");
+               return -ENODEV;
+       }
+
+       if (dcr_len != SDRAM_DCR_RESOURCE_LEN) {
+               ppc4xx_edac_printk(KERN_ERR,
+                                  "Unexpected DCR length %d, expected %d.\n",
+                                  dcr_len, SDRAM_DCR_RESOURCE_LEN);
+               return -ENODEV;
+       }
+
+       /*  Attempt to map the DCR extent. */
+
+       *dcr_host = dcr_map(np, dcr_base, dcr_len);
+
+       if (!DCR_MAP_OK(*dcr_host)) {
+               ppc4xx_edac_printk(KERN_INFO, "Failed to map DCRs.\n");
+                   return -ENODEV;
+       }
+
+       return 0;
+}
+
+/**
+ * ppc4xx_edac_probe - check controller and bind driver
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller being probed for driver binding.
+ * @match: A pointer to the OpenFirmware device tree match
+ *         information associated with the controller being probed
+ *         for driver binding.
+ *
+ * This routine probes a specific ibm,sdram-4xx-ddr2 controller
+ * instance for binding with the driver.
+ *
+ * Returns 0 if the controller instance was successfully bound to the
+ * driver; otherwise, < 0 on error.
+ */
+static int __devinit
+ppc4xx_edac_probe(struct of_device *op, const struct of_device_id *match)
+{
+       int status = 0;
+       u32 mcopt1, memcheck;
+       dcr_host_t dcr_host;
+       const struct device_node *np = op->node;
+       struct mem_ctl_info *mci = NULL;
+       static int ppc4xx_edac_instance;
+
+       /*
+        * At this point, we only support the controller realized on
+        * the AMCC PPC 405EX[r]. Reject anything else.
+        */
+
+       if (!of_device_is_compatible(np, "ibm,sdram-405ex") &&
+           !of_device_is_compatible(np, "ibm,sdram-405exr")) {
+               ppc4xx_edac_printk(KERN_NOTICE,
+                                  "Only the PPC405EX[r] is supported.\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Next, get the DCR property and attempt to map it so that we
+        * can probe the controller.
+        */
+
+       status = ppc4xx_edac_map_dcrs(np, &dcr_host);
+
+       if (status)
+               return status;
+
+       /*
+        * First determine whether ECC is enabled at all. If not,
+        * there is no useful checking or monitoring that can be done
+        * for this controller.
+        */
+
+       mcopt1 = mfsdram(&dcr_host, SDRAM_MCOPT1);
+       memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
+
+       if (memcheck == SDRAM_MCOPT1_MCHK_NON) {
+               ppc4xx_edac_printk(KERN_INFO, "%s: No ECC memory detected or "
+                                  "ECC is disabled.\n", np->full_name);
+               status = -ENODEV;
+               goto done;
+       }
+
+       /*
+        * At this point, we know ECC is enabled, allocate an EDAC
+        * controller instance and perform the appropriate
+        * initialization.
+        */
+
+       mci = edac_mc_alloc(sizeof(struct ppc4xx_edac_pdata),
+                           ppc4xx_edac_nr_csrows,
+                           ppc4xx_edac_nr_chans,
+                           ppc4xx_edac_instance);
+
+       if (mci == NULL) {
+               ppc4xx_edac_printk(KERN_ERR, "%s: "
+                                  "Failed to allocate EDAC MC instance!\n",
+                                  np->full_name);
+               status = -ENOMEM;
+               goto done;
+       }
+
+       status = ppc4xx_edac_mc_init(mci, op, match, &dcr_host, mcopt1);
+
+       if (status) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Failed to initialize instance!\n");
+               goto fail;
+       }
+
+       /*
+        * We have a valid, initialized EDAC instance bound to the
+        * controller. Attempt to register it with the EDAC subsystem
+        * and, if necessary, register interrupts.
+        */
+
+       if (edac_mc_add_mc(mci)) {
+               ppc4xx_edac_mc_printk(KERN_ERR, mci,
+                                     "Failed to add instance!\n");
+               status = -ENODEV;
+               goto fail;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               status = ppc4xx_edac_register_irq(op, mci);
+
+               if (status)
+                       goto fail1;
+       }
+
+       ppc4xx_edac_instance++;
+
+       return 0;
+
+ fail1:
+       edac_mc_del_mc(mci->dev);
+
+ fail:
+       edac_mc_free(mci);
+
+ done:
+       return status;
+}
+
+/**
+ * ppc4xx_edac_remove - unbind driver from controller
+ * @op: A pointer to the OpenFirmware device tree node associated
+ *      with the controller this EDAC instance is to be unbound/removed
+ *      from.
+ *
+ * This routine unbinds the EDAC memory controller instance associated
+ * with the specified ibm,sdram-4xx-ddr2 controller described by the
+ * OpenFirmware device tree node passed as a parameter.
+ *
+ * Unconditionally returns 0.
+ */
+static int
+ppc4xx_edac_remove(struct of_device *op)
+{
+       struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
+       struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               free_irq(pdata->irqs.sec, mci);
+               free_irq(pdata->irqs.ded, mci);
+       }
+
+       dcr_unmap(pdata->dcr_host, SDRAM_DCR_RESOURCE_LEN);
+
+       edac_mc_del_mc(mci->dev);
+       edac_mc_free(mci);
+
+       return 0;
+}
+
+/**
+ * ppc4xx_edac_opstate_init - initialize EDAC reporting method
+ *
+ * This routine ensures that the EDAC memory controller reporting
+ * method is mapped to a sane value as the EDAC core defines the value
+ * to EDAC_OPSTATE_INVAL by default. We don't call the global
+ * opstate_init as that defaults to polling and we want interrupt as
+ * the default.
+ */
+static inline void __init
+ppc4xx_edac_opstate_init(void)
+{
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_INT:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_INT;
+               break;
+       }
+
+       ppc4xx_edac_printk(KERN_INFO, "Reporting type: %s\n",
+                          ((edac_op_state == EDAC_OPSTATE_POLL) ?
+                           EDAC_OPSTATE_POLL_STR :
+                           ((edac_op_state == EDAC_OPSTATE_INT) ?
+                            EDAC_OPSTATE_INT_STR :
+                            EDAC_OPSTATE_UNKNOWN_STR)));
+}
+
+/**
+ * ppc4xx_edac_init - driver/module insertion entry point
+ *
+ * This routine is the driver/module insertion entry point. It
+ * initializes the EDAC memory controller reporting state and
+ * registers the driver as an OpenFirmware device tree platform
+ * driver.
+ */
+static int __init
+ppc4xx_edac_init(void)
+{
+       ppc4xx_edac_printk(KERN_INFO, PPC4XX_EDAC_MODULE_REVISION "\n");
+
+       ppc4xx_edac_opstate_init();
+
+       return of_register_platform_driver(&ppc4xx_edac_driver);
+}
+
+/**
+ * ppc4xx_edac_exit - driver/module removal entry point
+ *
+ * This routine is the driver/module removal entry point. It
+ * unregisters the driver as an OpenFirmware device tree platform
+ * driver.
+ */
+static void __exit
+ppc4xx_edac_exit(void)
+{
+       of_unregister_platform_driver(&ppc4xx_edac_driver);
+}
+
+module_init(ppc4xx_edac_init);
+module_exit(ppc4xx_edac_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Grant Erickson <gerickson@nuovations.com>");
+MODULE_DESCRIPTION("EDAC MC Driver for the PPC4xx IBM DDR2 Memory Controller");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting State: "
+                "0=" EDAC_OPSTATE_POLL_STR ", 2=" EDAC_OPSTATE_INT_STR);
diff --git a/drivers/edac/ppc4xx_edac.h b/drivers/edac/ppc4xx_edac.h
new file mode 100644 (file)
index 0000000..d315476
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ *   Grant Erickson <gerickson@nuovations.com>
+ *
+ * This file defines processor mnemonics for accessing and managing
+ * the IBM DDR1/DDR2 ECC controller found in the 405EX[r], 440SP,
+ * 440SPe, 460EX, 460GT and 460SX.
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ */
+
+#ifndef __PPC4XX_EDAC_H
+#define __PPC4XX_EDAC_H
+
+#include <linux/types.h>
+
+/*
+ * Macro for generating register field mnemonics
+ */
+#define PPC_REG_BITS                   32
+#define PPC_REG_VAL(bit, val)          ((val) << ((PPC_REG_BITS - 1) - (bit)))
+#define PPC_REG_DECODE(bit, val)       ((val) >> ((PPC_REG_BITS - 1) - (bit)))
+
+/*
+ * IBM 4xx DDR1/DDR2 SDRAM memory controller registers (at least those
+ * relevant to ECC)
+ */
+#define SDRAM_BESR                     0x00    /* Error status (read/clear) */
+#define SDRAM_BESRT                    0x01    /* Error statuss (test/set)  */
+#define SDRAM_BEARL                    0x02    /* Error address low         */
+#define SDRAM_BEARH                    0x03    /* Error address high        */
+#define SDRAM_WMIRQ                    0x06    /* Write master (read/clear) */
+#define SDRAM_WMIRQT                   0x07    /* Write master (test/set)   */
+#define SDRAM_MCOPT1                   0x20    /* Controller options 1      */
+#define SDRAM_MBXCF_BASE               0x40    /* Bank n configuration base */
+#define        SDRAM_MBXCF(n)                  (SDRAM_MBXCF_BASE + (4 * (n)))
+#define SDRAM_MB0CF                    SDRAM_MBXCF(0)
+#define SDRAM_MB1CF                    SDRAM_MBXCF(1)
+#define SDRAM_MB2CF                    SDRAM_MBXCF(2)
+#define SDRAM_MB3CF                    SDRAM_MBXCF(3)
+#define SDRAM_ECCCR                    0x98    /* ECC error status          */
+#define SDRAM_ECCES                    SDRAM_ECCCR
+
+/*
+ * PLB Master IDs
+ */
+#define        SDRAM_PLB_M0ID_FIRST            0
+#define        SDRAM_PLB_M0ID_ICU              SDRAM_PLB_M0ID_FIRST
+#define        SDRAM_PLB_M0ID_PCIE0            1
+#define        SDRAM_PLB_M0ID_PCIE1            2
+#define        SDRAM_PLB_M0ID_DMA              3
+#define        SDRAM_PLB_M0ID_DCU              4
+#define        SDRAM_PLB_M0ID_OPB              5
+#define        SDRAM_PLB_M0ID_MAL              6
+#define        SDRAM_PLB_M0ID_SEC              7
+#define        SDRAM_PLB_M0ID_AHB              8
+#define SDRAM_PLB_M0ID_LAST            SDRAM_PLB_M0ID_AHB
+#define SDRAM_PLB_M0ID_COUNT           (SDRAM_PLB_M0ID_LAST - \
+                                        SDRAM_PLB_M0ID_FIRST + 1)
+
+/*
+ * Memory Controller Bus Error Status Register
+ */
+#define SDRAM_BESR_MASK                        PPC_REG_VAL(7, 0xFF)
+#define SDRAM_BESR_M0ID_MASK           PPC_REG_VAL(3, 0xF)
+#define        SDRAM_BESR_M0ID_DECODE(n)       PPC_REG_DECODE(3, n)
+#define SDRAM_BESR_M0ID_ICU            PPC_REG_VAL(3, SDRAM_PLB_M0ID_ICU)
+#define SDRAM_BESR_M0ID_PCIE0          PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE0)
+#define SDRAM_BESR_M0ID_PCIE1          PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE1)
+#define SDRAM_BESR_M0ID_DMA            PPC_REG_VAL(3, SDRAM_PLB_M0ID_DMA)
+#define SDRAM_BESR_M0ID_DCU            PPC_REG_VAL(3, SDRAM_PLB_M0ID_DCU)
+#define SDRAM_BESR_M0ID_OPB            PPC_REG_VAL(3, SDRAM_PLB_M0ID_OPB)
+#define SDRAM_BESR_M0ID_MAL            PPC_REG_VAL(3, SDRAM_PLB_M0ID_MAL)
+#define SDRAM_BESR_M0ID_SEC            PPC_REG_VAL(3, SDRAM_PLB_M0ID_SEC)
+#define SDRAM_BESR_M0ID_AHB            PPC_REG_VAL(3, SDRAM_PLB_M0ID_AHB)
+#define SDRAM_BESR_M0ET_MASK           PPC_REG_VAL(6, 0x7)
+#define SDRAM_BESR_M0ET_NONE           PPC_REG_VAL(6, 0)
+#define SDRAM_BESR_M0ET_ECC            PPC_REG_VAL(6, 1)
+#define SDRAM_BESR_M0RW_MASK           PPC_REG_VAL(7, 1)
+#define SDRAM_BESR_M0RW_WRITE          PPC_REG_VAL(7, 0)
+#define SDRAM_BESR_M0RW_READ           PPC_REG_VAL(7, 1)
+
+/*
+ * Memory Controller PLB Write Master Interrupt Register
+ */
+#define SDRAM_WMIRQ_MASK               PPC_REG_VAL(8, 0x1FF)
+#define        SDRAM_WMIRQ_ENCODE(id)          PPC_REG_VAL((id % \
+                                                    SDRAM_PLB_M0ID_COUNT), 1)
+#define SDRAM_WMIRQ_ICU                        PPC_REG_VAL(SDRAM_PLB_M0ID_ICU, 1)
+#define SDRAM_WMIRQ_PCIE0              PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE0, 1)
+#define SDRAM_WMIRQ_PCIE1              PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE1, 1)
+#define SDRAM_WMIRQ_DMA                        PPC_REG_VAL(SDRAM_PLB_M0ID_DMA, 1)
+#define SDRAM_WMIRQ_DCU                        PPC_REG_VAL(SDRAM_PLB_M0ID_DCU, 1)
+#define SDRAM_WMIRQ_OPB                        PPC_REG_VAL(SDRAM_PLB_M0ID_OPB, 1)
+#define SDRAM_WMIRQ_MAL                        PPC_REG_VAL(SDRAM_PLB_M0ID_MAL, 1)
+#define SDRAM_WMIRQ_SEC                        PPC_REG_VAL(SDRAM_PLB_M0ID_SEC, 1)
+#define SDRAM_WMIRQ_AHB                        PPC_REG_VAL(SDRAM_PLB_M0ID_AHB, 1)
+
+/*
+ * Memory Controller Options 1 Register
+ */
+#define SDRAM_MCOPT1_MCHK_MASK     PPC_REG_VAL(3, 0x3)  /* ECC mask         */
+#define SDRAM_MCOPT1_MCHK_NON      PPC_REG_VAL(3, 0x0)  /* No ECC gen       */
+#define SDRAM_MCOPT1_MCHK_GEN      PPC_REG_VAL(3, 0x2)  /* ECC gen          */
+#define SDRAM_MCOPT1_MCHK_CHK      PPC_REG_VAL(3, 0x1)  /* ECC gen and chk  */
+#define SDRAM_MCOPT1_MCHK_CHK_REP   PPC_REG_VAL(3, 0x3)         /* ECC gen/chk/rpt  */
+#define SDRAM_MCOPT1_MCHK_DECODE(n) ((((u32)(n)) >> 28) & 0x3)
+#define SDRAM_MCOPT1_RDEN_MASK     PPC_REG_VAL(4, 0x1)  /* Rgstrd DIMM mask */
+#define SDRAM_MCOPT1_RDEN          PPC_REG_VAL(4, 0x1)  /* Rgstrd DIMM enbl */
+#define SDRAM_MCOPT1_WDTH_MASK     PPC_REG_VAL(7, 0x1)  /* Width mask       */
+#define SDRAM_MCOPT1_WDTH_32       PPC_REG_VAL(7, 0x0)  /* 32 bits          */
+#define SDRAM_MCOPT1_WDTH_16       PPC_REG_VAL(7, 0x1)  /* 16 bits          */
+#define SDRAM_MCOPT1_DDR_TYPE_MASK  PPC_REG_VAL(11, 0x1) /* DDR type mask    */
+#define SDRAM_MCOPT1_DDR1_TYPE     PPC_REG_VAL(11, 0x0) /* DDR1 type        */
+#define SDRAM_MCOPT1_DDR2_TYPE     PPC_REG_VAL(11, 0x1) /* DDR2 type        */
+
+/*
+ * Memory Bank 0 - n Configuration Register
+ */
+#define SDRAM_MBCF_BA_MASK             PPC_REG_VAL(12, 0x1FFF)
+#define SDRAM_MBCF_SZ_MASK             PPC_REG_VAL(19, 0xF)
+#define SDRAM_MBCF_SZ_DECODE(mbxcf)    PPC_REG_DECODE(19, mbxcf)
+#define SDRAM_MBCF_SZ_4MB              PPC_REG_VAL(19, 0x0)
+#define SDRAM_MBCF_SZ_8MB              PPC_REG_VAL(19, 0x1)
+#define SDRAM_MBCF_SZ_16MB             PPC_REG_VAL(19, 0x2)
+#define SDRAM_MBCF_SZ_32MB             PPC_REG_VAL(19, 0x3)
+#define SDRAM_MBCF_SZ_64MB             PPC_REG_VAL(19, 0x4)
+#define SDRAM_MBCF_SZ_128MB            PPC_REG_VAL(19, 0x5)
+#define SDRAM_MBCF_SZ_256MB            PPC_REG_VAL(19, 0x6)
+#define SDRAM_MBCF_SZ_512MB            PPC_REG_VAL(19, 0x7)
+#define SDRAM_MBCF_SZ_1GB              PPC_REG_VAL(19, 0x8)
+#define SDRAM_MBCF_SZ_2GB              PPC_REG_VAL(19, 0x9)
+#define SDRAM_MBCF_SZ_4GB              PPC_REG_VAL(19, 0xA)
+#define SDRAM_MBCF_SZ_8GB              PPC_REG_VAL(19, 0xB)
+#define SDRAM_MBCF_AM_MASK             PPC_REG_VAL(23, 0xF)
+#define SDRAM_MBCF_AM_MODE0            PPC_REG_VAL(23, 0x0)
+#define SDRAM_MBCF_AM_MODE1            PPC_REG_VAL(23, 0x1)
+#define SDRAM_MBCF_AM_MODE2            PPC_REG_VAL(23, 0x2)
+#define SDRAM_MBCF_AM_MODE3            PPC_REG_VAL(23, 0x3)
+#define SDRAM_MBCF_AM_MODE4            PPC_REG_VAL(23, 0x4)
+#define SDRAM_MBCF_AM_MODE5            PPC_REG_VAL(23, 0x5)
+#define SDRAM_MBCF_AM_MODE6            PPC_REG_VAL(23, 0x6)
+#define SDRAM_MBCF_AM_MODE7            PPC_REG_VAL(23, 0x7)
+#define SDRAM_MBCF_AM_MODE8            PPC_REG_VAL(23, 0x8)
+#define SDRAM_MBCF_AM_MODE9            PPC_REG_VAL(23, 0x9)
+#define SDRAM_MBCF_BE_MASK             PPC_REG_VAL(31, 0x1)
+#define SDRAM_MBCF_BE_DISABLE          PPC_REG_VAL(31, 0x0)
+#define SDRAM_MBCF_BE_ENABLE           PPC_REG_VAL(31, 0x1)
+
+/*
+ * ECC Error Status
+ */
+#define SDRAM_ECCES_MASK               PPC_REG_VAL(21, 0x3FFFFF)
+#define SDRAM_ECCES_BNCE_MASK          PPC_REG_VAL(15, 0xFFFF)
+#define SDRAM_ECCES_BNCE_ENCODE(lane)  PPC_REG_VAL(((lane) & 0xF), 1)
+#define SDRAM_ECCES_CKBER_MASK         PPC_REG_VAL(17, 0x3)
+#define SDRAM_ECCES_CKBER_NONE         PPC_REG_VAL(17, 0)
+#define SDRAM_ECCES_CKBER_16_ECC_0_3   PPC_REG_VAL(17, 2)
+#define SDRAM_ECCES_CKBER_32_ECC_0_3   PPC_REG_VAL(17, 1)
+#define SDRAM_ECCES_CKBER_32_ECC_4_8   PPC_REG_VAL(17, 2)
+#define SDRAM_ECCES_CKBER_32_ECC_0_8   PPC_REG_VAL(17, 3)
+#define SDRAM_ECCES_CE                 PPC_REG_VAL(18, 1)
+#define SDRAM_ECCES_UE                 PPC_REG_VAL(19, 1)
+#define SDRAM_ECCES_BKNER_MASK         PPC_REG_VAL(21, 0x3)
+#define SDRAM_ECCES_BK0ER              PPC_REG_VAL(20, 1)
+#define SDRAM_ECCES_BK1ER              PPC_REG_VAL(21, 1)
+
+#endif /* __PPC4XX_EDAC_H */
index 8f0f7c44930540aa6829fdbe92b085d7c4009a46..5f1b5400d96abf6cd741165ffc9bfcf1d781406e 100644 (file)
@@ -68,7 +68,8 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
  *     pointing to completely the wrong place for example
  */
 static void dmi_table(u8 *buf, int len, int num,
-                     void (*decode)(const struct dmi_header *))
+                     void (*decode)(const struct dmi_header *, void *),
+                     void *private_data)
 {
        u8 *data = buf;
        int i = 0;
@@ -89,7 +90,7 @@ static void dmi_table(u8 *buf, int len, int num,
                while ((data - buf < len - 1) && (data[0] || data[1]))
                        data++;
                if (data - buf < len - 1)
-                       decode(dm);
+                       decode(dm, private_data);
                data += 2;
                i++;
        }
@@ -99,7 +100,8 @@ static u32 dmi_base;
 static u16 dmi_len;
 static u16 dmi_num;
 
-static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
+static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
+               void *))
 {
        u8 *buf;
 
@@ -107,7 +109,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
        if (buf == NULL)
                return -1;
 
-       dmi_table(buf, dmi_len, dmi_num, decode);
+       dmi_table(buf, dmi_len, dmi_num, decode, NULL);
 
        dmi_iounmap(buf, dmi_len);
        return 0;
@@ -295,7 +297,7 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
  *     and machine entries. For 2.5 we should pull the smbus controller info
  *     out of here.
  */
-static void __init dmi_decode(const struct dmi_header *dm)
+static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
 {
        switch(dm->type) {
        case 0:         /* BIOS Information */
@@ -598,10 +600,12 @@ int dmi_get_year(int field)
 /**
  *     dmi_walk - Walk the DMI table and get called back for every record
  *     @decode: Callback function
+ *     @private_data: Private data to be passed to the callback function
  *
  *     Returns -1 when the DMI table can't be reached, 0 on success.
  */
-int dmi_walk(void (*decode)(const struct dmi_header *))
+int dmi_walk(void (*decode)(const struct dmi_header *, void *),
+            void *private_data)
 {
        u8 *buf;
 
@@ -612,7 +616,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *))
        if (buf == NULL)
                return -1;
 
-       dmi_table(buf, dmi_len, dmi_num, decode);
+       dmi_table(buf, dmi_len, dmi_num, decode, private_data);
 
        iounmap(buf);
        return 0;
index 3d2565441b3691786c373a2ef49922aa743de737..edb02530e461af4f91e442cdd581f91aa934c588 100644 (file)
@@ -42,9 +42,9 @@ config DEBUG_GPIO
        depends on DEBUG_KERNEL
        help
          Say Y here to add some extra checks and diagnostics to GPIO calls.
-         The checks help ensure that GPIOs have been properly initialized
-         before they are used and that sleeping calls aren not made from
-         nonsleeping contexts.  They can make bitbanged serial protocols
+         These checks help ensure that GPIOs have been properly initialized
+         before they are used, and that sleeping calls are not made from
+         non-sleeping contexts.  They can make bitbanged serial protocols
          slower.  The diagnostics help catch the type of setup errors
          that are most common when setting up new platforms or boards.
 
index 42fb2fd24c0c03cd20b21dab5038fde07d3be30c..51a8d4103be53beb3dd90bd1328d89935cf6573c 100644 (file)
@@ -69,20 +69,24 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
  * those calls have no teeth) we can't avoid autorequesting.  This nag
  * message should motivate switching to explicit requests... so should
  * the weaker cleanup after faults, compared to gpio_request().
+ *
+ * NOTE: the autorequest mechanism is going away; at this point it's
+ * only "legal" in the sense that (old) code using it won't break yet,
+ * but instead only triggers a WARN() stack dump.
  */
 static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
 {
-       if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
-               struct gpio_chip *chip = desc->chip;
-               int gpio = chip->base + offset;
+       const struct gpio_chip *chip = desc->chip;
+       const int gpio = chip->base + offset;
 
+       if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
+                       "autorequest GPIO-%d\n", gpio)) {
                if (!try_module_get(chip->owner)) {
                        pr_err("GPIO-%d: module can't be gotten \n", gpio);
                        clear_bit(FLAG_REQUESTED, &desc->flags);
                        /* lose */
                        return -EIO;
                }
-               pr_warning("GPIO-%d autorequested\n", gpio);
                desc_set_label(desc, "[auto]");
                /* caller must chip->request() w/o spinlock */
                if (chip->request)
@@ -438,6 +442,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
        unsigned long           flags;
        struct gpio_desc        *desc;
        int                     status = -EINVAL;
+       char                    *ioname = NULL;
 
        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
@@ -461,11 +466,14 @@ int gpio_export(unsigned gpio, bool direction_may_change)
        }
        spin_unlock_irqrestore(&gpio_lock, flags);
 
+       if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
+               ioname = desc->chip->names[gpio - desc->chip->base];
+
        if (status == 0) {
                struct device   *dev;
 
                dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                                       desc, "gpio%d", gpio);
+                                   desc, ioname ? ioname : "gpio%d", gpio);
                if (dev) {
                        if (direction_may_change)
                                status = sysfs_create_group(&dev->kobj,
@@ -513,6 +521,7 @@ void gpio_unexport(unsigned gpio)
        mutex_lock(&sysfs_lock);
 
        desc = &gpio_desc[gpio];
+
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
                struct device   *dev = NULL;
 
index 1c3a8c5571408a6f0a698a53b58f93f6f471a9a9..a04639dc633dcbed29b950e660deab8b37ba8cea 100644 (file)
@@ -42,6 +42,26 @@ static struct drm_display_mode std_modes[] = {
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 };
 
+static void drm_mode_validate_flag(struct drm_connector *connector,
+                                  int flags)
+{
+       struct drm_display_mode *mode, *t;
+
+       if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
+               return;
+
+       list_for_each_entry_safe(mode, t, &connector->modes, head) {
+               if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
+                               !(flags & DRM_MODE_FLAG_INTERLACE))
+                       mode->status = MODE_NO_INTERLACE;
+               if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
+                               !(flags & DRM_MODE_FLAG_DBLSCAN))
+                       mode->status = MODE_NO_DBLESCAN;
+       }
+
+       return;
+}
+
 /**
  * drm_helper_probe_connector_modes - get complete set of display modes
  * @dev: DRM device
@@ -72,6 +92,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
        struct drm_connector_helper_funcs *connector_funcs =
                connector->helper_private;
        int count = 0;
+       int mode_flags = 0;
 
        DRM_DEBUG("%s\n", drm_get_connector_name(connector));
        /* set all modes to the unverified state */
@@ -96,6 +117,13 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
        if (maxX && maxY)
                drm_mode_validate_size(dev, &connector->modes, maxX,
                                       maxY, 0);
+
+       if (connector->interlace_allowed)
+               mode_flags |= DRM_MODE_FLAG_INTERLACE;
+       if (connector->doublescan_allowed)
+               mode_flags |= DRM_MODE_FLAG_DBLSCAN;
+       drm_mode_validate_flag(connector, mode_flags);
+
        list_for_each_entry_safe(mode, t, &connector->modes, head) {
                if (mode->status == MODE_OK)
                        mode->status = connector_funcs->mode_valid(connector,
@@ -885,7 +913,6 @@ bool drm_helper_plugged_event(struct drm_device *dev)
 /**
  * drm_initial_config - setup a sane initial connector configuration
  * @dev: DRM device
- * @can_grow: this configuration is growable
  *
  * LOCKING:
  * Called at init time, must take mode config lock.
@@ -897,7 +924,7 @@ bool drm_helper_plugged_event(struct drm_device *dev)
  * RETURNS:
  * Zero if everything went ok, nonzero otherwise.
  */
-bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
+bool drm_helper_initial_config(struct drm_device *dev)
 {
        struct drm_connector *connector;
        int count = 0;
index c67400067b8573c9be015391601152dc4acd6f90..ca9c61656714b3da8ef3d76938c622e28aa3af13 100644 (file)
@@ -125,10 +125,8 @@ static bool edid_is_valid(struct edid *edid)
                DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
                goto bad;
        }
-       if (edid->revision > 3) {
-               DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision);
-               goto bad;
-       }
+       if (edid->revision > 4)
+               DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
 
        for (i = 0; i < EDID_LENGTH; i++)
                csum += raw_edid[i];
@@ -162,7 +160,7 @@ static bool edid_vendor(struct edid *edid, char *vendor)
        edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@';
        edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) |
                          ((edid->mfg_id[1] & 0xe0) >> 5)) + '@';
-       edid_vendor[2] = (edid->mfg_id[2] & 0x1f) + '@';
+       edid_vendor[2] = (edid->mfg_id[1] & 0x1f) + '@';
 
        return !strncmp(edid_vendor, vendor, 3);
 }
index c1173d8c4588fbe4fed12152b5345f4f6911c9b4..4984aa89cf3ddb5e805f3f2f0a6f628d211ea895 100644 (file)
@@ -505,7 +505,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        struct drm_local_map *map = NULL;
        struct drm_gem_object *obj;
        struct drm_hash_item *hash;
-       unsigned long prot;
        int ret = 0;
 
        mutex_lock(&dev->struct_mutex);
@@ -538,11 +537,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        vma->vm_ops = obj->dev->driver->gem_vm_ops;
        vma->vm_private_data = map->handle;
        /* FIXME: use pgprot_writecombine when available */
-       prot = pgprot_val(vma->vm_page_prot);
-#ifdef CONFIG_X86
-       prot |= _PAGE_CACHE_WC;
-#endif
-       vma->vm_page_prot = __pgprot(prot);
+       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
        /* Take a ref for this mapping of the object, so that the fault
         * handler can dereference the mmap offset's pointer to the object.
index 5de573a981cb19d5da7789270bfd0b05bdf8006f..bc0c6849360cd378d8129a7a362c4d3b176392a4 100644 (file)
@@ -451,6 +451,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
 
        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
 }
+EXPORT_SYMBOL(drm_sysfs_hotplug_event);
 
 /**
  * drm_sysfs_device_add - adds a class device to sysfs for a character driver
index 85549f615b1f23560f78831c550c3d1747a4358f..c23b3a95b7cee3fcc7429e14cbe5d286b0b0d4ff 100644 (file)
@@ -922,7 +922,7 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
         * Some of the preallocated space is taken by the GTT
         * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
         */
-       if (IS_G4X(dev))
+       if (IS_G4X(dev) || IS_IGD(dev))
                overhead = 4096;
        else
                overhead = (*aperture_size / 1024) + 4096;
@@ -1030,13 +1030,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto destroy_ringbuffer;
 
-       /* FIXME: re-add hotplug support */
-#if 0
-       ret = drm_hotplug_init(dev);
-       if (ret)
-               goto destroy_ringbuffer;
-#endif
-
        /* Always safe in the mode setting case. */
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = 1;
@@ -1049,7 +1042,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        intel_modeset_init(dev);
 
-       drm_helper_initial_config(dev, false);
+       drm_helper_initial_config(dev);
 
        return 0;
 
index c1685d0c704faa540c78990400c65a184a8d65a7..317b1223e091c134bba16913fc7aa441710cd841 100644 (file)
@@ -159,6 +159,9 @@ typedef struct drm_i915_private {
        u32 irq_mask_reg;
        u32 pipestat[2];
 
+       u32 hotplug_supported_mask;
+       struct work_struct hotplug_work;
+
        int tex_lru_log_granularity;
        int allow_batchbuffer;
        struct mem_block *agp_heap;
@@ -297,6 +300,7 @@ typedef struct drm_i915_private {
                 *
                 * A reference is held on the buffer while on this list.
                 */
+               spinlock_t active_list_lock;
                struct list_head active_list;
 
                /**
@@ -810,6 +814,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
                                                      IS_I915GM(dev)))
 #define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev))
+#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
index e0389ad1477d22f48d24931509fd522f4ac1b6ff..1449b452cc63c0b92cd7039905f4ccdce31ba494 100644 (file)
@@ -1072,6 +1072,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        case -EAGAIN:
                return VM_FAULT_OOM;
        case -EFAULT:
+       case -EINVAL:
                return VM_FAULT_SIGBUS;
        default:
                return VM_FAULT_NOPAGE;
@@ -1324,8 +1325,10 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno)
                obj_priv->active = 1;
        }
        /* Move from whatever list we were on to the tail of execution. */
+       spin_lock(&dev_priv->mm.active_list_lock);
        list_move_tail(&obj_priv->list,
                       &dev_priv->mm.active_list);
+       spin_unlock(&dev_priv->mm.active_list_lock);
        obj_priv->last_rendering_seqno = seqno;
 }
 
@@ -1467,6 +1470,7 @@ i915_gem_retire_request(struct drm_device *dev,
        /* Move any buffers on the active list that are no longer referenced
         * by the ringbuffer to the flushing/inactive lists as appropriate.
         */
+       spin_lock(&dev_priv->mm.active_list_lock);
        while (!list_empty(&dev_priv->mm.active_list)) {
                struct drm_gem_object *obj;
                struct drm_i915_gem_object *obj_priv;
@@ -1481,7 +1485,7 @@ i915_gem_retire_request(struct drm_device *dev,
                 * this seqno.
                 */
                if (obj_priv->last_rendering_seqno != request->seqno)
-                       return;
+                       goto out;
 
 #if WATCH_LRU
                DRM_INFO("%s: retire %d moves to inactive list %p\n",
@@ -1493,6 +1497,8 @@ i915_gem_retire_request(struct drm_device *dev,
                else
                        i915_gem_object_move_to_inactive(obj);
        }
+out:
+       spin_unlock(&dev_priv->mm.active_list_lock);
 }
 
 /**
@@ -1990,20 +1996,23 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
        int regnum = obj_priv->fence_reg;
        uint32_t val;
        uint32_t pitch_val;
+       uint32_t fence_size_bits;
 
-       if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
+       if ((obj_priv->gtt_offset & ~I830_FENCE_START_MASK) ||
            (obj_priv->gtt_offset & (obj->size - 1))) {
-               WARN(1, "%s: object 0x%08x not 1M or size aligned\n",
+               WARN(1, "%s: object 0x%08x not 512K or size aligned\n",
                     __func__, obj_priv->gtt_offset);
                return;
        }
 
        pitch_val = (obj_priv->stride / 128) - 1;
-
+       WARN_ON(pitch_val & ~0x0000000f);
        val = obj_priv->gtt_offset;
        if (obj_priv->tiling_mode == I915_TILING_Y)
                val |= 1 << I830_FENCE_TILING_Y_SHIFT;
-       val |= I830_FENCE_SIZE_BITS(obj->size);
+       fence_size_bits = I830_FENCE_SIZE_BITS(obj->size);
+       WARN_ON(fence_size_bits & ~0x00000f00);
+       val |= fence_size_bits;
        val |= pitch_val << I830_FENCE_PITCH_SHIFT;
        val |= I830_FENCE_REG_VALID;
 
@@ -2194,7 +2203,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                return -EBUSY;
        if (alignment == 0)
                alignment = i915_gem_get_gtt_alignment(obj);
-       if (alignment & (PAGE_SIZE - 1)) {
+       if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) {
                DRM_ERROR("Invalid object alignment requested %u\n", alignment);
                return -EINVAL;
        }
@@ -2211,15 +2220,20 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                }
        }
        if (obj_priv->gtt_space == NULL) {
+               bool lists_empty;
+
                /* If the gtt is empty and we're still having trouble
                 * fitting our object in, we're out of memory.
                 */
 #if WATCH_LRU
                DRM_INFO("%s: GTT full, evicting something\n", __func__);
 #endif
-               if (list_empty(&dev_priv->mm.inactive_list) &&
-                   list_empty(&dev_priv->mm.flushing_list) &&
-                   list_empty(&dev_priv->mm.active_list)) {
+               spin_lock(&dev_priv->mm.active_list_lock);
+               lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
+                              list_empty(&dev_priv->mm.flushing_list) &&
+                              list_empty(&dev_priv->mm.active_list));
+               spin_unlock(&dev_priv->mm.active_list_lock);
+               if (lists_empty) {
                        DRM_ERROR("GTT full, but LRU list empty\n");
                        return -ENOMEM;
                }
@@ -3675,6 +3689,7 @@ i915_gem_idle(struct drm_device *dev)
 
        i915_gem_retire_requests(dev);
 
+       spin_lock(&dev_priv->mm.active_list_lock);
        if (!dev_priv->mm.wedged) {
                /* Active and flushing should now be empty as we've
                 * waited for a sequence higher than any pending execbuffer
@@ -3701,6 +3716,7 @@ i915_gem_idle(struct drm_device *dev)
                obj_priv->obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
                i915_gem_object_move_to_inactive(obj_priv->obj);
        }
+       spin_unlock(&dev_priv->mm.active_list_lock);
 
        while (!list_empty(&dev_priv->mm.flushing_list)) {
                struct drm_i915_gem_object *obj_priv;
@@ -3949,7 +3965,10 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
        if (ret != 0)
                return ret;
 
+       spin_lock(&dev_priv->mm.active_list_lock);
        BUG_ON(!list_empty(&dev_priv->mm.active_list));
+       spin_unlock(&dev_priv->mm.active_list_lock);
+
        BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
        BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
        BUG_ON(!list_empty(&dev_priv->mm.request_list));
@@ -3993,6 +4012,7 @@ i915_gem_load(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
 
+       spin_lock_init(&dev_priv->mm.active_list_lock);
        INIT_LIST_HEAD(&dev_priv->mm.active_list);
        INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
        INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
index 131c088f8c8a0ef3193d450cd0034b4406365de6..8d0b943e2c5aced503603a5848e291ea0a0c9694 100644 (file)
@@ -105,12 +105,14 @@ i915_dump_lru(struct drm_device *dev, const char *where)
        struct drm_i915_gem_object      *obj_priv;
 
        DRM_INFO("active list %s {\n", where);
+       spin_lock(&dev_priv->mm.active_list_lock);
        list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
                            list)
        {
                DRM_INFO("    %p: %08x\n", obj_priv,
                         obj_priv->last_rendering_seqno);
        }
+       spin_unlock(&dev_priv->mm.active_list_lock);
        DRM_INFO("}\n");
        DRM_INFO("flushing list %s {\n", where);
        list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
index 455ec970b3854e64c38eace44e1d78bca9fe7db1..a1ac0c5e7307282a00fc859a240f5c4bf2c3dcca 100644 (file)
@@ -69,10 +69,13 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv;
+       spinlock_t *lock = NULL;
 
        switch (list) {
        case ACTIVE_LIST:
                seq_printf(m, "Active:\n");
+               lock = &dev_priv->mm.active_list_lock;
+               spin_lock(lock);
                head = &dev_priv->mm.active_list;
                break;
        case INACTIVE_LIST:
@@ -104,6 +107,9 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
                        seq_printf(m, " (fence: %d\n", obj_priv->fence_reg);
                seq_printf(m, "\n");
        }
+
+       if (lock)
+           spin_unlock(lock);
        return 0;
 }
 
index 4cce1aef438e9fc06ed357ccc0c5520b0e9fde27..6be3f927c86a78b9a4e85afbfc8abc48a2619d1b 100644 (file)
@@ -216,6 +216,22 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        else
                tile_width = 512;
 
+       /* check maximum stride & object size */
+       if (IS_I965G(dev)) {
+               /* i965 stores the end address of the gtt mapping in the fence
+                * reg, so dont bother to check the size */
+               if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
+                       return false;
+       } else if (IS_I9XX(dev)) {
+               if (stride / tile_width > I830_FENCE_MAX_PITCH_VAL ||
+                   size > (I830_FENCE_MAX_SIZE_VAL << 20))
+                       return false;
+       } else {
+               if (stride / 128 > I830_FENCE_MAX_PITCH_VAL ||
+                   size > (I830_FENCE_MAX_SIZE_VAL << 19))
+                       return false;
+       }
+
        /* 965+ just needs multiples of tile width */
        if (IS_I965G(dev)) {
                if (stride & (tile_width - 1))
index 87b6b603469ea278780af278fb9b7dc92d013ed0..ee7ce7b78cf79b9dd0d18033866c83fd2d060d1e 100644 (file)
 /** Interrupts that we mask and unmask at runtime. */
 #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
 
-/** These are all of the interrupts used by the driver */
-#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
-                                   I915_INTERRUPT_ENABLE_VAR)
-
 #define I915_PIPE_VBLANK_STATUS        (PIPE_START_VBLANK_INTERRUPT_STATUS |\
                                 PIPE_VBLANK_INTERRUPT_STATUS)
 
@@ -187,6 +183,19 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
        return I915_READ(reg);
 }
 
+/*
+ * Handle hotplug events outside the interrupt handler proper.
+ */
+static void i915_hotplug_work_func(struct work_struct *work)
+{
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   hotplug_work);
+       struct drm_device *dev = dev_priv->dev;
+
+       /* Just fire off a uevent and let userspace tell us what to do */
+       drm_sysfs_hotplug_event(dev);
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -244,6 +253,20 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
                ret = IRQ_HANDLED;
 
+               /* Consume port.  Then clear IIR or we'll miss events */
+               if ((I915_HAS_HOTPLUG(dev)) &&
+                   (iir & I915_DISPLAY_PORT_INTERRUPT)) {
+                       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+
+                       DRM_DEBUG("hotplug event received, stat 0x%08x\n",
+                                 hotplug_status);
+                       if (hotplug_status & dev_priv->hotplug_supported_mask)
+                               schedule_work(&dev_priv->hotplug_work);
+
+                       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
+                       I915_READ(PORT_HOTPLUG_STAT);
+               }
+
                I915_WRITE(IIR, iir);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
@@ -528,17 +551,24 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
 
        atomic_set(&dev_priv->irq_received, 0);
 
+       if (I915_HAS_HOTPLUG(dev)) {
+               I915_WRITE(PORT_HOTPLUG_EN, 0);
+               I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+       }
+
        I915_WRITE(HWSTAM, 0xeffe);
        I915_WRITE(PIPEASTAT, 0);
        I915_WRITE(PIPEBSTAT, 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
        (void) I915_READ(IER);
+       INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
 }
 
 int i915_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
 
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
@@ -550,13 +580,35 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        dev_priv->pipestat[0] = 0;
        dev_priv->pipestat[1] = 0;
 
+       if (I915_HAS_HOTPLUG(dev)) {
+               u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+
+               /* Leave other bits alone */
+               hotplug_en |= HOTPLUG_EN_MASK;
+               I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+
+               dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS |
+                       TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS |
+                       SDVOB_HOTPLUG_INT_STATUS;
+               if (IS_G4X(dev)) {
+                       dev_priv->hotplug_supported_mask |=
+                               HDMIB_HOTPLUG_INT_STATUS |
+                               HDMIC_HOTPLUG_INT_STATUS |
+                               HDMID_HOTPLUG_INT_STATUS;
+               }
+               /* Enable in IER... */
+               enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
+               /* and unmask in IMR */
+               i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
+       }
+
        /* Disable pipe interrupt enables, clear pending pipe status */
        I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
        I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
        /* Clear pending interrupt status */
        I915_WRITE(IIR, I915_READ(IIR));
 
-       I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+       I915_WRITE(IER, enable_mask);
        I915_WRITE(IMR, dev_priv->irq_mask_reg);
        (void) I915_READ(IER);
 
@@ -575,6 +627,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
 
        dev_priv->vblank_pipe = 0;
 
+       if (I915_HAS_HOTPLUG(dev)) {
+               I915_WRITE(PORT_HOTPLUG_EN, 0);
+               I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+       }
+
        I915_WRITE(HWSTAM, 0xffffffff);
        I915_WRITE(PIPEASTAT, 0);
        I915_WRITE(PIPEBSTAT, 0);
index 377cc588f5e99d834f4e59aad3a83d7c9e749ef6..e805b590ae71bf2adb31058ea2801e01adafaee2 100644 (file)
 #define   I830_FENCE_SIZE_BITS(size)   ((ffs((size) >> 19) - 1) << 8)
 #define   I830_FENCE_PITCH_SHIFT       4
 #define   I830_FENCE_REG_VALID         (1<<0)
+#define   I830_FENCE_MAX_PITCH_VAL     0x10
+#define   I830_FENCE_MAX_SIZE_VAL      (1<<8)
 
 #define   I915_FENCE_START_MASK                0x0ff00000
 #define   I915_FENCE_SIZE_BITS(size)   ((ffs((size) >> 20) - 1) << 8)
 #define   I965_FENCE_PITCH_SHIFT       2
 #define   I965_FENCE_TILING_Y_SHIFT    1
 #define   I965_FENCE_REG_VALID         (1<<0)
+#define   I965_FENCE_MAX_PITCH_VAL     0x0400
 
 /*
  * Instruction and interrupt control regs
 #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV       (0 << 2)
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV       (1 << 2)
 #define CRT_HOTPLUG_MASK                       (0x3fc) /* Bits 9-2 */
+#define CRT_FORCE_HOTPLUG_MASK                 0xfffffe1f
+#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \
+                        HDMIC_HOTPLUG_INT_EN |   \
+                        HDMID_HOTPLUG_INT_EN |   \
+                        SDVOB_HOTPLUG_INT_EN |   \
+                        SDVOC_HOTPLUG_INT_EN |   \
+                        TV_HOTPLUG_INT_EN |      \
+                        CRT_HOTPLUG_INT_EN)
 
 
 #define PORT_HOTPLUG_STAT      0x61114
index 2b6d44381c310874926eb9f2e8d55b5b6e91fad8..9bdd959260a542c1c08a7433eb124438eb75a3d2 100644 (file)
@@ -41,7 +41,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
 
        temp = I915_READ(ADPA);
        temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
-       temp &= ~ADPA_DAC_ENABLE;
+       temp |= ADPA_DAC_ENABLE;
 
        switch(mode) {
        case DRM_MODE_DPMS_ON:
@@ -158,7 +158,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
        else
                tries = 1;
        hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-       hotplug_en &= ~(CRT_HOTPLUG_MASK);
+       hotplug_en &= CRT_FORCE_HOTPLUG_MASK;
        hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
 
        if (IS_GM45(dev))
index d9c50ff94d7633d2bb6d166e73793bad1eb6691b..64773ce52964113517d62802a85a1809792558b2 100644 (file)
@@ -636,7 +636,7 @@ void
 intel_wait_for_vblank(struct drm_device *dev)
 {
        /* Wait for 20ms, i.e. one cycle at 50hz. */
-       udelay(20000);
+       mdelay(20);
 }
 
 static int
@@ -1106,6 +1106,26 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       /* SDVO TV has fixed PLL values depend on its clock range,
+          this mirrors vbios setting. */
+       if (is_sdvo && is_tv) {
+               if (adjusted_mode->clock >= 100000
+                               && adjusted_mode->clock < 140500) {
+                       clock.p1 = 2;
+                       clock.p2 = 10;
+                       clock.n = 3;
+                       clock.m1 = 16;
+                       clock.m2 = 8;
+               } else if (adjusted_mode->clock >= 140500
+                               && adjusted_mode->clock <= 200000) {
+                       clock.p1 = 1;
+                       clock.p2 = 10;
+                       clock.n = 6;
+                       clock.m1 = 12;
+                       clock.m2 = 8;
+               }
+       }
+
        if (IS_IGD(dev))
                fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
        else
index e42019e5d6610ee3bdd927a0dd94887a9ba178d8..07d7ec976168e5bf952991927d6815ff91d2bf83 100644 (file)
@@ -76,6 +76,7 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
                drm_mode_connector_update_edid_property(&intel_output->base,
                                                        edid);
                ret = drm_add_edid_modes(&intel_output->base, edid);
+               intel_output->base.display_info.raw_edid = NULL;
                kfree(edid);
        }
 
index fbe6f3931b1b116cb022daa2238ee78d2e7c359c..7b31f55f55c8a9f3b8be5b9eca246bc1ab26075d 100644 (file)
@@ -273,20 +273,20 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        int i;
 
-       DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
+       printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
        for (i = 0; i < args_len; i++)
-               printk("%02X ", ((u8 *)args)[i]);
+               printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]);
        for (; i < 8; i++)
-               printk("   ");
+               printk(KERN_DEBUG "   ");
        for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
                if (cmd == sdvo_cmd_names[i].cmd) {
-                       printk("(%s)", sdvo_cmd_names[i].name);
+                       printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name);
                        break;
                }
        }
        if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
-               printk("(%02X)",cmd);
-       printk("\n");
+               printk(KERN_DEBUG "(%02X)", cmd);
+       printk(KERN_DEBUG "\n");
 }
 #else
 #define intel_sdvo_debug_write(o, c, a, l)
@@ -323,17 +323,18 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output,
                                      u8 status)
 {
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int i;
 
-       DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv));
+       printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv));
        for (i = 0; i < response_len; i++)
-               printk("%02X ", ((u8 *)response)[i]);
+               printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]);
        for (; i < 8; i++)
-               printk("   ");
+               printk(KERN_DEBUG "   ");
        if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-               printk("(%s)", cmd_status_names[status]);
+               printk(KERN_DEBUG "(%s)", cmd_status_names[status]);
        else
-               printk("(??? %d)", status);
-       printk("\n");
+               printk(KERN_DEBUG "(??? %d)", status);
+       printk(KERN_DEBUG "\n");
 }
 #else
 #define intel_sdvo_debug_response(o, r, l, s)
@@ -588,9 +589,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
        struct intel_sdvo_preferred_input_timing_args args;
        uint8_t status;
 
+       memset(&args, 0, sizeof(args));
        args.clock = clock;
        args.width = width;
        args.height = height;
+       args.interlace = 0;
+       args.scaled = 0;
        intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
                             &args, sizeof(args));
        status = intel_sdvo_read_response(output, NULL, 0);
@@ -683,7 +687,7 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
        dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
                ((v_blank_len >> 8) & 0xf);
 
-       dtd->part2.h_sync_off = h_sync_offset;
+       dtd->part2.h_sync_off = h_sync_offset & 0xff;
        dtd->part2.h_sync_width = h_sync_len & 0xff;
        dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
                (v_sync_len & 0xf);
@@ -705,27 +709,10 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
 static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
                                         struct intel_sdvo_dtd *dtd)
 {
-       uint16_t width, height;
-       uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
-       uint16_t h_sync_offset, v_sync_offset;
-
-       width = mode->crtc_hdisplay;
-       height = mode->crtc_vdisplay;
-
-       /* do some mode translations */
-       h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
-       h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
-
-       v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
-       v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
-
-       h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
-       v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
-
        mode->hdisplay = dtd->part1.h_active;
        mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
        mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
-       mode->hsync_start += (dtd->part2.sync_off_width_high & 0xa0) << 2;
+       mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
        mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
        mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
        mode->htotal = mode->hdisplay + dtd->part1.h_blank;
@@ -735,7 +722,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
        mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
        mode->vsync_start = mode->vdisplay;
        mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
-       mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0a) << 2;
+       mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
        mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
        mode->vsync_end = mode->vsync_start +
                (dtd->part2.v_sync_off_width & 0xf);
@@ -745,7 +732,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
 
        mode->clock = dtd->part1.clock * 10;
 
-       mode->flags &= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
+       mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
        if (dtd->part2.dtd_flags & 0x2)
                mode->flags |= DRM_MODE_FLAG_PHSYNC;
        if (dtd->part2.dtd_flags & 0x4)
@@ -924,6 +911,27 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
                                SDVO_HBUF_TX_VSYNC);
 }
 
+static void intel_sdvo_set_tv_format(struct intel_output *output)
+{
+       struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+       struct intel_sdvo_tv_format *format, unset;
+       u8 status;
+
+       format = &sdvo_priv->tv_format;
+       memset(&unset, 0, sizeof(unset));
+       if (memcmp(format, &unset, sizeof(*format))) {
+               DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
+                               SDVO_NAME(sdvo_priv));
+               format->ntsc_m = 1;
+               intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, format,
+                               sizeof(*format));
+               status = intel_sdvo_read_response(output, NULL, 0);
+               if (status != SDVO_CMD_STATUS_SUCCESS)
+                       DRM_DEBUG("%s: Failed to set TV format\n",
+                                       SDVO_NAME(sdvo_priv));
+       }
+}
+
 static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
@@ -968,6 +976,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                                             &input_dtd);
                        intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
 
+                       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+                       mode->clock = adjusted_mode->clock;
+
+                       adjusted_mode->clock *=
+                               intel_sdvo_get_pixel_multiplier(mode);
                } else {
                        return false;
                }
@@ -1012,7 +1026,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                sdvox |= SDVO_AUDIO_ENABLE;
        }
 
-       intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
+       /* We have tried to get input timing in mode_fixup, and filled into
+          adjusted_mode */
+       if (sdvo_priv->is_tv)
+               intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
+       else
+               intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
 
        /* If it's a TV, we already set the output timing in mode_fixup.
         * Otherwise, the output timing is equal to the input timing.
@@ -1027,6 +1046,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        /* Set the input timing to the screen. Assume always input 0. */
        intel_sdvo_set_target_input(output, true, false);
 
+       if (sdvo_priv->is_tv)
+               intel_sdvo_set_tv_format(output);
+
        /* We would like to use intel_sdvo_create_preferred_input_timing() to
         * provide the device with a timing it can support, if it supports that
         * feature.  However, presumably we would need to adjust the CRTC to
@@ -1395,7 +1417,7 @@ static void
 intel_sdvo_check_tv_format(struct intel_output *output)
 {
        struct intel_sdvo_priv *dev_priv = output->dev_priv;
-       struct intel_sdvo_tv_format format, unset;
+       struct intel_sdvo_tv_format format;
        uint8_t status;
 
        intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
@@ -1403,15 +1425,7 @@ intel_sdvo_check_tv_format(struct intel_output *output)
        if (status != SDVO_CMD_STATUS_SUCCESS)
                return;
 
-       memset(&unset, 0, sizeof(unset));
-       if (memcmp(&format, &unset, sizeof(format))) {
-               DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
-                         SDVO_NAME(dev_priv));
-
-               format.ntsc_m = true;
-               intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0);
-               status = intel_sdvo_read_response(output, NULL, 0);
-       }
+       memcpy(&dev_priv->tv_format, &format, sizeof(format));
 }
 
 /*
@@ -1420,68 +1434,70 @@ intel_sdvo_check_tv_format(struct intel_output *output)
  * XXX: all 60Hz refresh?
  */
 struct drm_display_mode sdvo_tv_modes[] = {
-       { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815680, 321, 384, 416,
-                  200, 0, 232, 201, 233, 4196112, 0,
+       { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,
+                  416, 0, 200, 201, 232, 233, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814080, 321, 384, 416,
-                  240, 0, 272, 241, 273, 4196112, 0,
+       { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,
+                  416, 0, 240, 241, 272, 273, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910080, 401, 464, 496,
-                  300, 0, 332, 301, 333, 4196112, 0,
+       { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,
+                  496, 0, 300, 301, 332, 333, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913280, 641, 704, 736,
-                  350, 0, 382, 351, 383, 4196112, 0,
+       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,
+                  736, 0, 350, 351, 382, 383, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
-                  400, 0, 432, 401, 433, 4196112, 0,
+       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,
+                  736, 0, 400, 401, 432, 433, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
-                  400, 0, 432, 401, 433, 4196112, 0,
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,
+                  736, 0, 480, 481, 512, 513, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624000, 705, 768, 800,
-                  480, 0, 512, 481, 513, 4196112, 0,
+       { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,
+                  800, 0, 480, 481, 512, 513, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232000, 705, 768, 800,
-                  576, 0, 608, 577, 609, 4196112, 0,
+       { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,
+                  800, 0, 576, 577, 608, 609, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751680, 721, 784, 816,
-                  350, 0, 382, 351, 383, 4196112, 0,
+       { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,
+                  816, 0, 350, 351, 382, 383, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199680, 721, 784, 816,
-                  400, 0, 432, 401, 433, 4196112, 0,
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,
+                  816, 0, 400, 401, 432, 433, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116480, 721, 784, 816,
-                  480, 0, 512, 481, 513, 4196112, 0,
+       { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,
+                  816, 0, 480, 481, 512, 513, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054080, 721, 784, 816,
-                  540, 0, 572, 541, 573, 4196112, 0,
+       { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,
+                  816, 0, 540, 541, 572, 573, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816640, 721, 784, 816,
-                  576, 0, 608, 577, 609, 4196112, 0,
+       { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,
+                  816, 0, 576, 577, 608, 609, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570560, 769, 832, 864,
-                  576, 0, 608, 577, 609, 4196112, 0,
+       { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,
+                  864, 0, 576, 577, 608, 609, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030080, 801, 864, 896,
-                  600, 0, 632, 601, 633, 4196112, 0,
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,
+                  896, 0, 600, 601, 632, 633, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581760, 833, 896, 928,
-                  624, 0, 656, 625, 657, 4196112, 0,
+       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,
+                  928, 0, 624, 625, 656, 657, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707040, 921, 984, 1016,
-                  766, 0, 798, 767, 799, 4196112, 0,
+       { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,
+                  1016, 0, 766, 767, 798, 799, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827200, 1025, 1088, 1120,
-                  768, 0, 800, 769, 801, 4196112, 0,
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,
+                  1120, 0, 768, 769, 800, 801, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265920, 1281, 1344, 1376,
-                  1024, 0, 1056, 1025, 1057, 4196112, 0,
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,
+                  1376, 0, 1024, 1025, 1056, 1057, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 };
 
 static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
        struct intel_output *output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+       struct intel_sdvo_sdtv_resolution_request tv_res;
        uint32_t reply = 0;
        uint8_t status;
        int i = 0;
@@ -1491,15 +1507,22 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
        /* Read the list of supported input resolutions for the selected TV
         * format.
         */
+       memset(&tv_res, 0, sizeof(tv_res));
+       memcpy(&tv_res, &sdvo_priv->tv_format, sizeof(tv_res));
        intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
-                            NULL, 0);
+                            &tv_res, sizeof(tv_res));
        status = intel_sdvo_read_response(output, &reply, 3);
        if (status != SDVO_CMD_STATUS_SUCCESS)
                return;
 
        for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
-               if (reply & (1 << i))
-                       drm_mode_probed_add(connector, &sdvo_tv_modes[i]);
+               if (reply & (1 << i)) {
+                       struct drm_display_mode *nmode;
+                       nmode = drm_mode_duplicate(connector->dev,
+                                       &sdvo_tv_modes[i]);
+                       if (nmode)
+                               drm_mode_probed_add(connector, nmode);
+               }
 }
 
 static int intel_sdvo_get_modes(struct drm_connector *connector)
index 1117b9c151a671d655779331dea38164f7508dd4..193938b7d7f9ea3cce94188fb733a15990282040 100644 (file)
@@ -100,6 +100,9 @@ struct intel_sdvo_preferred_input_timing_args {
     u16 clock;
     u16 width;
     u16 height;
+    u8 interlace:1;
+    u8 scaled:1;
+    u8 pad:6;
 } __attribute__((packed));
 
 /* I2C registers for SDVO */
index ceca9471a75a2df08780e395c024d0a84fe587a4..d2c32983242dcda215d17badc211378711ed9750 100644 (file)
@@ -1570,33 +1570,49 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
        struct drm_device *dev = connector->dev;
        struct intel_output *intel_output = to_intel_output(connector);
        struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_crtc *crtc = encoder->crtc;
        int ret = 0;
+       bool changed = false;
 
        ret = drm_connector_property_set_value(connector, property, val);
        if (ret < 0)
                goto out;
 
-       if (property == dev->mode_config.tv_left_margin_property)
+       if (property == dev->mode_config.tv_left_margin_property &&
+               tv_priv->margin[TV_MARGIN_LEFT] != val) {
                tv_priv->margin[TV_MARGIN_LEFT] = val;
-       else if (property == dev->mode_config.tv_right_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_right_margin_property &&
+               tv_priv->margin[TV_MARGIN_RIGHT] != val) {
                tv_priv->margin[TV_MARGIN_RIGHT] = val;
-       else if (property == dev->mode_config.tv_top_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_top_margin_property &&
+               tv_priv->margin[TV_MARGIN_TOP] != val) {
                tv_priv->margin[TV_MARGIN_TOP] = val;
-       else if (property == dev->mode_config.tv_bottom_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_bottom_margin_property &&
+               tv_priv->margin[TV_MARGIN_BOTTOM] != val) {
                tv_priv->margin[TV_MARGIN_BOTTOM] = val;
-       else if (property == dev->mode_config.tv_mode_property) {
+               changed = true;
+       } else if (property == dev->mode_config.tv_mode_property) {
                if (val >= NUM_TV_MODES) {
                        ret = -EINVAL;
                        goto out;
                }
+               if (!strcmp(tv_priv->tv_format, tv_modes[val].name))
+                       goto out;
+
                tv_priv->tv_format = tv_modes[val].name;
-               intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+               changed = true;
        } else {
                ret = -EINVAL;
                goto out;
        }
 
-       intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+       if (changed && crtc)
+               drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+                               crtc->y, crtc->fb);
 out:
        return ret;
 }
index 9d14eee3ed092e52e82b7c05aa20c2e30502f237..bc9d09dfa8e7de7063ebea70c6371d0cecf89a9d 100644 (file)
@@ -388,17 +388,17 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)
                DRM_INFO("Loading RS780 CP Microcode\n");
                for (i = 0; i < PM4_UCODE_SIZE; i++) {
                        RADEON_WRITE(R600_CP_ME_RAM_DATA,
-                                    RV670_cp_microcode[i][0]);
+                                    RS780_cp_microcode[i][0]);
                        RADEON_WRITE(R600_CP_ME_RAM_DATA,
-                                    RV670_cp_microcode[i][1]);
+                                    RS780_cp_microcode[i][1]);
                        RADEON_WRITE(R600_CP_ME_RAM_DATA,
-                                    RV670_cp_microcode[i][2]);
+                                    RS780_cp_microcode[i][2]);
                }
 
                RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
                DRM_INFO("Loading RS780 PFP Microcode\n");
                for (i = 0; i < PFP_UCODE_SIZE; i++)
-                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV670_pfp_microcode[i]);
+                       RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RS780_pfp_microcode[i]);
        }
        RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
        RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
index e85c8fe9ffcfd9df88f824503af6c105bebb048f..7e67dcb3d4f657d4bab800b8390b4af976b4554d 100644 (file)
@@ -29,11 +29,11 @@ config HID
 
          For docs and specs, see http://www.usb.org/developers/hidpage/
 
-         If unsure, say Y
+         If unsure, say Y.
 
 config HID_DEBUG
        bool "HID debugging support"
-       default y if !EMBEDDED
+       default y
        depends on HID
        ---help---
        This option lets the HID layer output diagnostics about its internal
@@ -44,7 +44,7 @@ config HID_DEBUG
        This feature is useful for those who are either debugging the HID parser
        or any HID hardware device.
 
-       If unsure, say N
+       If unsure, say Y.
 
 config HIDRAW
        bool "/dev/hidraw raw HID device support"
@@ -70,18 +70,6 @@ source "drivers/hid/usbhid/Kconfig"
 menu "Special HID drivers"
        depends on HID
 
-config HID_COMPAT
-       bool "Load all HID drivers on hid core load"
-       default y
-       ---help---
-       Compatible option for older userspace. If you have system without udev
-       support of module loading through aliases and also old
-       module-init-tools which can't handle hid bus, choose Y here. Otherwise
-       say N. If you say N and your userspace is old enough, the only
-       functionality you lose is modules autoloading.
-
-       If unsure, say Y.
-
 config HID_A4TECH
        tristate "A4 tech" if EMBEDDED
        depends on USB_HID
@@ -128,6 +116,14 @@ config HID_CYPRESS
        ---help---
        Support for cypress mouse and barcode readers.
 
+config DRAGONRISE_FF
+       tristate "DragonRise Inc. force feedback support"
+       depends on USB_HID
+       select INPUT_FF_MEMLESS
+       ---help---
+       Say Y here if you want to enable force feedback support for DragonRise Inc.
+       game controllers.
+
 config HID_EZKEY
        tristate "Ezkey" if EMBEDDED
        depends on USB_HID
@@ -135,6 +131,13 @@ config HID_EZKEY
        ---help---
        Support for Ezkey BTC 8193 keyboard.
 
+config HID_KYE
+       tristate "Kye" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Support for Kye/Genius Ergo Mouse.
+
 config HID_GYRATION
        tristate "Gyration" if EMBEDDED
        depends on USB_HID
@@ -142,6 +145,13 @@ config HID_GYRATION
        ---help---
        Support for Gyration remote control.
 
+config HID_KENSINGTON
+       tristate "Kensington" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Support for Kensington Slimblade Trackball.
+
 config HID_LOGITECH
        tristate "Logitech" if EMBEDDED
        depends on USB_HID
@@ -243,7 +253,7 @@ config GREENASIA_FF
        select INPUT_FF_MEMLESS
        ---help---
        Say Y here if you have a GreenAsia (Product ID 0x12) based game controller
-       (like MANTA Warior MM816 and SpeedLink Strike2 SL-6635) or adapter
+       (like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter
        and want to enable force feedback support for it.
 
 config HID_TOPSEED
index fbd021f153f1a3642abde8a327c5e6a6ee6d633e..1f7cb0fd4505c3e82aa3d521e35a01dac124f88c 100644 (file)
@@ -8,10 +8,6 @@ obj-$(CONFIG_HID)              += hid.o
 hid-$(CONFIG_HID_DEBUG)                += hid-debug.o
 hid-$(CONFIG_HIDRAW)           += hidraw.o
 
-ifdef CONFIG_HID_COMPAT
-obj-m                          += hid-dummy.o
-endif
-
 hid-logitech-objs              := hid-lg.o
 ifdef CONFIG_LOGITECH_FF
        hid-logitech-objs       += hid-lgff.o
@@ -26,8 +22,11 @@ obj-$(CONFIG_HID_BELKIN)     += hid-belkin.o
 obj-$(CONFIG_HID_CHERRY)       += hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
 obj-$(CONFIG_HID_CYPRESS)      += hid-cypress.o
+obj-$(CONFIG_DRAGONRISE_FF)    += hid-drff.o
 obj-$(CONFIG_HID_EZKEY)                += hid-ezkey.o
 obj-$(CONFIG_HID_GYRATION)     += hid-gyration.o
+obj-$(CONFIG_HID_KENSINGTON)   += hid-kensington.o
+obj-$(CONFIG_HID_KYE)          += hid-kye.o
 obj-$(CONFIG_HID_LOGITECH)     += hid-logitech.o
 obj-$(CONFIG_HID_MICROSOFT)    += hid-microsoft.o
 obj-$(CONFIG_HID_MONTEREY)     += hid-monterey.o
index ebca00e6c103f742b22a9044d9d057ef456487c3..42ea359e94cffcb4b2fe626664fc9e671e870848 100644 (file)
@@ -158,5 +158,3 @@ static void a4_exit(void)
 module_init(a4_init);
 module_exit(a4_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(a4tech);
index aa28aed0e46cb4d400cdd8f419cfbb8cedefa877..7359d9d88e4683d5fee89c8599d4b22ea2b508f6 100644 (file)
@@ -53,7 +53,7 @@ struct apple_key_translation {
        u8 flags;
 };
 
-static struct apple_key_translation apple_fn_keys[] = {
+static const struct apple_key_translation apple_fn_keys[] = {
        { KEY_BACKSPACE, KEY_DELETE },
        { KEY_ENTER,    KEY_INSERT },
        { KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
@@ -75,7 +75,7 @@ static struct apple_key_translation apple_fn_keys[] = {
        { }
 };
 
-static struct apple_key_translation powerbook_fn_keys[] = {
+static const struct apple_key_translation powerbook_fn_keys[] = {
        { KEY_BACKSPACE, KEY_DELETE },
        { KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
        { KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
@@ -94,7 +94,7 @@ static struct apple_key_translation powerbook_fn_keys[] = {
        { }
 };
 
-static struct apple_key_translation powerbook_numlock_keys[] = {
+static const struct apple_key_translation powerbook_numlock_keys[] = {
        { KEY_J,        KEY_KP1 },
        { KEY_K,        KEY_KP2 },
        { KEY_L,        KEY_KP3 },
@@ -117,16 +117,16 @@ static struct apple_key_translation powerbook_numlock_keys[] = {
        { }
 };
 
-static struct apple_key_translation apple_iso_keyboard[] = {
+static const struct apple_key_translation apple_iso_keyboard[] = {
        { KEY_GRAVE,    KEY_102ND },
        { KEY_102ND,    KEY_GRAVE },
        { }
 };
 
-static struct apple_key_translation *apple_find_translation(
-               struct apple_key_translation *table, u16 from)
+static const struct apple_key_translation *apple_find_translation(
+               const struct apple_key_translation *table, u16 from)
 {
-       struct apple_key_translation *trans;
+       const struct apple_key_translation *trans;
 
        /* Look for the translation */
        for (trans = table; trans->from; trans++)
@@ -140,7 +140,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
                struct hid_usage *usage, __s32 value)
 {
        struct apple_sc *asc = hid_get_drvdata(hid);
-       struct apple_key_translation *trans;
+       const struct apple_key_translation *trans;
 
        if (usage->code == KEY_FN) {
                asc->fn_on = !!value;
@@ -253,7 +253,7 @@ static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
 static void apple_setup_input(struct input_dev *input)
 {
-       struct apple_key_translation *trans;
+       const struct apple_key_translation *trans;
 
        set_bit(KEY_NUMLOCK, input->keybit);
 
@@ -387,6 +387,12 @@ static const struct hid_device_id apple_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
                        APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS),
+               .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO),
@@ -468,5 +474,3 @@ static void apple_exit(void)
 module_init(apple_init);
 module_exit(apple_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(apple);
index 12c8a9ba6ed69badc7340d770954b249c29d1076..2f6723133a4b7d4eb45f50b45ea50185493f8c8c 100644 (file)
@@ -101,5 +101,3 @@ static void belkin_exit(void)
 module_init(belkin_init);
 module_exit(belkin_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(belkin);
index b833b9769abab3f11af9fbf2dbffcda687a34a37..ab8209e7e45ca41fe691d97cd24bc8011db2179e 100644 (file)
@@ -83,5 +83,3 @@ static void ch_exit(void)
 module_init(ch_init);
 module_exit(ch_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(cherry);
index a54d4096e0f7f80722249025e986dbc365a5218a..7f91076d8493ae5b653f01f6814028cab391b357 100644 (file)
@@ -76,5 +76,3 @@ static void ch_exit(void)
 module_init(ch_init);
 module_exit(ch_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(chicony);
index 1cc967448f4d5c760a8d75329c4e76bb82f4000f..5746a5903bcea1a17bfcc7349a2a867bd0833d32 100644 (file)
@@ -1236,6 +1236,9 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) },
@@ -1262,6 +1265,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
        { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
@@ -1269,6 +1273,8 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
@@ -1813,14 +1819,21 @@ void hid_unregister_driver(struct hid_driver *hdrv)
 }
 EXPORT_SYMBOL_GPL(hid_unregister_driver);
 
-#ifdef CONFIG_HID_COMPAT
-static void hid_compat_load(struct work_struct *ws)
+int hid_check_keys_pressed(struct hid_device *hid)
 {
-       request_module("hid-dummy");
+       struct hid_input *hidinput;
+       int i;
+
+       list_for_each_entry(hidinput, &hid->inputs, list) {
+               for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++)
+                       if (hidinput->input->key[i])
+                               return 1;
+       }
+
+       return 0;
 }
-static DECLARE_WORK(hid_compat_work, hid_compat_load);
-static struct workqueue_struct *hid_compat_wq;
-#endif
+
+EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
 
 static int __init hid_init(void)
 {
@@ -1836,15 +1849,6 @@ static int __init hid_init(void)
        if (ret)
                goto err_bus;
 
-#ifdef CONFIG_HID_COMPAT
-       hid_compat_wq = create_singlethread_workqueue("hid_compat");
-       if (!hid_compat_wq) {
-               hidraw_exit();
-               goto err;
-       }
-       queue_work(hid_compat_wq, &hid_compat_work);
-#endif
-
        return 0;
 err_bus:
        bus_unregister(&hid_bus_type);
@@ -1854,9 +1858,6 @@ err:
 
 static void __exit hid_exit(void)
 {
-#ifdef CONFIG_HID_COMPAT
-       destroy_workqueue(hid_compat_wq);
-#endif
        hidraw_exit();
        bus_unregister(&hid_bus_type);
 }
index 5d69d27b935d629b2d04c39b982957fe4f533fe6..9d6d3b91773bbbcbed9858c8e73b89627277aae9 100644 (file)
@@ -154,5 +154,3 @@ static void cp_exit(void)
 module_init(cp_init);
 module_exit(cp_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(cypress);
diff --git a/drivers/hid/hid-drff.c b/drivers/hid/hid-drff.c
new file mode 100644 (file)
index 0000000..34f3eb6
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Force feedback support for DragonRise Inc. game controllers
+ *
+ * From what I have gathered, these devices are mass produced in China and are
+ * distributed under several vendors. They often share the same design as
+ * the original PlayStation DualShock controller.
+ *
+ * 0079:0006 "DragonRise Inc.   Generic   USB  Joystick  "
+ *  - tested with a Tesun USB-703 game controller.
+ *
+ * Copyright (c) 2009 Richard Walmsley <richwalm@gmail.com>
+ */
+
+/*
+ * 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
+ */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+
+struct drff_device {
+       struct hid_report *report;
+};
+
+static int drff_play(struct input_dev *dev, void *data,
+                                struct ff_effect *effect)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct drff_device *drff = data;
+       int strong, weak;
+
+       strong = effect->u.rumble.strong_magnitude;
+       weak = effect->u.rumble.weak_magnitude;
+
+       dbg_hid("called with 0x%04x 0x%04x", strong, weak);
+
+       if (strong || weak) {
+               strong = strong * 0xff / 0xffff;
+               weak = weak * 0xff / 0xffff;
+
+               /* While reverse engineering this device, I found that when
+                  this value is set, it causes the strong rumble to function
+                  at a near maximum speed, so we'll bypass it. */
+               if (weak == 0x0a)
+                       weak = 0x0b;
+
+               drff->report->field[0]->value[0] = 0x51;
+               drff->report->field[0]->value[1] = 0x00;
+               drff->report->field[0]->value[2] = weak;
+               drff->report->field[0]->value[4] = strong;
+               usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
+
+               drff->report->field[0]->value[0] = 0xfa;
+               drff->report->field[0]->value[1] = 0xfe;
+       } else {
+               drff->report->field[0]->value[0] = 0xf3;
+               drff->report->field[0]->value[1] = 0x00;
+       }
+
+       drff->report->field[0]->value[2] = 0x00;
+       drff->report->field[0]->value[4] = 0x00;
+       dbg_hid("running with 0x%02x 0x%02x", strong, weak);
+       usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+static int drff_init(struct hid_device *hid)
+{
+       struct drff_device *drff;
+       struct hid_report *report;
+       struct hid_input *hidinput = list_first_entry(&hid->inputs,
+                                               struct hid_input, list);
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct input_dev *dev = hidinput->input;
+       int error;
+
+       if (list_empty(report_list)) {
+               dev_err(&hid->dev, "no output reports found\n");
+               return -ENODEV;
+       }
+
+       report = list_first_entry(report_list, struct hid_report, list);
+       if (report->maxfield < 1) {
+               dev_err(&hid->dev, "no fields in the report\n");
+               return -ENODEV;
+       }
+
+       if (report->field[0]->report_count < 7) {
+               dev_err(&hid->dev, "not enough values in the field\n");
+               return -ENODEV;
+       }
+
+       drff = kzalloc(sizeof(struct drff_device), GFP_KERNEL);
+       if (!drff)
+               return -ENOMEM;
+
+       set_bit(FF_RUMBLE, dev->ffbit);
+
+       error = input_ff_create_memless(dev, drff, drff_play);
+       if (error) {
+               kfree(drff);
+               return error;
+       }
+
+       drff->report = report;
+       drff->report->field[0]->value[0] = 0xf3;
+       drff->report->field[0]->value[1] = 0x00;
+       drff->report->field[0]->value[2] = 0x00;
+       drff->report->field[0]->value[3] = 0x00;
+       drff->report->field[0]->value[4] = 0x00;
+       drff->report->field[0]->value[5] = 0x00;
+       drff->report->field[0]->value[6] = 0x00;
+       usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
+
+       dev_info(&hid->dev, "Force Feedback for DragonRise Inc. game "
+              "controllers by Richard Walmsley <richwalm@gmail.com>\n");
+
+       return 0;
+}
+
+static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       dev_dbg(&hdev->dev, "DragonRise Inc. HID hardware probe...");
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err;
+       }
+
+       drff_init(hdev);
+
+       return 0;
+err:
+       return ret;
+}
+
+static const struct hid_device_id dr_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006),  },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, dr_devices);
+
+static struct hid_driver dr_driver = {
+       .name = "dragonrise",
+       .id_table = dr_devices,
+       .probe = dr_probe,
+};
+
+static int __init dr_init(void)
+{
+       return hid_register_driver(&dr_driver);
+}
+
+static void __exit dr_exit(void)
+{
+       hid_unregister_driver(&dr_driver);
+}
+
+module_init(dr_init);
+module_exit(dr_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c
deleted file mode 100644 (file)
index b4cc0f7..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <linux/autoconf.h>
-#include <linux/module.h>
-#include <linux/hid.h>
-
-static int __init hid_dummy_init(void)
-{
-#ifdef CONFIG_HID_A4TECH_MODULE
-       HID_COMPAT_CALL_DRIVER(a4tech);
-#endif
-#ifdef CONFIG_HID_APPLE_MODULE
-       HID_COMPAT_CALL_DRIVER(apple);
-#endif
-#ifdef CONFIG_HID_BELKIN_MODULE
-       HID_COMPAT_CALL_DRIVER(belkin);
-#endif
-#ifdef CONFIG_HID_BRIGHT_MODULE
-       HID_COMPAT_CALL_DRIVER(bright);
-#endif
-#ifdef CONFIG_HID_CHERRY_MODULE
-       HID_COMPAT_CALL_DRIVER(cherry);
-#endif
-#ifdef CONFIG_HID_CHICONY_MODULE
-       HID_COMPAT_CALL_DRIVER(chicony);
-#endif
-#ifdef CONFIG_HID_CYPRESS_MODULE
-       HID_COMPAT_CALL_DRIVER(cypress);
-#endif
-#ifdef CONFIG_HID_DELL_MODULE
-       HID_COMPAT_CALL_DRIVER(dell);
-#endif
-#ifdef CONFIG_HID_EZKEY_MODULE
-       HID_COMPAT_CALL_DRIVER(ezkey);
-#endif
-#ifdef CONFIG_HID_GYRATION_MODULE
-       HID_COMPAT_CALL_DRIVER(gyration);
-#endif
-#ifdef CONFIG_HID_LOGITECH_MODULE
-       HID_COMPAT_CALL_DRIVER(logitech);
-#endif
-#ifdef CONFIG_HID_MICROSOFT_MODULE
-       HID_COMPAT_CALL_DRIVER(microsoft);
-#endif
-#ifdef CONFIG_HID_MONTEREY_MODULE
-       HID_COMPAT_CALL_DRIVER(monterey);
-#endif
-#ifdef CONFIG_HID_NTRIG_MODULE
-       HID_COMPAT_CALL_DRIVER(ntrig);
-#endif
-#ifdef CONFIG_HID_PANTHERLORD_MODULE
-       HID_COMPAT_CALL_DRIVER(pantherlord);
-#endif
-#ifdef CONFIG_HID_PETALYNX_MODULE
-       HID_COMPAT_CALL_DRIVER(petalynx);
-#endif
-#ifdef CONFIG_HID_SAMSUNG_MODULE
-       HID_COMPAT_CALL_DRIVER(samsung);
-#endif
-#ifdef CONFIG_HID_SONY_MODULE
-       HID_COMPAT_CALL_DRIVER(sony);
-#endif
-#ifdef CONFIG_HID_SUNPLUS_MODULE
-       HID_COMPAT_CALL_DRIVER(sunplus);
-#endif
-#ifdef CONFIG_GREENASIA_FF_MODULE
-       HID_COMPAT_CALL_DRIVER(greenasia);
-#endif
-#ifdef CONFIG_THRUSTMASTER_FF_MODULE
-       HID_COMPAT_CALL_DRIVER(thrustmaster);
-#endif
-#ifdef CONFIG_ZEROPLUS_FF_MODULE
-       HID_COMPAT_CALL_DRIVER(zeroplus);
-#endif
-
-       return -EIO;
-}
-module_init(hid_dummy_init);
-
-MODULE_LICENSE("GPL");
index deb42f931b7ef53edcecb6f8273d2758f9f683e3..0a1fe054799ba2899efb74ab8dbb984be13609f9 100644 (file)
@@ -91,5 +91,3 @@ static void ez_exit(void)
 module_init(ez_init);
 module_exit(ez_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(ezkey);
index 71211f6a4f027161e88b2a85a0a39ec4315b62ee..510ad3ab8d3369b5cb298813310b48790d73ed27 100644 (file)
@@ -181,5 +181,3 @@ static void __exit ga_exit(void)
 module_init(ga_init);
 module_exit(ga_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(greenasia);
index 04a0afec52acede3f6dd087ef7cd576f23e9c60a..d42d222097a80e7cfa049165676b0283c19ac3f7 100644 (file)
@@ -94,5 +94,3 @@ static void gyration_exit(void)
 module_init(gyration_init);
 module_exit(gyration_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(gyration);
index 88511970508d71b8ceae437ae78726ca35563cc8..bdeda4c7cc13ecd00202385050f03136122ff103 100644 (file)
@@ -67,6 +67,9 @@
 #define USB_DEVICE_ID_APPLE_GEYSER4_ANSI       0x021a
 #define USB_DEVICE_ID_APPLE_GEYSER4_ISO        0x021b
 #define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
+#define USB_DEVICE_ID_APPLE_ALU_MINI_ANSI      0x021d
+#define USB_DEVICE_ID_APPLE_ALU_MINI_ISO       0x021e
+#define USB_DEVICE_ID_APPLE_ALU_MINI_JIS       0x021f
 #define USB_DEVICE_ID_APPLE_ALU_ANSI   0x0220
 #define USB_DEVICE_ID_APPLE_ALU_ISO    0x0221
 #define USB_DEVICE_ID_APPLE_ALU_JIS    0x0222
 #define USB_VENDOR_ID_DMI              0x0c0b
 #define USB_DEVICE_ID_DMI_ENC          0x5fab
 
+#define USB_VENDOR_ID_DRAGONRISE       0x0079
+
 #define USB_VENDOR_ID_ELO              0x04E7
 #define USB_DEVICE_ID_ELO_TS2700       0x0020
 
 #define USB_DEVICE_ID_LD_POWERCONTROL  0x2030
 #define USB_DEVICE_ID_LD_MACHINETEST   0x2040
 
+#define USB_VENDOR_ID_KENSINGTON       0x047d
+#define USB_DEVICE_ID_KS_SLIMBLADE     0x2041
+
 #define USB_VENDOR_ID_LOGITECH         0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_VENDOR_ID_ZEROPLUS         0x0c12
 
 #define USB_VENDOR_ID_KYE              0x0458
+#define USB_DEVICE_ID_KYE_ERGO_525V    0x0087
 #define USB_DEVICE_ID_KYE_GPEN_560     0x5003
 
+
 #endif
diff --git a/drivers/hid/hid-kensington.c b/drivers/hid/hid-kensington.c
new file mode 100644 (file)
index 0000000..7353bd7
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  HID driver for Kensigton Slimblade Trackball
+ *
+ *  Copyright (c) 2009 Jiri Kosina
+ */
+
+/*
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ks_map_key(c)  hid_map_usage(hi, usage, bit, max, EV_KEY, (c))
+
+static int ks_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0x01: ks_map_key(BTN_MIDDLE);      break;
+       case 0x02: ks_map_key(BTN_SIDE);        break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static const struct hid_device_id ks_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, ks_devices);
+
+static struct hid_driver ks_driver = {
+       .name = "kensington",
+       .id_table = ks_devices,
+       .input_mapping = ks_input_mapping,
+};
+
+static int ks_init(void)
+{
+       return hid_register_driver(&ks_driver);
+}
+
+static void ks_exit(void)
+{
+       hid_unregister_driver(&ks_driver);
+}
+
+module_init(ks_init);
+module_exit(ks_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
new file mode 100644 (file)
index 0000000..72ee3fe
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  HID driver for Kye/Genius devices not fully compliant with HID standard
+ *
+ *  Copyright (c) 2009 Jiri Kosina
+ *  Copyright (c) 2009 Tomas Hanak
+ */
+
+/*
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/* the fixups that need to be done:
+ *   - change led usage page to button for extra buttons
+ *   - report size 8 count 1 must be size 1 count 8 for button bitfield
+ *   - change the button usage range to 4-7 for the extra buttons
+ */
+static void kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       if (rsize >= 74 &&
+               rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
+               rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
+               rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
+               rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
+               rdesc[73] == 0x95 && rdesc[74] == 0x01) {
+               dev_info(&hdev->dev, "fixing up Kye/Genius Ergo Mouse report "
+                               "descriptor\n");
+               rdesc[62] = 0x09;
+               rdesc[64] = 0x04;
+               rdesc[66] = 0x07;
+               rdesc[72] = 0x01;
+               rdesc[74] = 0x08;
+       }
+}
+
+static const struct hid_device_id kye_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, kye_devices);
+
+static struct hid_driver kye_driver = {
+       .name = "kye",
+       .id_table = kye_devices,
+       .report_fixup = kye_report_fixup,
+};
+
+static int kye_init(void)
+{
+       return hid_register_driver(&kye_driver);
+}
+
+static void kye_exit(void)
+{
+       hid_unregister_driver(&kye_driver);
+}
+
+module_init(kye_init);
+module_exit(kye_exit);
+MODULE_LICENSE("GPL");
index 83e07c9f4144d01de82813ece5077a0f4ed76257..7b80cb694982015e1f2c10fbc7795b9d98f0754c 100644 (file)
@@ -326,5 +326,3 @@ static void lg_exit(void)
 module_init(lg_init);
 module_exit(lg_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(logitech);
index 25b10dcad90d52c38dce6069397a1df19f13c8d0..5e9e37a0506dd96adc8164855fdfac69c7e6fd1e 100644 (file)
@@ -210,5 +210,3 @@ static void ms_exit(void)
 module_init(ms_init);
 module_exit(ms_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(microsoft);
index f3a85a065f18f490190d0e883e25783398f96206..240f87618be6edef76b34b14f87b890da82d16db 100644 (file)
@@ -78,5 +78,3 @@ static void mr_exit(void)
 module_init(mr_init);
 module_exit(mr_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(monterey);
index db44fbd7bdf6aad2eeb9ed11d4af4c5f09bca14c..c5b252be9c217888b46f587a58e41d847142e651 100644 (file)
@@ -78,5 +78,3 @@ static void ntrig_exit(void)
 module_init(ntrig_init);
 module_exit(ntrig_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(ntrig);
index 10945fe12d50eda52239e8c5e35ce0b42a8231ea..2e83e8ff891a47aff5086e89b9b37c5d1767af6b 100644 (file)
@@ -118,5 +118,3 @@ static void pl_exit(void)
 module_init(pl_init);
 module_exit(pl_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(petalynx);
index 46941f979b9d058202f9ce71f8b70e341457c62a..4db9a3483760f6ade53829076198f105161e1cd4 100644 (file)
@@ -9,9 +9,12 @@
  *   - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
  *
  *  0e8f:0003 "GreenAsia Inc.    USB Joystick     "
- *   - tested with K??ng Gaming gamepad
+ *   - tested with König Gaming gamepad
  *
- *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
+ *  0e8f:0003 "GASIA USB Gamepad"
+ *   - another version of the König gamepad
+ *
+ *  Copyright (c) 2007, 2009 Anssi Hannula <anssi.hannula@gmail.com>
  */
 
 /*
@@ -46,6 +49,8 @@
 
 struct plff_device {
        struct hid_report *report;
+       s32 *strong;
+       s32 *weak;
 };
 
 static int hid_plff_play(struct input_dev *dev, void *data,
@@ -62,8 +67,8 @@ static int hid_plff_play(struct input_dev *dev, void *data,
        left = left * 0x7f / 0xffff;
        right = right * 0x7f / 0xffff;
 
-       plff->report->field[0]->value[2] = left;
-       plff->report->field[0]->value[3] = right;
+       *plff->strong = left;
+       *plff->weak = right;
        debug("running with 0x%02x 0x%02x", left, right);
        usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
 
@@ -80,6 +85,8 @@ static int plff_init(struct hid_device *hid)
        struct list_head *report_ptr = report_list;
        struct input_dev *dev;
        int error;
+       s32 *strong;
+       s32 *weak;
 
        /* The device contains one output report per physical device, all
           containing 1 field, which contains 4 ff00.0002 usages and 4 16bit
@@ -87,7 +94,12 @@ static int plff_init(struct hid_device *hid)
 
           The input reports also contain a field which contains
           8 ff00.0001 usages and 8 boolean values. Their meaning is
-          currently unknown. */
+          currently unknown.
+          
+          A version of the 0e8f:0003 exists that has all the values in
+          separate fields and misses the extra input field, thus resembling
+          Zeroplus (hid-zpff) devices.
+       */
 
        if (list_empty(report_list)) {
                dev_err(&hid->dev, "no output reports found\n");
@@ -110,8 +122,21 @@ static int plff_init(struct hid_device *hid)
                        return -ENODEV;
                }
 
-               if (report->field[0]->report_count < 4) {
-                       dev_err(&hid->dev, "not enough values in the field\n");
+               if (report->field[0]->report_count >= 4) {
+                       report->field[0]->value[0] = 0x00;
+                       report->field[0]->value[1] = 0x00;
+                       strong = &report->field[0]->value[2];
+                       weak = &report->field[0]->value[3];
+                       debug("detected single-field device");
+               } else if (report->maxfield >= 4 && report->field[0]->maxusage == 1 &&
+                               report->field[0]->usage[0].hid == (HID_UP_LED | 0x43)) {
+                       report->field[0]->value[0] = 0x00;
+                       report->field[1]->value[0] = 0x00;
+                       strong = &report->field[2]->value[0];
+                       weak = &report->field[3]->value[0];
+                       debug("detected 4-field device");
+               } else {
+                       dev_err(&hid->dev, "not enough fields or values\n");
                        return -ENODEV;
                }
 
@@ -130,10 +155,11 @@ static int plff_init(struct hid_device *hid)
                }
 
                plff->report = report;
-               plff->report->field[0]->value[0] = 0x00;
-               plff->report->field[0]->value[1] = 0x00;
-               plff->report->field[0]->value[2] = 0x00;
-               plff->report->field[0]->value[3] = 0x00;
+               plff->strong = strong;
+               plff->weak = weak;
+
+               *strong = 0x00;
+               *weak = 0x00;
                usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
        }
 
@@ -180,7 +206,7 @@ static const struct hid_device_id pl_devices[] = {
                .driver_data = 1 }, /* Twin USB Joystick */
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR),
                .driver_data = 1 }, /* Twin USB Joystick */
-       { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, /* GreenAsia Inc. USB Joystick */
+       { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), },
        { }
 };
 MODULE_DEVICE_TABLE(hid, pl_devices);
@@ -204,5 +230,3 @@ static void pl_exit(void)
 module_init(pl_init);
 module_exit(pl_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(pantherlord);
index 15f3c04924506008eb6d3f85a2c9a21393fa87c3..07083aa6c19ae615a81338c77855d143162df113 100644 (file)
@@ -96,5 +96,3 @@ static void samsung_exit(void)
 module_init(samsung_init);
 module_exit(samsung_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(samsung);
index dd5a3979a4defd1e606669da4ccc91800a0c60c3..c2599388a3504ce4df3bb110f976dfab47581cf5 100644 (file)
@@ -148,5 +148,3 @@ static void sony_exit(void)
 module_init(sony_init);
 module_exit(sony_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(sony);
index 5ba68f7dbb780e1626de6ff1be615e27a8f3a162..e0a8fd36a85b70e174d4763ea50e9d709bb456fd 100644 (file)
@@ -78,5 +78,3 @@ static void sp_exit(void)
 module_init(sp_init);
 module_exit(sp_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(sunplus);
index 1b7cba0f7e1f71b289f984ba7b26f95dfdab173c..7c1f7b50330cd6d5bd6b13e9388560c2ef3a5950 100644 (file)
@@ -265,5 +265,3 @@ static void tm_exit(void)
 module_init(tm_init);
 module_exit(tm_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(thrustmaster);
index cca64a0564a9ed3cb2b369bc8d842c5ea8ac7a18..152ccfabeba5cf59d523d59feeac2e0abde04f4a 100644 (file)
@@ -73,5 +73,3 @@ static void ts_exit(void)
 module_init(ts_init);
 module_exit(ts_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(topseed);
index ea82f3718b218c2d6262a5b7f50db3f627ddfde1..85a198a185372967fa487a744d1d5517216a9136 100644 (file)
@@ -158,5 +158,3 @@ static void zp_exit(void)
 module_init(zp_init);
 module_exit(zp_exit);
 MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(zeroplus);
index 02b19db5442ebd1d1fce7c0716bb2a071f528e12..e263d47311790b7e215bfd4dbf119999e87064aa 100644 (file)
@@ -181,9 +181,17 @@ static int hidraw_open(struct inode *inode, struct file *file)
 
        dev = hidraw_table[minor];
        if (!dev->open++) {
+               if (dev->hid->ll_driver->power) {
+                       err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON);
+                       if (err < 0)
+                               goto out_unlock;
+               }
                err = dev->hid->ll_driver->open(dev->hid);
-               if (err < 0)
+               if (err < 0) {
+                       if (dev->hid->ll_driver->power)
+                               dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
                        dev->open--;
+               }
        }
 
 out_unlock:
@@ -209,10 +217,13 @@ static int hidraw_release(struct inode * inode, struct file * file)
        list_del(&list->node);
        dev = hidraw_table[minor];
        if (!--dev->open) {
-               if (list->hidraw->exist)
+               if (list->hidraw->exist) {
+                       if (dev->hid->ll_driver->power)
+                               dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
                        dev->hid->ll_driver->close(dev->hid);
-               else
+               } else {
                        kfree(list->hidraw);
+               }
        }
 
        kfree(list);
index f0a0f72238aba24c66c8ecaab0ca917064609add..4306cb1b8ce5c91275be6566825ce02ec6f210fb 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2008 Jiri Kosina
+ *  Copyright (c) 2007-2008 Oliver Neukum
  */
 
 /*
@@ -27,6 +28,7 @@
 #include <asm/byteorder.h>
 #include <linux/input.h>
 #include <linux/wait.h>
+#include <linux/workqueue.h>
 
 #include <linux/usb.h>
 
@@ -53,6 +55,10 @@ static unsigned int hid_mousepoll_interval;
 module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
 MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
+static unsigned int ignoreled;
+module_param_named(ignoreled, ignoreled, uint, 0644);
+MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
+
 /* Quirks specified at module load time */
 static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
 module_param_array_named(quirks, quirks_param, charp, NULL, 0444);
@@ -63,8 +69,13 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
 /*
  * Input submission and I/O error handler.
  */
+static DEFINE_MUTEX(hid_open_mut);
+static struct workqueue_struct *resumption_waker;
 
 static void hid_io_error(struct hid_device *hid);
+static int hid_submit_out(struct hid_device *hid);
+static int hid_submit_ctrl(struct hid_device *hid);
+static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid);
 
 /* Start up the input URB */
 static int hid_start_in(struct hid_device *hid)
@@ -73,15 +84,16 @@ static int hid_start_in(struct hid_device *hid)
        int rc = 0;
        struct usbhid_device *usbhid = hid->driver_data;
 
-       spin_lock_irqsave(&usbhid->inlock, flags);
-       if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+       spin_lock_irqsave(&usbhid->lock, flags);
+       if (hid->open > 0 &&
                        !test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
+                       !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&
                        !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
                rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
                if (rc != 0)
                        clear_bit(HID_IN_RUNNING, &usbhid->iofl);
        }
-       spin_unlock_irqrestore(&usbhid->inlock, flags);
+       spin_unlock_irqrestore(&usbhid->lock, flags);
        return rc;
 }
 
@@ -145,7 +157,7 @@ static void hid_io_error(struct hid_device *hid)
        unsigned long flags;
        struct usbhid_device *usbhid = hid->driver_data;
 
-       spin_lock_irqsave(&usbhid->inlock, flags);
+       spin_lock_irqsave(&usbhid->lock, flags);
 
        /* Stop when disconnected */
        if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
@@ -175,7 +187,51 @@ static void hid_io_error(struct hid_device *hid)
        mod_timer(&usbhid->io_retry,
                        jiffies + msecs_to_jiffies(usbhid->retry_delay));
 done:
-       spin_unlock_irqrestore(&usbhid->inlock, flags);
+       spin_unlock_irqrestore(&usbhid->lock, flags);
+}
+
+static void usbhid_mark_busy(struct usbhid_device *usbhid)
+{
+       struct usb_interface *intf = usbhid->intf;
+
+       usb_mark_last_busy(interface_to_usbdev(intf));
+}
+
+static int usbhid_restart_out_queue(struct usbhid_device *usbhid)
+{
+       struct hid_device *hid = usb_get_intfdata(usbhid->intf);
+       int kicked;
+
+       if (!hid)
+               return 0;
+
+       if ((kicked = (usbhid->outhead != usbhid->outtail))) {
+               dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
+               if (hid_submit_out(hid)) {
+                       clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+                       wake_up(&usbhid->wait);
+               }
+       }
+       return kicked;
+}
+
+static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)
+{
+       struct hid_device *hid = usb_get_intfdata(usbhid->intf);
+       int kicked;
+
+       WARN_ON(hid == NULL);
+       if (!hid)
+               return 0;
+
+       if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
+               dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
+               if (hid_submit_ctrl(hid)) {
+                       clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+                       wake_up(&usbhid->wait);
+               }
+       }
+       return kicked;
 }
 
 /*
@@ -190,12 +246,23 @@ static void hid_irq_in(struct urb *urb)
 
        switch (urb->status) {
        case 0:                 /* success */
+               usbhid_mark_busy(usbhid);
                usbhid->retry_delay = 0;
                hid_input_report(urb->context, HID_INPUT_REPORT,
                                 urb->transfer_buffer,
                                 urb->actual_length, 1);
+               /*
+                * autosuspend refused while keys are pressed
+                * because most keyboards don't wake up when
+                * a key is released
+                */
+               if (hid_check_keys_pressed(hid))
+                       set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
+               else
+                       clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
                break;
        case -EPIPE:            /* stall */
+               usbhid_mark_busy(usbhid);
                clear_bit(HID_IN_RUNNING, &usbhid->iofl);
                set_bit(HID_CLEAR_HALT, &usbhid->iofl);
                schedule_work(&usbhid->reset_work);
@@ -209,6 +276,7 @@ static void hid_irq_in(struct urb *urb)
        case -EPROTO:           /* protocol error or unplug */
        case -ETIME:            /* protocol error or unplug */
        case -ETIMEDOUT:        /* Should never happen, but... */
+               usbhid_mark_busy(usbhid);
                clear_bit(HID_IN_RUNNING, &usbhid->iofl);
                hid_io_error(hid);
                return;
@@ -239,16 +307,25 @@ static int hid_submit_out(struct hid_device *hid)
        report = usbhid->out[usbhid->outtail].report;
        raw_report = usbhid->out[usbhid->outtail].raw_report;
 
-       usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-       usbhid->urbout->dev = hid_to_usb_dev(hid);
-       memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length);
-       kfree(raw_report);
+       if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
+               usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+               usbhid->urbout->dev = hid_to_usb_dev(hid);
+               memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length);
+               kfree(raw_report);
 
-       dbg_hid("submitting out urb\n");
+               dbg_hid("submitting out urb\n");
 
-       if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
-               err_hid("usb_submit_urb(out) failed");
-               return -1;
+               if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
+                       err_hid("usb_submit_urb(out) failed");
+                       return -1;
+               }
+       } else {
+               /*
+                * queue work to wake up the device.
+                * as the work queue is freezeable, this is safe
+                * with respect to STD and STR
+                */
+               queue_work(resumption_waker, &usbhid->restart_work);
        }
 
        return 0;
@@ -266,41 +343,50 @@ static int hid_submit_ctrl(struct hid_device *hid)
        raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
        dir = usbhid->ctrl[usbhid->ctrltail].dir;
 
-       len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-       if (dir == USB_DIR_OUT) {
-               usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
-               usbhid->urbctrl->transfer_buffer_length = len;
-               memcpy(usbhid->ctrlbuf, raw_report, len);
-               kfree(raw_report);
-       } else {
-               int maxpacket, padlen;
-
-               usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
-               maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
-               if (maxpacket > 0) {
-                       padlen = DIV_ROUND_UP(len, maxpacket);
-                       padlen *= maxpacket;
-                       if (padlen > usbhid->bufsize)
-                               padlen = usbhid->bufsize;
-               } else
-                       padlen = 0;
-               usbhid->urbctrl->transfer_buffer_length = padlen;
-       }
-       usbhid->urbctrl->dev = hid_to_usb_dev(hid);
+       if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
+               len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+               if (dir == USB_DIR_OUT) {
+                       usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
+                       usbhid->urbctrl->transfer_buffer_length = len;
+                       memcpy(usbhid->ctrlbuf, raw_report, len);
+                       kfree(raw_report);
+               } else {
+                       int maxpacket, padlen;
+
+                       usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
+                       maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
+                       if (maxpacket > 0) {
+                               padlen = DIV_ROUND_UP(len, maxpacket);
+                               padlen *= maxpacket;
+                               if (padlen > usbhid->bufsize)
+                                       padlen = usbhid->bufsize;
+                       } else
+                               padlen = 0;
+                       usbhid->urbctrl->transfer_buffer_length = padlen;
+               }
+               usbhid->urbctrl->dev = hid_to_usb_dev(hid);
 
-       usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
-       usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
-       usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
-       usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
-       usbhid->cr->wLength = cpu_to_le16(len);
+               usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
+               usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
+               usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
+               usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
+               usbhid->cr->wLength = cpu_to_le16(len);
 
-       dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n",
-               usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
-               usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
+               dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n",
+                       usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+                       usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
 
-       if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
-               err_hid("usb_submit_urb(ctrl) failed");
-               return -1;
+               if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
+                       err_hid("usb_submit_urb(ctrl) failed");
+                       return -1;
+               }
+       } else {
+               /*
+                * queue work to wake up the device.
+                * as the work queue is freezeable, this is safe
+                * with respect to STD and STR
+                */
+               queue_work(resumption_waker, &usbhid->restart_work);
        }
 
        return 0;
@@ -332,7 +418,7 @@ static void hid_irq_out(struct urb *urb)
                                "received\n", urb->status);
        }
 
-       spin_lock_irqsave(&usbhid->outlock, flags);
+       spin_lock_irqsave(&usbhid->lock, flags);
 
        if (unplug)
                usbhid->outtail = usbhid->outhead;
@@ -344,12 +430,12 @@ static void hid_irq_out(struct urb *urb)
                        clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
                        wake_up(&usbhid->wait);
                }
-               spin_unlock_irqrestore(&usbhid->outlock, flags);
+               spin_unlock_irqrestore(&usbhid->lock, flags);
                return;
        }
 
        clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-       spin_unlock_irqrestore(&usbhid->outlock, flags);
+       spin_unlock_irqrestore(&usbhid->lock, flags);
        wake_up(&usbhid->wait);
 }
 
@@ -361,12 +447,11 @@ static void hid_ctrl(struct urb *urb)
 {
        struct hid_device *hid = urb->context;
        struct usbhid_device *usbhid = hid->driver_data;
-       unsigned long flags;
-       int unplug = 0;
+       int unplug = 0, status = urb->status;
 
-       spin_lock_irqsave(&usbhid->ctrllock, flags);
+       spin_lock(&usbhid->lock);
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
                        hid_input_report(urb->context,
@@ -383,7 +468,7 @@ static void hid_ctrl(struct urb *urb)
                break;
        default:                /* error */
                dev_warn(&urb->dev->dev, "ctrl urb status %d "
-                               "received\n", urb->status);
+                               "received\n", status);
        }
 
        if (unplug)
@@ -396,19 +481,18 @@ static void hid_ctrl(struct urb *urb)
                        clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
                        wake_up(&usbhid->wait);
                }
-               spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+               spin_unlock(&usbhid->lock);
                return;
        }
 
        clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+       spin_unlock(&usbhid->lock);
        wake_up(&usbhid->wait);
 }
 
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
 {
        int head;
-       unsigned long flags;
        struct usbhid_device *usbhid = hid->driver_data;
        int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 
@@ -416,18 +500,13 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
                return;
 
        if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
-
-               spin_lock_irqsave(&usbhid->outlock, flags);
-
                if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
-                       spin_unlock_irqrestore(&usbhid->outlock, flags);
                        dev_warn(&hid->dev, "output queue full\n");
                        return;
                }
 
                usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
                if (!usbhid->out[usbhid->outhead].raw_report) {
-                       spin_unlock_irqrestore(&usbhid->outlock, flags);
                        dev_warn(&hid->dev, "output queueing failed\n");
                        return;
                }
@@ -438,15 +517,10 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
                if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
                        if (hid_submit_out(hid))
                                clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-
-               spin_unlock_irqrestore(&usbhid->outlock, flags);
                return;
        }
 
-       spin_lock_irqsave(&usbhid->ctrllock, flags);
-
        if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
-               spin_unlock_irqrestore(&usbhid->ctrllock, flags);
                dev_warn(&hid->dev, "control queue full\n");
                return;
        }
@@ -454,7 +528,6 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
        if (dir == USB_DIR_OUT) {
                usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
                if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
-                       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
                        dev_warn(&hid->dev, "control queueing failed\n");
                        return;
                }
@@ -467,15 +540,25 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
        if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
                if (hid_submit_ctrl(hid))
                        clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+}
+
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+       unsigned long flags;
 
-       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+       spin_lock_irqsave(&usbhid->lock, flags);
+       __usbhid_submit_report(hid, report, dir);
+       spin_unlock_irqrestore(&usbhid->lock, flags);
 }
 EXPORT_SYMBOL_GPL(usbhid_submit_report);
 
 static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
        struct hid_device *hid = input_get_drvdata(dev);
+       struct usbhid_device *usbhid = hid->driver_data;
        struct hid_field *field;
+       unsigned long flags;
        int offset;
 
        if (type == EV_FF)
@@ -490,6 +573,15 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
        }
 
        hid_set_field(field, offset, value);
+       if (value) {
+               spin_lock_irqsave(&usbhid->lock, flags);
+               usbhid->ledcount++;
+               spin_unlock_irqrestore(&usbhid->lock, flags);
+       } else {
+               spin_lock_irqsave(&usbhid->lock, flags);
+               usbhid->ledcount--;
+               spin_unlock_irqrestore(&usbhid->lock, flags);
+       }
        usbhid_submit_report(hid, field->report, USB_DIR_OUT);
 
        return 0;
@@ -538,15 +630,22 @@ int usbhid_open(struct hid_device *hid)
        struct usbhid_device *usbhid = hid->driver_data;
        int res;
 
+       mutex_lock(&hid_open_mut);
        if (!hid->open++) {
                res = usb_autopm_get_interface(usbhid->intf);
+               /* the device must be awake to reliable request remote wakeup */
                if (res < 0) {
                        hid->open--;
+                       mutex_unlock(&hid_open_mut);
                        return -EIO;
                }
+               usbhid->intf->needs_remote_wakeup = 1;
+               if (hid_start_in(hid))
+                       hid_io_error(hid);
+               usb_autopm_put_interface(usbhid->intf);
        }
-       if (hid_start_in(hid))
-               hid_io_error(hid);
+       mutex_unlock(&hid_open_mut);
        return 0;
 }
 
@@ -554,10 +653,22 @@ void usbhid_close(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
+       mutex_lock(&hid_open_mut);
+
+       /* protecting hid->open to make sure we don't restart
+        * data acquistion due to a resumption we no longer
+        * care about
+        */
+       spin_lock_irq(&usbhid->lock);
        if (!--hid->open) {
+               spin_unlock_irq(&usbhid->lock);
                usb_kill_urb(usbhid->urbin);
-               usb_autopm_put_interface(usbhid->intf);
+               flush_scheduled_work();
+               usbhid->intf->needs_remote_wakeup = 0;
+       } else {
+               spin_unlock_irq(&usbhid->lock);
        }
+       mutex_unlock(&hid_open_mut);
 }
 
 /*
@@ -687,6 +798,25 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
        return ret;
 }
 
+static void usbhid_restart_queues(struct usbhid_device *usbhid)
+{
+       if (usbhid->urbout)
+               usbhid_restart_out_queue(usbhid);
+       usbhid_restart_ctrl_queue(usbhid);
+}
+
+static void __usbhid_restart_queues(struct work_struct *work)
+{
+       struct usbhid_device *usbhid =
+               container_of(work, struct usbhid_device, restart_work);
+       int r;
+
+       r = usb_autopm_get_interface(usbhid->intf);
+       if (r < 0)
+               return;
+       usb_autopm_put_interface(usbhid->intf);
+}
+
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
@@ -711,6 +841,9 @@ static int usbhid_parse(struct hid_device *hid)
        quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
                        le16_to_cpu(dev->descriptor.idProduct));
 
+       if (quirks & HID_QUIRK_IGNORE)
+               return -ENODEV;
+
        /* Many keyboards and mice don't like to be polled for reports,
         * so we will always set the HID_QUIRK_NOGET flag for them. */
        if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
@@ -850,11 +983,11 @@ static int usbhid_start(struct hid_device *hid)
 
        init_waitqueue_head(&usbhid->wait);
        INIT_WORK(&usbhid->reset_work, hid_reset);
+       INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
        setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
 
-       spin_lock_init(&usbhid->inlock);
-       spin_lock_init(&usbhid->outlock);
-       spin_lock_init(&usbhid->ctrllock);
+       spin_lock_init(&usbhid->lock);
+       spin_lock_init(&usbhid->lock);
 
        usbhid->intf = intf;
        usbhid->ifnum = interface->desc.bInterfaceNumber;
@@ -906,15 +1039,14 @@ static void usbhid_stop(struct hid_device *hid)
                return;
 
        clear_bit(HID_STARTED, &usbhid->iofl);
-       spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
+       spin_lock_irq(&usbhid->lock);   /* Sync with error handler */
        set_bit(HID_DISCONNECTED, &usbhid->iofl);
-       spin_unlock_irq(&usbhid->inlock);
+       spin_unlock_irq(&usbhid->lock);
        usb_kill_urb(usbhid->urbin);
        usb_kill_urb(usbhid->urbout);
        usb_kill_urb(usbhid->urbctrl);
 
-       del_timer_sync(&usbhid->io_retry);
-       cancel_work_sync(&usbhid->reset_work);
+       hid_cancel_delayed_stuff(usbhid);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_disconnect(hid);
@@ -935,12 +1067,28 @@ static void usbhid_stop(struct hid_device *hid)
        hid_free_buffers(hid_to_usb_dev(hid), hid);
 }
 
+static int usbhid_power(struct hid_device *hid, int lvl)
+{
+       int r = 0;
+
+       switch (lvl) {
+       case PM_HINT_FULLON:
+               r = usbhid_get_power(hid);
+               break;
+       case PM_HINT_NORMAL:
+               usbhid_put_power(hid);
+               break;
+       }
+       return r;
+}
+
 static struct hid_ll_driver usb_hid_driver = {
        .parse = usbhid_parse,
        .start = usbhid_start,
        .stop = usbhid_stop,
        .open = usbhid_open,
        .close = usbhid_close,
+       .power = usbhid_power,
        .hidinput_input_event = usb_hidinput_input_event,
 };
 
@@ -1049,19 +1197,126 @@ static void hid_disconnect(struct usb_interface *intf)
        kfree(usbhid);
 }
 
+static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
+{
+       del_timer_sync(&usbhid->io_retry);
+       cancel_work_sync(&usbhid->restart_work);
+       cancel_work_sync(&usbhid->reset_work);
+}
+
+static void hid_cease_io(struct usbhid_device *usbhid)
+{
+       del_timer(&usbhid->io_retry);
+       usb_kill_urb(usbhid->urbin);
+       usb_kill_urb(usbhid->urbctrl);
+       usb_kill_urb(usbhid->urbout);
+}
+
+/* Treat USB reset pretty much the same as suspend/resume */
+static int hid_pre_reset(struct usb_interface *intf)
+{
+       struct hid_device *hid = usb_get_intfdata(intf);
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       spin_lock_irq(&usbhid->lock);
+       set_bit(HID_RESET_PENDING, &usbhid->iofl);
+       spin_unlock_irq(&usbhid->lock);
+       cancel_work_sync(&usbhid->restart_work);
+       hid_cease_io(usbhid);
+
+       return 0;
+}
+
+/* Same routine used for post_reset and reset_resume */
+static int hid_post_reset(struct usb_interface *intf)
+{
+       struct usb_device *dev = interface_to_usbdev (intf);
+       struct hid_device *hid = usb_get_intfdata(intf);
+       struct usbhid_device *usbhid = hid->driver_data;
+       int status;
+       spin_lock_irq(&usbhid->lock);
+       clear_bit(HID_RESET_PENDING, &usbhid->iofl);
+       spin_unlock_irq(&usbhid->lock);
+       hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
+       /* FIXME: Any more reinitialization needed? */
+       status = hid_start_in(hid);
+       if (status < 0)
+               hid_io_error(hid);
+       usbhid_restart_queues(usbhid);
+
+       return 0;
+}
+
+int usbhid_get_power(struct hid_device *hid)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+       return usb_autopm_get_interface(usbhid->intf);
+}
+
+void usbhid_put_power(struct hid_device *hid)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+       usb_autopm_put_interface(usbhid->intf);
+}
+
+
+#ifdef CONFIG_PM
 static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
-       struct hid_device *hid = usb_get_intfdata (intf);
+       struct hid_device *hid = usb_get_intfdata(intf);
        struct usbhid_device *usbhid = hid->driver_data;
+       struct usb_device *udev = interface_to_usbdev(intf);
+       int status;
 
-       if (!test_bit(HID_STARTED, &usbhid->iofl))
-               return 0;
+       if (udev->auto_pm) {
+               spin_lock_irq(&usbhid->lock);   /* Sync with error handler */
+               if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
+                   && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
+                   && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
+                   && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
+                   && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
+                   && (!usbhid->ledcount || ignoreled))
+               {
+                       set_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+                       spin_unlock_irq(&usbhid->lock);
+               } else {
+                       usbhid_mark_busy(usbhid);
+                       spin_unlock_irq(&usbhid->lock);
+                       return -EBUSY;
+               }
 
-       spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
-       set_bit(HID_SUSPENDED, &usbhid->iofl);
-       spin_unlock_irq(&usbhid->inlock);
-       del_timer_sync(&usbhid->io_retry);
-       usb_kill_urb(usbhid->urbin);
+       } else {
+               spin_lock_irq(&usbhid->lock);
+               set_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+               spin_unlock_irq(&usbhid->lock);
+               if (usbhid_wait_io(hid) < 0)
+                       return -EIO;
+       }
+
+       if (!ignoreled && udev->auto_pm) {
+               spin_lock_irq(&usbhid->lock);
+               if (test_bit(HID_LED_ON, &usbhid->iofl)) {
+                       spin_unlock_irq(&usbhid->lock);
+                       usbhid_mark_busy(usbhid);
+                       return -EBUSY;
+               }
+               spin_unlock_irq(&usbhid->lock);
+       }
+
+       hid_cancel_delayed_stuff(usbhid);
+       hid_cease_io(usbhid);
+
+       if (udev->auto_pm && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
+               /* lost race against keypresses */
+               status = hid_start_in(hid);
+               if (status < 0)
+                       hid_io_error(hid);
+               usbhid_mark_busy(usbhid);
+               return -EBUSY;
+       }
        dev_dbg(&intf->dev, "suspend\n");
        return 0;
 }
@@ -1075,32 +1330,33 @@ static int hid_resume(struct usb_interface *intf)
        if (!test_bit(HID_STARTED, &usbhid->iofl))
                return 0;
 
-       clear_bit(HID_SUSPENDED, &usbhid->iofl);
+       clear_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+       usbhid_mark_busy(usbhid);
+
+       if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
+           test_bit(HID_RESET_PENDING, &usbhid->iofl))
+               schedule_work(&usbhid->reset_work);
        usbhid->retry_delay = 0;
        status = hid_start_in(hid);
-       dev_dbg(&intf->dev, "resume status %d\n", status);
-       return status;
-}
+       if (status < 0)
+               hid_io_error(hid);
+       usbhid_restart_queues(usbhid);
 
-/* Treat USB reset pretty much the same as suspend/resume */
-static int hid_pre_reset(struct usb_interface *intf)
-{
-       /* FIXME: What if the interface is already suspended? */
-       hid_suspend(intf, PMSG_ON);
+       dev_dbg(&intf->dev, "resume status %d\n", status);
        return 0;
 }
 
-/* Same routine used for post_reset and reset_resume */
-static int hid_post_reset(struct usb_interface *intf)
+static int hid_reset_resume(struct usb_interface *intf)
 {
-       struct usb_device *dev = interface_to_usbdev (intf);
-
-       hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-       /* FIXME: Any more reinitialization needed? */
+       struct hid_device *hid = usb_get_intfdata(intf);
+       struct usbhid_device *usbhid = hid->driver_data;
 
-       return hid_resume(intf);
+       clear_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+       return hid_post_reset(intf);
 }
 
+#endif /* CONFIG_PM */
+
 static struct usb_device_id hid_usb_ids [] = {
        { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
                .bInterfaceClass = USB_INTERFACE_CLASS_HID },
@@ -1113,9 +1369,11 @@ static struct usb_driver hid_driver = {
        .name =         "usbhid",
        .probe =        hid_probe,
        .disconnect =   hid_disconnect,
+#ifdef CONFIG_PM
        .suspend =      hid_suspend,
        .resume =       hid_resume,
-       .reset_resume = hid_post_reset,
+       .reset_resume = hid_reset_resume,
+#endif
        .pre_reset =    hid_pre_reset,
        .post_reset =   hid_post_reset,
        .id_table =     hid_usb_ids,
@@ -1134,7 +1392,11 @@ static struct hid_driver hid_usb_driver = {
 
 static int __init hid_init(void)
 {
-       int retval;
+       int retval = -ENOMEM;
+
+       resumption_waker = create_freezeable_workqueue("usbhid_resumer");
+       if (!resumption_waker)
+               goto no_queue;
        retval = hid_register_driver(&hid_usb_driver);
        if (retval)
                goto hid_register_fail;
@@ -1158,6 +1420,8 @@ hiddev_init_fail:
 usbhid_quirks_init_fail:
        hid_unregister_driver(&hid_usb_driver);
 hid_register_fail:
+       destroy_workqueue(resumption_waker);
+no_queue:
        return retval;
 }
 
@@ -1167,6 +1431,7 @@ static void __exit hid_exit(void)
        hiddev_exit();
        usbhid_quirks_exit();
        hid_unregister_driver(&hid_usb_driver);
+       destroy_workqueue(resumption_waker);
 }
 
 module_init(hid_init);
index aa214170baf414c0b9e1459415dd537be32325a8..e9b436d2d94434c17fb1030d50528341edd71659 100644 (file)
@@ -246,10 +246,12 @@ static int hiddev_release(struct inode * inode, struct file * file)
        spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
 
        if (!--list->hiddev->open) {
-               if (list->hiddev->exist)
+               if (list->hiddev->exist) {
                        usbhid_close(list->hiddev->hid);
-               else
+                       usbhid_put_power(list->hiddev->hid);
+               } else {
                        kfree(list->hiddev);
+               }
        }
 
        kfree(list);
@@ -300,6 +302,17 @@ static int hiddev_open(struct inode *inode, struct file *file)
        list_add_tail(&list->node, &hiddev_table[i]->list);
        spin_unlock_irq(&list->hiddev->list_lock);
 
+       if (!list->hiddev->open++)
+               if (list->hiddev->exist) {
+                       struct hid_device *hid = hiddev_table[i]->hid;
+                       res = usbhid_get_power(hid);
+                       if (res < 0) {
+                               res = -EIO;
+                               goto bail;
+                       }
+                       usbhid_open(hid);
+               }
+
        return 0;
 bail:
        file->private_data = NULL;
@@ -875,16 +888,21 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
        hiddev->hid = hid;
        hiddev->exist = 1;
 
+       /* when lock_kernel() usage is fixed in usb_open(),
+        * we could also fix it here */
+       lock_kernel();
        retval = usb_register_dev(usbhid->intf, &hiddev_class);
        if (retval) {
                err_hid("Not able to get a minor for this device.");
                hid->hiddev = NULL;
+               unlock_kernel();
                kfree(hiddev);
                return -1;
        } else {
                hid->minor = usbhid->intf->minor;
                hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
        }
+       unlock_kernel();
 
        return 0;
 }
index 9eb30564be9c0c8fba2d92ccb958ba3ed6c08913..08f505ca2e3db47426a2940fb2876a2e89ba9e14 100644 (file)
@@ -38,7 +38,10 @@ int usbhid_wait_io(struct hid_device* hid);
 void usbhid_close(struct hid_device *hid);
 int usbhid_open(struct hid_device *hid);
 void usbhid_init_reports(struct hid_device *hid);
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+void usbhid_submit_report
+(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+int usbhid_get_power(struct hid_device *hid);
+void usbhid_put_power(struct hid_device *hid);
 
 /* iofl flags */
 #define HID_CTRL_RUNNING       1
@@ -49,6 +52,9 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
 #define HID_CLEAR_HALT         6
 #define HID_DISCONNECTED       7
 #define HID_STARTED            8
+#define HID_REPORTED_IDLE      9
+#define HID_KEYS_PRESSED       10
+#define HID_LED_ON             11
 
 /*
  * USB-specific HID struct, to be pointed to
@@ -66,7 +72,6 @@ struct usbhid_device {
        struct urb *urbin;                                              /* Input URB */
        char *inbuf;                                                    /* Input buffer */
        dma_addr_t inbuf_dma;                                           /* Input buffer dma */
-       spinlock_t inlock;                                              /* Input fifo spinlock */
 
        struct urb *urbctrl;                                            /* Control URB */
        struct usb_ctrlrequest *cr;                                     /* Control request struct */
@@ -75,21 +80,22 @@ struct usbhid_device {
        unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
        char *ctrlbuf;                                                  /* Control buffer */
        dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
-       spinlock_t ctrllock;                                            /* Control fifo spinlock */
 
        struct urb *urbout;                                             /* Output URB */
        struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE];              /* Output pipe fifo */
        unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
        char *outbuf;                                                   /* Output buffer */
        dma_addr_t outbuf_dma;                                          /* Output buffer dma */
-       spinlock_t outlock;                                             /* Output fifo spinlock */
 
+       spinlock_t lock;                                                /* fifo spinlock */
        unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
        struct timer_list io_retry;                                     /* Retry timer */
        unsigned long stop_retry;                                       /* Time to give up, in jiffies */
        unsigned int retry_delay;                                       /* Delay length in ms */
        struct work_struct reset_work;                                  /* Task context for resets */
+       struct work_struct restart_work;                                /* waking up for output to be done in a task */
        wait_queue_head_t wait;                                         /* For sleeping */
+       int ledcount;                                                   /* counting the number of active leds */
 };
 
 #define        hid_to_usb_dev(hid_dev) \
index b4eea0292c1a240cc8d7c71cfd6772baaa51537b..ce52bf2f235ed541660fe4a76d728272203ea816 100644 (file)
@@ -343,12 +343,13 @@ config SENSORS_FSCPOS
          will be called fscpos.
 
 config SENSORS_FSCHMD
-       tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
+       tristate "Fujitsu Siemens Computers sensor chips"
        depends on X86 && I2C
        help
-         If you say yes here you get support for various Fujitsu Siemens
-         Computers sensor chips, including support for the integrated
-         watchdog.
+         If you say yes here you get support for the following Fujitsu
+         Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes,
+         Heimdall, Heracles, Hades and Syleus including support for the
+         integrated watchdog.
 
          This is a merged driver for FSC sensor chips replacing the fscpos,
          fscscy and fscher drivers and adding support for several other FSC
@@ -570,6 +571,17 @@ config SENSORS_LM93
          This driver can also be built as a module.  If so, the module
          will be called lm93.
 
+config SENSORS_LTC4215
+       tristate "Linear Technology LTC4215"
+       depends on I2C && EXPERIMENTAL
+       default n
+       help
+         If you say yes here you get support for Linear Technology LTC4215
+         Hot Swap Controller I2C interface.
+
+         This driver can also be built as a module. If so, the module will
+         be called ltc4215.
+
 config SENSORS_LTC4245
        tristate "Linear Technology LTC4245"
        depends on I2C && EXPERIMENTAL
@@ -581,6 +593,15 @@ config SENSORS_LTC4245
          This driver can also be built as a module. If so, the module will
          be called ltc4245.
 
+config SENSORS_LM95241
+       tristate "National Semiconductor LM95241 sensor chip"
+       depends on I2C
+       help
+         If you say yes here you get support for LM95241 sensor chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called lm95241.
+
 config SENSORS_MAX1111
        tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
        depends on SPI_MASTER
@@ -635,6 +656,20 @@ config SENSORS_PC87427
          This driver can also be built as a module.  If so, the module
          will be called pc87427.
 
+config SENSORS_PCF8591
+       tristate "Philips PCF8591 ADC/DAC"
+       depends on I2C
+       default n
+       help
+         If you say yes here you get support for Philips PCF8591 4-channel
+         ADC, 1-channel DAC chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called pcf8591.
+
+         These devices are hard to detect and rarely found on mainstream
+         hardware.  If unsure, say N.
+
 config SENSORS_SIS5595
        tristate "Silicon Integrated Systems Corp. SiS5595"
        depends on PCI
@@ -827,7 +862,7 @@ config SENSORS_W83627HF
          will be called w83627hf.
 
 config SENSORS_W83627EHF
-       tristate "Winbond W83627EHF/DHG"
+       tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
        select HWMON_VID
        help
          If you say yes here you get support for the hardware
@@ -838,6 +873,8 @@ config SENSORS_W83627EHF
          chip suited for specific Intel processors that use PECI such as
          the Core 2 Duo.
 
+         This driver also supports the W83667HG chip.
+
          This driver can also be built as a module.  If so, the module
          will be called w83627ehf.
 
@@ -895,6 +932,22 @@ config SENSORS_LIS3LV02D
          Say Y here if you have an applicable laptop and want to experience
          the awesome power of lis3lv02d.
 
+config SENSORS_LIS3_SPI
+       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
+       depends on !ACPI && SPI_MASTER && INPUT
+       default n
+       help
+         This driver provides support for the LIS3LV02Dx accelerometer connected
+         via SPI. The accelerometer data is readable via
+         /sys/devices/platform/lis3lv02d.
+
+         This driver also provides an absolute input class device, allowing
+         the laptop to act as a pinball machine-esque joystick.
+
+         This driver can also be built as modules.  If so, the core module
+         will be called lis3lv02d and a specific module for the SPI transport
+         is called lis3lv02d_spi.
+
 config SENSORS_APPLESMC
        tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
        depends on INPUT && X86
index 2e80f37f39eb4e03676b21ae20ec6e0db1b6a0ed..3a6b1f06f8f4a50bd7440da3e7dbc34a0aee7567 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_SENSORS_IBMPEX)  += ibmpex.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
 obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
+obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
 obj-$(CONFIG_SENSORS_LM70)     += lm70.o
 obj-$(CONFIG_SENSORS_LM75)     += lm75.o
@@ -64,12 +65,15 @@ obj-$(CONFIG_SENSORS_LM87)  += lm87.o
 obj-$(CONFIG_SENSORS_LM90)     += lm90.o
 obj-$(CONFIG_SENSORS_LM92)     += lm92.o
 obj-$(CONFIG_SENSORS_LM93)     += lm93.o
+obj-$(CONFIG_SENSORS_LM95241)  += lm95241.o
+obj-$(CONFIG_SENSORS_LTC4215)  += ltc4215.o
 obj-$(CONFIG_SENSORS_LTC4245)  += ltc4245.o
 obj-$(CONFIG_SENSORS_MAX1111)  += max1111.o
 obj-$(CONFIG_SENSORS_MAX1619)  += max1619.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
 obj-$(CONFIG_SENSORS_PC87360)  += pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)  += pc87427.o
+obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_SENSORS_SIS5595)  += sis5595.o
 obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
index 7415381601c3f40fdc77481485553606712728d2..53f88f5118167a8e3ebfb392ed199fb3f3c31175 100644 (file)
@@ -81,71 +81,84 @@ struct ds1621_data {
        u8 conf;                        /* Register encoding, combined */
 };
 
-static int ds1621_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id);
-static int ds1621_detect(struct i2c_client *client, int kind,
-                        struct i2c_board_info *info);
-static void ds1621_init_client(struct i2c_client *client);
-static int ds1621_remove(struct i2c_client *client);
-static struct ds1621_data *ds1621_update_client(struct device *dev);
-
-static const struct i2c_device_id ds1621_id[] = {
-       { "ds1621", ds1621 },
-       { "ds1625", ds1621 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ds1621_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver ds1621_driver = {
-       .class          = I2C_CLASS_HWMON,
-       .driver = {
-               .name   = "ds1621",
-       },
-       .probe          = ds1621_probe,
-       .remove         = ds1621_remove,
-       .id_table       = ds1621_id,
-       .detect         = ds1621_detect,
-       .address_data   = &addr_data,
-};
-
-/* All registers are word-sized, except for the configuration register.
+/* Temperature registers are word-sized.
    DS1621 uses a high-byte first convention, which is exactly opposite to
    the SMBus standard. */
-static int ds1621_read_value(struct i2c_client *client, u8 reg)
+static int ds1621_read_temp(struct i2c_client *client, u8 reg)
 {
-       if (reg == DS1621_REG_CONF)
-               return i2c_smbus_read_byte_data(client, reg);
-       else
-               return swab16(i2c_smbus_read_word_data(client, reg));
+       int ret;
+
+       ret = i2c_smbus_read_word_data(client, reg);
+       if (ret < 0)
+               return ret;
+       return swab16(ret);
 }
 
-static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
+static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value)
 {
-       if (reg == DS1621_REG_CONF)
-               return i2c_smbus_write_byte_data(client, reg, value);
-       else
-               return i2c_smbus_write_word_data(client, reg, swab16(value));
+       return i2c_smbus_write_word_data(client, reg, swab16(value));
 }
 
 static void ds1621_init_client(struct i2c_client *client)
 {
-       int reg = ds1621_read_value(client, DS1621_REG_CONF);
+       u8 conf, new_conf;
+
+       new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
        /* switch to continuous conversion mode */
-       reg &= ~ DS1621_REG_CONFIG_1SHOT;
+       new_conf &= ~DS1621_REG_CONFIG_1SHOT;
 
        /* setup output polarity */
        if (polarity == 0)
-               reg &= ~DS1621_REG_CONFIG_POLARITY;
+               new_conf &= ~DS1621_REG_CONFIG_POLARITY;
        else if (polarity == 1)
-               reg |= DS1621_REG_CONFIG_POLARITY;
+               new_conf |= DS1621_REG_CONFIG_POLARITY;
        
-       ds1621_write_value(client, DS1621_REG_CONF, reg);
+       if (conf != new_conf)
+               i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf);
        
        /* start conversion */
        i2c_smbus_write_byte(client, DS1621_COM_START);
 }
 
+static struct ds1621_data *ds1621_update_client(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1621_data *data = i2c_get_clientdata(client);
+       u8 new_conf;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               int i;
+
+               dev_dbg(&client->dev, "Starting ds1621 update\n");
+
+               data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+
+               for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+                       data->temp[i] = ds1621_read_temp(client,
+                                                        DS1621_REG_TEMP[i]);
+
+               /* reset alarms if necessary */
+               new_conf = data->conf;
+               if (data->temp[0] > data->temp[1])      /* input > min */
+                       new_conf &= ~DS1621_ALARM_TEMP_LOW;
+               if (data->temp[0] < data->temp[2])      /* input < max */
+                       new_conf &= ~DS1621_ALARM_TEMP_HIGH;
+               if (data->conf != new_conf)
+                       i2c_smbus_write_byte_data(client, DS1621_REG_CONF,
+                                                 new_conf);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
 static ssize_t show_temp(struct device *dev, struct device_attribute *da,
                         char *buf)
 {
@@ -160,13 +173,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct i2c_client *client = to_i2c_client(dev);
-       struct ds1621_data *data = ds1621_update_client(dev);
+       struct ds1621_data *data = i2c_get_clientdata(client);
        u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
 
        mutex_lock(&data->update_lock);
        data->temp[attr->index] = val;
-       ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
-                          data->temp[attr->index]);
+       ds1621_write_temp(client, DS1621_REG_TEMP[attr->index],
+                         data->temp[attr->index]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -228,13 +241,14 @@ static int ds1621_detect(struct i2c_client *client, int kind,
                /* The NVB bit should be low if no EEPROM write has been 
                   requested during the latest 10ms, which is highly 
                   improbable in our case. */
-               conf = ds1621_read_value(client, DS1621_REG_CONF);
-               if (conf & DS1621_REG_CONFIG_NVB)
+               conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+               if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
                        return -ENODEV;
                /* The 7 lowest bits of a temperature should always be 0. */
                for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
-                       temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
-                       if (temp & 0x007f)
+                       temp = i2c_smbus_read_word_data(client,
+                                                       DS1621_REG_TEMP[i]);
+                       if (temp < 0 || (temp & 0x7f00))
                                return -ENODEV;
                }
        }
@@ -294,45 +308,25 @@ static int ds1621_remove(struct i2c_client *client)
        return 0;
 }
 
+static const struct i2c_device_id ds1621_id[] = {
+       { "ds1621", ds1621 },
+       { "ds1625", ds1621 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1621_id);
 
-static struct ds1621_data *ds1621_update_client(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1621_data *data = i2c_get_clientdata(client);
-       u8 new_conf;
-
-       mutex_lock(&data->update_lock);
-
-       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-           || !data->valid) {
-               int i;
-
-               dev_dbg(&client->dev, "Starting ds1621 update\n");
-
-               data->conf = ds1621_read_value(client, DS1621_REG_CONF);
-
-               for (i = 0; i < ARRAY_SIZE(data->temp); i++)
-                       data->temp[i] = ds1621_read_value(client,
-                                                         DS1621_REG_TEMP[i]);
-
-               /* reset alarms if necessary */
-               new_conf = data->conf;
-               if (data->temp[0] > data->temp[1])      /* input > min */
-                       new_conf &= ~DS1621_ALARM_TEMP_LOW;
-               if (data->temp[0] < data->temp[2])      /* input < max */
-                       new_conf &= ~DS1621_ALARM_TEMP_HIGH;
-               if (data->conf != new_conf)
-                       ds1621_write_value(client, DS1621_REG_CONF,
-                                          new_conf);
-
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
-
-       return data;
-}
+/* This is the driver that will be inserted */
+static struct i2c_driver ds1621_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "ds1621",
+       },
+       .probe          = ds1621_probe,
+       .remove         = ds1621_remove,
+       .id_table       = ds1621_id,
+       .detect         = ds1621_detect,
+       .address_data   = &addr_data,
+};
 
 static int __init ds1621_init(void)
 {
index 18a1ba888165adf489e38189e78d459b1cec6688..e2107e533ede3371aeff3e4213bac1e06c624dfb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * f75375s.c - driver for the Fintek F75375/SP and F75373
  *             hardware monitoring features
- * Copyright (C) 2006-2007  Riku Voipio <riku.voipio@movial.fi>
+ * Copyright (C) 2006-2007  Riku Voipio
  *
  * Datasheets available at:
  *
@@ -721,7 +721,7 @@ static void __exit sensors_f75375_exit(void)
        i2c_del_driver(&f75375_driver);
 }
 
-MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>");
+MODULE_AUTHOR("Riku Voipio");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver");
 
index d07f4ef750923ca728556ed353ca6eb8ae052873..ea955edde87e5127fc4c7f57d7d0c0b51ed3b1e4 100644 (file)
@@ -1,6 +1,6 @@
 /* fschmd.c
  *
- * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com>
  *
  * 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
@@ -19,7 +19,7 @@
 
 /*
  *  Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
- *  Scylla, Heracles and Heimdall chips
+ *  Scylla, Heracles, Heimdall, Hades and Syleus chips
  *
  *  Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
  *  (candidate) fschmd drivers:
@@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
+I2C_CLIENT_INSMOD_7(fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl);
 
 /*
  * The FSCHMD registers and other defines
@@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
 #define FSCHMD_CONTROL_ALERT_LED       0x01
 
 /* watchdog */
-#define FSCHMD_REG_WDOG_PRESET         0x28
-#define FSCHMD_REG_WDOG_STATE          0x23
-#define FSCHMD_REG_WDOG_CONTROL                0x21
+static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
+       { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
+static const u8 FSCHMD_REG_WDOG_STATE[7] =
+       { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
+static const u8 FSCHMD_REG_WDOG_PRESET[7] =
+       { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
 
 #define FSCHMD_WDOG_CONTROL_TRIGGER    0x10
 #define FSCHMD_WDOG_CONTROL_STARTED    0x10 /* the same as trigger */
@@ -87,70 +90,95 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
 #define FSCHMD_WDOG_STATE_CARDRESET    0x02
 
 /* voltages, weird order is to keep the same order as the old drivers */
-static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
+static const u8 FSCHMD_REG_VOLT[7][6] = {
+       { 0x45, 0x42, 0x48 },                           /* pos */
+       { 0x45, 0x42, 0x48 },                           /* her */
+       { 0x45, 0x42, 0x48 },                           /* scy */
+       { 0x45, 0x42, 0x48 },                           /* hrc */
+       { 0x45, 0x42, 0x48 },                           /* hmd */
+       { 0x21, 0x20, 0x22 },                           /* hds */
+       { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 },         /* syl */
+};
+
+static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
 
 /* minimum pwm at which the fan is driven (pwm can by increased depending on
    the temp. Notice that for the scy some fans share there minimum speed.
    Also notice that with the scy the sensor order is different than with the
    other chips, this order was in the 2.4 driver and kept for consistency. */
-static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
+static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
        { 0x55, 0x65 },                                 /* pos */
        { 0x55, 0x65, 0xb5 },                           /* her */
        { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 },         /* scy */
        { 0x55, 0x65, 0xa5, 0xb5 },                     /* hrc */
        { 0x55, 0x65, 0xa5, 0xb5, 0xc5 },               /* hmd */
+       { 0x55, 0x65, 0xa5, 0xb5, 0xc5 },               /* hds */
+       { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 },   /* syl */
 };
 
 /* actual fan speed */
-static const u8 FSCHMD_REG_FAN_ACT[5][6] = {
+static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
        { 0x0e, 0x6b, 0xab },                           /* pos */
        { 0x0e, 0x6b, 0xbb },                           /* her */
        { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb },         /* scy */
        { 0x0e, 0x6b, 0xab, 0xbb },                     /* hrc */
        { 0x5b, 0x6b, 0xab, 0xbb, 0xcb },               /* hmd */
+       { 0x5b, 0x6b, 0xab, 0xbb, 0xcb },               /* hds */
+       { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 },   /* syl */
 };
 
 /* fan status registers */
-static const u8 FSCHMD_REG_FAN_STATE[5][6] = {
+static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
        { 0x0d, 0x62, 0xa2 },                           /* pos */
        { 0x0d, 0x62, 0xb2 },                           /* her */
        { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 },         /* scy */
        { 0x0d, 0x62, 0xa2, 0xb2 },                     /* hrc */
        { 0x52, 0x62, 0xa2, 0xb2, 0xc2 },               /* hmd */
+       { 0x52, 0x62, 0xa2, 0xb2, 0xc2 },               /* hds */
+       { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 },   /* syl */
 };
 
 /* fan ripple / divider registers */
-static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
+static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
        { 0x0f, 0x6f, 0xaf },                           /* pos */
        { 0x0f, 0x6f, 0xbf },                           /* her */
        { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf },         /* scy */
        { 0x0f, 0x6f, 0xaf, 0xbf },                     /* hrc */
        { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },               /* hmd */
+       { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },               /* hds */
+       { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 },   /* syl */
 };
 
-static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
+static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
 
 /* Fan status register bitmasks */
 #define FSCHMD_FAN_ALARM       0x04 /* called fault by FSC! */
-#define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */
+#define FSCHMD_FAN_NOT_PRESENT 0x08
+#define FSCHMD_FAN_DISABLED    0x80
 
 
 /* actual temperature registers */
-static const u8 FSCHMD_REG_TEMP_ACT[5][5] = {
+static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
        { 0x64, 0x32, 0x35 },                           /* pos */
        { 0x64, 0x32, 0x35 },                           /* her */
        { 0x64, 0xD0, 0x32, 0x35 },                     /* scy */
        { 0x64, 0x32, 0x35 },                           /* hrc */
        { 0x70, 0x80, 0x90, 0xd0, 0xe0 },               /* hmd */
+       { 0x70, 0x80, 0x90, 0xd0, 0xe0 },               /* hds */
+       { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8,           /* syl */
+         0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
 };
 
 /* temperature state registers */
-static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
+static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
        { 0x71, 0x81, 0x91 },                           /* pos */
        { 0x71, 0x81, 0x91 },                           /* her */
        { 0x71, 0xd1, 0x81, 0x91 },                     /* scy */
        { 0x71, 0x81, 0x91 },                           /* hrc */
        { 0x71, 0x81, 0x91, 0xd1, 0xe1 },               /* hmd */
+       { 0x71, 0x81, 0x91, 0xd1, 0xe1 },               /* hds */
+       { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9,           /* syl */
+         0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
 };
 
 /* temperature high limit registers, FSC does not document these. Proven to be
@@ -158,24 +186,31 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
    in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
    at these addresses, but doesn't want to confirm they are the same as with
    the fscher?? */
-static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
+static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
        { 0, 0, 0 },                                    /* pos */
        { 0x76, 0x86, 0x96 },                           /* her */
        { 0x76, 0xd6, 0x86, 0x96 },                     /* scy */
        { 0x76, 0x86, 0x96 },                           /* hrc */
        { 0x76, 0x86, 0x96, 0xd6, 0xe6 },               /* hmd */
+       { 0x76, 0x86, 0x96, 0xd6, 0xe6 },               /* hds */
+       { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa,           /* syl */
+         0xba, 0xca, 0xda, 0xea, 0xfa },
 };
 
 /* These were found through experimenting with an fscher, currently they are
    not used, but we keep them around for future reference.
+   On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
+   AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
+   the fan speed.
 static const u8 FSCHER_REG_TEMP_AUTOP1[] =     { 0x73, 0x83, 0x93 };
 static const u8 FSCHER_REG_TEMP_AUTOP2[] =     { 0x75, 0x85, 0x95 }; */
 
-static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
+static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
 
 /* temp status register bitmasks */
 #define FSCHMD_TEMP_WORKING    0x01
 #define FSCHMD_TEMP_ALERT      0x02
+#define FSCHMD_TEMP_DISABLED   0x80
 /* there only really is an alarm if the sensor is working and alert == 1 */
 #define FSCHMD_TEMP_ALARM_MASK \
        (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
@@ -201,6 +236,8 @@ static const struct i2c_device_id fschmd_id[] = {
        { "fscscy", fscscy },
        { "fschrc", fschrc },
        { "fschmd", fschmd },
+       { "fschds", fschds },
+       { "fscsyl", fscsyl },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, fschmd_id);
@@ -242,14 +279,14 @@ struct fschmd_data {
        u8 watchdog_control;    /* watchdog control register */
        u8 watchdog_state;      /* watchdog status register */
        u8 watchdog_preset;     /* watchdog counter preset on trigger val */
-       u8 volt[3];             /* 12, 5, battery voltage */
-       u8 temp_act[5];         /* temperature */
-       u8 temp_status[5];      /* status of sensor */
-       u8 temp_max[5];         /* high temp limit, notice: undocumented! */
-       u8 fan_act[6];          /* fans revolutions per second */
-       u8 fan_status[6];       /* fan status */
-       u8 fan_min[6];          /* fan min value for rps */
-       u8 fan_ripple[6];       /* divider for rps */
+       u8 volt[6];             /* voltage */
+       u8 temp_act[11];        /* temperature */
+       u8 temp_status[11];     /* status of sensor */
+       u8 temp_max[11];        /* high temp limit, notice: undocumented! */
+       u8 fan_act[7];          /* fans revolutions per second */
+       u8 fan_status[7];       /* fan status */
+       u8 fan_min[7];          /* fan min value for rps */
+       u8 fan_ripple[7];       /* divider for rps */
 };
 
 /* Global variables to hold information read from special DMI tables, which are
@@ -257,8 +294,8 @@ struct fschmd_data {
    protect these with a lock as they are only modified from our attach function
    which always gets called with the i2c-core lock held and never accessed
    before the attach function is done with them. */
-static int dmi_mult[3] = { 490, 200, 100 };
-static int dmi_offset[3] = { 0, 0, 0 };
+static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
+static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
 static int dmi_vref = -1;
 
 /* Somewhat ugly :( global data pointer list with all fschmd devices, so that
@@ -450,10 +487,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
        struct device_attribute *devattr, char *buf)
 {
        int index = to_sensor_dev_attr(devattr)->index;
-       int val = fschmd_update_device(dev)->fan_min[index];
+       struct fschmd_data *data = fschmd_update_device(dev);
+       int val = data->fan_min[index];
 
-       /* 0 = allow turning off, 1-255 = 50-100% */
-       if (val)
+       /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
+       if (val || data->kind == fscsyl - 1)
                val = val / 2 + 128;
 
        return sprintf(buf, "%d\n", val);
@@ -466,8 +504,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
        struct fschmd_data *data = dev_get_drvdata(dev);
        unsigned long v = simple_strtoul(buf, NULL, 10);
 
-       /* register: 0 = allow turning off, 1-255 = 50-100% */
-       if (v) {
+       /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
+       if (v || data->kind == fscsyl - 1) {
                v = SENSORS_LIMIT(v, 128, 255);
                v = (v - 128) * 2 + 1;
        }
@@ -522,11 +560,15 @@ static ssize_t store_alert_led(struct device *dev,
        return count;
 }
 
+static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
+
 static struct sensor_device_attribute fschmd_attr[] = {
        SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
        SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
        SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
-       SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
+       SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3),
+       SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4),
+       SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5),
 };
 
 static struct sensor_device_attribute fschmd_temp_attr[] = {
@@ -550,6 +592,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = {
        SENSOR_ATTR(temp5_max,   0644, show_temp_max, store_temp_max, 4),
        SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
        SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
+       SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5),
+       SENSOR_ATTR(temp6_max,   0644, show_temp_max, store_temp_max, 5),
+       SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5),
+       SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5),
+       SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6),
+       SENSOR_ATTR(temp7_max,   0644, show_temp_max, store_temp_max, 6),
+       SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6),
+       SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6),
+       SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7),
+       SENSOR_ATTR(temp8_max,   0644, show_temp_max, store_temp_max, 7),
+       SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7),
+       SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7),
+       SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8),
+       SENSOR_ATTR(temp9_max,   0644, show_temp_max, store_temp_max, 8),
+       SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8),
+       SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8),
+       SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9),
+       SENSOR_ATTR(temp10_max,   0644, show_temp_max, store_temp_max, 9),
+       SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9),
+       SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9),
+       SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10),
+       SENSOR_ATTR(temp11_max,   0644, show_temp_max, store_temp_max, 10),
+       SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10),
+       SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10),
 };
 
 static struct sensor_device_attribute fschmd_fan_attr[] = {
@@ -589,6 +655,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
        SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
        SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
                store_pwm_auto_point1_pwm, 5),
+       SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6),
+       SENSOR_ATTR(fan7_div,   0644, show_fan_div, store_fan_div, 6),
+       SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6),
+       SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6),
+       SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 6),
 };
 
 
@@ -624,10 +696,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
        data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
 
        /* Write new timeout value */
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET,
-               data->watchdog_preset);
+       i2c_smbus_write_byte_data(data->client,
+               FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
        /* Write new control register, do not trigger! */
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
+       i2c_smbus_write_byte_data(data->client,
+               FSCHMD_REG_WDOG_CONTROL[data->kind],
                data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
 
        ret = data->watchdog_preset * resolution;
@@ -662,8 +735,9 @@ static int watchdog_trigger(struct fschmd_data *data)
        }
 
        data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
-                                       data->watchdog_control);
+       i2c_smbus_write_byte_data(data->client,
+                                 FSCHMD_REG_WDOG_CONTROL[data->kind],
+                                 data->watchdog_control);
 leave:
        mutex_unlock(&data->watchdog_lock);
        return ret;
@@ -682,7 +756,8 @@ static int watchdog_stop(struct fschmd_data *data)
        data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
        /* Don't store the stop flag in our watchdog control register copy, as
           its a write only bit (read always returns 0) */
-       i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
+       i2c_smbus_write_byte_data(data->client,
+               FSCHMD_REG_WDOG_CONTROL[data->kind],
                data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
 leave:
        mutex_unlock(&data->watchdog_lock);
@@ -856,7 +931,7 @@ static struct file_operations watchdog_fops = {
 
 /* DMI decode routine to read voltage scaling factors from special DMI tables,
    which are available on FSC machines with an fscher or later chip. */
-static void fschmd_dmi_decode(const struct dmi_header *header)
+static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
 {
        int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
 
@@ -912,6 +987,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header)
                        dmi_mult[i] = mult[i] * 10;
                        dmi_offset[i] = offset[i] * 10;
                }
+               /* According to the docs there should be separate dmi entries
+                  for the mult's and offsets of in3-5 of the syl, but on
+                  my test machine these are not present */
+               dmi_mult[3] = dmi_mult[2];
+               dmi_mult[4] = dmi_mult[1];
+               dmi_mult[5] = dmi_mult[2];
+               dmi_offset[3] = dmi_offset[2];
+               dmi_offset[4] = dmi_offset[1];
+               dmi_offset[5] = dmi_offset[2];
                dmi_vref = vref;
        }
 }
@@ -920,8 +1004,6 @@ static int fschmd_detect(struct i2c_client *client, int kind,
                         struct i2c_board_info *info)
 {
        struct i2c_adapter *adapter = client->adapter;
-       const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
-                                               "fschrc", "fschmd" };
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -948,11 +1030,15 @@ static int fschmd_detect(struct i2c_client *client, int kind,
                        kind = fschrc;
                else if (!strcmp(id, "HMD"))
                        kind = fschmd;
+               else if (!strcmp(id, "HDS"))
+                       kind = fschds;
+               else if (!strcmp(id, "SYL"))
+                       kind = fscsyl;
                else
                        return -ENODEV;
        }
 
-       strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE);
+       strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
 
        return 0;
 }
@@ -961,8 +1047,8 @@ static int fschmd_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct fschmd_data *data;
-       const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
-                                       "Heracles", "Heimdall" };
+       const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
+                               "Heracles", "Heimdall", "Hades", "Syleus" };
        const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
        int i, err;
        enum chips kind = id->driver_data;
@@ -991,7 +1077,7 @@ static int fschmd_probe(struct i2c_client *client,
 
        /* Read the special DMI table for fscher and newer chips */
        if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
-               dmi_walk(fschmd_dmi_decode);
+               dmi_walk(fschmd_dmi_decode, NULL);
                if (dmi_vref == -1) {
                        dev_warn(&client->dev,
                                "Couldn't get voltage scaling factors from "
@@ -1000,21 +1086,25 @@ static int fschmd_probe(struct i2c_client *client,
                }
        }
 
+       /* i2c kind goes from 1-6, we want from 0-5 to address arrays */
+       data->kind = kind - 1;
+
        /* Read in some never changing registers */
        data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
        data->global_control = i2c_smbus_read_byte_data(client,
                                        FSCHMD_REG_CONTROL);
        data->watchdog_control = i2c_smbus_read_byte_data(client,
-                                       FSCHMD_REG_WDOG_CONTROL);
+                                       FSCHMD_REG_WDOG_CONTROL[data->kind]);
        data->watchdog_state = i2c_smbus_read_byte_data(client,
-                                       FSCHMD_REG_WDOG_STATE);
+                                       FSCHMD_REG_WDOG_STATE[data->kind]);
        data->watchdog_preset = i2c_smbus_read_byte_data(client,
-                                       FSCHMD_REG_WDOG_PRESET);
+                                       FSCHMD_REG_WDOG_PRESET[data->kind]);
 
-       /* i2c kind goes from 1-5, we want from 0-4 to address arrays */
-       data->kind = kind - 1;
+       err = device_create_file(&client->dev, &dev_attr_alert_led);
+       if (err)
+               goto exit_detach;
 
-       for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
+       for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
                err = device_create_file(&client->dev,
                                        &fschmd_attr[i].dev_attr);
                if (err)
@@ -1027,6 +1117,16 @@ static int fschmd_probe(struct i2c_client *client,
                                show_temp_max)
                        continue;
 
+               if (kind == fscsyl) {
+                       if (i % 4 == 0)
+                               data->temp_status[i / 4] =
+                                       i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_TEMP_STATE
+                                               [data->kind][i / 4]);
+                       if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
+                               continue;
+               }
+
                err = device_create_file(&client->dev,
                                        &fschmd_temp_attr[i].dev_attr);
                if (err)
@@ -1040,6 +1140,16 @@ static int fschmd_probe(struct i2c_client *client,
                                        "pwm3_auto_point1_pwm"))
                        continue;
 
+               if (kind == fscsyl) {
+                       if (i % 5 == 0)
+                               data->fan_status[i / 5] =
+                                       i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_FAN_STATE
+                                               [data->kind][i / 5]);
+                       if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
+                               continue;
+               }
+
                err = device_create_file(&client->dev,
                                        &fschmd_fan_attr[i].dev_attr);
                if (err)
@@ -1126,7 +1236,8 @@ static int fschmd_remove(struct i2c_client *client)
        if (data->hwmon_dev)
                hwmon_device_unregister(data->hwmon_dev);
 
-       for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)
+       device_remove_file(&client->dev, &dev_attr_alert_led);
+       for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
                device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
        for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
                device_remove_file(&client->dev,
@@ -1171,7 +1282,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
                                        data->temp_act[i] < data->temp_max[i])
                                i2c_smbus_write_byte_data(client,
                                        FSCHMD_REG_TEMP_STATE[data->kind][i],
-                                       FSCHMD_TEMP_ALERT);
+                                       data->temp_status[i]);
                }
 
                for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
@@ -1193,12 +1304,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
                                        data->fan_act[i])
                                i2c_smbus_write_byte_data(client,
                                        FSCHMD_REG_FAN_STATE[data->kind][i],
-                                       FSCHMD_FAN_ALARM);
+                                       data->fan_status[i]);
                }
 
-               for (i = 0; i < 3; i++)
+               for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
                        data->volt[i] = i2c_smbus_read_byte_data(client,
-                                               FSCHMD_REG_VOLT[i]);
+                                              FSCHMD_REG_VOLT[data->kind][i]);
 
                data->last_updated = jiffies;
                data->valid = 1;
@@ -1220,8 +1331,8 @@ static void __exit fschmd_exit(void)
 }
 
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
-MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
-                       "Heimdall driver");
+MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
+                       "and Syleus driver");
 MODULE_LICENSE("GPL");
 
 module_init(fschmd_init);
index a4d92d246d52620e1efb09288df69fdcbf352303..d3612a1f198135d1a719428fc5f77e417674e671 100644 (file)
 #define HDAPS_INPUT_FUZZ       4       /* input event threshold */
 #define HDAPS_INPUT_FLAT       4
 
+#define HDAPS_X_AXIS           (1 << 0)
+#define HDAPS_Y_AXIS           (1 << 1)
+#define HDAPS_BOTH_AXES                (HDAPS_X_AXIS | HDAPS_Y_AXIS)
+
 static struct platform_device *pdev;
 static struct input_polled_dev *hdaps_idev;
 static unsigned int hdaps_invert;
@@ -182,11 +186,11 @@ static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
        km_activity = inb(HDAPS_PORT_KMACT);
        __device_complete();
 
-       /* if hdaps_invert is set, negate the two values */
-       if (hdaps_invert) {
+       /* hdaps_invert is a bitvector to negate the axes */
+       if (hdaps_invert & HDAPS_X_AXIS)
                *x = -*x;
+       if (hdaps_invert & HDAPS_Y_AXIS)
                *y = -*y;
-       }
 
        return 0;
 }
@@ -436,7 +440,8 @@ static ssize_t hdaps_invert_store(struct device *dev,
 {
        int invert;
 
-       if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0))
+       if (sscanf(buf, "%d", &invert) != 1 ||
+           invert < 0 || invert > HDAPS_BOTH_AXES)
                return -EINVAL;
 
        hdaps_invert = invert;
@@ -483,56 +488,52 @@ static int __init hdaps_dmi_match(const struct dmi_system_id *id)
 /* hdaps_dmi_match_invert - found an inverted match. */
 static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
 {
-       hdaps_invert = 1;
-       printk(KERN_INFO "hdaps: inverting axis readings.\n");
+       hdaps_invert = (unsigned long)id->driver_data;
+       printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
+              hdaps_invert);
        return hdaps_dmi_match(id);
 }
 
-#define HDAPS_DMI_MATCH_NORMAL(vendor, model) {                \
-       .ident = vendor " " model,                      \
-       .callback = hdaps_dmi_match,                    \
-       .matches = {                                    \
-               DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
-               DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
-       }                                               \
-}
-
-#define HDAPS_DMI_MATCH_INVERT(vendor, model) {                \
+#define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) {  \
        .ident = vendor " " model,                      \
        .callback = hdaps_dmi_match_invert,             \
+       .driver_data = (void *)axes,                    \
        .matches = {                                    \
                DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
                DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
        }                                               \
 }
 
+#define HDAPS_DMI_MATCH_NORMAL(vendor, model)          \
+       HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
+
 /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
    "ThinkPad T42p", so the order of the entries matters.
    If your ThinkPad is not recognized, please update to latest
    BIOS. This is especially the case for some R52 ThinkPads. */
 static struct dmi_system_id __initdata hdaps_whitelist[] = {
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"),
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES),
        HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES),
        { .ident = NULL }
 };
 
@@ -627,8 +628,9 @@ static void __exit hdaps_exit(void)
 module_init(hdaps_init);
 module_exit(hdaps_exit);
 
-module_param_named(invert, hdaps_invert, bool, 0);
-MODULE_PARM_DESC(invert, "invert data along each axis");
+module_param_named(invert, hdaps_invert, int, 0);
+MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, "
+                "2 invert y-axis, 3 invert both axes.");
 
 MODULE_AUTHOR("Robert Love");
 MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
index 29c83b5b96974bb88cbeb67d896ba46ee71469f2..55d3dc565be6cbd4209762aa40815c7c37a02a35 100644 (file)
@@ -85,25 +85,31 @@ MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
 
 /**
  * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
- * @handle: the handle of the device
+ * @lis3: pointer to the device struct
  *
- * Returns AE_OK on success.
+ * Returns 0 on success.
  */
-acpi_status lis3lv02d_acpi_init(acpi_handle handle)
+int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
 {
-       return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL);
+       struct acpi_device *dev = lis3->bus_priv;
+       if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI,
+                                NULL, NULL) != AE_OK)
+               return -EINVAL;
+
+       return 0;
 }
 
 /**
  * lis3lv02d_acpi_read - ACPI ALRD method: read a register
- * @handle: the handle of the device
+ * @lis3: pointer to the device struct
  * @reg:    the register to read
  * @ret:    result of the operation
  *
- * Returns AE_OK on success.
+ * Returns 0 on success.
  */
-acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret)
+int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
 {
+       struct acpi_device *dev = lis3->bus_priv;
        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
        struct acpi_object_list args = { 1, &arg0 };
        unsigned long long lret;
@@ -111,21 +117,22 @@ acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret)
 
        arg0.integer.value = reg;
 
-       status = acpi_evaluate_integer(handle, "ALRD", &args, &lret);
+       status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret);
        *ret = lret;
-       return status;
+       return (status != AE_OK) ? -EINVAL : 0;
 }
 
 /**
  * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
- * @handle: the handle of the device
+ * @lis3: pointer to the device struct
  * @reg:    the register to write to
  * @val:    the value to write
  *
- * Returns AE_OK on success.
+ * Returns 0 on success.
  */
-acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val)
+int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
 {
+       struct acpi_device *dev = lis3->bus_priv;
        unsigned long long ret; /* Not used when writting */
        union acpi_object in_obj[2];
        struct acpi_object_list args = { 2, in_obj };
@@ -135,12 +142,15 @@ acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val)
        in_obj[1].type          = ACPI_TYPE_INTEGER;
        in_obj[1].integer.value = val;
 
-       return acpi_evaluate_integer(handle, "ALWR", &args, &ret);
+       if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK)
+               return -EINVAL;
+
+       return 0;
 }
 
 static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
 {
-       adev.ac = *((struct axis_conversion *)dmi->driver_data);
+       lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data);
        printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
 
        return 1;
@@ -187,6 +197,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
        AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
        AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
+       AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
        AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
        AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd),
        AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
@@ -201,6 +212,8 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
                        PRODUCT_NAME, "HP Pavilion dv5",
                        BOARD_NAME, "3600",
                        y_inverted),
+       AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted),
+       AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted),
        { NULL, }
 /* Laptop models without axis info (yet):
  * "NC6910" "HP Compaq 6910"
@@ -214,7 +227,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
 
 static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value)
 {
-       acpi_handle handle = adev.device->handle;
+       struct acpi_device *dev = lis3_dev.bus_priv;
        unsigned long long ret; /* Not used when writing */
        union acpi_object in_obj[1];
        struct acpi_object_list args = { 1, in_obj };
@@ -222,7 +235,7 @@ static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness
        in_obj[0].type          = ACPI_TYPE_INTEGER;
        in_obj[0].integer.value = !!value;
 
-       acpi_evaluate_integer(handle, "ALED", &args, &ret);
+       acpi_evaluate_integer(dev->handle, "ALED", &args, &ret);
 }
 
 static struct delayed_led_classdev hpled_led = {
@@ -254,28 +267,11 @@ static void lis3lv02d_enum_resources(struct acpi_device *device)
        acpi_status status;
 
        status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                                       lis3lv02d_get_resource, &adev.irq);
+                                       lis3lv02d_get_resource, &lis3_dev.irq);
        if (ACPI_FAILURE(status))
                printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
 }
 
-static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
-{
-       u8 lo, hi;
-
-       adev.read(handle, reg - 1, &lo);
-       adev.read(handle, reg, &hi);
-       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
-       return (s16)((hi << 8) | lo);
-}
-
-static s16 lis3lv02d_read_8(acpi_handle handle, int reg)
-{
-       s8 lo;
-       adev.read(handle, reg, &lo);
-       return lo;
-}
-
 static int lis3lv02d_add(struct acpi_device *device)
 {
        int ret;
@@ -283,51 +279,35 @@ static int lis3lv02d_add(struct acpi_device *device)
        if (!device)
                return -EINVAL;
 
-       adev.device = device;
-       adev.init = lis3lv02d_acpi_init;
-       adev.read = lis3lv02d_acpi_read;
-       adev.write = lis3lv02d_acpi_write;
+       lis3_dev.bus_priv = device;
+       lis3_dev.init = lis3lv02d_acpi_init;
+       lis3_dev.read = lis3lv02d_acpi_read;
+       lis3_dev.write = lis3lv02d_acpi_write;
        strcpy(acpi_device_name(device), DRIVER_NAME);
        strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
-       device->driver_data = &adev;
-
-       lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami);
-       switch (adev.whoami) {
-       case LIS_DOUBLE_ID:
-               printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n");
-               adev.read_data = lis3lv02d_read_16;
-               adev.mdps_max_val = 2048;
-               break;
-       case LIS_SINGLE_ID:
-               printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n");
-               adev.read_data = lis3lv02d_read_8;
-               adev.mdps_max_val = 128;
-               break;
-       default:
-               printk(KERN_ERR DRIVER_NAME
-                       ": unknown sensor type 0x%X\n", adev.whoami);
-               return -EINVAL;
-       }
+       device->driver_data = &lis3_dev;
+
+       /* obtain IRQ number of our device from ACPI */
+       lis3lv02d_enum_resources(device);
 
        /* If possible use a "standard" axes order */
        if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
                printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
                                 "using default axes configuration\n");
-               adev.ac = lis3lv02d_axis_normal;
+               lis3_dev.ac = lis3lv02d_axis_normal;
        }
 
-       INIT_WORK(&hpled_led.work, delayed_set_status_worker);
-       ret = led_classdev_register(NULL, &hpled_led.led_classdev);
+       /* call the core layer do its init */
+       ret = lis3lv02d_init_device(&lis3_dev);
        if (ret)
                return ret;
 
-       /* obtain IRQ number of our device from ACPI */
-       lis3lv02d_enum_resources(adev.device);
-
-       ret = lis3lv02d_init_device(&adev);
+       INIT_WORK(&hpled_led.work, delayed_set_status_worker);
+       ret = led_classdev_register(NULL, &hpled_led.led_classdev);
        if (ret) {
+               lis3lv02d_joystick_disable();
+               lis3lv02d_poweroff(&lis3_dev);
                flush_work(&hpled_led.work);
-               led_classdev_unregister(&hpled_led.led_classdev);
                return ret;
        }
 
@@ -340,7 +320,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
                return -EINVAL;
 
        lis3lv02d_joystick_disable();
-       lis3lv02d_poweroff(device->handle);
+       lis3lv02d_poweroff(&lis3_dev);
 
        flush_work(&hpled_led.work);
        led_classdev_unregister(&hpled_led.led_classdev);
@@ -353,19 +333,19 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
 {
        /* make sure the device is off when we suspend */
-       lis3lv02d_poweroff(device->handle);
+       lis3lv02d_poweroff(&lis3_dev);
        return 0;
 }
 
 static int lis3lv02d_resume(struct acpi_device *device)
 {
        /* put back the device in the right state (ACPI might turn it on) */
-       mutex_lock(&adev.lock);
-       if (adev.usage > 0)
-               lis3lv02d_poweron(device->handle);
+       mutex_lock(&lis3_dev.lock);
+       if (lis3_dev.usage > 0)
+               lis3lv02d_poweron(&lis3_dev);
        else
-               lis3lv02d_poweroff(device->handle);
-       mutex_unlock(&adev.lock);
+               lis3lv02d_poweroff(&lis3_dev);
+       mutex_unlock(&lis3_dev.lock);
        return 0;
 }
 #else
index 8bb2158f0453c01f3c089ffaa88d8eea2927fd9d..778eb77959837eed9c1172cfe4524d0273434b54 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
-#include <acpi/acpi_drivers.h>
 #include <asm/atomic.h>
 #include "lis3lv02d.h"
 
  * joystick.
  */
 
-struct acpi_lis3lv02d adev = {
-       .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(adev.misc_wait),
+struct lis3lv02d lis3_dev = {
+       .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
 };
 
-EXPORT_SYMBOL_GPL(adev);
+EXPORT_SYMBOL_GPL(lis3_dev);
 
-static int lis3lv02d_add_fs(struct acpi_device *device);
+static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
+{
+       s8 lo;
+       if (lis3->read(lis3, reg, &lo) < 0)
+               return 0;
+
+       return lo;
+}
+
+static s16 lis3lv02d_read_16(struct lis3lv02d *lis3, int reg)
+{
+       u8 lo, hi;
+
+       lis3->read(lis3, reg - 1, &lo);
+       lis3->read(lis3, reg, &hi);
+       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
+       return (s16)((hi << 8) | lo);
+}
 
 /**
  * lis3lv02d_get_axis - For the given axis, give the value converted
@@ -78,36 +94,36 @@ static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
 
 /**
  * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
- * @handle: the handle to the device
- * @x:      where to store the X axis value
- * @y:      where to store the Y axis value
- * @z:      where to store the Z axis value
+ * @lis3: pointer to the device struct
+ * @x:    where to store the X axis value
+ * @y:    where to store the Y axis value
+ * @z:    where to store the Z axis value
  *
  * Note that 40Hz input device can eat up about 10% CPU at 800MHZ
  */
-static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z)
+static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
 {
        int position[3];
 
-       position[0] = adev.read_data(handle, OUTX);
-       position[1] = adev.read_data(handle, OUTY);
-       position[2] = adev.read_data(handle, OUTZ);
+       position[0] = lis3_dev.read_data(lis3, OUTX);
+       position[1] = lis3_dev.read_data(lis3, OUTY);
+       position[2] = lis3_dev.read_data(lis3, OUTZ);
 
-       *x = lis3lv02d_get_axis(adev.ac.x, position);
-       *y = lis3lv02d_get_axis(adev.ac.y, position);
-       *z = lis3lv02d_get_axis(adev.ac.z, position);
+       *x = lis3lv02d_get_axis(lis3_dev.ac.x, position);
+       *y = lis3lv02d_get_axis(lis3_dev.ac.y, position);
+       *z = lis3lv02d_get_axis(lis3_dev.ac.z, position);
 }
 
-void lis3lv02d_poweroff(acpi_handle handle)
+void lis3lv02d_poweroff(struct lis3lv02d *lis3)
 {
-       adev.is_on = 0;
+       lis3_dev.is_on = 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
 
-void lis3lv02d_poweron(acpi_handle handle)
+void lis3lv02d_poweron(struct lis3lv02d *lis3)
 {
-       adev.is_on = 1;
-       adev.init(handle);
+       lis3_dev.is_on = 1;
+       lis3_dev.init(lis3);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
@@ -116,13 +132,13 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
  * device will always be on until a call to lis3lv02d_decrease_use(). Not to be
  * used from interrupt context.
  */
-static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev)
+static void lis3lv02d_increase_use(struct lis3lv02d *dev)
 {
        mutex_lock(&dev->lock);
        dev->usage++;
        if (dev->usage == 1) {
                if (!dev->is_on)
-                       lis3lv02d_poweron(dev->device->handle);
+                       lis3lv02d_poweron(dev);
        }
        mutex_unlock(&dev->lock);
 }
@@ -131,12 +147,12 @@ static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev)
  * To be called whenever a usage of the device is stopped.
  * It will make sure to turn off the device when there is not usage.
  */
-static void lis3lv02d_decrease_use(struct acpi_lis3lv02d *dev)
+static void lis3lv02d_decrease_use(struct lis3lv02d *dev)
 {
        mutex_lock(&dev->lock);
        dev->usage--;
        if (dev->usage == 0)
-               lis3lv02d_poweroff(dev->device->handle);
+               lis3lv02d_poweroff(dev);
        mutex_unlock(&dev->lock);
 }
 
@@ -147,10 +163,10 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
         * the lid is closed. This leads to interrupts as soon as a little move
         * is done.
         */
-       atomic_inc(&adev.count);
+       atomic_inc(&lis3_dev.count);
 
-       wake_up_interruptible(&adev.misc_wait);
-       kill_fasync(&adev.async_queue, SIGIO, POLL_IN);
+       wake_up_interruptible(&lis3_dev.misc_wait);
+       kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
        return IRQ_HANDLED;
 }
 
@@ -158,10 +174,10 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
 {
        int ret;
 
-       if (test_and_set_bit(0, &adev.misc_opened))
+       if (test_and_set_bit(0, &lis3_dev.misc_opened))
                return -EBUSY; /* already open */
 
-       atomic_set(&adev.count, 0);
+       atomic_set(&lis3_dev.count, 0);
 
        /*
         * The sensor can generate interrupts for free-fall and direction
@@ -174,25 +190,25 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
         * io-apic is not configurable (and generates a warning) but I keep it
         * in case of support for other hardware.
         */
-       ret = request_irq(adev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
-                         DRIVER_NAME, &adev);
+       ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
+                         DRIVER_NAME, &lis3_dev);
 
        if (ret) {
-               clear_bit(0, &adev.misc_opened);
-               printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", adev.irq);
+               clear_bit(0, &lis3_dev.misc_opened);
+               printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
                return -EBUSY;
        }
-       lis3lv02d_increase_use(&adev);
-       printk("lis3: registered interrupt %d\n", adev.irq);
+       lis3lv02d_increase_use(&lis3_dev);
+       printk("lis3: registered interrupt %d\n", lis3_dev.irq);
        return 0;
 }
 
 static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
-       fasync_helper(-1, file, 0, &adev.async_queue);
-       lis3lv02d_decrease_use(&adev);
-       free_irq(adev.irq, &adev);
-       clear_bit(0, &adev.misc_opened); /* release the device */
+       fasync_helper(-1, file, 0, &lis3_dev.async_queue);
+       lis3lv02d_decrease_use(&lis3_dev);
+       free_irq(lis3_dev.irq, &lis3_dev);
+       clear_bit(0, &lis3_dev.misc_opened); /* release the device */
        return 0;
 }
 
@@ -207,10 +223,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
        if (count < 1)
                return -EINVAL;
 
-       add_wait_queue(&adev.misc_wait, &wait);
+       add_wait_queue(&lis3_dev.misc_wait, &wait);
        while (true) {
                set_current_state(TASK_INTERRUPTIBLE);
-               data = atomic_xchg(&adev.count, 0);
+               data = atomic_xchg(&lis3_dev.count, 0);
                if (data)
                        break;
 
@@ -240,22 +256,22 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
 
 out:
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&adev.misc_wait, &wait);
+       remove_wait_queue(&lis3_dev.misc_wait, &wait);
 
        return retval;
 }
 
 static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
 {
-       poll_wait(file, &adev.misc_wait, wait);
-       if (atomic_read(&adev.count))
+       poll_wait(file, &lis3_dev.misc_wait, wait);
+       if (atomic_read(&lis3_dev.count))
                return POLLIN | POLLRDNORM;
        return 0;
 }
 
 static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
 {
-       return fasync_helper(fd, file, on, &adev.async_queue);
+       return fasync_helper(fd, file, on, &lis3_dev.async_queue);
 }
 
 static const struct file_operations lis3lv02d_misc_fops = {
@@ -283,12 +299,12 @@ static int lis3lv02d_joystick_kthread(void *data)
        int x, y, z;
 
        while (!kthread_should_stop()) {
-               lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z);
-               input_report_abs(adev.idev, ABS_X, x - adev.xcalib);
-               input_report_abs(adev.idev, ABS_Y, y - adev.ycalib);
-               input_report_abs(adev.idev, ABS_Z, z - adev.zcalib);
+               lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+               input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib);
+               input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib);
+               input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib);
 
-               input_sync(adev.idev);
+               input_sync(lis3_dev.idev);
 
                try_to_freeze();
                msleep_interruptible(MDPS_POLL_INTERVAL);
@@ -299,11 +315,11 @@ static int lis3lv02d_joystick_kthread(void *data)
 
 static int lis3lv02d_joystick_open(struct input_dev *input)
 {
-       lis3lv02d_increase_use(&adev);
-       adev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
-       if (IS_ERR(adev.kthread)) {
-               lis3lv02d_decrease_use(&adev);
-               return PTR_ERR(adev.kthread);
+       lis3lv02d_increase_use(&lis3_dev);
+       lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
+       if (IS_ERR(lis3_dev.kthread)) {
+               lis3lv02d_decrease_use(&lis3_dev);
+               return PTR_ERR(lis3_dev.kthread);
        }
 
        return 0;
@@ -311,45 +327,46 @@ static int lis3lv02d_joystick_open(struct input_dev *input)
 
 static void lis3lv02d_joystick_close(struct input_dev *input)
 {
-       kthread_stop(adev.kthread);
-       lis3lv02d_decrease_use(&adev);
+       kthread_stop(lis3_dev.kthread);
+       lis3lv02d_decrease_use(&lis3_dev);
 }
 
 static inline void lis3lv02d_calibrate_joystick(void)
 {
-       lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib);
+       lis3lv02d_get_xyz(&lis3_dev,
+               &lis3_dev.xcalib, &lis3_dev.ycalib, &lis3_dev.zcalib);
 }
 
 int lis3lv02d_joystick_enable(void)
 {
        int err;
 
-       if (adev.idev)
+       if (lis3_dev.idev)
                return -EINVAL;
 
-       adev.idev = input_allocate_device();
-       if (!adev.idev)
+       lis3_dev.idev = input_allocate_device();
+       if (!lis3_dev.idev)
                return -ENOMEM;
 
        lis3lv02d_calibrate_joystick();
 
-       adev.idev->name       = "ST LIS3LV02DL Accelerometer";
-       adev.idev->phys       = DRIVER_NAME "/input0";
-       adev.idev->id.bustype = BUS_HOST;
-       adev.idev->id.vendor  = 0;
-       adev.idev->dev.parent = &adev.pdev->dev;
-       adev.idev->open       = lis3lv02d_joystick_open;
-       adev.idev->close      = lis3lv02d_joystick_close;
+       lis3_dev.idev->name       = "ST LIS3LV02DL Accelerometer";
+       lis3_dev.idev->phys       = DRIVER_NAME "/input0";
+       lis3_dev.idev->id.bustype = BUS_HOST;
+       lis3_dev.idev->id.vendor  = 0;
+       lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev;
+       lis3_dev.idev->open       = lis3lv02d_joystick_open;
+       lis3_dev.idev->close      = lis3lv02d_joystick_close;
 
-       set_bit(EV_ABS, adev.idev->evbit);
-       input_set_abs_params(adev.idev, ABS_X, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
-       input_set_abs_params(adev.idev, ABS_Y, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
-       input_set_abs_params(adev.idev, ABS_Z, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
+       set_bit(EV_ABS, lis3_dev.idev->evbit);
+       input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
+       input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
+       input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
 
-       err = input_register_device(adev.idev);
+       err = input_register_device(lis3_dev.idev);
        if (err) {
-               input_free_device(adev.idev);
-               adev.idev = NULL;
+               input_free_device(lis3_dev.idev);
+               lis3_dev.idev = NULL;
        }
 
        return err;
@@ -358,71 +375,40 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
 
 void lis3lv02d_joystick_disable(void)
 {
-       if (!adev.idev)
+       if (!lis3_dev.idev)
                return;
 
        misc_deregister(&lis3lv02d_misc_device);
-       input_unregister_device(adev.idev);
-       adev.idev = NULL;
+       input_unregister_device(lis3_dev.idev);
+       lis3_dev.idev = NULL;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
 
-/*
- * Initialise the accelerometer and the various subsystems.
- * Should be rather independant of the bus system.
- */
-int lis3lv02d_init_device(struct acpi_lis3lv02d *dev)
-{
-       mutex_init(&dev->lock);
-       lis3lv02d_add_fs(dev->device);
-       lis3lv02d_increase_use(dev);
-
-       if (lis3lv02d_joystick_enable())
-               printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
-
-       printk("lis3_init_device: irq %d\n", dev->irq);
-
-       /* if we did not get an IRQ from ACPI - we have nothing more to do */
-       if (!dev->irq) {
-               printk(KERN_ERR DRIVER_NAME
-                       ": No IRQ in ACPI. Disabling /dev/freefall\n");
-               goto out;
-       }
-
-       printk("lis3: registering device\n");
-       if (misc_register(&lis3lv02d_misc_device))
-               printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
-out:
-       lis3lv02d_decrease_use(dev);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
-
 /* Sysfs stuff */
 static ssize_t lis3lv02d_position_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        int x, y, z;
 
-       lis3lv02d_increase_use(&adev);
-       lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z);
-       lis3lv02d_decrease_use(&adev);
+       lis3lv02d_increase_use(&lis3_dev);
+       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       lis3lv02d_decrease_use(&lis3_dev);
        return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
 }
 
 static ssize_t lis3lv02d_calibrate_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "(%d,%d,%d)\n", adev.xcalib, adev.ycalib, adev.zcalib);
+       return sprintf(buf, "(%d,%d,%d)\n", lis3_dev.xcalib, lis3_dev.ycalib, lis3_dev.zcalib);
 }
 
 static ssize_t lis3lv02d_calibrate_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       lis3lv02d_increase_use(&adev);
+       lis3lv02d_increase_use(&lis3_dev);
        lis3lv02d_calibrate_joystick();
-       lis3lv02d_decrease_use(&adev);
+       lis3lv02d_decrease_use(&lis3_dev);
        return count;
 }
 
@@ -434,9 +420,9 @@ static ssize_t lis3lv02d_rate_show(struct device *dev,
        u8 ctrl;
        int val;
 
-       lis3lv02d_increase_use(&adev);
-       adev.read(adev.device->handle, CTRL_REG1, &ctrl);
-       lis3lv02d_decrease_use(&adev);
+       lis3lv02d_increase_use(&lis3_dev);
+       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
+       lis3lv02d_decrease_use(&lis3_dev);
        val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4;
        return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]);
 }
@@ -458,23 +444,73 @@ static struct attribute_group lis3lv02d_attribute_group = {
 };
 
 
-static int lis3lv02d_add_fs(struct acpi_device *device)
+static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
 {
-       adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
-       if (IS_ERR(adev.pdev))
-               return PTR_ERR(adev.pdev);
+       lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+       if (IS_ERR(lis3_dev.pdev))
+               return PTR_ERR(lis3_dev.pdev);
 
-       return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
+       return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
 }
 
 int lis3lv02d_remove_fs(void)
 {
-       sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
-       platform_device_unregister(adev.pdev);
+       sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
+       platform_device_unregister(lis3_dev.pdev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
 
+/*
+ * Initialise the accelerometer and the various subsystems.
+ * Should be rather independant of the bus system.
+ */
+int lis3lv02d_init_device(struct lis3lv02d *dev)
+{
+       dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
+
+       switch (dev->whoami) {
+       case LIS_DOUBLE_ID:
+               printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n");
+               dev->read_data = lis3lv02d_read_16;
+               dev->mdps_max_val = 2048;
+               break;
+       case LIS_SINGLE_ID:
+               printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n");
+               dev->read_data = lis3lv02d_read_8;
+               dev->mdps_max_val = 128;
+               break;
+       default:
+               printk(KERN_ERR DRIVER_NAME
+                       ": unknown sensor type 0x%X\n", lis3_dev.whoami);
+               return -EINVAL;
+       }
+
+       mutex_init(&dev->lock);
+       lis3lv02d_add_fs(dev);
+       lis3lv02d_increase_use(dev);
+
+       if (lis3lv02d_joystick_enable())
+               printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
+
+       printk("lis3_init_device: irq %d\n", dev->irq);
+
+       /* bail if we did not get an IRQ from the bus layer */
+       if (!dev->irq) {
+               printk(KERN_ERR DRIVER_NAME
+                       ": No IRQ. Disabling /dev/freefall\n");
+               goto out;
+       }
+
+       printk("lis3: registering device\n");
+       if (misc_register(&lis3lv02d_misc_device))
+               printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
+out:
+       lis3lv02d_decrease_use(dev);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
+
 MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
 MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
 MODULE_LICENSE("GPL");
index 75972bf372ff474a2fd1a43cdaf85db9ddddebd4..745ec96806d485a0f93f33932e2a588e6a8ab546 100644 (file)
@@ -159,14 +159,14 @@ struct axis_conversion {
        s8      z;
 };
 
-struct acpi_lis3lv02d {
-       struct acpi_device      *device;   /* The ACPI device */
-       acpi_status (*init) (acpi_handle handle);
-       acpi_status (*write) (acpi_handle handle, int reg, u8 val);
-       acpi_status (*read) (acpi_handle handle, int reg, u8 *ret);
+struct lis3lv02d {
+       void                    *bus_priv; /* used by the bus layer only */
+       int (*init) (struct lis3lv02d *lis3);
+       int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
+       int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
 
        u8                      whoami;    /* 3Ah: 2-byte registries, 3Bh: 1-byte registries */
-       s16 (*read_data) (acpi_handle handle, int reg);
+       s16 (*read_data) (struct lis3lv02d *lis3, int reg);
        int                     mdps_max_val;
 
        struct input_dev        *idev;     /* input device */
@@ -187,11 +187,11 @@ struct acpi_lis3lv02d {
        unsigned long           misc_opened; /* bit0: whether the device is open */
 };
 
-int lis3lv02d_init_device(struct acpi_lis3lv02d *dev);
+int lis3lv02d_init_device(struct lis3lv02d *lis3);
 int lis3lv02d_joystick_enable(void);
 void lis3lv02d_joystick_disable(void);
-void lis3lv02d_poweroff(acpi_handle handle);
-void lis3lv02d_poweron(acpi_handle handle);
+void lis3lv02d_poweroff(struct lis3lv02d *lis3);
+void lis3lv02d_poweron(struct lis3lv02d *lis3);
 int lis3lv02d_remove_fs(void);
 
-extern struct acpi_lis3lv02d adev;
+extern struct lis3lv02d lis3_dev;
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
new file mode 100644 (file)
index 0000000..07ae74b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * lis3lv02d_spi - SPI glue layer for lis3lv02d
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#include "lis3lv02d.h"
+
+#define DRV_NAME       "lis3lv02d_spi"
+#define LIS3_SPI_READ  0x80
+
+static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v)
+{
+       struct spi_device *spi = lis3->bus_priv;
+       int ret = spi_w8r8(spi, reg | LIS3_SPI_READ);
+       if (ret < 0)
+               return -EINVAL;
+
+       *v = (u8) ret;
+       return 0;
+}
+
+static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val)
+{
+       u8 tmp[2] = { reg, val };
+       struct spi_device *spi = lis3->bus_priv;
+       return spi_write(spi, tmp, sizeof(tmp));
+}
+
+static int lis3_spi_init(struct lis3lv02d *lis3)
+{
+       u8 reg;
+       int ret;
+
+       /* power up the device */
+       ret = lis3->read(lis3, CTRL_REG1, &reg);
+       if (ret < 0)
+               return ret;
+
+       reg |= CTRL1_PD0;
+       return lis3->write(lis3, CTRL_REG1, reg);
+}
+
+static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 };
+
+static int __devinit lis302dl_spi_probe(struct spi_device *spi)
+{
+       int ret;
+
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_0;
+       ret = spi_setup(spi);
+       if (ret < 0)
+               return ret;
+
+       lis3_dev.bus_priv = spi;
+       lis3_dev.init = lis3_spi_init;
+       lis3_dev.read = lis3_spi_read;
+       lis3_dev.write = lis3_spi_write;
+       lis3_dev.irq = spi->irq;
+       lis3_dev.ac = lis3lv02d_axis_normal;
+       spi_set_drvdata(spi, &lis3_dev);
+
+       ret = lis3lv02d_init_device(&lis3_dev);
+       return ret;
+}
+
+static int __devexit lis302dl_spi_remove(struct spi_device *spi)
+{
+       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
+       lis3lv02d_joystick_disable();
+       lis3lv02d_poweroff(lis3);
+       return 0;
+}
+
+static struct spi_driver lis302dl_spi_driver = {
+       .driver  = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = lis302dl_spi_probe,
+       .remove = __devexit_p(lis302dl_spi_remove),
+};
+
+static int __init lis302dl_init(void)
+{
+       return spi_register_driver(&lis302dl_spi_driver);
+}
+
+static void __exit lis302dl_exit(void)
+{
+       spi_unregister_driver(&lis302dl_spi_driver);
+}
+
+module_init(lis302dl_init);
+module_exit(lis302dl_exit);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("lis3lv02d SPI glue layer");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
new file mode 100644 (file)
index 0000000..091d95f
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware
+ *             monitoring
+ * Copyright (C) 2008 Davide Rizzo <elpa-rizzo@gmail.com>
+ *
+ * Based on the max1619 driver. The LM95241 is a sensor chip made by National
+ *   Semiconductors.
+ * It reports up to three temperatures (its own plus up to
+ * two external ones). Complete datasheet can be
+ * obtained from National's website at:
+ *   http://www.national.com/ds.cgi/LM/LM95241.pdf
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+static const unsigned short normal_i2c[] = {
+       0x19, 0x2a, 0x2b, I2C_CLIENT_END};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(lm95241);
+
+/* LM95241 registers */
+#define LM95241_REG_R_MAN_ID           0xFE
+#define LM95241_REG_R_CHIP_ID          0xFF
+#define LM95241_REG_R_STATUS           0x02
+#define LM95241_REG_RW_CONFIG          0x03
+#define LM95241_REG_RW_REM_FILTER      0x06
+#define LM95241_REG_RW_TRUTHERM                0x07
+#define LM95241_REG_W_ONE_SHOT         0x0F
+#define LM95241_REG_R_LOCAL_TEMPH      0x10
+#define LM95241_REG_R_REMOTE1_TEMPH    0x11
+#define LM95241_REG_R_REMOTE2_TEMPH    0x12
+#define LM95241_REG_R_LOCAL_TEMPL      0x20
+#define LM95241_REG_R_REMOTE1_TEMPL    0x21
+#define LM95241_REG_R_REMOTE2_TEMPL    0x22
+#define LM95241_REG_RW_REMOTE_MODEL    0x30
+
+/* LM95241 specific bitfields */
+#define CFG_STOP 0x40
+#define CFG_CR0076 0x00
+#define CFG_CR0182 0x10
+#define CFG_CR1000 0x20
+#define CFG_CR2700 0x30
+#define R1MS_SHIFT 0
+#define R2MS_SHIFT 2
+#define R1MS_MASK (0x01 << (R1MS_SHIFT))
+#define R2MS_MASK (0x01 << (R2MS_SHIFT))
+#define R1DF_SHIFT 1
+#define R2DF_SHIFT 2
+#define R1DF_MASK (0x01 << (R1DF_SHIFT))
+#define R2DF_MASK (0x01 << (R2DF_SHIFT))
+#define R1FE_MASK 0x01
+#define R2FE_MASK 0x05
+#define TT1_SHIFT 0
+#define TT2_SHIFT 4
+#define TT_OFF 0
+#define TT_ON 1
+#define TT_MASK 7
+#define MANUFACTURER_ID 0x01
+#define DEFAULT_REVISION 0xA4
+
+/* Conversions and various macros */
+#define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \
+    (val_h)) * 1000 + (val_l) * 1000 / 256)
+
+/* Functions declaration */
+static int lm95241_attach_adapter(struct i2c_adapter *adapter);
+static int lm95241_detect(struct i2c_adapter *adapter, int address,
+                         int kind);
+static void lm95241_init_client(struct i2c_client *client);
+static int lm95241_detach_client(struct i2c_client *client);
+static struct lm95241_data *lm95241_update_device(struct device *dev);
+
+/* Driver data (common to all clients) */
+static struct i2c_driver lm95241_driver = {
+       .driver = {
+               .name   = "lm95241",
+       },
+       .attach_adapter = lm95241_attach_adapter,
+       .detach_client  = lm95241_detach_client,
+};
+
+/* Client data (each client gets its own) */
+struct lm95241_data {
+       struct i2c_client client;
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       unsigned long last_updated, rate; /* in jiffies */
+       char valid; /* zero until following fields are valid */
+       /* registers values */
+       u8 local_h, local_l; /* local */
+       u8 remote1_h, remote1_l; /* remote1 */
+       u8 remote2_h, remote2_l; /* remote2 */
+       u8 config, model, trutherm;
+};
+
+/* Sysfs stuff */
+#define show_temp(value) \
+static ssize_t show_##value(struct device *dev, \
+    struct device_attribute *attr, char *buf) \
+{ \
+       struct lm95241_data *data = lm95241_update_device(dev); \
+       snprintf(buf, PAGE_SIZE - 1, "%d\n", \
+               TEMP_FROM_REG(data->value##_h, data->value##_l)); \
+       return strlen(buf); \
+}
+show_temp(local);
+show_temp(remote1);
+show_temp(remote2);
+
+static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct lm95241_data *data = lm95241_update_device(dev);
+
+       snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->rate / HZ);
+       return strlen(buf);
+}
+
+static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       strict_strtol(buf, 10, &data->rate);
+       data->rate = data->rate * HZ / 1000;
+
+       return count;
+}
+
+#define show_type(flag) \
+static ssize_t show_type##flag(struct device *dev, \
+                                  struct device_attribute *attr, char *buf) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       snprintf(buf, PAGE_SIZE - 1, \
+               data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \
+       return strlen(buf); \
+}
+show_type(1);
+show_type(2);
+
+#define show_min(flag) \
+static ssize_t show_min##flag(struct device *dev, \
+    struct device_attribute *attr, char *buf) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       snprintf(buf, PAGE_SIZE - 1, \
+               data->config & R##flag##DF_MASK ?       \
+               "-127000\n" : "0\n"); \
+       return strlen(buf); \
+}
+show_min(1);
+show_min(2);
+
+#define show_max(flag) \
+static ssize_t show_max##flag(struct device *dev, \
+    struct device_attribute *attr, char *buf) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       snprintf(buf, PAGE_SIZE - 1, \
+               data->config & R##flag##DF_MASK ? \
+               "127000\n" : "255000\n"); \
+       return strlen(buf); \
+}
+show_max(1);
+show_max(2);
+
+#define set_type(flag) \
+static ssize_t set_type##flag(struct device *dev, \
+                                 struct device_attribute *attr, \
+                                 const char *buf, size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       long val; \
+       strict_strtol(buf, 10, &val); \
+\
+       if ((val == 1) || (val == 2)) { \
+\
+               mutex_lock(&data->update_lock); \
+\
+               data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \
+               if (val == 1) { \
+                       data->model |= R##flag##MS_MASK; \
+                       data->trutherm |= (TT_ON << TT##flag##_SHIFT); \
+               } \
+               else { \
+                       data->model &= ~R##flag##MS_MASK; \
+                       data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \
+               } \
+\
+               data->valid = 0; \
+\
+               i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \
+                                         data->model); \
+               i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \
+                                         data->trutherm); \
+\
+               mutex_unlock(&data->update_lock); \
+\
+       } \
+       return count; \
+}
+set_type(1);
+set_type(2);
+
+#define set_min(flag) \
+static ssize_t set_min##flag(struct device *dev, \
+       struct device_attribute *devattr, const char *buf, size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       long val; \
+       strict_strtol(buf, 10, &val); \
+\
+       mutex_lock(&data->update_lock); \
+\
+       if (val < 0) \
+               data->config |= R##flag##DF_MASK; \
+       else \
+               data->config &= ~R##flag##DF_MASK; \
+\
+       data->valid = 0; \
+\
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
+               data->config); \
+\
+       mutex_unlock(&data->update_lock); \
+\
+       return count; \
+}
+set_min(1);
+set_min(2);
+
+#define set_max(flag) \
+static ssize_t set_max##flag(struct device *dev, \
+       struct device_attribute *devattr, const char *buf, size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm95241_data *data = i2c_get_clientdata(client); \
+\
+       long val; \
+       strict_strtol(buf, 10, &val); \
+\
+       mutex_lock(&data->update_lock); \
+\
+       if (val <= 127000) \
+               data->config |= R##flag##DF_MASK; \
+       else \
+               data->config &= ~R##flag##DF_MASK; \
+\
+       data->valid = 0; \
+\
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
+               data->config); \
+\
+       mutex_unlock(&data->update_lock); \
+\
+       return count; \
+}
+set_max(1);
+set_max(2);
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL);
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL);
+static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL);
+static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1);
+static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2);
+static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1);
+static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2);
+static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1);
+static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2);
+static DEVICE_ATTR(rate, S_IWUSR | S_IRUGO, show_rate, set_rate);
+
+static struct attribute *lm95241_attributes[] = {
+       &dev_attr_temp1_input.attr,
+       &dev_attr_temp2_input.attr,
+       &dev_attr_temp3_input.attr,
+       &dev_attr_temp2_type.attr,
+       &dev_attr_temp3_type.attr,
+       &dev_attr_temp2_min.attr,
+       &dev_attr_temp3_min.attr,
+       &dev_attr_temp2_max.attr,
+       &dev_attr_temp3_max.attr,
+       &dev_attr_rate.attr,
+       NULL
+};
+
+static const struct attribute_group lm95241_group = {
+       .attrs = lm95241_attributes,
+};
+
+/* Init/exit code */
+static int lm95241_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_probe(adapter, &addr_data, lm95241_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int lm95241_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *new_client;
+       struct lm95241_data *data;
+       int err = 0;
+       const char *name = "";
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               goto exit;
+
+       data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       /* The common I2C client data is placed right before the
+          LM95241-specific data. */
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       new_client->adapter = adapter;
+       new_client->driver = &lm95241_driver;
+       new_client->flags = 0;
+
+       /*
+        * Now we do the remaining detection. A negative kind means that
+        * the driver was loaded with no force parameter (default), so we
+        * must both detect and identify the chip. A zero kind means that
+        * the driver was loaded with the force parameter, the detection
+        * step shall be skipped. A positive kind means that the driver
+        * was loaded with the force parameter and a given kind of chip is
+        * requested, so both the detection and the identification steps
+        * are skipped.
+        */
+       if (kind < 0) { /* detection */
+               if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
+                    != MANUFACTURER_ID)
+               || (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
+                   < DEFAULT_REVISION)) {
+                       dev_dbg(&adapter->dev,
+                               "LM95241 detection failed at 0x%02x.\n",
+                               address);
+                       goto exit_free;
+               }
+       }
+
+       if (kind <= 0) { /* identification */
+               if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
+                    == MANUFACTURER_ID)
+               && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
+                   >= DEFAULT_REVISION)) {
+
+                       kind = lm95241;
+
+                       if (kind <= 0) { /* identification failed */
+                               dev_info(&adapter->dev, "Unsupported chip\n");
+                               goto exit_free;
+                       }
+               }
+       }
+
+       if (kind == lm95241)
+               name = "lm95241";
+
+       /* We can fill in the remaining client fields */
+       strlcpy(new_client->name, name, I2C_NAME_SIZE);
+       data->valid = 0;
+       mutex_init(&data->update_lock);
+
+       /* Tell the I2C layer a new client has arrived */
+       err = i2c_attach_client(new_client);
+       if (err)
+               goto exit_free;
+
+       /* Initialize the LM95241 chip */
+       lm95241_init_client(new_client);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
+       if (err)
+               goto exit_detach;
+
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
+       sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
+exit_detach:
+       i2c_detach_client(new_client);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static void lm95241_init_client(struct i2c_client *client)
+{
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       data->rate = HZ;    /* 1 sec default */
+       data->valid = 0;
+       data->config = CFG_CR0076;
+       data->model = 0;
+       data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
+
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
+                                 data->config);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
+                                 R1FE_MASK | R2FE_MASK);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+                                 data->trutherm);
+       i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+                                 data->model);
+}
+
+static int lm95241_detach_client(struct i2c_client *client)
+{
+       struct lm95241_data *data = i2c_get_clientdata(client);
+       int err;
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm95241_group);
+
+       err = i2c_detach_client(client);
+       if (err)
+               return err;
+
+       kfree(data);
+       return 0;
+}
+
+static struct lm95241_data *lm95241_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95241_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + data->rate) ||
+           !data->valid) {
+               dev_dbg(&client->dev, "Updating lm95241 data.\n");
+               data->local_h =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_LOCAL_TEMPH);
+               data->local_l =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_LOCAL_TEMPL);
+               data->remote1_h =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE1_TEMPH);
+               data->remote1_l =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE1_TEMPL);
+               data->remote2_h =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE2_TEMPH);
+               data->remote2_l =
+                       i2c_smbus_read_byte_data(client,
+                                                LM95241_REG_R_REMOTE2_TEMPL);
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+static int __init sensors_lm95241_init(void)
+{
+       return i2c_add_driver(&lm95241_driver);
+}
+
+static void __exit sensors_lm95241_exit(void)
+{
+       i2c_del_driver(&lm95241_driver);
+}
+
+MODULE_AUTHOR("Davide Rizzo <elpa-rizzo@gmail.com>");
+MODULE_DESCRIPTION("LM95241 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm95241_init);
+module_exit(sensors_lm95241_exit);
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
new file mode 100644 (file)
index 0000000..9386e2a
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Driver for Linear Technology LTC4215 I2C Hot Swap Controller
+ *
+ * Copyright (C) 2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * 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; version 2 of the License.
+ *
+ * Datasheet:
+ * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1163,P17572,D12697
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(ltc4215);
+
+/* Here are names of the chip's registers (a.k.a. commands) */
+enum ltc4215_cmd {
+       LTC4215_CONTROL                 = 0x00, /* rw */
+       LTC4215_ALERT                   = 0x01, /* rw */
+       LTC4215_STATUS                  = 0x02, /* ro */
+       LTC4215_FAULT                   = 0x03, /* rw */
+       LTC4215_SENSE                   = 0x04, /* rw */
+       LTC4215_SOURCE                  = 0x05, /* rw */
+       LTC4215_ADIN                    = 0x06, /* rw */
+};
+
+struct ltc4215_data {
+       struct device *hwmon_dev;
+
+       struct mutex update_lock;
+       bool valid;
+       unsigned long last_updated; /* in jiffies */
+
+       /* Registers */
+       u8 regs[7];
+};
+
+static struct ltc4215_data *ltc4215_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ltc4215_data *data = i2c_get_clientdata(client);
+       s32 val;
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       /* The chip's A/D updates 10 times per second */
+       if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {
+
+               dev_dbg(&client->dev, "Starting ltc4215 update\n");
+
+               /* Read all registers */
+               for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+                       val = i2c_smbus_read_byte_data(client, i);
+                       if (unlikely(val < 0))
+                               data->regs[i] = 0;
+                       else
+                               data->regs[i] = val;
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/* Return the voltage from the given register in millivolts */
+static int ltc4215_get_voltage(struct device *dev, u8 reg)
+{
+       struct ltc4215_data *data = ltc4215_update_device(dev);
+       const u8 regval = data->regs[reg];
+       u32 voltage = 0;
+
+       switch (reg) {
+       case LTC4215_SENSE:
+               /* 151 uV per increment */
+               voltage = regval * 151 / 1000;
+               break;
+       case LTC4215_SOURCE:
+               /* 60.5 mV per increment */
+               voltage = regval * 605 / 10;
+               break;
+       case LTC4215_ADIN:
+               /* The ADIN input is divided by 12.5, and has 4.82 mV
+                * per increment, so we have the additional multiply */
+               voltage = regval * 482 * 125 / 1000;
+               break;
+       default:
+               /* If we get here, the developer messed up */
+               WARN_ON_ONCE(1);
+               break;
+       }
+
+       return voltage;
+}
+
+/* Return the current from the sense resistor in mA */
+static unsigned int ltc4215_get_current(struct device *dev)
+{
+       struct ltc4215_data *data = ltc4215_update_device(dev);
+
+       /* The strange looking conversions that follow are fixed-point
+        * math, since we cannot do floating point in the kernel.
+        *
+        * Step 1: convert sense register to microVolts
+        * Step 2: convert voltage to milliAmperes
+        *
+        * If you play around with the V=IR equation, you come up with
+        * the following: X uV / Y mOhm == Z mA
+        *
+        * With the resistors that are fractions of a milliOhm, we multiply
+        * the voltage and resistance by 10, to shift the decimal point.
+        * Now we can use the normal division operator again.
+        */
+
+       /* Calculate voltage in microVolts (151 uV per increment) */
+       const unsigned int voltage = data->regs[LTC4215_SENSE] * 151;
+
+       /* Calculate current in milliAmperes (4 milliOhm sense resistor) */
+       const unsigned int curr = voltage / 4;
+
+       return curr;
+}
+
+static ssize_t ltc4215_show_voltage(struct device *dev,
+                                   struct device_attribute *da,
+                                   char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       const int voltage = ltc4215_get_voltage(dev, attr->index);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
+}
+
+static ssize_t ltc4215_show_current(struct device *dev,
+                                   struct device_attribute *da,
+                                   char *buf)
+{
+       const unsigned int curr = ltc4215_get_current(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", curr);
+}
+
+static ssize_t ltc4215_show_power(struct device *dev,
+                                 struct device_attribute *da,
+                                 char *buf)
+{
+       const unsigned int curr = ltc4215_get_current(dev);
+       const int output_voltage = ltc4215_get_voltage(dev, LTC4215_ADIN);
+
+       /* current in mA * voltage in mV == power in uW */
+       const unsigned int power = abs(output_voltage * curr);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", power);
+}
+
+static ssize_t ltc4215_show_alarm(struct device *dev,
+                                         struct device_attribute *da,
+                                         char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+       struct ltc4215_data *data = ltc4215_update_device(dev);
+       const u8 reg = data->regs[attr->index];
+       const u32 mask = attr->nr;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
+}
+
+/* These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+#define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4215_show_voltage, NULL, ltc4215_cmd_idx)
+
+#define LTC4215_CURRENT(name) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4215_show_current, NULL, 0);
+
+#define LTC4215_POWER(name) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4215_show_power, NULL, 0);
+
+#define LTC4215_ALARM(name, mask, reg) \
+       static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
+       ltc4215_show_alarm, NULL, (mask), reg)
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Current */
+LTC4215_CURRENT(curr1_input);
+LTC4215_ALARM(curr1_max_alarm, (1 << 2),       LTC4215_STATUS);
+
+/* Power (virtual) */
+LTC4215_POWER(power1_input);
+LTC4215_ALARM(power1_alarm,    (1 << 3),       LTC4215_STATUS);
+
+/* Input Voltage */
+LTC4215_VOLTAGE(in1_input,                     LTC4215_ADIN);
+LTC4215_ALARM(in1_max_alarm,   (1 << 0),       LTC4215_STATUS);
+LTC4215_ALARM(in1_min_alarm,   (1 << 1),       LTC4215_STATUS);
+
+/* Output Voltage */
+LTC4215_VOLTAGE(in2_input,                     LTC4215_SOURCE);
+
+/* Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ltc4215_attributes[] = {
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+       &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_power1_input.dev_attr.attr,
+       &sensor_dev_attr_power1_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+
+       NULL,
+};
+
+static const struct attribute_group ltc4215_group = {
+       .attrs = ltc4215_attributes,
+};
+
+static int ltc4215_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct ltc4215_data *data;
+       int ret;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto out_kzalloc;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Initialize the LTC4215 chip */
+       /* TODO */
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
+       if (ret)
+               goto out_sysfs_create_group;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto out_hwmon_device_register;
+       }
+
+       return 0;
+
+out_hwmon_device_register:
+       sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
+out_sysfs_create_group:
+       kfree(data);
+out_kzalloc:
+       return ret;
+}
+
+static int ltc4215_remove(struct i2c_client *client)
+{
+       struct ltc4215_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
+
+       kfree(data);
+
+       return 0;
+}
+
+static int ltc4215_detect(struct i2c_client *client,
+                         int kind,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       if (kind < 0) {         /* probed detection - check the chip type */
+               s32 v;          /* 8 bits from the chip, or -ERRNO */
+
+               /*
+                * Register 0x01 bit b7 is reserved, expect 0
+                * Register 0x03 bit b6 and b7 are reserved, expect 0
+                */
+               v = i2c_smbus_read_byte_data(client, LTC4215_ALERT);
+               if (v < 0 || (v & (1 << 7)) != 0)
+                       return -ENODEV;
+
+               v = i2c_smbus_read_byte_data(client, LTC4215_FAULT);
+               if (v < 0 || (v & ((1 << 6) | (1 << 7))) != 0)
+                               return -ENODEV;
+       }
+
+       strlcpy(info->type, "ltc4215", I2C_NAME_SIZE);
+       dev_info(&adapter->dev, "ltc4215 %s at address 0x%02x\n",
+                       kind < 0 ? "probed" : "forced",
+                       client->addr);
+
+       return 0;
+}
+
+static const struct i2c_device_id ltc4215_id[] = {
+       { "ltc4215", ltc4215 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4215_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4215_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "ltc4215",
+       },
+       .probe          = ltc4215_probe,
+       .remove         = ltc4215_remove,
+       .id_table       = ltc4215_id,
+       .detect         = ltc4215_detect,
+       .address_data   = &addr_data,
+};
+
+static int __init ltc4215_init(void)
+{
+       return i2c_add_driver(&ltc4215_driver);
+}
+
+static void __exit ltc4215_exit(void)
+{
+       i2c_del_driver(&ltc4215_driver);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("LTC4215 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ltc4215_init);
+module_exit(ltc4215_exit);
similarity index 96%
rename from drivers/i2c/chips/pcf8591.c
rename to drivers/hwmon/pcf8591.c
index 16ce3e193776a673b47efbf7af6e50a68878553f..1d7ffebd679d0cce6f25c9e1946d7e9739c1b4b5 100644 (file)
@@ -1,6 +1,6 @@
 /*
     Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
-    Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with 
+    Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
     the help of Jean Delvare <khali@linux-fr.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -41,13 +41,13 @@ MODULE_PARM_DESC(input_mode,
        " 3 = two differential inputs\n");
 
 /* The PCF8591 control byte
-      7    6    5    4    3    2    1    0  
+      7    6    5    4    3    2    1    0
    |  0 |AOEF|   AIP   |  0 |AINC|  AICH   | */
 
 /* Analog Output Enable Flag (analog output active if 1) */
 #define PCF8591_CONTROL_AOEF           0x40
-                                       
-/* Analog Input Programming 
+
+/* Analog Input Programming
    0x00 = four single ended inputs
    0x10 = three differential inputs
    0x20 = single ended and differential mixed
@@ -58,7 +58,7 @@ MODULE_PARM_DESC(input_mode,
 #define PCF8591_CONTROL_AINC           0x04
 
 /* Channel selection
-   0x00 = channel 0 
+   0x00 = channel 0
    0x01 = channel 1
    0x02 = channel 2
    0x03 = channel 3 */
@@ -114,7 +114,7 @@ static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr
        return -EINVAL;
 }
 
-static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, 
+static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO,
                   show_out0_ouput, set_out0_output);
 
 static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf)
@@ -139,7 +139,7 @@ static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr
        return count;
 }
 
-static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, 
+static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
                   show_out0_enable, set_out0_enable);
 
 static struct attribute *pcf8591_attributes[] = {
@@ -196,7 +196,7 @@ static int pcf8591_probe(struct i2c_client *client,
                err = -ENOMEM;
                goto exit;
        }
-       
+
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
 
@@ -249,8 +249,8 @@ static void pcf8591_init_client(struct i2c_client *client)
        data->aout = PCF8591_INIT_AOUT;
 
        i2c_smbus_write_byte_data(client, data->control, data->aout);
-       
-       /* The first byte transmitted contains the conversion code of the 
+
+       /* The first byte transmitted contains the conversion code of the
           previous read cycle. FLUSH IT! */
        i2c_smbus_read_byte(client);
 }
@@ -267,8 +267,8 @@ static int pcf8591_read_channel(struct device *dev, int channel)
                data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
                              | channel;
                i2c_smbus_write_byte(client, data->control);
-       
-               /* The first byte transmitted contains the conversion code of 
+
+               /* The first byte transmitted contains the conversion code of
                   the previous read cycle. FLUSH IT! */
                i2c_smbus_read_byte(client);
        }
index feae743ba99163c2475b0f51663c89fc7e7f1375..e64b42058b219772d0c28ecf0a8780f8ef7ea1ab 100644 (file)
@@ -36,6 +36,7 @@
     w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
                                                0x8860 0xa1
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
+    w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
 */
 
 #include <linux/module.h>
 #include <asm/io.h>
 #include "lm75.h"
 
-enum kinds { w83627ehf, w83627dhg };
+enum kinds { w83627ehf, w83627dhg, w83667hg };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
 static const char * w83627ehf_device_names[] = {
        "w83627ehf",
        "w83627dhg",
+       "w83667hg",
 };
 
 static unsigned short force_id;
@@ -71,6 +73,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
  */
 
 #define W83627EHF_LD_HWM       0x0b
+#define W83667HG_LD_VID        0x0d
 
 #define SIO_REG_LDSEL          0x07    /* Logical device select */
 #define SIO_REG_DEVID          0x20    /* Device ID (2 bytes) */
@@ -83,6 +86,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627EHF_ID       0x8850
 #define SIO_W83627EHG_ID       0x8860
 #define SIO_W83627DHG_ID       0xa020
+#define SIO_W83667HG_ID        0xa510
 #define SIO_ID_MASK            0xFFF0
 
 static inline void
@@ -289,6 +293,7 @@ struct w83627ehf_data {
        u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
        u8 pwm_enable[4]; /* 1->manual
                             2->thermal cruise (also called SmartFan I) */
+       u8 pwm_num;             /* number of pwm */
        u8 pwm[4];
        u8 target_temp[4];
        u8 tolerance[4];
@@ -298,6 +303,9 @@ struct w83627ehf_data {
 
        u8 vid;
        u8 vrm;
+
+       u8 temp3_disable;
+       u8 in6_skip;
 };
 
 struct w83627ehf_sio_data {
@@ -866,25 +874,37 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
        return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
 }
 
-static struct sensor_device_attribute sda_temp[] = {
+static struct sensor_device_attribute sda_temp_input[] = {
        SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
        SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
        SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
+};
+
+static struct sensor_device_attribute sda_temp_max[] = {
        SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
                    store_temp1_max, 0),
        SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
                    store_temp_max, 0),
        SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
                    store_temp_max, 1),
+};
+
+static struct sensor_device_attribute sda_temp_max_hyst[] = {
        SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
                    store_temp1_max_hyst, 0),
        SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
                    store_temp_max_hyst, 0),
        SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
                    store_temp_max_hyst, 1),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
        SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
        SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
        SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
+
+static struct sensor_device_attribute sda_temp_type[] = {
        SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
        SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
        SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
@@ -1181,6 +1201,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
        for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
                device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
        for (i = 0; i < data->in_num; i++) {
+               if ((i == 6) && data->in6_skip)
+                       continue;
                device_remove_file(dev, &sda_in_input[i].dev_attr);
                device_remove_file(dev, &sda_in_alarm[i].dev_attr);
                device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1192,15 +1214,22 @@ static void w83627ehf_device_remove_files(struct device *dev)
                device_remove_file(dev, &sda_fan_div[i].dev_attr);
                device_remove_file(dev, &sda_fan_min[i].dev_attr);
        }
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < data->pwm_num; i++) {
                device_remove_file(dev, &sda_pwm[i].dev_attr);
                device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
                device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
                device_remove_file(dev, &sda_target_temp[i].dev_attr);
                device_remove_file(dev, &sda_tolerance[i].dev_attr);
        }
-       for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
-               device_remove_file(dev, &sda_temp[i].dev_attr);
+       for (i = 0; i < 3; i++) {
+               if ((i == 2) && data->temp3_disable)
+                       continue;
+               device_remove_file(dev, &sda_temp_input[i].dev_attr);
+               device_remove_file(dev, &sda_temp_max[i].dev_attr);
+               device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
+               device_remove_file(dev, &sda_temp_type[i].dev_attr);
+       }
 
        device_remove_file(dev, &dev_attr_name);
        device_remove_file(dev, &dev_attr_cpu0_vid);
@@ -1222,6 +1251,8 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
        for (i = 0; i < 2; i++) {
                tmp = w83627ehf_read_value(data,
                                           W83627EHF_REG_TEMP_CONFIG[i]);
+               if ((i == 1) && data->temp3_disable)
+                       continue;
                if (tmp & 0x01)
                        w83627ehf_write_value(data,
                                              W83627EHF_REG_TEMP_CONFIG[i],
@@ -1272,8 +1303,17 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
        data->name = w83627ehf_device_names[sio_data->kind];
        platform_set_drvdata(pdev, data);
 
-       /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
-       data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
+       /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
+       data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
+       /* 667HG has 3 pwms */
+       data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4;
+
+       /* Check temp3 configuration bit for 667HG */
+       if (sio_data->kind == w83667hg) {
+               data->temp3_disable = w83627ehf_read_value(data,
+                                       W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
+               data->in6_skip = !data->temp3_disable;
+       }
 
        /* Initialize the chip */
        w83627ehf_init_device(data);
@@ -1281,44 +1321,64 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
        data->vrm = vid_which_vrm();
        superio_enter(sio_data->sioreg);
        /* Read VID value */
-       superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
-       if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
-               /* Set VID input sensibility if needed. In theory the BIOS
-                  should have set it, but in practice it's not always the
-                  case. We only do it for the W83627EHF/EHG because the
-                  W83627DHG is more complex in this respect. */
-               if (sio_data->kind == w83627ehf) {
-                       en_vrm10 = superio_inb(sio_data->sioreg,
-                                              SIO_REG_EN_VRM10);
-                       if ((en_vrm10 & 0x08) && data->vrm == 90) {
-                               dev_warn(dev, "Setting VID input voltage to "
-                                        "TTL\n");
-                               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
-                                            en_vrm10 & ~0x08);
-                       } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
-                               dev_warn(dev, "Setting VID input voltage to "
-                                        "VRM10\n");
-                               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
-                                            en_vrm10 | 0x08);
-                       }
-               }
-
-               data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
-               if (sio_data->kind == w83627ehf) /* 6 VID pins only */
-                       data->vid &= 0x3f;
-
+       if (sio_data->kind == w83667hg) {
+               /* W83667HG has different pins for VID input and output, so
+               we can get the VID input values directly at logical device D
+               0xe3. */
+               superio_select(sio_data->sioreg, W83667HG_LD_VID);
+               data->vid = superio_inb(sio_data->sioreg, 0xe3);
                err = device_create_file(dev, &dev_attr_cpu0_vid);
                if (err)
                        goto exit_release;
        } else {
-               dev_info(dev, "VID pins in output mode, CPU VID not "
-                        "available\n");
+               superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+               if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
+                       /* Set VID input sensibility if needed. In theory the
+                          BIOS should have set it, but in practice it's not
+                          always the case. We only do it for the W83627EHF/EHG
+                          because the W83627DHG is more complex in this
+                          respect. */
+                       if (sio_data->kind == w83627ehf) {
+                               en_vrm10 = superio_inb(sio_data->sioreg,
+                                                      SIO_REG_EN_VRM10);
+                               if ((en_vrm10 & 0x08) && data->vrm == 90) {
+                                       dev_warn(dev, "Setting VID input "
+                                                "voltage to TTL\n");
+                                       superio_outb(sio_data->sioreg,
+                                                    SIO_REG_EN_VRM10,
+                                                    en_vrm10 & ~0x08);
+                               } else if (!(en_vrm10 & 0x08)
+                                          && data->vrm == 100) {
+                                       dev_warn(dev, "Setting VID input "
+                                                "voltage to VRM10\n");
+                                       superio_outb(sio_data->sioreg,
+                                                    SIO_REG_EN_VRM10,
+                                                    en_vrm10 | 0x08);
+                               }
+                       }
+
+                       data->vid = superio_inb(sio_data->sioreg,
+                                               SIO_REG_VID_DATA);
+                       if (sio_data->kind == w83627ehf) /* 6 VID pins only */
+                               data->vid &= 0x3f;
+
+                       err = device_create_file(dev, &dev_attr_cpu0_vid);
+                       if (err)
+                               goto exit_release;
+               } else {
+                       dev_info(dev, "VID pins in output mode, CPU VID not "
+                                "available\n");
+               }
        }
 
        /* fan4 and fan5 share some pins with the GPIO and serial flash */
-
-       fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
-       fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
+       if (sio_data->kind == w83667hg) {
+               fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+               fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
+       } else {
+               fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+               fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
+       }
        superio_exit(sio_data->sioreg);
 
        /* It looks like fan4 and fan5 pins can be alternatively used
@@ -1329,9 +1389,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 
        data->has_fan = 0x07; /* fan1, fan2 and fan3 */
        i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
-       if ((i & (1 << 2)) && (!fan4pin))
+       if ((i & (1 << 2)) && fan4pin)
                data->has_fan |= (1 << 3);
-       if (!(i & (1 << 1)) && (!fan5pin))
+       if (!(i & (1 << 1)) && fan5pin)
                data->has_fan |= (1 << 4);
 
        /* Read fan clock dividers immediately */
@@ -1344,14 +1404,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                        goto exit_remove;
 
        /* if fan4 is enabled create the sf3 files for it */
-       if (data->has_fan & (1 << 3))
+       if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
                for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
                        if ((err = device_create_file(dev,
                                &sda_sf3_arrays_fan4[i].dev_attr)))
                                goto exit_remove;
                }
 
-       for (i = 0; i < data->in_num; i++)
+       for (i = 0; i < data->in_num; i++) {
+               if ((i == 6) && data->in6_skip)
+                       continue;
                if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
                        || (err = device_create_file(dev,
                                &sda_in_alarm[i].dev_attr))
@@ -1360,6 +1422,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                        || (err = device_create_file(dev,
                                &sda_in_max[i].dev_attr)))
                        goto exit_remove;
+       }
 
        for (i = 0; i < 5; i++) {
                if (data->has_fan & (1 << i)) {
@@ -1372,7 +1435,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                                || (err = device_create_file(dev,
                                        &sda_fan_min[i].dev_attr)))
                                goto exit_remove;
-                       if (i < 4 && /* w83627ehf only has 4 pwm */
+                       if (i < data->pwm_num &&
                                ((err = device_create_file(dev,
                                        &sda_pwm[i].dev_attr))
                                || (err = device_create_file(dev,
@@ -1387,9 +1450,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                }
        }
 
-       for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
-               if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
+       for (i = 0; i < 3; i++) {
+               if ((i == 2) && data->temp3_disable)
+                       continue;
+               if ((err = device_create_file(dev,
+                               &sda_temp_input[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_max[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_max_hyst[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_alarm[i].dev_attr))
+                       || (err = device_create_file(dev,
+                               &sda_temp_type[i].dev_attr)))
                        goto exit_remove;
+       }
 
        err = device_create_file(dev, &dev_attr_name);
        if (err)
@@ -1442,6 +1517,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
        static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
        static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
        static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+       static const char __initdata sio_name_W83667HG[] = "W83667HG";
 
        u16 val;
        const char *sio_name;
@@ -1466,6 +1542,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
                sio_data->kind = w83627dhg;
                sio_name = sio_name_W83627DHG;
                break;
+       case SIO_W83667HG_ID:
+               sio_data->kind = w83667hg;
+               sio_name = sio_name_W83667HG;
+               break;
        default:
                if (val != 0xffff)
                        pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
index 230238df56c4d238d3fd4e9d184c7e1d1f608968..10411848fd704f58e790cc3587a92e07bd6f22c6 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/i2c.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
+#include <linux/dmi.h>
 
 /* I801 SMBus address offsets */
 #define SMBHSTSTS      (0 + i801_smba)
@@ -616,10 +617,81 @@ static void __init input_apanel_init(void)
 static void __init input_apanel_init(void) {}
 #endif
 
+#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
+struct dmi_onboard_device_info {
+       const char *name;
+       u8 type;
+       unsigned short i2c_addr;
+       const char *i2c_type;
+};
+
+static struct dmi_onboard_device_info __devinitdata dmi_devices[] = {
+       { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
+       { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
+       { "Hades",  DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
+};
+
+static void __devinit dmi_check_onboard_device(u8 type, const char *name,
+                                              struct i2c_adapter *adap)
+{
+       int i;
+       struct i2c_board_info info;
+
+       for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) {
+               /* & ~0x80, ignore enabled/disabled bit */
+               if ((type & ~0x80) != dmi_devices[i].type)
+                       continue;
+               if (strcmp(name, dmi_devices[i].name))
+                       continue;
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               info.addr = dmi_devices[i].i2c_addr;
+               strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
+               i2c_new_device(adap, &info);
+               break;
+       }
+}
+
+/* We use our own function to check for onboard devices instead of
+   dmi_find_device() as some buggy BIOS's have the devices we are interested
+   in marked as disabled */
+static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
+                                               void *adap)
+{
+       int i, count;
+
+       if (dm->type != 10)
+               return;
+
+       count = (dm->length - sizeof(struct dmi_header)) / 2;
+       for (i = 0; i < count; i++) {
+               const u8 *d = (char *)(dm + 1) + (i * 2);
+               const char *name = ((char *) dm) + dm->length;
+               u8 type = d[0];
+               u8 s = d[1];
+
+               if (!s)
+                       continue;
+               s--;
+               while (s > 0 && name[0]) {
+                       name += strlen(name) + 1;
+                       s--;
+               }
+               if (name[0] == 0) /* Bogus string reference */
+                       continue;
+
+               dmi_check_onboard_device(type, name, adap);
+       }
+}
+#endif
+
 static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        unsigned char temp;
        int err;
+#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
+       const char *vendor;
+#endif
 
        I801_dev = dev;
        i801_features = 0;
@@ -712,6 +784,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
                i2c_new_device(&i801_adapter, &info);
        }
 #endif
+#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
+       vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+       if (vendor && !strcmp(vendor, "FUJITSU SIEMENS"))
+               dmi_walk(dmi_check_onboard_devices, &i801_adapter);
+#endif
 
        return 0;
 
index c80312c1f38278051f7209745bf170f5d4f35b4e..8f8c81eb0aee750006a7949ed530d10a4257503c 100644 (file)
@@ -64,19 +64,6 @@ config SENSORS_PCA9539
          This driver is deprecated and will be dropped soon. Use
          drivers/gpio/pca953x.c instead.
 
-config SENSORS_PCF8591
-       tristate "Philips PCF8591"
-       depends on EXPERIMENTAL
-       default n
-       help
-         If you say yes here you get support for Philips PCF8591 chips.
-
-         This driver can also be built as a module.  If so, the module
-         will be called pcf8591.
-
-         These devices are hard to detect and rarely found on mainstream
-         hardware.  If unsure, say N.
-
 config SENSORS_MAX6875
        tristate "Maxim MAX6875 Power supply supervisor"
        depends on EXPERIMENTAL
index d142f238a2de43f8af6169811b9a64e86803a9a2..55a37603718332dcceab0ef5c90f38a6cb054a8e 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
 obj-$(CONFIG_SENSORS_PCA9539)  += pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)  += pcf8574.o
 obj-$(CONFIG_PCF8575)          += pcf8575.o
-obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_SENSORS_TSL2550)  += tsl2550.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
index 640c9920724287a42a5e9bbbd03a63a9aaa57cb3..cf06494bb74453d61f7552108d0fbc6d23e7d275 100644 (file)
@@ -222,7 +222,8 @@ comment "IDE chipset support/bugfixes"
 
 config IDE_GENERIC
        tristate "generic/default IDE chipset support"
-       depends on ALPHA || X86 || IA64 || M32R || MIPS
+       depends on ALPHA || X86 || IA64 || M32R || MIPS || ARCH_RPC || ARCH_SHARK
+       default ARM && (ARCH_RPC || ARCH_SHARK)
        help
          This is the generic IDE driver.  This driver attaches to the
          fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and
@@ -680,7 +681,7 @@ endif
 # TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF
 config BLK_DEV_IDE_PMAC
        tristate "PowerMac on-board IDE support"
-       depends on PPC_PMAC && IDE=y
+       depends on PPC_PMAC
        select IDE_TIMINGS
        select BLK_DEV_IDEDMA_PCI
        help
@@ -731,11 +732,6 @@ config BLK_DEV_IDE_AT91
        depends on ARM && ARCH_AT91 && !ARCH_AT91RM9200 && !ARCH_AT91X40
        select IDE_TIMINGS
 
-config IDE_ARM
-       tristate "ARM IDE support"
-       depends on ARM && (ARCH_RPC || ARCH_SHARK)
-       default y
-
 config BLK_DEV_IDE_ICSIDE
        tristate "ICS IDE interface support"
        depends on ARM && ARCH_ACORN
@@ -774,27 +770,20 @@ config BLK_DEV_GAYLE
          This includes on-board IDE interfaces on some Amiga models (A600,
          A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion
          bus (M-Tech E-Matrix 530 expansion card).
-         Say Y if you have an Amiga with a Gayle IDE interface and want to use
-         IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
-         it.
-         Note that you also have to enable Zorro bus support if you want to
-         use Gayle IDE interfaces on the Zorro expansion bus.
 
-config BLK_DEV_IDEDOUBLER
-       bool "Amiga IDE Doubler support (EXPERIMENTAL)"
-       depends on BLK_DEV_GAYLE && EXPERIMENTAL
-       ---help---
-         This feature provides support for the so-called `IDE doublers' (made
+         It also provides support for the so-called `IDE doublers' (made
          by various manufacturers, e.g. Eyetech) that can be connected to
          the on-board IDE interface of some Amiga models. Using such an IDE
          doubler, you can connect up to four instead of two IDE devices to
-         the Amiga's on-board IDE interface.
+         the Amiga's on-board IDE interface. The feature is enabled at kernel
+         runtime using the "gayle.doubler" kernel boot parameter.
 
-         Note that the normal Amiga Gayle IDE driver may not work correctly
-         if you have an IDE doubler and don't enable this feature!
+         Say Y if you have an Amiga with a Gayle IDE interface and want to use
+         IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
+         it.
 
-         Say Y if you have an IDE doubler.  The feature is enabled at kernel
-         runtime using the "gayle.doubler" kernel boot parameter.
+         Note that you also have to enable Zorro bus support if you want to
+         use Gayle IDE interfaces on the Zorro expansion bus.
 
 config BLK_DEV_BUDDHA
        tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
index 9b4bbe1cdc1ad9eeb511fe607853d8a6ba985ba1..81df925f0e8b932c3e821e29dbe2e94d636a2d08 100644 (file)
@@ -21,8 +21,6 @@ ide-core-$(CONFIG_IDE_LEGACY)         += ide-legacy.o
 
 obj-$(CONFIG_IDE)                      += ide-core.o
 
-obj-$(CONFIG_IDE_ARM)                  += ide_arm.o
-
 obj-$(CONFIG_BLK_DEV_ALI14XX)          += ali14xx.o
 obj-$(CONFIG_BLK_DEV_UMC8672)          += umc8672.o
 obj-$(CONFIG_BLK_DEV_DTC2278)          += dtc2278.o
index d516168464fcea89cf2256cf433a08ad6f619c77..537da1cde16d6aa00c21d5b51d9c73aa6a7c71fa 100644 (file)
@@ -189,20 +189,20 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
 }
 
 /**
- *     ali15x3_dma_setup       -       begin a DMA phase
+ *     ali_dma_check   -       DMA check
  *     @drive: target device
  *     @cmd: command
  *
  *     Returns 1 if the DMA cannot be performed, zero on success.
  */
 
-static int ali15x3_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
+static int ali_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        if (m5229_revision < 0xC2 && drive->media != ide_disk) {
                if (cmd->tf_flags & IDE_TFLAG_WRITE)
                        return 1;       /* try PIO instead of DMA */
        }
-       return ide_dma_setup(drive, cmd);
+       return 0;
 }
 
 /**
@@ -503,13 +503,13 @@ static const struct ide_port_ops ali_port_ops = {
 
 static const struct ide_dma_ops ali_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ali15x3_dma_setup,
+       .dma_setup              = ide_dma_setup,
        .dma_start              = ide_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
+       .dma_check              = ali_dma_check,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 27547121daff67f15b4d3cd6244cae717e416d74..8eda552326e9030db0de6b26eebe46caf39caf48 100644 (file)
@@ -192,15 +192,9 @@ static void at91_ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
        struct ide_taskfile *tf = &cmd->tf;
        u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
 
-       if (cmd->tf_flags & IDE_FTFLAG_FLAGGED)
+       if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (cmd->tf_flags & IDE_FTFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               at91_ide_output_data(drive, NULL, &data, 2);
-       }
-
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                ide_mm_outb(tf->hob_feature, io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
@@ -233,19 +227,11 @@ static void at91_ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
        struct ide_io_ports *io_ports = &hwif->io_ports;
        struct ide_taskfile *tf = &cmd->tf;
 
-       if (cmd->tf_flags & IDE_FTFLAG_IN_DATA) {
-               u16 data;
-
-               at91_ide_input_data(drive, NULL, &data, 2);
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       ide_mm_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       ide_mm_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = ide_mm_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = ide_mm_inb(io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = ide_mm_inb(io_ports->nsect_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
@@ -258,18 +244,18 @@ static void at91_ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf->device = ide_mm_inb(io_ports->device_addr);
 
        if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               ide_mm_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+               ide_mm_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = ide_mm_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = ide_mm_inb(io_ports->feature_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = ide_mm_inb(io_ports->nsect_addr);
+                       tf->hob_nsect = ide_mm_inb(io_ports->nsect_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = ide_mm_inb(io_ports->lbal_addr);
+                       tf->hob_lbal  = ide_mm_inb(io_ports->lbal_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = ide_mm_inb(io_ports->lbam_addr);
+                       tf->hob_lbam  = ide_mm_inb(io_ports->lbam_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = ide_mm_inb(io_ports->lbah_addr);
+                       tf->hob_lbah  = ide_mm_inb(io_ports->lbah_addr);
        }
 }
 
@@ -295,8 +281,9 @@ static const struct ide_tp_ops at91_ide_tp_ops = {
        .exec_command   = ide_exec_command,
        .read_status    = ide_read_status,
        .read_altstatus = ide_read_altstatus,
-       .set_irq        = ide_set_irq,
+       .write_devctl   = ide_write_devctl,
 
+       .dev_select     = ide_dev_select,
        .tf_load        = at91_ide_tf_load,
        .tf_read        = at91_ide_tf_read,
 
index d3a9d6c15328de9b11f545160624a67e914d8401..46013644c965c1638faf8f519cd1578a177d114d 100644 (file)
@@ -50,7 +50,7 @@ static _auide_hwif auide_hwif;
 
 #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
 
-void auide_insw(unsigned long port, void *addr, u32 count)
+static inline void auide_insw(unsigned long port, void *addr, u32 count)
 {
        _auide_hwif *ahwif = &auide_hwif;
        chan_tab_t *ctp;
@@ -68,7 +68,7 @@ void auide_insw(unsigned long port, void *addr, u32 count)
        ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
 }
 
-void auide_outsw(unsigned long port, void *addr, u32 count)
+static inline void auide_outsw(unsigned long port, void *addr, u32 count)
 {
        _auide_hwif *ahwif = &auide_hwif;
        chan_tab_t *ctp;
@@ -236,7 +236,7 @@ static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
                        if (++count >= PRD_ENTRIES) {
                                printk(KERN_WARNING "%s: DMA table too small\n",
                                       drive->name);
-                               goto use_pio_instead;
+                               return 0;
                        }
 
                        /* Lets enable intr for the last descriptor only */
@@ -272,16 +272,11 @@ static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
        if (count)
                return 1;
 
- use_pio_instead:
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 
 static int auide_dma_end(ide_drive_t *drive)
 {
-       ide_destroy_dmatable(drive);
-
        return 0;
 }
 
@@ -292,12 +287,9 @@ static void auide_dma_start(ide_drive_t *drive )
 
 static int auide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       if (auide_build_dmatable(drive, cmd) == 0) {
-               ide_map_sg(drive, cmd);
+       if (auide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
-       drive->waiting_for_dma = 1;
        return 0;
 }
 
@@ -322,16 +314,11 @@ static void auide_dma_host_set(ide_drive_t *drive, int on)
 
 static void auide_ddma_tx_callback(int irq, void *param)
 {
-       _auide_hwif *ahwif = (_auide_hwif*)param;
-       ahwif->drive->waiting_for_dma = 0;
 }
 
 static void auide_ddma_rx_callback(int irq, void *param)
 {
-       _auide_hwif *ahwif = (_auide_hwif*)param;
-       ahwif->drive->waiting_for_dma = 0;
 }
-
 #endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
 
 static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags)
@@ -353,7 +340,6 @@ static const struct ide_dma_ops au1xxx_dma_ops = {
        .dma_end                = auide_dma_end,
        .dma_test_irq           = auide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
 };
 
 static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
@@ -481,9 +467,9 @@ static const struct ide_tp_ops au1xxx_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
index bf0e3f4708242320b75a7dc705be76ef6174b13b..80b777e4247b168644ca75691de11ea9d17e6edb 100644 (file)
@@ -318,7 +318,6 @@ static int cmd646_1_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = 0, dma_cmd = 0;
 
-       drive->waiting_for_dma = 0;
        /* get DMA status */
        dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
        /* read DMA command state */
@@ -327,8 +326,6 @@ static int cmd646_1_dma_end(ide_drive_t *drive)
        outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
        /* clear the INTR & ERROR bits */
        outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
-       /* and free any DMA resources */
-       ide_destroy_dmatable(drive);
        /* verify good DMA status */
        return (dma_stat & 7) != 4;
 }
@@ -384,7 +381,6 @@ static const struct ide_dma_ops cmd64x_dma_ops = {
        .dma_test_irq           = cmd64x_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
@@ -396,7 +392,6 @@ static const struct ide_dma_ops cmd646_rev1_dma_ops = {
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
@@ -408,7 +403,6 @@ static const struct ide_dma_ops cmd648_dma_ops = {
        .dma_test_irq           = cmd648_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 8e8b35a899012961aa6967cb5e8dd7115cf0afb4..40bf05eddf6ea1ef55c01e1c87be2ca9f88657b7 100644 (file)
@@ -92,8 +92,7 @@ static u8 cs5530_udma_filter(ide_drive_t *drive)
                if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
                    (mateid[ATA_ID_UDMA_MODES] & 7))
                        goto out;
-               if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
-                   (mateid[ATA_ID_MWDMA_MODES] & 7))
+               if (mateid[ATA_ID_MWDMA_MODES] & 7)
                        mask = 0;
        }
 out:
index d5dcf4899607a2fffc8d73af02f9113b29a6460d..353a35bbba636dcd1d3a22e1dd275efc7894319e 100644 (file)
@@ -236,7 +236,6 @@ static const struct ide_dma_ops cs5536_dma_ops = {
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
 };
 
 static const struct ide_port_info cs5536_info = {
index b368a5effc3a029240a7dde6ff8abd265fc39346..afa2af9a362beb9464f69b5d79397481f9b2fbd9 100644 (file)
@@ -89,9 +89,9 @@ static const struct ide_tp_ops falconide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
index dc778251cb050b6b188e3a19c9edffa7d512d06f..c7119516c5a7ccaff6029fbacc3e3a7dfe1017ec 100644 (file)
 
 #define GAYLE_NEXT_PORT        0x1000
 
-#ifndef CONFIG_BLK_DEV_IDEDOUBLER
-#define GAYLE_NUM_HWIFS                1
-#define GAYLE_NUM_PROBE_HWIFS  GAYLE_NUM_HWIFS
-#define GAYLE_HAS_CONTROL_REG  1
-#else /* CONFIG_BLK_DEV_IDEDOUBLER */
 #define GAYLE_NUM_HWIFS                2
 #define GAYLE_NUM_PROBE_HWIFS  (ide_doubler ? GAYLE_NUM_HWIFS : \
                                               GAYLE_NUM_HWIFS-1)
@@ -66,8 +61,6 @@
 static int ide_doubler;
 module_param_named(doubler, ide_doubler, bool, 0);
 MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-
 
     /*
      *  Check and acknowledge the interrupt status
@@ -151,10 +144,7 @@ static int __init gayle_init(void)
 found:
        printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
                         a4000 ? 4000 : 1200,
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-                        ide_doubler ? ", IDE doubler" :
-#endif
-                        "");
+                        ide_doubler ? ", IDE doubler" : "");
 
        if (a4000) {
            phys_base = GAYLE_BASE_4000;
index dbaf184ed9c5a47f74be619ebabb612c344379d5..a0eb87f59134141340181afe21c12d615d0a4484 100644 (file)
@@ -835,12 +835,6 @@ static int hpt370_dma_end(ide_drive_t *drive)
        return ide_dma_end(drive);
 }
 
-static void hpt370_dma_timeout(ide_drive_t *drive)
-{
-       hpt370_irq_timeout(drive);
-       ide_dma_timeout(drive);
-}
-
 /* returns 1 if DMA IRQ issued, 0 otherwise */
 static int hpt374_dma_test_irq(ide_drive_t *drive)
 {
@@ -1423,7 +1417,6 @@ static const struct ide_dma_ops hpt37x_dma_ops = {
        .dma_test_irq           = hpt374_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
@@ -1435,7 +1428,7 @@ static const struct ide_dma_ops hpt370_dma_ops = {
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = hpt370_dma_timeout,
+       .dma_clear              = hpt370_irq_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
@@ -1447,7 +1440,6 @@ static const struct ide_dma_ops hpt36x_dma_ops = {
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = hpt366_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index c7e5c2246b79e1b29836055921e116daacafe102..2fb0f29650099c8c5ccb706c96dae78c85944c21 100644 (file)
 /*
  * This routine is invoked from ide.c to prepare for access to a given drive.
  */
-static void ht6560b_selectproc (ide_drive_t *drive)
+static void ht6560b_dev_select(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        unsigned long flags;
@@ -143,6 +143,8 @@ static void ht6560b_selectproc (ide_drive_t *drive)
 #endif
        }
        local_irq_restore(flags);
+
+       outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr);
 }
 
 /*
@@ -305,15 +307,29 @@ static int probe_ht6560b;
 module_param_named(probe, probe_ht6560b, bool, 0);
 MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
 
+static const struct ide_tp_ops ht6560b_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = ht6560b_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
+};
+
 static const struct ide_port_ops ht6560b_port_ops = {
        .init_dev               = ht6560b_init_dev,
        .set_pio_mode           = ht6560b_set_pio_mode,
-       .selectproc             = ht6560b_selectproc,
 };
 
 static const struct ide_port_info ht6560b_port_info __initdata = {
        .name                   = DRV_NAME,
        .chipset                = ide_ht6560b,
+       .tp_ops                 = &ht6560b_tp_ops,
        .port_ops               = &ht6560b_port_ops,
        .host_flags             = IDE_HFLAG_SERIALIZE | /* is this needed? */
                                  IDE_HFLAG_NO_DMA |
index 51ce404fe53234b976cf851dd0b482c5200302b9..4e16ce68b0630988a574f51270b12a4a49bd3dc5 100644 (file)
@@ -287,13 +287,8 @@ static int icside_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        struct expansion_card *ec = ECARD_DEV(hwif->dev);
 
-       drive->waiting_for_dma = 0;
-
        disable_dma(ec->dma);
 
-       /* Teardown mappings after DMA has completed. */
-       ide_destroy_dmatable(drive);
-
        return get_dma_residue(ec->dma) != 0;
 }
 
@@ -346,8 +341,6 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        set_dma_sg(ec->dma, hwif->sg_table, cmd->sg_nents);
        set_dma_mode(ec->dma, dma_mode);
 
-       drive->waiting_for_dma = 1;
-
        return 0;
 }
 
@@ -377,7 +370,6 @@ static const struct ide_dma_ops icside_v6_dma_ops = {
        .dma_start              = icside_dma_start,
        .dma_end                = icside_dma_end,
        .dma_test_irq           = icside_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
 };
 #else
index 2fb5d28a9be5e16bf73833c5e9c5c7db8511ab89..3e43b889dd64ab55422e5b1432831586a21b5cca 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/cdrom.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/scatterlist.h>
+
 #include <scsi/scsi.h>
 
 #ifdef DEBUG
@@ -69,56 +71,6 @@ int ide_check_atapi_device(ide_drive_t *drive, const char *s)
 }
 EXPORT_SYMBOL_GPL(ide_check_atapi_device);
 
-/* PIO data transfer routine using the scatter gather table. */
-int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                   unsigned int bcount, int write)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
-       struct scatterlist *sg = pc->sg;
-       char *buf;
-       int count, done = 0;
-
-       while (bcount) {
-               count = min(sg->length - pc->b_count, bcount);
-
-               if (PageHighMem(sg_page(sg))) {
-                       unsigned long flags;
-
-                       local_irq_save(flags);
-                       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
-                       xf(drive, NULL, buf + pc->b_count, count);
-                       kunmap_atomic(buf - sg->offset, KM_IRQ0);
-                       local_irq_restore(flags);
-               } else {
-                       buf = sg_virt(sg);
-                       xf(drive, NULL, buf + pc->b_count, count);
-               }
-
-               bcount -= count;
-               pc->b_count += count;
-               done += count;
-
-               if (pc->b_count == sg->length) {
-                       if (!--pc->sg_cnt)
-                               break;
-                       pc->sg = sg = sg_next(sg);
-                       pc->b_count = 0;
-               }
-       }
-
-       if (bcount) {
-               printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name,
-                       bcount, write ? "padding with zeros"
-                                     : "discarding data");
-               ide_pad_transfer(drive, write, bcount);
-       }
-
-       return done;
-}
-EXPORT_SYMBOL_GPL(ide_io_buffers);
-
 void ide_init_pc(struct ide_atapi_pc *pc)
 {
        memset(pc, 0, sizeof(*pc));
@@ -324,12 +276,14 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
 {
        struct ide_atapi_pc *pc = drive->pc;
        ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd *cmd = &hwif->cmd;
        struct request *rq = hwif->rq;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        xfer_func_t *xferfunc;
-       unsigned int timeout, temp;
+       unsigned int timeout, done;
        u16 bcount;
        u8 stat, ireason, dsc = 0;
+       u8 write = !!(pc->flags & PC_FLAG_WRITING);
 
        debug_log("Enter %s - interrupt handler\n", __func__);
 
@@ -340,8 +294,13 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
        stat = tp_ops->read_status(hwif);
 
        if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
-               if (hwif->dma_ops->dma_end(drive) ||
-                   (drive->media == ide_tape && (stat & ATA_ERR))) {
+               int rc;
+
+               drive->waiting_for_dma = 0;
+               rc = hwif->dma_ops->dma_end(drive);
+               ide_dma_unmap_sg(drive, cmd);
+
+               if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) {
                        if (drive->media == ide_floppy)
                                printk(KERN_ERR "%s: DMA %s error\n",
                                        drive->name, rq_data_dir(pc->rq)
@@ -357,7 +316,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
 
        /* No more interrupts */
        if ((stat & ATA_DRQ) == 0) {
-               int uptodate;
+               int uptodate, error;
+               unsigned int done;
 
                debug_log("Packet command completed, %d bytes transferred\n",
                          pc->xferred);
@@ -404,16 +364,24 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
 
                if (blk_special_request(rq)) {
                        rq->errors = 0;
-                       ide_complete_rq(drive, 0, blk_rq_bytes(rq));
+                       done = blk_rq_bytes(rq);
+                       error = 0;
                } else {
+
                        if (blk_fs_request(rq) == 0 && uptodate <= 0) {
                                if (rq->errors == 0)
                                        rq->errors = -EIO;
                        }
-                       ide_complete_rq(drive, uptodate ? 0 : -EIO,
-                                       ide_rq_bytes(rq));
+
+                       if (drive->media == ide_tape)
+                               done = ide_rq_bytes(rq); /* FIXME */
+                       else
+                               done = blk_rq_bytes(rq);
+
+                       error = uptodate ? 0 : -EIO;
                }
 
+               ide_complete_rq(drive, error, done);
                return ide_stopped;
        }
 
@@ -433,8 +401,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                return ide_do_reset(drive);
        }
 
-       if (((ireason & ATAPI_IO) == ATAPI_IO) ==
-               !!(pc->flags & PC_FLAG_WRITING)) {
+       if (((ireason & ATAPI_IO) == ATAPI_IO) == write) {
                /* Hopefully, we will never get here */
                printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
                                "to %s!\n", drive->name,
@@ -443,45 +410,30 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                return ide_do_reset(drive);
        }
 
-       if (!(pc->flags & PC_FLAG_WRITING)) {
-               /* Reading - Check that we have enough space */
-               temp = pc->xferred + bcount;
-               if (temp > pc->req_xfer) {
-                       if (temp > pc->buf_size) {
-                               printk(KERN_ERR "%s: The device wants to send "
-                                               "us more data than expected - "
-                                               "discarding data\n",
-                                               drive->name);
-
-                               ide_pad_transfer(drive, 0, bcount);
-                               goto next_irq;
-                       }
-                       debug_log("The device wants to send us more data than "
-                                 "expected - allowing transfer\n");
-               }
-               xferfunc = tp_ops->input_data;
-       } else
-               xferfunc = tp_ops->output_data;
-
-       if ((drive->media == ide_floppy && !pc->buf) ||
-           (drive->media == ide_tape && pc->bh)) {
-               int done = drive->pc_io_buffers(drive, pc, bcount,
-                                 !!(pc->flags & PC_FLAG_WRITING));
-
-               /* FIXME: don't do partial completions */
-               if (drive->media == ide_floppy)
-                       ide_complete_rq(drive, 0,
-                                       done ? done : ide_rq_bytes(rq));
-       } else
-               xferfunc(drive, NULL, pc->cur_pos, bcount);
+       xferfunc = write ? tp_ops->output_data : tp_ops->input_data;
+
+       if (drive->media == ide_floppy && pc->buf == NULL) {
+               done = min_t(unsigned int, bcount, cmd->nleft);
+               ide_pio_bytes(drive, cmd, write, done);
+       } else if (drive->media == ide_tape && pc->bh) {
+               done = drive->pc_io_buffers(drive, pc, bcount, write);
+       } else {
+               done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred);
+               xferfunc(drive, NULL, pc->cur_pos, done);
+       }
 
        /* Update the current position */
-       pc->xferred += bcount;
-       pc->cur_pos += bcount;
+       pc->xferred += done;
+       pc->cur_pos += done;
+
+       bcount -= done;
+
+       if (bcount)
+               ide_pad_transfer(drive, write, bcount);
+
+       debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n",
+                 rq->cmd[0], done, bcount);
 
-       debug_log("[cmd %x] transferred %d bytes on that intr.\n",
-                 rq->cmd[0], bcount);
-next_irq:
        /* And set the interrupt handler again */
        ide_set_handler(drive, ide_pc_intr, timeout);
        return ide_started;
@@ -611,6 +563,10 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
                                             : ide_pc_intr),
                        timeout);
 
+       /* Send the actual packet */
+       if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
+               hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
+
        /* Begin DMA, if necessary */
        if (dev_is_idecd(drive)) {
                if (drive->dma)
@@ -622,10 +578,6 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
                }
        }
 
-       /* Send the actual packet */
-       if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
-               hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
-
        return ide_started;
 }
 
@@ -633,7 +585,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        struct ide_atapi_pc *pc;
        ide_hwif_t *hwif = drive->hwif;
-       const struct ide_dma_ops *dma_ops = hwif->dma_ops;
        ide_expiry_t *expiry = NULL;
        struct request *rq = hwif->rq;
        unsigned int timeout;
@@ -647,12 +598,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
                expiry = ide_cd_expiry;
                timeout = ATAPI_WAIT_PC;
 
-               if (drive->dma) {
-                       if (ide_build_sglist(drive, cmd))
-                               drive->dma = !dma_ops->dma_setup(drive, cmd);
-                       else
-                               drive->dma = 0;
-               }
+               if (drive->dma)
+                       drive->dma = !ide_dma_prepare(drive, cmd);
        } else {
                pc = drive->pc;
 
@@ -670,13 +617,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
                        ide_dma_off(drive);
                }
 
-               if ((pc->flags & PC_FLAG_DMA_OK) &&
-                    (drive->dev_flags & IDE_DFLAG_USING_DMA)) {
-                       if (ide_build_sglist(drive, cmd))
-                               drive->dma = !dma_ops->dma_setup(drive, cmd);
-                       else
-                               drive->dma = 0;
-               }
+               if (pc->flags & PC_FLAG_DMA_OK)
+                       drive->dma = !ide_dma_prepare(drive, cmd);
 
                if (!drive->dma)
                        pc->flags &= ~PC_FLAG_DMA_OK;
index 3f630e4080d42abec2711eb597ccf8ff17fc616d..35729a47f797f3d721b8cb26f0ec820cde9927ae 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
  * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
- * Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2005, 2007-2009  Bartlomiej Zolnierkiewicz
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  * See Documentation/cdrom/ide-cd for usage information.
  *
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
- * For those wishing to work on this driver, please be sure you download
- * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
- * (SFF-8020i rev 2.6) standards. These documents can be obtained by
- * anonymous ftp from:
- * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
- * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
+ *
+ * Documentation:
+ *     Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards.
  *
  * For historical changelog please see:
  *     Documentation/ide/ChangeLog.ide-cd.1994-2004
@@ -245,73 +242,34 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
        elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
 }
 
-static void cdrom_end_request(ide_drive_t *drive, int uptodate)
+static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
 {
-       struct request *rq = drive->hwif->rq;
-       int nsectors = rq->hard_cur_sectors;
-
-       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, uptodate: 0x%x, nsectors: %d",
-                                   rq->cmd[0], uptodate, nsectors);
-
-       if (blk_sense_request(rq) && uptodate) {
-               /*
-                * For REQ_TYPE_SENSE, "rq->buffer" points to the original
-                * failed request
-                */
-               struct request *failed = (struct request *) rq->buffer;
-               struct cdrom_info *info = drive->driver_data;
-               void *sense = &info->sense_data;
-
-               if (failed) {
-                       if (failed->sense) {
-                               sense = failed->sense;
-                               failed->sense_len = rq->sense_len;
-                       }
-                       cdrom_analyze_sense_data(drive, failed, sense);
-                       /*
-                        * now end the failed request
-                        */
-                       if (blk_fs_request(failed)) {
-                               if (ide_end_rq(drive, failed, -EIO,
-                                               failed->hard_nr_sectors << 9))
-                                       BUG();
-                       } else {
-                               if (blk_end_request(failed, -EIO,
-                                                   failed->data_len))
-                                       BUG();
-                       }
-               } else
-                       cdrom_analyze_sense_data(drive, NULL, sense);
-       }
-
-       if (!rq->current_nr_sectors && blk_fs_request(rq))
-               uptodate = 1;
-       /* make sure it's fully ended */
-       if (blk_pc_request(rq))
-               nsectors = (rq->data_len + 511) >> 9;
-       if (!nsectors)
-               nsectors = 1;
-
-       ide_debug_log(IDE_DBG_FUNC, "uptodate: 0x%x, nsectors: %d",
-                                   uptodate, nsectors);
-
-       if (blk_fs_request(rq) == 0 && uptodate <= 0 && rq->errors == 0)
-               rq->errors = -EIO;
+       /*
+        * For REQ_TYPE_SENSE, "rq->buffer" points to the original
+        * failed request
+        */
+       struct request *failed = (struct request *)rq->buffer;
+       struct cdrom_info *info = drive->driver_data;
+       void *sense = &info->sense_data;
 
-       ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
-}
+       if (failed) {
+               if (failed->sense) {
+                       sense = failed->sense;
+                       failed->sense_len = rq->sense_len;
+               }
+               cdrom_analyze_sense_data(drive, failed, sense);
 
-static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st)
-{
-       if (st & 0x80)
-               return;
-       ide_dump_status(drive, msg, st);
+               if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed)))
+                       BUG();
+       } else
+               cdrom_analyze_sense_data(drive, NULL, sense);
 }
 
 /*
  * Returns:
  * 0: if the request should be continued.
- * 1: if the request was ended.
+ * 1: if the request will be going through error recovery.
+ * 2: if the request should be ended.
  */
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 {
@@ -332,12 +290,6 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
        err = ide_read_error(drive);
        sense_key = err >> 4;
 
-       if (rq == NULL) {
-               printk(KERN_ERR PFX "%s: missing rq in %s\n",
-                               drive->name, __func__);
-               return 1;
-       }
-
        ide_debug_log(IDE_DBG_RQ, "stat: 0x%x, good_stat: 0x%x, cmd[0]: 0x%x, "
                                  "rq->cmd_type: 0x%x, err: 0x%x",
                                  stat, good_stat, rq->cmd[0], rq->cmd_type,
@@ -350,10 +302,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 * Just give up.
                 */
                rq->cmd_flags |= REQ_FAILED;
-               cdrom_end_request(drive, 0);
-               ide_error(drive, "request sense failure", stat);
-               return 1;
-
+               return 2;
        } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
                /* All other functions, except for READ. */
 
@@ -456,21 +405,19 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                         * No point in retrying after an illegal request or data
                         * protect error.
                         */
-                       ide_dump_status_no_sense(drive, "command error", stat);
+                       ide_dump_status(drive, "command error", stat);
                        do_end_request = 1;
                } else if (sense_key == MEDIUM_ERROR) {
                        /*
                         * No point in re-trying a zillion times on a bad
                         * sector. If we got here the error is not correctable.
                         */
-                       ide_dump_status_no_sense(drive,
-                                                "media error (bad sector)",
-                                                stat);
+                       ide_dump_status(drive, "media error (bad sector)",
+                                       stat);
                        do_end_request = 1;
                } else if (sense_key == BLANK_CHECK) {
                        /* disk appears blank ?? */
-                       ide_dump_status_no_sense(drive, "media error (blank)",
-                                                stat);
+                       ide_dump_status(drive, "media error (blank)", stat);
                        do_end_request = 1;
                } else if ((err & ~ATA_ABORTED) != 0) {
                        /* go to the default handler for other errors */
@@ -495,14 +442,12 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 */
                if (stat & ATA_ERR)
                        cdrom_queue_request_sense(drive, NULL, NULL);
+               return 1;
        } else {
                blk_dump_rq_flags(rq, PFX "bad rq");
-               cdrom_end_request(drive, 0);
+               return 2;
        }
 
-       /* retry, or handle the next request */
-       return 1;
-
 end_request:
        if (stat & ATA_ERR) {
                struct request_queue *q = drive->queue;
@@ -515,10 +460,9 @@ end_request:
                hwif->rq = NULL;
 
                cdrom_queue_request_sense(drive, rq->sense, rq);
+               return 1;
        } else
-               cdrom_end_request(drive, 0);
-
-       return 1;
+               return 2;
 }
 
 /*
@@ -562,101 +506,13 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
        if (rq->cmd_type == REQ_TYPE_ATA_PC)
                rq->cmd_flags |= REQ_FAILED;
 
-       cdrom_end_request(drive, 0);
        return -1;
 }
 
-/*
- * Assume that the drive will always provide data in multiples of at least
- * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise.
- */
-static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
+static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       ide_debug_log(IDE_DBG_FUNC, "len: %d", len);
-
-       if ((len % SECTOR_SIZE) == 0)
-               return 0;
+       struct request *rq = cmd->rq;
 
-       printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name,
-                       __func__, len);
-
-       if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES)
-               printk(KERN_ERR PFX "This drive is not supported by this "
-                               "version of the driver\n");
-       else {
-               printk(KERN_ERR PFX "Trying to limit transfer sizes\n");
-               drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES;
-       }
-
-       return 1;
-}
-
-static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
-                                                struct request *rq)
-{
-       ide_debug_log(IDE_DBG_RQ, "rq->cmd_flags: 0x%x", rq->cmd_flags);
-
-       if (rq_data_dir(rq) == READ) {
-               unsigned short sectors_per_frame =
-                       queue_hardsect_size(drive->queue) >> SECTOR_BITS;
-               int nskip = rq->sector & (sectors_per_frame - 1);
-
-               /*
-                * If the requested sector doesn't start on a frame boundary,
-                * we must adjust the start of the transfer so that it does,
-                * and remember to skip the first few sectors.
-                *
-                * If the rq->current_nr_sectors field is larger than the size
-                * of the buffer, it will mean that we're to skip a number of
-                * sectors equal to the amount by which rq->current_nr_sectors
-                * is larger than the buffer size.
-                */
-               if (nskip > 0) {
-                       /* sanity check... */
-                       if (rq->current_nr_sectors !=
-                           bio_cur_sectors(rq->bio)) {
-                               printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
-                                               drive->name, __func__,
-                                               rq->current_nr_sectors);
-                               cdrom_end_request(drive, 0);
-                               return ide_stopped;
-                       }
-                       rq->current_nr_sectors += nskip;
-               }
-       }
-
-       /* set up the command */
-       rq->timeout = ATAPI_WAIT_PC;
-
-       return ide_started;
-}
-
-/*
- * Fix up a possibly partially-processed request so that we can start it over
- * entirely, or even put it back on the request queue.
- */
-static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
-{
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (rq->buffer != bio_data(rq->bio)) {
-               sector_t n =
-                       (rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
-
-               rq->buffer = bio_data(rq->bio);
-               rq->nr_sectors += n;
-               rq->sector -= n;
-       }
-       rq->current_nr_sectors = bio_cur_sectors(rq->bio);
-       rq->hard_cur_sectors = rq->current_nr_sectors;
-       rq->hard_nr_sectors = rq->nr_sectors;
-       rq->hard_sector = rq->sector;
-       rq->q->prep_rq_fn(rq->q, rq);
-}
-
-static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
-{
        ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
 
        /*
@@ -664,11 +520,14 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
         * and some drives don't send them.  Sigh.
         */
        if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
-           rq->data_len > 0 && rq->data_len <= 5)
-               while (rq->data_len > 0) {
-                       *(u8 *)rq->data++ = 0;
-                       --rq->data_len;
+           cmd->nleft > 0 && cmd->nleft <= 5) {
+               unsigned int ofs = cmd->nbytes - cmd->nleft;
+
+               while (cmd->nleft > 0) {
+                       *((u8 *)rq->data + ofs++) = 0;
+                       cmd->nleft--;
                }
+       }
 }
 
 int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
@@ -748,24 +607,26 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
        return (flags & REQ_FAILED) ? -EIO : 0;
 }
 
-/*
- * Called from blk_end_request_callback() after the data of the request is
- * completed and before the request itself is completed. By returning value '1',
- * blk_end_request_callback() returns immediately without completing it.
- */
-static int cdrom_newpc_intr_dummy_cb(struct request *rq)
+static void ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       return 1;
+       unsigned int nr_bytes = cmd->nbytes - cmd->nleft;
+
+       if (cmd->tf_flags & IDE_TFLAG_WRITE)
+               nr_bytes -= cmd->last_xfer_len;
+
+       if (nr_bytes > 0)
+               ide_complete_rq(drive, 0, nr_bytes);
 }
 
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd *cmd = &hwif->cmd;
        struct request *rq = hwif->rq;
-       xfer_func_t *xferfunc;
        ide_expiry_t *expiry = NULL;
        int dma_error = 0, dma, stat, thislen, uptodate = 0;
-       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
+       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors;
+       int sense = blk_sense_request(rq);
        unsigned int timeout;
        u16 len;
        u8 ireason;
@@ -777,7 +638,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        dma = drive->dma;
        if (dma) {
                drive->dma = 0;
+               drive->waiting_for_dma = 0;
                dma_error = hwif->dma_ops->dma_end(drive);
+               ide_dma_unmap_sg(drive, cmd);
                if (dma_error) {
                        printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
                                        write ? "write" : "read");
@@ -785,27 +648,24 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                }
        }
 
-       if (cdrom_decode_status(drive, 0, &stat))
+       rc = cdrom_decode_status(drive, 0, &stat);
+       if (rc) {
+               if (rc == 2)
+                       goto out_end;
                return ide_stopped;
+       }
 
        /* using dma, transfer is complete now */
        if (dma) {
                if (dma_error)
                        return ide_error(drive, "dma error", stat);
-               if (blk_fs_request(rq)) {
-                       ide_complete_rq(drive, 0, rq->nr_sectors
-                               ? (rq->nr_sectors << 9) : ide_rq_bytes(rq));
-                       return ide_stopped;
-               } else if (rq->cmd_type == REQ_TYPE_ATA_PC && !rq->bio) {
-                       ide_complete_rq(drive, 0, 512);
-                       return ide_stopped;
-               }
-               goto end_request;
+               uptodate = 1;
+               goto out_end;
        }
 
        ide_read_bcount_and_ireason(drive, &len, &ireason);
 
-       thislen = blk_fs_request(rq) ? len : rq->data_len;
+       thislen = blk_fs_request(rq) ? len : cmd->nleft;
        if (thislen > len)
                thislen = len;
 
@@ -820,60 +680,30 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                         * Otherwise, complete the command normally.
                         */
                        uptodate = 1;
-                       if (rq->current_nr_sectors > 0) {
+                       if (cmd->nleft > 0) {
                                printk(KERN_ERR PFX "%s: %s: data underrun "
-                                               "(%d blocks)\n",
-                                               drive->name, __func__,
-                                               rq->current_nr_sectors);
+                                       "(%u bytes)\n", drive->name, __func__,
+                                       cmd->nleft);
                                if (!write)
                                        rq->cmd_flags |= REQ_FAILED;
                                uptodate = 0;
                        }
-                       cdrom_end_request(drive, uptodate);
-                       return ide_stopped;
                } else if (!blk_pc_request(rq)) {
-                       ide_cd_request_sense_fixup(drive, rq);
+                       ide_cd_request_sense_fixup(drive, cmd);
                        /* complain if we still have data left to transfer */
-                       uptodate = rq->data_len ? 0 : 1;
+                       uptodate = cmd->nleft ? 0 : 1;
+                       if (uptodate == 0)
+                               rq->cmd_flags |= REQ_FAILED;
                }
-               goto end_request;
+               goto out_end;
        }
 
        /* check which way to transfer data */
-       if (ide_cd_check_ireason(drive, rq, len, ireason, write))
-               return ide_stopped;
+       rc = ide_cd_check_ireason(drive, rq, len, ireason, write);
+       if (rc)
+               goto out_end;
 
-       if (blk_fs_request(rq)) {
-               if (write == 0) {
-                       int nskip;
-
-                       if (ide_cd_check_transfer_size(drive, len)) {
-                               cdrom_end_request(drive, 0);
-                               return ide_stopped;
-                       }
-
-                       /*
-                        * First, figure out if we need to bit-bucket
-                        * any of the leading sectors.
-                        */
-                       nskip = min_t(int, rq->current_nr_sectors
-                                          - bio_cur_sectors(rq->bio),
-                                          thislen >> 9);
-                       if (nskip > 0) {
-                               ide_pad_transfer(drive, write, nskip << 9);
-                               rq->current_nr_sectors -= nskip;
-                               thislen -= (nskip << 9);
-                       }
-               }
-       }
-
-       if (ireason == 0) {
-               write = 1;
-               xferfunc = hwif->tp_ops->output_data;
-       } else {
-               write = 0;
-               xferfunc = hwif->tp_ops->input_data;
-       }
+       cmd->last_xfer_len = 0;
 
        ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
                                  "ireason: 0x%x",
@@ -881,75 +711,31 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
        /* transfer data */
        while (thislen > 0) {
-               u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
-               int blen = rq->data_len;
-
-               /* bio backed? */
-               if (rq->bio) {
-                       if (blk_fs_request(rq)) {
-                               ptr = rq->buffer;
-                               blen = rq->current_nr_sectors << 9;
-                       } else {
-                               ptr = bio_data(rq->bio);
-                               blen = bio_iovec(rq->bio)->bv_len;
-                       }
-               }
+               int blen = min_t(int, thislen, cmd->nleft);
 
-               if (!ptr) {
-                       if (blk_fs_request(rq) && !write)
-                               /*
-                                * If the buffers are full, pipe the rest into
-                                * oblivion.
-                                */
-                               ide_pad_transfer(drive, 0, thislen);
-                       else {
-                               printk(KERN_ERR PFX "%s: confused, missing data\n",
-                                               drive->name);
-                               blk_dump_rq_flags(rq, rq_data_dir(rq)
-                                                 ? "cdrom_newpc_intr, write"
-                                                 : "cdrom_newpc_intr, read");
-                       }
+               if (cmd->nleft == 0)
                        break;
-               }
-
-               if (blen > thislen)
-                       blen = thislen;
 
-               xferfunc(drive, NULL, ptr, blen);
+               ide_pio_bytes(drive, cmd, write, blen);
+               cmd->last_xfer_len += blen;
 
                thislen -= blen;
                len -= blen;
 
-               if (blk_fs_request(rq)) {
-                       rq->buffer += blen;
-                       rq->nr_sectors -= (blen >> 9);
-                       rq->current_nr_sectors -= (blen >> 9);
-                       rq->sector += (blen >> 9);
-
-                       if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-                               cdrom_end_request(drive, 1);
-               } else {
-                       rq->data_len -= blen;
-
-                       /*
-                        * The request can't be completed until DRQ is cleared.
-                        * So complete the data, but don't complete the request
-                        * using the dummy function for the callback feature
-                        * of blk_end_request_callback().
-                        */
-                       if (rq->bio)
-                               blk_end_request_callback(rq, 0, blen,
-                                                cdrom_newpc_intr_dummy_cb);
-                       else
-                               rq->data += blen;
-               }
-               if (!write && blk_sense_request(rq))
+               if (sense && write == 0)
                        rq->sense_len += blen;
        }
 
        /* pad, if necessary */
-       if (!blk_fs_request(rq) && len > 0)
-               ide_pad_transfer(drive, write, len);
+       if (len > 0) {
+               if (blk_fs_request(rq) == 0 || write == 0)
+                       ide_pad_transfer(drive, write, len);
+               else {
+                       printk(KERN_ERR PFX "%s: confused, missing data\n",
+                               drive->name);
+                       blk_dump_rq_flags(rq, "cdrom_newpc_intr");
+               }
+       }
 
        if (blk_pc_request(rq)) {
                timeout = rq->timeout;
@@ -963,21 +749,50 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        ide_set_handler(drive, cdrom_newpc_intr, timeout);
        return ide_started;
 
-end_request:
-       if (blk_pc_request(rq)) {
+out_end:
+       if (blk_pc_request(rq) && rc == 0) {
                unsigned int dlen = rq->data_len;
 
-               if (dma)
-                       rq->data_len = 0;
+               rq->data_len = 0;
 
                if (blk_end_request(rq, 0, dlen))
                        BUG();
 
                hwif->rq = NULL;
        } else {
-               if (!uptodate)
-                       rq->cmd_flags |= REQ_FAILED;
-               cdrom_end_request(drive, uptodate);
+               if (sense && uptodate)
+                       ide_cd_complete_failed_rq(drive, rq);
+
+               if (blk_fs_request(rq)) {
+                       if (cmd->nleft == 0)
+                               uptodate = 1;
+               } else {
+                       if (uptodate <= 0 && rq->errors == 0)
+                               rq->errors = -EIO;
+               }
+
+               if (uptodate == 0)
+                       ide_cd_error_cmd(drive, cmd);
+
+               /* make sure it's fully ended */
+               if (blk_pc_request(rq))
+                       nsectors = (rq->data_len + 511) >> 9;
+               else
+                       nsectors = rq->hard_nr_sectors;
+
+               if (nsectors == 0)
+                       nsectors = 1;
+
+               if (blk_fs_request(rq) == 0) {
+                       rq->data_len -= (cmd->nbytes - cmd->nleft);
+                       if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
+                               rq->data_len += cmd->last_xfer_len;
+               }
+
+               ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
+
+               if (sense && rc == 2)
+                       ide_error(drive, "request sense failure", stat);
        }
        return ide_stopped;
 }
@@ -985,42 +800,40 @@ end_request:
 static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *cd = drive->driver_data;
+       struct request_queue *q = drive->queue;
        int write = rq_data_dir(rq) == WRITE;
        unsigned short sectors_per_frame =
-               queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+               queue_hardsect_size(q) >> SECTOR_BITS;
 
-       ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, write: 0x%x, "
+       ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
                                  "secs_per_frame: %u",
-                                 rq->cmd[0], write, sectors_per_frame);
+                                 rq->cmd[0], rq->cmd_flags, sectors_per_frame);
 
        if (write) {
                /* disk has become write protected */
-               if (get_disk_ro(cd->disk)) {
-                       cdrom_end_request(drive, 0);
+               if (get_disk_ro(cd->disk))
                        return ide_stopped;
-               }
        } else {
                /*
                 * We may be retrying this request after an error.  Fix up any
                 * weirdness which might be present in the request packet.
                 */
-               ide_cd_restore_request(drive, rq);
+               q->prep_rq_fn(q, rq);
        }
 
-       /* use DMA, if possible / writes *must* be hardware frame aligned */
+       /* fs requests *must* be hardware frame aligned */
        if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
-           (rq->sector & (sectors_per_frame - 1))) {
-               if (write) {
-                       cdrom_end_request(drive, 0);
-                       return ide_stopped;
-               }
-               drive->dma = 0;
-       } else
-               drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+           (rq->sector & (sectors_per_frame - 1)))
+               return ide_stopped;
+
+       /* use DMA, if possible */
+       drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
        if (write)
                cd->devinfo.media_written = 1;
 
+       rq->timeout = ATAPI_WAIT_PC;
+
        return ide_started;
 }
 
@@ -1068,6 +881,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                                        sector_t block)
 {
        struct ide_cmd cmd;
+       int uptodate = 0, nsectors;
 
        ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
                                  rq->cmd[0], (unsigned long long)block);
@@ -1077,10 +891,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
 
        if (blk_fs_request(rq)) {
                if (cdrom_start_rw(drive, rq) == ide_stopped)
-                       return ide_stopped;
-
-               if (ide_cd_prepare_rw_request(drive, rq) == ide_stopped)
-                       return ide_stopped;
+                       goto out_end;
        } else if (blk_sense_request(rq) || blk_pc_request(rq) ||
                   rq->cmd_type == REQ_TYPE_ATA_PC) {
                if (!rq->timeout)
@@ -1089,12 +900,13 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                cdrom_do_block_pc(drive, rq);
        } else if (blk_special_request(rq)) {
                /* right now this can only be a reset... */
-               cdrom_end_request(drive, 1);
-               return ide_stopped;
+               uptodate = 1;
+               goto out_end;
        } else {
                blk_dump_rq_flags(rq, DRV_NAME " bad flags");
-               cdrom_end_request(drive, 0);
-               return ide_stopped;
+               if (rq->errors == 0)
+                       rq->errors = -EIO;
+               goto out_end;
        }
 
        memset(&cmd, 0, sizeof(cmd));
@@ -1104,7 +916,22 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
 
        cmd.rq = rq;
 
+       if (blk_fs_request(rq) || rq->data_len) {
+               ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? (rq->nr_sectors << 9)
+                                                        : rq->data_len);
+               ide_map_sg(drive, &cmd);
+       }
+
        return ide_issue_pc(drive, &cmd);
+out_end:
+       nsectors = rq->hard_nr_sectors;
+
+       if (nsectors == 0)
+               nsectors = 1;
+
+       ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);
+
+       return ide_stopped;
 }
 
 /*
@@ -1696,9 +1523,6 @@ static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
 #endif
 
 static const struct cd_list_entry ide_cd_quirks_list[] = {
-       /* Limit transfer size per interrupt. */
-       { "SAMSUNG CD-ROM SCR-2430", NULL,   IDE_AFLAG_LIMIT_NFRAMES         },
-       { "SAMSUNG CD-ROM SCR-2432", NULL,   IDE_AFLAG_LIMIT_NFRAMES         },
        /* SCR-3231 doesn't support the SET_CD_SPEED command. */
        { "SAMSUNG CD-ROM SCR-3231", NULL,   IDE_AFLAG_NO_SPEED_SELECT       },
        /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
@@ -1759,18 +1583,18 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 {
        struct cdrom_info *cd = drive->driver_data;
        struct cdrom_device_info *cdi = &cd->devinfo;
+       struct request_queue *q = drive->queue;
        u16 *id = drive->id;
        char *fw_rev = (char *)&id[ATA_ID_FW_REV];
        int nslots;
 
        ide_debug_log(IDE_DBG_PROBE, "enter");
 
-       blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
-       blk_queue_dma_alignment(drive->queue, 31);
-       blk_queue_update_dma_pad(drive->queue, 15);
-       drive->queue->unplug_delay = (1 * HZ) / 1000;
-       if (!drive->queue->unplug_delay)
-               drive->queue->unplug_delay = 1;
+       blk_queue_prep_rq(q, ide_cdrom_prep_fn);
+       blk_queue_dma_alignment(q, 31);
+       blk_queue_update_dma_pad(q, 15);
+
+       q->unplug_delay = max((1 * HZ) / 1000, 1);
 
        drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
        drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
@@ -1788,8 +1612,7 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 
        nslots = ide_cdrom_probe_capabilities(drive);
 
-       /* set correct block size */
-       blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
+       blk_queue_hardsect_size(q, CD_FRAMESIZE);
 
        if (ide_cdrom_register(drive, nslots)) {
                printk(KERN_ERR PFX "%s: %s failed to register device with the"
@@ -1968,9 +1791,6 @@ static struct block_device_operations idecd_ops = {
 };
 
 /* module options */
-static char *ignore;
-module_param(ignore, charp, 0400);
-
 static unsigned long debug_mask;
 module_param(debug_mask, ulong, 0644);
 
@@ -1991,15 +1811,6 @@ static int ide_cd_probe(ide_drive_t *drive)
        if (drive->media != ide_cdrom && drive->media != ide_optical)
                goto failed;
 
-       /* skip drives that we were told to ignore */
-       if (ignore != NULL) {
-               if (strstr(ignore, drive->name)) {
-                       printk(KERN_INFO PFX "ignoring drive %s\n",
-                                        drive->name);
-                       goto failed;
-               }
-       }
-
        drive->debug_mask = debug_mask;
        drive->irq_handler = cdrom_newpc_intr;
 
index ca934c8a12891c68ea29815b99d4e92fef408efd..c998cf8e971a3f7bfbf70e7e42f40091349619eb 100644 (file)
@@ -227,7 +227,7 @@ static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
        ide_no_data_taskfile(drive, &cmd);
 
        /* if OK, compute maximum address value */
-       if ((tf->status & 0x01) == 0)
+       if (!(tf->status & ATA_ERR))
                addr = ide_get_lba_addr(tf, lba48) + 1;
 
        return addr;
@@ -267,7 +267,7 @@ static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
        ide_no_data_taskfile(drive, &cmd);
 
        /* if OK, compute maximum address value */
-       if ((tf->status & 0x01) == 0)
+       if (!(tf->status & ATA_ERR))
                addr_set = ide_get_lba_addr(tf, lba48) + 1;
 
        return addr_set;
index 75a9ea2e4c822e6f14988dbe5f296b85327893df..16fc46edc32df6390ef7e52d83a06925a25175df 100644 (file)
@@ -38,10 +38,9 @@ int config_drive_for_dma(ide_drive_t *drive)
         * Enable DMA on any drive that has mode2 DMA
         * (multi or single) enabled
         */
-       if (id[ATA_ID_FIELD_VALID] & 2) /* regular DMA */
-               if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
-                   (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
-                       return 1;
+       if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
+           (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
+               return 1;
 
        /* Consult the list of known "good" drives */
        if (ide_dma_good_drive(drive))
@@ -166,8 +165,6 @@ use_pio_instead:
        printk(KERN_ERR "%s: %s\n", drive->name,
                count ? "DMA table too small" : "empty DMA table?");
 
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 EXPORT_SYMBOL_GPL(ide_build_dmatable);
@@ -218,7 +215,6 @@ int ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        /* clear INTR & ERROR flags */
        ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
 
-       drive->waiting_for_dma = 1;
        return 0;
 }
 EXPORT_SYMBOL_GPL(ide_dma_setup);
@@ -292,8 +288,6 @@ int ide_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = 0, dma_cmd = 0, mask;
 
-       drive->waiting_for_dma = 0;
-
        /* stop DMA */
        if (hwif->host_flags & IDE_HFLAG_MMIO) {
                dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
@@ -310,8 +304,6 @@ int ide_dma_end(ide_drive_t *drive)
        /* clear INTR & ERROR bits */
        ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
 
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
        wmb();
 
        /* verify good DMA status */
@@ -338,9 +330,8 @@ const struct ide_dma_ops sff_dma_ops = {
        .dma_start              = ide_dma_start,
        .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 EXPORT_SYMBOL_GPL(sff_dma_ops);
index 3dbf80c15491573cf7188d8597ea2e4217f9d416..a0b8cab1d9a682249200fce35bc5ea5c8223079f 100644 (file)
@@ -89,15 +89,16 @@ static const struct drive_list_entry drive_blacklist[] = {
 ide_startstop_t ide_dma_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct ide_cmd *cmd = &hwif->cmd;
        u8 stat = 0, dma_stat = 0;
 
+       drive->waiting_for_dma = 0;
        dma_stat = hwif->dma_ops->dma_end(drive);
+       ide_dma_unmap_sg(drive, cmd);
        stat = hwif->tp_ops->read_status(hwif);
 
        if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
                if (!dma_stat) {
-                       struct ide_cmd *cmd = &hwif->cmd;
-
                        if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
                                ide_finish_cmd(drive, cmd, stat);
                        else
@@ -117,8 +118,8 @@ int ide_dma_good_drive(ide_drive_t *drive)
 }
 
 /**
- *     ide_build_sglist        -       map IDE scatter gather for DMA I/O
- *     @drive: the drive to build the DMA table for
+ *     ide_dma_map_sg  -       map IDE scatter gather for DMA I/O
+ *     @drive: the drive to map the DMA table for
  *     @cmd: command
  *
  *     Perform the DMA mapping magic necessary to access the source or
@@ -127,23 +128,19 @@ int ide_dma_good_drive(ide_drive_t *drive)
  *     operate in a portable fashion.
  */
 
-int ide_build_sglist(ide_drive_t *drive, struct ide_cmd *cmd)
+static int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct scatterlist *sg = hwif->sg_table;
        int i;
 
-       ide_map_sg(drive, cmd);
-
        if (cmd->tf_flags & IDE_TFLAG_WRITE)
                cmd->sg_dma_direction = DMA_TO_DEVICE;
        else
                cmd->sg_dma_direction = DMA_FROM_DEVICE;
 
        i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction);
-       if (i == 0)
-               ide_map_sg(drive, cmd);
-       else {
+       if (i) {
                cmd->orig_sg_nents = cmd->sg_nents;
                cmd->sg_nents = i;
        }
@@ -152,7 +149,7 @@ int ide_build_sglist(ide_drive_t *drive, struct ide_cmd *cmd)
 }
 
 /**
- *     ide_destroy_dmatable    -       clean up DMA mapping
+ *     ide_dma_unmap_sg        -       clean up DMA mapping
  *     @drive: The drive to unmap
  *
  *     Teardown mappings after DMA has completed. This must be called
@@ -162,15 +159,14 @@ int ide_build_sglist(ide_drive_t *drive, struct ide_cmd *cmd)
  *     time.
  */
 
-void ide_destroy_dmatable(ide_drive_t *drive)
+void ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct ide_cmd *cmd = &hwif->cmd;
 
        dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents,
                     cmd->sg_dma_direction);
 }
-EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+EXPORT_SYMBOL_GPL(ide_dma_unmap_sg);
 
 /**
  *     ide_dma_off_quietly     -       Generic DMA kill
@@ -249,12 +245,11 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
        case XFER_UDMA_0:
                if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
                        break;
-
+               mask = id[ATA_ID_UDMA_MODES];
                if (port_ops && port_ops->udma_filter)
-                       mask = port_ops->udma_filter(drive);
+                       mask &= port_ops->udma_filter(drive);
                else
-                       mask = hwif->ultra_mask;
-               mask &= id[ATA_ID_UDMA_MODES];
+                       mask &= hwif->ultra_mask;
 
                /*
                 * avoid false cable warning from eighty_ninty_three()
@@ -265,18 +260,23 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
                }
                break;
        case XFER_MW_DMA_0:
-               if ((id[ATA_ID_FIELD_VALID] & 2) == 0)
-                       break;
+               mask = id[ATA_ID_MWDMA_MODES];
+
+               /* Also look for the CF specific MWDMA modes... */
+               if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) {
+                       u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1;
+
+                       mask |= ((2 << mode) - 1) << 3;
+               }
+
                if (port_ops && port_ops->mdma_filter)
-                       mask = port_ops->mdma_filter(drive);
+                       mask &= port_ops->mdma_filter(drive);
                else
-                       mask = hwif->mwdma_mask;
-               mask &= id[ATA_ID_MWDMA_MODES];
+                       mask &= hwif->mwdma_mask;
                break;
        case XFER_SW_DMA_0:
-               if (id[ATA_ID_FIELD_VALID] & 2) {
-                       mask = id[ATA_ID_SWDMA_MODES] & hwif->swdma_mask;
-               } else if (id[ATA_ID_OLD_DMA_MODES] >> 8) {
+               mask = id[ATA_ID_SWDMA_MODES];
+               if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) {
                        u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
 
                        /*
@@ -284,8 +284,9 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
                         * (the maximum allowed mode is XFER_SW_DMA_2)
                         */
                        if (mode <= 2)
-                               mask = ((2 << mode) - 1) & hwif->swdma_mask;
+                               mask = (2 << mode) - 1;
                }
+               mask &= hwif->swdma_mask;
                break;
        default:
                BUG();
@@ -402,11 +403,10 @@ int ide_id_dma_bug(ide_drive_t *drive)
                if ((id[ATA_ID_UDMA_MODES] >> 8) &&
                    (id[ATA_ID_MWDMA_MODES] >> 8))
                        goto err_out;
-       } else if (id[ATA_ID_FIELD_VALID] & 2) {
-               if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
-                   (id[ATA_ID_SWDMA_MODES] >> 8))
-                       goto err_out;
-       }
+       } else if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
+                  (id[ATA_ID_SWDMA_MODES] >> 8))
+               goto err_out;
+
        return 0;
 err_out:
        printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name);
@@ -460,21 +460,6 @@ void ide_dma_lost_irq(ide_drive_t *drive)
 }
 EXPORT_SYMBOL_GPL(ide_dma_lost_irq);
 
-void ide_dma_timeout(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
-
-       if (hwif->dma_ops->dma_test_irq(drive))
-               return;
-
-       ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif));
-
-       hwif->dma_ops->dma_end(drive);
-}
-EXPORT_SYMBOL_GPL(ide_dma_timeout);
-
 /*
  * un-busy the port etc, and clear any pending DMA status. we want to
  * retry the current request in pio mode instead of risking tossing it
@@ -483,6 +468,8 @@ EXPORT_SYMBOL_GPL(ide_dma_timeout);
 ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
 {
        ide_hwif_t *hwif = drive->hwif;
+       const struct ide_dma_ops *dma_ops = hwif->dma_ops;
+       struct ide_cmd *cmd = &hwif->cmd;
        struct request *rq;
        ide_startstop_t ret = ide_stopped;
 
@@ -492,12 +479,23 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
 
        if (error < 0) {
                printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
-               (void)hwif->dma_ops->dma_end(drive);
+               drive->waiting_for_dma = 0;
+               (void)dma_ops->dma_end(drive);
+               ide_dma_unmap_sg(drive, cmd);
                ret = ide_error(drive, "dma timeout error",
                                hwif->tp_ops->read_status(hwif));
        } else {
                printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
-               hwif->dma_ops->dma_timeout(drive);
+               if (dma_ops->dma_clear)
+                       dma_ops->dma_clear(drive);
+               printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+               if (dma_ops->dma_test_irq(drive) == 0) {
+                       ide_dump_status(drive, "DMA timeout",
+                                       hwif->tp_ops->read_status(hwif));
+                       drive->waiting_for_dma = 0;
+                       (void)dma_ops->dma_end(drive);
+                       ide_dma_unmap_sg(drive, cmd);
+               }
        }
 
        /*
@@ -567,3 +565,25 @@ int ide_allocate_dma_engine(ide_hwif_t *hwif)
        return 0;
 }
 EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
+
+int ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd)
+{
+       const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops;
+
+       if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
+           (dma_ops->dma_check && dma_ops->dma_check(drive, cmd)))
+               goto out;
+       ide_map_sg(drive, cmd);
+       if (ide_dma_map_sg(drive, cmd) == 0)
+               goto out_map;
+       if (dma_ops->dma_setup(drive, cmd))
+               goto out_dma_unmap;
+       drive->waiting_for_dma = 1;
+       return 0;
+out_dma_unmap:
+       ide_dma_unmap_sg(drive, cmd);
+out_map:
+       ide_map_sg(drive, cmd);
+out:
+       return 1;
+}
index 11664976eea30cbde1f846cfcdde5147ed17c309..5d5fb961b5ce8ee83e9e6e5cfc216ca3d0314d65 100644 (file)
@@ -165,11 +165,12 @@ static ide_startstop_t do_reset1(ide_drive_t *, int);
 static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        u8 stat;
 
-       SELECT_DRIVE(drive);
+       tp_ops->dev_select(drive);
        udelay(10);
-       stat = hwif->tp_ops->read_status(hwif);
+       stat = tp_ops->read_status(hwif);
 
        if (OK_STAT(stat, 0, ATA_BUSY))
                printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name);
@@ -348,7 +349,7 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
        /* For an ATAPI device, first try an ATAPI SRST. */
        if (drive->media != ide_disk && !do_not_try_atapi) {
                pre_reset(drive);
-               SELECT_DRIVE(drive);
+               tp_ops->dev_select(drive);
                udelay(20);
                tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                ndelay(400);
@@ -401,15 +402,14 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
         * immediate interrupt due to the edge transition it produces.
         * This single interrupt gives us a "fast poll" for drives that
         * recover from reset very quickly, saving us the first 50ms wait time.
-        *
-        * TODO: add ->softreset method and stop abusing ->set_irq
         */
        /* set SRST and nIEN */
-       tp_ops->set_irq(hwif, 4);
+       tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS);
        /* more than enough time */
        udelay(10);
        /* clear SRST, leave nIEN (unless device is on the quirk list) */
-       tp_ops->set_irq(hwif, drive->quirk_list == 2);
+       tp_ops->write_devctl(hwif, (drive->quirk_list == 2 ? 0 : ATA_NIEN) |
+                            ATA_DEVCTL_OBS);
        /* more than enough time */
        udelay(10);
        hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
index 7ae66233483519ac52cc0921f0b2c61229c6153c..2b4868d95f8b0597de827c36df575cec1375d8f7 100644 (file)
  */
 #define IDEFLOPPY_PC_DELAY     (HZ/20) /* default delay for ZIP 100 (50ms) */
 
-static void idefloppy_update_buffers(ide_drive_t *drive,
-                               struct ide_atapi_pc *pc)
-{
-       struct request *rq = pc->rq;
-       struct bio *bio = rq->bio;
-
-       while ((bio = rq->bio) != NULL)
-               ide_complete_rq(drive, 0, ide_rq_bytes(rq));
-}
-
 static int ide_floppy_callback(ide_drive_t *drive, int dsc)
 {
        struct ide_disk_obj *floppy = drive->driver_data;
@@ -213,7 +203,6 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive,
        memcpy(rq->cmd, pc->c, 12);
 
        pc->rq = rq;
-       pc->b_count = 0;
        if (rq->cmd_flags & REQ_RW)
                pc->flags |= PC_FLAG_WRITING;
        pc->buf = NULL;
@@ -227,7 +216,6 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy,
        ide_init_pc(pc);
        memcpy(pc->c, rq->cmd, sizeof(pc->c));
        pc->rq = rq;
-       pc->b_count = 0;
        if (rq->data_len && rq_data_dir(rq) == WRITE)
                pc->flags |= PC_FLAG_WRITING;
        pc->buf = rq->data;
@@ -244,10 +232,11 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                                             struct request *rq, sector_t block)
 {
        struct ide_disk_obj *floppy = drive->driver_data;
-       ide_hwif_t *hwif = drive->hwif;
        struct ide_cmd cmd;
        struct ide_atapi_pc *pc;
 
+       ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]);
+
        if (drive->debug_mask & IDE_DBG_RQ)
                blk_dump_rq_flags(rq, (rq->rq_disk
                                        ? rq->rq_disk->disk_name
@@ -294,13 +283,10 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
        cmd.rq = rq;
 
        if (blk_fs_request(rq) || pc->req_xfer) {
-               ide_init_sg_cmd(&cmd, rq->nr_sectors << 9);
+               ide_init_sg_cmd(&cmd, pc->req_xfer);
                ide_map_sg(drive, &cmd);
        }
 
-       pc->sg = hwif->sg_table;
-       pc->sg_cnt = cmd.sg_nents;
-
        pc->rq = rq;
 
        return ide_floppy_issue_pc(drive, &cmd, pc);
@@ -385,9 +371,11 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
        struct gendisk *disk = floppy->disk;
        struct ide_atapi_pc pc;
        u8 *cap_desc;
-       u8 header_len, desc_cnt;
+       u8 pc_buf[256], header_len, desc_cnt;
        int i, rc = 1, blocks, length;
 
+       ide_debug_log(IDE_DBG_FUNC, "enter");
+
        drive->bios_cyl = 0;
        drive->bios_head = drive->bios_sect = 0;
        floppy->blocks = 0;
@@ -395,6 +383,9 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
        drive->capacity64 = 0;
 
        ide_floppy_create_read_capacity_cmd(&pc);
+       pc.buf = &pc_buf[0];
+       pc.buf_size = sizeof(pc_buf);
+
        if (ide_queue_pc_tail(drive, disk, &pc)) {
                printk(KERN_ERR PFX "Can't get floppy parameters\n");
                return 1;
@@ -485,8 +476,6 @@ static void ide_floppy_setup(ide_drive_t *drive)
        u16 *id = drive->id;
 
        drive->pc_callback       = ide_floppy_callback;
-       drive->pc_update_buffers = idefloppy_update_buffers;
-       drive->pc_io_buffers     = ide_io_buffers;
 
        /*
         * We used to check revisions here. At this point however I'm giving up.
index 8f8be8546038d5950d5e944e26871fc7f0186a49..cd8a42027ede72f10c0acd0a96e7c0fb6ad2e4f6 100644 (file)
@@ -36,9 +36,9 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive,
                                            int __user *arg)
 {
        struct ide_disk_obj *floppy = drive->driver_data;
-       u8 header_len, desc_cnt;
        int i, blocks, length, u_array_size, u_index;
        int __user *argp;
+       u8 pc_buf[256], header_len, desc_cnt;
 
        if (get_user(u_array_size, arg))
                return -EFAULT;
@@ -47,6 +47,9 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive,
                return -EINVAL;
 
        ide_floppy_create_read_capacity_cmd(pc);
+       pc->buf = &pc_buf[0];
+       pc->buf_size = sizeof(pc_buf);
+
        if (ide_queue_pc_tail(drive, floppy->disk, pc)) {
                printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                return -EIO;
index 9d03e82115365686cf5cc8f759b533ea7b29b481..7812ca0be13beb1c5af1ba98ea8b29b4bd2cbf4b 100644 (file)
@@ -1,27 +1,22 @@
 /*
  * generic/default IDE host driver
  *
- * Copyright (C) 2004, 2008 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz
  * This code was split off from ide.c.  See it for original copyrights.
  *
  * May be copied or modified under the terms of the GNU General Public License.
  */
 
-/*
- * For special cases new interfaces may be added using sysfs, i.e.
- *
- *     echo -n "0x168:0x36e:10" > /sys/class/ide_generic/add
- *
- * will add an interface using I/O ports 0x168-0x16f/0x36e and IRQ 10.
- */
-
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/ide.h>
 #include <linux/pci_ids.h>
 
-/* FIXME: convert m32r to use ide_platform host driver */
+/* FIXME: convert arm and m32r to use ide_platform host driver */
+#ifdef CONFIG_ARM
+#include <asm/irq.h>
+#endif
 #ifdef CONFIG_M32R
 #include <asm/m32r.h>
 #endif
@@ -36,62 +31,11 @@ static const struct ide_port_info ide_generic_port_info = {
        .host_flags             = IDE_HFLAG_NO_DMA,
 };
 
-static ssize_t store_add(struct class *cls, const char *buf, size_t n)
-{
-       unsigned int base, ctl;
-       int irq, rc;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
-
-       if (sscanf(buf, "%x:%x:%d", &base, &ctl, &irq) != 3)
-               return -EINVAL;
-
-       memset(&hw, 0, sizeof(hw));
-       ide_std_init_ports(&hw, base, ctl);
-       hw.irq = irq;
-       hw.chipset = ide_generic;
-
-       rc = ide_host_add(&ide_generic_port_info, hws, NULL);
-       if (rc)
-               return rc;
-
-       return n;
-};
-
-static struct class_attribute ide_generic_class_attrs[] = {
-       __ATTR(add, S_IWUSR, NULL, store_add),
-       __ATTR_NULL
-};
-
-static void ide_generic_class_release(struct class *cls)
-{
-       kfree(cls);
-}
-
-static int __init ide_generic_sysfs_init(void)
-{
-       struct class *cls;
-       int rc;
-
-       cls = kzalloc(sizeof(*cls), GFP_KERNEL);
-       if (!cls)
-               return -ENOMEM;
-
-       cls->name = DRV_NAME;
-       cls->owner = THIS_MODULE;
-       cls->class_release = ide_generic_class_release;
-       cls->class_attrs = ide_generic_class_attrs;
-
-       rc = class_register(cls);
-       if (rc) {
-               kfree(cls);
-               return rc;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) \
-       || defined(CONFIG_PLAT_OPSPUT)
+#ifdef CONFIG_ARM
+static const u16 legacy_bases[] = { 0x1f0 };
+static const int legacy_irqs[]  = { IRQ_HARDDISK };
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) || \
+      defined(CONFIG_PLAT_OPSPUT)
 static const u16 legacy_bases[] = { 0x1f0 };
 static const int legacy_irqs[]  = { PLD_IRQ_CFIREQ };
 #elif defined(CONFIG_PLAT_MAPPI3)
@@ -107,11 +51,11 @@ static const int legacy_irqs[]  = { 14, 15, 11, 10, 8, 12 };
 
 static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
 {
+#ifdef CONFIG_PCI
        struct pci_dev *p = NULL;
        u16 val;
 
        for_each_pci_dev(p) {
-
                if (pci_resource_start(p, 0) == 0x1f0)
                        *primary = 1;
                if (pci_resource_start(p, 2) == 0x170)
@@ -126,7 +70,6 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
                /* Intel MPIIX - PIO ATA on non PCI side of bridge */
                if (p->vendor == PCI_VENDOR_ID_INTEL &&
                    p->device == PCI_DEVICE_ID_INTEL_82371MX) {
-
                        pci_read_config_word(p, 0x6C, &val);
                        if (val & 0x8000) {
                                /* ATA port enabled */
@@ -137,6 +80,7 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
                        }
                }
        }
+#endif
 }
 
 static int __init ide_generic_init(void)
@@ -168,6 +112,7 @@ static int __init ide_generic_init(void)
                                printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
                                                "not free.\n",
                                                DRV_NAME, io_addr, io_addr + 7);
+                               rc = -EBUSY;
                                continue;
                        }
 
@@ -176,6 +121,7 @@ static int __init ide_generic_init(void)
                                                "not free.\n",
                                                DRV_NAME, io_addr + 0x206);
                                release_region(io_addr, 8);
+                               rc = -EBUSY;
                                continue;
                        }
 
@@ -196,10 +142,6 @@ static int __init ide_generic_init(void)
                }
        }
 
-       if (ide_generic_sysfs_init())
-               printk(KERN_ERR DRV_NAME ": failed to create ide_generic "
-                                        "class\n");
-
        return rc;
 }
 
index ff8339ed59ab0b2afe072904690de895c67dcc7c..dac9a6d44963ecbfe7b5b82cc4619bb8f7681c76 100644 (file)
@@ -54,9 +54,6 @@ static void h8300_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
        if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA)
-               mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr);
-
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                outb(tf->hob_feature, io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
@@ -90,18 +87,11 @@ static void h8300_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
        struct ide_io_ports *io_ports = &hwif->io_ports;
        struct ide_taskfile *tf = &cmd->tf;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
-               u16 data = mm_inw(io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = inb(io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = inb(io_ports->nsect_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
@@ -114,18 +104,18 @@ static void h8300_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf->device = inb(io_ports->device_addr);
 
        if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+               outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = inb(io_ports->feature_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = inb(io_ports->nsect_addr);
+                       tf->hob_nsect = inb(io_ports->nsect_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = inb(io_ports->lbal_addr);
+                       tf->hob_lbal  = inb(io_ports->lbal_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = inb(io_ports->lbam_addr);
+                       tf->hob_lbam  = inb(io_ports->lbam_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = inb(io_ports->lbah_addr);
+                       tf->hob_lbah  = inb(io_ports->lbah_addr);
        }
 }
 
@@ -159,9 +149,9 @@ static const struct ide_tp_ops h8300_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = h8300_tf_load,
        .tf_read                = h8300_tf_read,
 
index 2d9c6dc3f956faefe93df9742359590498265a84..9cac281d82c485857a6f62d9d346c0d51de6de1e 100644 (file)
@@ -64,23 +64,26 @@ u8 ide_read_altstatus(ide_hwif_t *hwif)
 }
 EXPORT_SYMBOL_GPL(ide_read_altstatus);
 
-void ide_set_irq(ide_hwif_t *hwif, int on)
+void ide_write_devctl(ide_hwif_t *hwif, u8 ctl)
 {
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
        if (hwif->host_flags & IDE_HFLAG_MMIO)
                writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
        else
                outb(ctl, hwif->io_ports.ctl_addr);
 }
-EXPORT_SYMBOL_GPL(ide_set_irq);
+EXPORT_SYMBOL_GPL(ide_write_devctl);
+
+void ide_dev_select(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 select = drive->select | ATA_DEVICE_OBS;
+
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               writeb(select, (void __iomem *)hwif->io_ports.device_addr);
+       else
+               outb(select, hwif->io_ports.device_addr);
+}
+EXPORT_SYMBOL_GPL(ide_dev_select);
 
 void ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
 {
@@ -99,15 +102,6 @@ void ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
        if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               if (mmio)
-                       writew(data, (void __iomem *)io_ports->data_addr);
-               else
-                       outw(data, io_ports->data_addr);
-       }
-
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                tf_outb(tf->hob_feature, io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
@@ -153,23 +147,11 @@ void ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf_inb  = ide_inb;
        }
 
-       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
-               u16 data;
-
-               if (mmio)
-                       data = readw((void __iomem *)io_ports->data_addr);
-               else
-                       data = inw(io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       tf_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       tf_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = tf_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = tf_inb(io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = tf_inb(io_ports->nsect_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
@@ -182,18 +164,18 @@ void ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf->device = tf_inb(io_ports->device_addr);
 
        if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               tf_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+               tf_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = tf_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = tf_inb(io_ports->feature_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = tf_inb(io_ports->nsect_addr);
+                       tf->hob_nsect = tf_inb(io_ports->nsect_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = tf_inb(io_ports->lbal_addr);
+                       tf->hob_lbal  = tf_inb(io_ports->lbal_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = tf_inb(io_ports->lbam_addr);
+                       tf->hob_lbam  = tf_inb(io_ports->lbam_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = tf_inb(io_ports->lbah_addr);
+                       tf->hob_lbah  = tf_inb(io_ports->lbah_addr);
        }
 }
 EXPORT_SYMBOL_GPL(ide_tf_read);
@@ -225,11 +207,10 @@ void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
        unsigned long data_addr = io_ports->data_addr;
+       unsigned int words = (len + 1) >> 1;
        u8 io_32bit = drive->io_32bit;
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
 
-       len++;
-
        if (io_32bit) {
                unsigned long uninitialized_var(flags);
 
@@ -238,27 +219,26 @@ void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
                        ata_vlb_sync(io_ports->nsect_addr);
                }
 
+               words >>= 1;
                if (mmio)
-                       __ide_mm_insl((void __iomem *)data_addr, buf, len / 4);
+                       __ide_mm_insl((void __iomem *)data_addr, buf, words);
                else
-                       insl(data_addr, buf, len / 4);
+                       insl(data_addr, buf, words);
 
                if ((io_32bit & 2) && !mmio)
                        local_irq_restore(flags);
 
-               if ((len & 3) >= 2) {
-                       if (mmio)
-                               __ide_mm_insw((void __iomem *)data_addr,
-                                               (u8 *)buf + (len & ~3), 1);
-                       else
-                               insw(data_addr, (u8 *)buf + (len & ~3), 1);
-               }
-       } else {
-               if (mmio)
-                       __ide_mm_insw((void __iomem *)data_addr, buf, len / 2);
-               else
-                       insw(data_addr, buf, len / 2);
+               if (((len + 1) & 3) < 2)
+                       return;
+
+               buf += len & ~3;
+               words = 1;
        }
+
+       if (mmio)
+               __ide_mm_insw((void __iomem *)data_addr, buf, words);
+       else
+               insw(data_addr, buf, words);
 }
 EXPORT_SYMBOL_GPL(ide_input_data);
 
@@ -271,11 +251,10 @@ void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
        unsigned long data_addr = io_ports->data_addr;
+       unsigned int words = (len + 1) >> 1;
        u8 io_32bit = drive->io_32bit;
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
 
-       len++;
-
        if (io_32bit) {
                unsigned long uninitialized_var(flags);
 
@@ -284,27 +263,26 @@ void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
                        ata_vlb_sync(io_ports->nsect_addr);
                }
 
+               words >>= 1;
                if (mmio)
-                       __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4);
+                       __ide_mm_outsl((void __iomem *)data_addr, buf, words);
                else
-                       outsl(data_addr, buf, len / 4);
+                       outsl(data_addr, buf, words);
 
                if ((io_32bit & 2) && !mmio)
                        local_irq_restore(flags);
 
-               if ((len & 3) >= 2) {
-                       if (mmio)
-                               __ide_mm_outsw((void __iomem *)data_addr,
-                                                (u8 *)buf + (len & ~3), 1);
-                       else
-                               outsw(data_addr, (u8 *)buf + (len & ~3), 1);
-               }
-       } else {
-               if (mmio)
-                       __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2);
-               else
-                       outsw(data_addr, buf, len / 2);
+               if (((len + 1) & 3) < 2)
+                       return;
+
+               buf += len & ~3;
+               words = 1;
        }
+
+       if (mmio)
+               __ide_mm_outsw((void __iomem *)data_addr, buf, words);
+       else
+               outsw(data_addr, buf, words);
 }
 EXPORT_SYMBOL_GPL(ide_output_data);
 
@@ -312,9 +290,9 @@ const struct ide_tp_ops default_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
index 1adc5e2e7fb3e859e91b7008cc5b9f215e53f020..1deb6d29b1869f27fcce14cb2501dfded416c46f 100644 (file)
@@ -73,6 +73,7 @@ EXPORT_SYMBOL_GPL(ide_end_rq);
 
 void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
 {
+       const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops;
        struct ide_taskfile *tf = &cmd->tf;
        struct request *rq = cmd->rq;
        u8 tf_cmd = tf->command;
@@ -80,7 +81,16 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
        tf->error = err;
        tf->status = stat;
 
-       drive->hwif->tp_ops->tf_read(drive, cmd);
+       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
+               u8 data[2];
+
+               tp_ops->input_data(drive, cmd, data, 2);
+
+               tf->data = data[0];
+               tf->hob_data = data[1];
+       }
+
+       tp_ops->tf_read(drive, cmd);
 
        if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) &&
            tf_cmd == ATA_CMD_IDLEIMMEDIATE) {
@@ -338,7 +348,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
        if (blk_pm_request(rq))
                ide_check_pm_state(drive, rq);
 
-       SELECT_DRIVE(drive);
+       drive->hwif->tp_ops->dev_select(drive);
        if (ide_wait_stat(&startstop, drive, drive->ready_stat,
                          ATA_BUSY | ATA_DRQ, WAIT_READY)) {
                printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
@@ -481,11 +491,10 @@ repeat:
                prev_port = hwif->host->cur_port;
                hwif->rq = NULL;
 
-               if (drive->dev_flags & IDE_DFLAG_SLEEPING) {
-                       if (time_before(drive->sleep, jiffies)) {
-                               ide_unlock_port(hwif);
-                               goto plug_device;
-                       }
+               if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
+                   time_after(drive->sleep, jiffies)) {
+                       ide_unlock_port(hwif);
+                       goto plug_device;
                }
 
                if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) &&
@@ -495,7 +504,9 @@ repeat:
                         * quirk_list may not like intr setups/cleanups
                         */
                        if (prev_port && prev_port->cur_dev->quirk_list == 0)
-                               prev_port->tp_ops->set_irq(prev_port, 0);
+                               prev_port->tp_ops->write_devctl(prev_port,
+                                                               ATA_NIEN |
+                                                               ATA_DEVCTL_OBS);
 
                        hwif->host->cur_port = hwif;
                }
index 5403e4a44be48eb777e684189148de4da686cb4d..27bb70ddd45929572086b1028d3d6bdb3b56d518 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-void SELECT_DRIVE(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       struct ide_cmd cmd;
-
-       if (port_ops && port_ops->selectproc)
-               port_ops->selectproc(drive);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.tf_flags = IDE_TFLAG_OUT_DEVICE;
-
-       drive->hwif->tp_ops->tf_load(drive, &cmd);
-}
-
 void SELECT_MASK(ide_drive_t *drive, int mask)
 {
        const struct ide_port_ops *port_ops = drive->hwif->port_ops;
@@ -55,7 +40,7 @@ u8 ide_read_error(ide_drive_t *drive)
        struct ide_cmd cmd;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.tf_flags = IDE_TFLAG_IN_FEATURE;
+       cmd.tf_flags = IDE_TFLAG_IN_ERROR;
 
        drive->hwif->tp_ops->tf_read(drive, &cmd);
 
@@ -306,6 +291,7 @@ int ide_driveid_update(ide_drive_t *drive)
        drive->id[ATA_ID_UDMA_MODES]  = id[ATA_ID_UDMA_MODES];
        drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
        drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES];
+       drive->id[ATA_ID_CFA_MODES]   = id[ATA_ID_CFA_MODES];
        /* anything more ? */
 
        kfree(id);
@@ -356,10 +342,10 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
        disable_irq_nosync(hwif->irq);
 
        udelay(1);
-       SELECT_DRIVE(drive);
+       tp_ops->dev_select(drive);
        SELECT_MASK(drive, 1);
        udelay(1);
-       tp_ops->set_irq(hwif, 0);
+       tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT;
@@ -371,7 +357,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
        tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
 
        if (drive->quirk_list == 2)
-               tp_ops->set_irq(hwif, 1);
+               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
 
        error = __ide_wait_stat(drive, drive->ready_stat,
                                ATA_BUSY | ATA_DRQ | ATA_ERR,
@@ -386,9 +372,14 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
                return error;
        }
 
-       id[ATA_ID_UDMA_MODES]  &= ~0xFF00;
-       id[ATA_ID_MWDMA_MODES] &= ~0x0F00;
-       id[ATA_ID_SWDMA_MODES] &= ~0x0F00;
+       if (speed >= XFER_SW_DMA_0) {
+               id[ATA_ID_UDMA_MODES]  &= ~0xFF00;
+               id[ATA_ID_MWDMA_MODES] &= ~0x0700;
+               id[ATA_ID_SWDMA_MODES] &= ~0x0700;
+               if (ata_id_is_cfa(id))
+                       id[ATA_ID_CFA_MODES] &= ~0x0E00;
+       } else  if (ata_id_is_cfa(id))
+               id[ATA_ID_CFA_MODES] &= ~0x01C0;
 
  skip:
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -401,12 +392,18 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
        if (speed >= XFER_UDMA_0) {
                i = 1 << (speed - XFER_UDMA_0);
                id[ATA_ID_UDMA_MODES] |= (i << 8 | i);
+       } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) {
+               i = speed - XFER_MW_DMA_2;
+               id[ATA_ID_CFA_MODES] |= i << 9;
        } else if (speed >= XFER_MW_DMA_0) {
                i = 1 << (speed - XFER_MW_DMA_0);
                id[ATA_ID_MWDMA_MODES] |= (i << 8 | i);
        } else if (speed >= XFER_SW_DMA_0) {
                i = 1 << (speed - XFER_SW_DMA_0);
                id[ATA_ID_SWDMA_MODES] |= (i << 8 | i);
+       } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) {
+               i = speed - XFER_PIO_4;
+               id[ATA_ID_CFA_MODES] |= i << 6;
        }
 
        if (!drive->init_speed)
index ebf2d21ebdcbdd3ccb7fdad35e1ffdafee1ac89f..bb7858ebb7d19b5499e96d6f13330adb86617009 100644 (file)
@@ -223,6 +223,7 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
                 * point.
                 */
                ide_hwif_t *hwif = drive->hwif;
+               const struct ide_tp_ops *tp_ops = hwif->tp_ops;
                struct request_queue *q = drive->queue;
                unsigned long flags;
                int rc;
@@ -232,8 +233,8 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
                rc = ide_wait_not_busy(hwif, 35000);
                if (rc)
                        printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
-               SELECT_DRIVE(drive);
-               hwif->tp_ops->set_irq(hwif, 1);
+               tp_ops->dev_select(drive);
+               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
                rc = ide_wait_not_busy(hwif, 100000);
                if (rc)
                        printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
index 548864510ba9a88cf4af72042e317fe899f9f5ab..d8c1c3e735bb12ea218527c849d5e6b3d4712cae 100644 (file)
@@ -260,7 +260,7 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
         * during the identify phase that the IRQ handler isn't expecting.
         */
        if (io_ports->ctl_addr)
-               tp_ops->set_irq(hwif, 0);
+               tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
 
        /* take a deep breath */
        msleep(50);
@@ -390,13 +390,13 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
         * (e.g. crw9624 as drive0 with disk as slave)
         */
        msleep(50);
-       SELECT_DRIVE(drive);
+       tp_ops->dev_select(drive);
        msleep(50);
 
        if (ide_read_device(drive) != drive->select && present == 0) {
                if (drive->dn & 1) {
                        /* exit with drive0 selected */
-                       SELECT_DRIVE(hwif->devices[0]);
+                       tp_ops->dev_select(hwif->devices[0]);
                        /* allow ATA_BUSY to assert & clear */
                        msleep(50);
                }
@@ -422,7 +422,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        printk(KERN_ERR "%s: no response (status = 0x%02x), "
                                        "resetting drive\n", drive->name, stat);
                        msleep(50);
-                       SELECT_DRIVE(drive);
+                       tp_ops->dev_select(drive);
                        msleep(50);
                        tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                        (void)ide_busy_sleep(hwif, WAIT_WORSTCASE, 0);
@@ -441,7 +441,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
        }
        if (drive->dn & 1) {
                /* exit with drive0 selected */
-               SELECT_DRIVE(hwif->devices[0]);
+               tp_ops->dev_select(hwif->devices[0]);
                msleep(50);
                /* ensure drive irq is clear */
                (void)tp_ops->read_status(hwif);
@@ -605,6 +605,7 @@ out:
 
 static int ide_port_wait_ready(ide_hwif_t *hwif)
 {
+       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        ide_drive_t *drive;
        int i, rc;
 
@@ -627,8 +628,8 @@ static int ide_port_wait_ready(ide_hwif_t *hwif)
                /* Ignore disks that we will not probe for later. */
                if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 ||
                    (drive->dev_flags & IDE_DFLAG_PRESENT)) {
-                       SELECT_DRIVE(drive);
-                       hwif->tp_ops->set_irq(hwif, 1);
+                       tp_ops->dev_select(drive);
+                       tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
                        mdelay(2);
                        rc = ide_wait_not_busy(hwif, 35000);
                        if (rc)
@@ -640,7 +641,7 @@ static int ide_port_wait_ready(ide_hwif_t *hwif)
 out:
        /* Exit function with master reselected (let's be sane) */
        if (i)
-               SELECT_DRIVE(hwif->devices[0]);
+               tp_ops->dev_select(hwif->devices[0]);
 
        return rc;
 }
@@ -845,7 +846,7 @@ static int init_irq (ide_hwif_t *hwif)
                irq_handler = ide_intr;
 
        if (io_ports->ctl_addr)
-               hwif->tp_ops->set_irq(hwif, 1);
+               hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
 
        if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
                goto out_up;
@@ -942,20 +943,16 @@ EXPORT_SYMBOL_GPL(ide_init_disk);
 static void drive_release_dev (struct device *dev)
 {
        ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
-       ide_hwif_t *hwif = drive->hwif;
 
        ide_proc_unregister_device(drive);
 
-       spin_lock_irq(&hwif->lock);
+       blk_cleanup_queue(drive->queue);
+       drive->queue = NULL;
+
        kfree(drive->id);
        drive->id = NULL;
+
        drive->dev_flags &= ~IDE_DFLAG_PRESENT;
-       /* Messed up locking ... */
-       spin_unlock_irq(&hwif->lock);
-       blk_cleanup_queue(drive->queue);
-       spin_lock_irq(&hwif->lock);
-       drive->queue = NULL;
-       spin_unlock_irq(&hwif->lock);
 
        complete(&drive->gendev_rel_comp);
 }
index 64dfa7458f8dad568ad75cd4c9fc9074cd41e747..cb942a9b580f6ee66bd9f6d50998a664719625c8 100644 (file)
@@ -297,19 +297,15 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
        return tape;
 }
 
-static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                  unsigned int bcount)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
 
        while (bcount) {
-               if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in "
-                               "idetape_input_buffers\n");
-                       ide_pad_transfer(drive, 0, bcount);
-                       return;
-               }
+               if (bh == NULL)
+                       break;
                count = min(
                        (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
                        bcount);
@@ -323,21 +319,21 @@ static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                atomic_set(&bh->b_count, 0);
                }
        }
+
        pc->bh = bh;
+
+       return bcount;
 }
 
-static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                   unsigned int bcount)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
 
        while (bcount) {
-               if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
-                                       __func__);
-                       return;
-               }
+               if (bh == NULL)
+                       break;
                count = min((unsigned int)pc->b_count, (unsigned int)bcount);
                drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count);
                bcount -= count;
@@ -352,6 +348,8 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                        }
                }
        }
+
+       return bcount;
 }
 
 static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
@@ -563,12 +561,14 @@ static void ide_tape_handle_dsc(ide_drive_t *drive)
 static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                unsigned int bcount, int write)
 {
+       unsigned int bleft;
+
        if (write)
-               idetape_output_buffers(drive, pc, bcount);
+               bleft = idetape_output_buffers(drive, pc, bcount);
        else
-               idetape_input_buffers(drive, pc, bcount);
+               bleft = idetape_input_buffers(drive, pc, bcount);
 
-       return bcount;
+       return bcount - bleft;
 }
 
 /*
@@ -2014,9 +2014,13 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc pc;
+       u8 pc_buf[256];
        char fw_rev[4], vendor_id[8], product_id[16];
 
        idetape_create_inquiry_cmd(&pc);
+       pc.buf = &pc_buf[0];
+       pc.buf_size = sizeof(pc_buf);
+
        if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
                printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
                                tape->name);
index 84532be97c006081aa5f1fea3ca85562e8b6f1f6..243421ce40d02ccee63b211f202017782e4d8262 100644 (file)
@@ -80,8 +80,14 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
 
        if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
                ide_tf_dump(drive->name, tf);
-               tp_ops->set_irq(hwif, 1);
+               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
                SELECT_MASK(drive, 0);
+
+               if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
+                       u8 data[2] = { tf->data, tf->hob_data };
+
+                       tp_ops->output_data(drive, cmd, data, 2);
+               }
                tp_ops->tf_load(drive, cmd);
        }
 
@@ -100,9 +106,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
                ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE);
                return ide_started;
        case ATA_PROT_DMA:
-               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
-                   ide_build_sglist(drive, cmd) == 0 ||
-                   dma_ops->dma_setup(drive, cmd))
+               if (ide_dma_prepare(drive, cmd))
                        return ide_stopped;
                hwif->expiry = dma_ops->dma_timer_expiry;
                ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
@@ -188,70 +192,68 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
        return stat;
 }
 
-static void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
-                         unsigned int write, unsigned int nr_bytes)
+void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
+                  unsigned int write, unsigned int len)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct scatterlist *sg = hwif->sg_table;
        struct scatterlist *cursg = cmd->cursg;
        struct page *page;
-#ifdef CONFIG_HIGHMEM
        unsigned long flags;
-#endif
        unsigned int offset;
        u8 *buf;
 
        cursg = cmd->cursg;
-       if (!cursg) {
-               cursg = sg;
-               cmd->cursg = sg;
-       }
+       if (cursg == NULL)
+               cursg = cmd->cursg = sg;
 
-       page = sg_page(cursg);
-       offset = cursg->offset + cmd->cursg_ofs;
+       while (len) {
+               unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
 
-       /* get the current page and offset */
-       page = nth_page(page, (offset >> PAGE_SHIFT));
-       offset %= PAGE_SIZE;
+               if (nr_bytes > PAGE_SIZE)
+                       nr_bytes = PAGE_SIZE;
 
-#ifdef CONFIG_HIGHMEM
-       local_irq_save(flags);
-#endif
-       buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
+               page = sg_page(cursg);
+               offset = cursg->offset + cmd->cursg_ofs;
 
-       cmd->nleft -= nr_bytes;
-       cmd->cursg_ofs += nr_bytes;
+               /* get the current page and offset */
+               page = nth_page(page, (offset >> PAGE_SHIFT));
+               offset %= PAGE_SIZE;
 
-       if (cmd->cursg_ofs == cursg->length) {
-               cmd->cursg = sg_next(cmd->cursg);
-               cmd->cursg_ofs = 0;
-       }
+               if (PageHighMem(page))
+                       local_irq_save(flags);
 
-       /* do the actual data transfer */
-       if (write)
-               hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
-       else
-               hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
+               buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
 
-       kunmap_atomic(buf, KM_BIO_SRC_IRQ);
-#ifdef CONFIG_HIGHMEM
-       local_irq_restore(flags);
-#endif
-}
+               cmd->nleft -= nr_bytes;
+               cmd->cursg_ofs += nr_bytes;
 
-static void ide_pio_multi(ide_drive_t *drive, struct ide_cmd *cmd,
-                         unsigned int write)
-{
-       unsigned int nsect;
+               if (cmd->cursg_ofs == cursg->length) {
+                       cursg = cmd->cursg = sg_next(cmd->cursg);
+                       cmd->cursg_ofs = 0;
+               }
+
+               /* do the actual data transfer */
+               if (write)
+                       hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
+               else
+                       hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
+
+               kunmap_atomic(buf, KM_BIO_SRC_IRQ);
 
-       nsect = min_t(unsigned int, cmd->nleft >> 9, drive->mult_count);
-       while (nsect--)
-               ide_pio_bytes(drive, cmd, write, SECTOR_SIZE);
+               if (PageHighMem(page))
+                       local_irq_restore(flags);
+
+               len -= nr_bytes;
+       }
 }
+EXPORT_SYMBOL_GPL(ide_pio_bytes);
 
 static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
                              unsigned int write)
 {
+       unsigned int nr_bytes;
+
        u8 saved_io_32bit = drive->io_32bit;
 
        if (cmd->tf_flags & IDE_TFLAG_FS)
@@ -263,9 +265,11 @@ static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
        touch_softlockup_watchdog();
 
        if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
-               ide_pio_multi(drive, cmd, write);
+               nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9);
        else
-               ide_pio_bytes(drive, cmd, write, SECTOR_SIZE);
+               nr_bytes = SECTOR_SIZE;
+
+       ide_pio_bytes(drive, cmd, write, nr_bytes);
 
        drive->io_32bit = saved_io_32bit;
 }
index 81f527af8fae75f097d4ba29d80d9d7929a15b74..001a56365be577691ad8227c244d5ee88f01965d 100644 (file)
@@ -43,6 +43,8 @@ static struct ide_timing ide_timing[] = {
        { XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
        { XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
 
+       { XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20,  80,   0 },
+       { XFER_MW_DMA_3,  25,   0,   0,   0,  65,  25, 100,   0 },
        { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
        { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
        { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
@@ -51,7 +53,8 @@ static struct ide_timing ide_timing[] = {
        { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
        { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
 
-       { XFER_PIO_5,     20,  50,  30, 100,  50,  30, 100,   0 },
+       { XFER_PIO_6,     10,  55,  20,  80,  55,  20,  80,   0 },
+       { XFER_PIO_5,     15,  65,  25, 100,  65,  25, 100,   0 },
        { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
        { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
 
@@ -90,6 +93,10 @@ u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
                /* conservative "downgrade" for all pre-ATA2 drives */
                if (pio < 3 && cycle < t->cycle)
                        cycle = 0; /* use standard timing */
+
+               /* Use the standard timing for the CF specific modes too */
+               if (pio > 4 && ata_id_is_cfa(id))
+                       cycle = 0;
        }
 
        return cycle ? cycle : t->cycle;
@@ -161,7 +168,8 @@ int ide_timing_compute(ide_drive_t *drive, u8 speed,
 
                if (speed <= XFER_PIO_2)
                        p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
-               else if (speed <= XFER_PIO_5)
+               else if ((speed <= XFER_PIO_4) ||
+                        (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
                        p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
                else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
                        p.cycle = id[ATA_ID_EIDE_DMA_MIN];
index 6910f6a257e86861168996d826e635dca0b009d7..af44be9d546cedf4283cf78458f3eaf2dbaa4136 100644 (file)
@@ -9,11 +9,11 @@ static const char *udma_str[] =
         { "UDMA/16", "UDMA/25",  "UDMA/33",  "UDMA/44",
           "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
 static const char *mwdma_str[] =
-       { "MWDMA0", "MWDMA1", "MWDMA2" };
+       { "MWDMA0", "MWDMA1", "MWDMA2", "MWDMA3", "MWDMA4" };
 static const char *swdma_str[] =
        { "SWDMA0", "SWDMA1", "SWDMA2" };
 static const char *pio_str[] =
-       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" };
+       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5", "PIO6" };
 
 /**
  *     ide_xfer_verbose        -       return IDE mode names
@@ -30,11 +30,11 @@ const char *ide_xfer_verbose(u8 mode)
 
        if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
                s = udma_str[i];
-       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2)
+       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_4)
                s = mwdma_str[i];
        else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
                s = swdma_str[i];
-       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5)
+       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_6)
                s = pio_str[i & 0x7];
        else if (mode == XFER_PIO_SLOW)
                s = "PIO SLOW";
@@ -79,7 +79,10 @@ u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
                }
 
                if (id[ATA_ID_FIELD_VALID] & 2) {             /* ATA2? */
-                       if (ata_id_has_iordy(id)) {
+                       if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 7))
+                               pio_mode = 4 + min_t(int, 2,
+                                                    id[ATA_ID_CFA_MODES] & 7);
+                       else if (ata_id_has_iordy(id)) {
                                if (id[ATA_ID_PIO_MODES] & 7) {
                                        overridden = 0;
                                        if (id[ATA_ID_PIO_MODES] & 4)
@@ -239,7 +242,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 
        BUG_ON(rate < XFER_PIO_0);
 
-       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_6)
                return ide_set_pio_mode(drive, rate);
 
        return ide_set_dma_mode(drive, rate);
diff --git a/drivers/ide/ide_arm.c b/drivers/ide/ide_arm.c
deleted file mode 100644 (file)
index cf63854..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * ARM default IDE host driver
- *
- * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
- * Based on code by: Russell King, Ian Molton and Alexander Schulz.
- *
- * May be copied or modified under the terms of the GNU General Public License.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/irq.h>
-
-#define DRV_NAME "ide_arm"
-
-#define IDE_ARM_IO     0x1f0
-#define IDE_ARM_IRQ    IRQ_HARDDISK
-
-static const struct ide_port_info ide_arm_port_info = {
-       .host_flags             = IDE_HFLAG_NO_DMA,
-};
-
-static int __init ide_arm_init(void)
-{
-       unsigned long base = IDE_ARM_IO, ctl = IDE_ARM_IO + 0x206;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
-
-       if (!request_region(base, 8, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                               DRV_NAME, base, base + 7);
-               return -EBUSY;
-       }
-
-       if (!request_region(ctl, 1, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                               DRV_NAME, ctl);
-               release_region(base, 8);
-               return -EBUSY;
-       }
-
-       memset(&hw, 0, sizeof(hw));
-       ide_std_init_ports(&hw, base, ctl);
-       hw.irq = IDE_ARM_IRQ;
-       hw.chipset = ide_generic;
-
-       return ide_host_add(&ide_arm_port_info, hws, NULL);
-}
-
-module_init(ide_arm_init);
-
-MODULE_LICENSE("GPL");
index 0d4ac65cf9494fe1a8bb0e0a231ef0229c8fb599..51aa745246dcb9551af49161014f533bd4d4e43c 100644 (file)
@@ -511,9 +511,8 @@ static struct ide_dma_ops it821x_pass_through_dma_ops = {
        .dma_start              = it821x_dma_start,
        .dma_end                = it821x_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
+       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 7b65fe5bf4490c8edd3839859c66e07397bc6cb1..71a39fb3856fee4a742646e76ffd6a5cc84b18b8 100644 (file)
@@ -66,18 +66,11 @@ static void superio_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
        struct ide_io_ports *io_ports = &drive->hwif->io_ports;
        struct ide_taskfile *tf = &cmd->tf;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
-               u16 data = inw(io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = inb(io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = inb(io_ports->nsect_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
@@ -90,28 +83,30 @@ static void superio_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf->device = superio_ide_inb(io_ports->device_addr);
 
        if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+               outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = inb(io_ports->feature_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = inb(io_ports->nsect_addr);
+                       tf->hob_nsect = inb(io_ports->nsect_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = inb(io_ports->lbal_addr);
+                       tf->hob_lbal  = inb(io_ports->lbal_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = inb(io_ports->lbam_addr);
+                       tf->hob_lbam  = inb(io_ports->lbam_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = inb(io_ports->lbah_addr);
+                       tf->hob_lbah  = inb(io_ports->lbah_addr);
        }
 }
 
+static void ns87415_dev_select(ide_drive_t *drive);
+
 static const struct ide_tp_ops superio_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = superio_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ns87415_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = superio_tf_read,
 
@@ -190,10 +185,18 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
        local_irq_restore(flags);
 }
 
-static void ns87415_selectproc (ide_drive_t *drive)
+static void ns87415_dev_select(ide_drive_t *drive)
 {
        ns87415_prepare_drive(drive,
                              !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
+
+       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
+}
+
+static void ns87415_dma_start(ide_drive_t *drive)
+{
+       ns87415_prepare_drive(drive, 1);
+       ide_dma_start(drive);
 }
 
 static int ns87415_dma_end(ide_drive_t *drive)
@@ -201,7 +204,6 @@ static int ns87415_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = 0, dma_cmd = 0;
 
-       drive->waiting_for_dma = 0;
        dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
        /* get DMA command mode */
        dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
@@ -210,21 +212,11 @@ static int ns87415_dma_end(ide_drive_t *drive)
        /* from ERRATA: clear the INTR & ERROR bits */
        dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
        outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD);
-       /* and free any DMA resources */
-       ide_destroy_dmatable(drive);
-       /* verify good DMA status */
-       return (dma_stat & 7) != 4;
-}
 
-static int ns87415_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       /* select DMA xfer */
-       ns87415_prepare_drive(drive, 1);
-       if (ide_dma_setup(drive, cmd) == 0)
-               return 0;
-       /* DMA failed: select PIO xfer */
        ns87415_prepare_drive(drive, 0);
-       return 1;
+
+       /* verify good DMA status */
+       return (dma_stat & 7) != 4;
 }
 
 static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
@@ -242,7 +234,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
         * Also, leave IRQ masked during drive probing, to prevent infinite
         * interrupts from a potentially floating INTA..
         *
-        * IRQs get unmasked in selectproc when drive is first used.
+        * IRQs get unmasked in dev_select() when drive is first used.
         */
        (void) pci_read_config_dword(dev, 0x40, &ctrl);
        (void) pci_read_config_byte(dev, 0x09, &progif);
@@ -270,7 +262,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
 #ifdef __sparc_v9__
                /*
                 * XXX: Reset the device, if we don't it will not respond to
-                *      SELECT_DRIVE() properly during first ide_probe_port().
+                *      dev_select() properly during first ide_probe_port().
                 */
                timeout = 10000;
                outb(12, hwif->io_ports.ctl_addr);
@@ -294,26 +286,35 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
        outb(0x60, hwif->dma_base + ATA_DMA_STATUS);
 }
 
-static const struct ide_port_ops ns87415_port_ops = {
-       .selectproc             = ns87415_selectproc,
+static const struct ide_tp_ops ns87415_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = ns87415_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
 };
 
 static const struct ide_dma_ops ns87415_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ns87415_dma_setup,
-       .dma_start              = ide_dma_start,
+       .dma_setup              = ide_dma_setup,
+       .dma_start              = ns87415_dma_start,
        .dma_end                = ns87415_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = superio_dma_sff_read_status,
 };
 
 static const struct ide_port_info ns87415_chipset __devinitdata = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_ns87415,
-       .port_ops       = &ns87415_port_ops,
+       .tp_ops         = &ns87415_tp_ops,
        .dma_ops        = &ns87415_dma_ops,
        .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
                          IDE_HFLAG_NO_ATAPI_DMA,
index f7536d1943f7ddd2001f73fd8f0dafe431290899..248a54bd2386f346e155c19a74f1c635215170a3 100644 (file)
@@ -258,12 +258,6 @@ static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
        ide_dma_lost_irq(drive);
 }
 
-static void pdc202xx_dma_timeout(ide_drive_t *drive)
-{
-       pdc202xx_reset(drive);
-       ide_dma_timeout(drive);
-}
-
 static int init_chipset_pdc202xx(struct pci_dev *dev)
 {
        unsigned long dmabase = pci_resource_start(dev, 4);
@@ -336,7 +330,7 @@ static const struct ide_dma_ops pdc20246_dma_ops = {
        .dma_test_irq           = pdc202xx_dma_test_irq,
        .dma_lost_irq           = pdc202xx_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = pdc202xx_dma_timeout,
+       .dma_clear              = pdc202xx_reset,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
@@ -348,7 +342,7 @@ static const struct ide_dma_ops pdc2026x_dma_ops = {
        .dma_test_irq           = pdc202xx_dma_test_irq,
        .dma_lost_irq           = pdc202xx_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = pdc202xx_dma_timeout,
+       .dma_clear              = pdc202xx_reset,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 2bfcfedaa0762399278b36aee7d27fa5eaebc7b1..052b9bf1f8fb69bd14a2c0491a2dd5e920cca540 100644 (file)
@@ -404,8 +404,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
 #define IDE_WAKEUP_DELAY       (1*HZ)
 
 static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *);
-static void pmac_ide_selectproc(ide_drive_t *drive);
-static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
 
 #define PMAC_IDE_REG(x) \
        ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x)))
@@ -415,8 +413,7 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
  * timing register when selecting that unit. This version is for
  * ASICs with a single timing register
  */
-static void
-pmac_ide_selectproc(ide_drive_t *drive)
+static void pmac_ide_apply_timings(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
@@ -434,8 +431,7 @@ pmac_ide_selectproc(ide_drive_t *drive)
  * timing register when selecting that unit. This version is for
  * ASICs with a dual timing register (Kauai)
  */
-static void
-pmac_ide_kauai_selectproc(ide_drive_t *drive)
+static void pmac_ide_kauai_apply_timings(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
@@ -464,9 +460,25 @@ pmac_ide_do_update_timings(ide_drive_t *drive)
        if (pmif->kind == controller_sh_ata6 ||
            pmif->kind == controller_un_ata6 ||
            pmif->kind == controller_k2_ata6)
-               pmac_ide_kauai_selectproc(drive);
+               pmac_ide_kauai_apply_timings(drive);
        else
-               pmac_ide_selectproc(drive);
+               pmac_ide_apply_timings(drive);
+}
+
+static void pmac_dev_select(ide_drive_t *drive)
+{
+       pmac_ide_apply_timings(drive);
+
+       writeb(drive->select | ATA_DEVICE_OBS,
+              (void __iomem *)drive->hwif->io_ports.device_addr);
+}
+
+static void pmac_kauai_dev_select(ide_drive_t *drive)
+{
+       pmac_ide_kauai_apply_timings(drive);
+
+       writeb(drive->select | ATA_DEVICE_OBS,
+              (void __iomem *)drive->hwif->io_ports.device_addr);
 }
 
 static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
@@ -476,17 +488,8 @@ static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
                                     + IDE_TIMING_CONFIG));
 }
 
-static void pmac_set_irq(ide_hwif_t *hwif, int on)
+static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl)
 {
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
        writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
        (void)readl((void __iomem *)(hwif->io_ports.data_addr
                                     + IDE_TIMING_CONFIG));
@@ -916,10 +919,18 @@ static u8 pmac_ide_cable_detect(ide_hwif_t *hwif)
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
        struct device_node *np = pmif->node;
        const char *cable = of_get_property(np, "cable-type", NULL);
+       struct device_node *root = of_find_node_by_path("/");
+       const char *model = of_get_property(root, "model", NULL);
 
        /* Get cable type from device-tree. */
-       if (cable && !strncmp(cable, "80-", 3))
-               return ATA_CBL_PATA80;
+       if (cable && !strncmp(cable, "80-", 3)) {
+               /* Some drives fail to detect 80c cable in PowerBook */
+               /* These machine use proprietary short IDE cable anyway */
+               if (!strncmp(model, "PowerBook", 9))
+                       return ATA_CBL_PATA40_SHORT;
+               else
+                       return ATA_CBL_PATA80;
+       }
 
        /*
         * G5's seem to have incorrect cable type in device-tree.
@@ -954,9 +965,9 @@ static const struct ide_tp_ops pmac_tp_ops = {
        .exec_command           = pmac_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = pmac_write_devctl,
 
-       .set_irq                = pmac_set_irq,
-
+       .dev_select             = pmac_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -964,19 +975,24 @@ static const struct ide_tp_ops pmac_tp_ops = {
        .output_data            = ide_output_data,
 };
 
-static const struct ide_port_ops pmac_ide_ata6_port_ops = {
-       .init_dev               = pmac_ide_init_dev,
-       .set_pio_mode           = pmac_ide_set_pio_mode,
-       .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_kauai_selectproc,
-       .cable_detect           = pmac_ide_cable_detect,
+static const struct ide_tp_ops pmac_ata6_tp_ops = {
+       .exec_command           = pmac_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = pmac_write_devctl,
+
+       .dev_select             = pmac_kauai_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
 };
 
 static const struct ide_port_ops pmac_ide_ata4_port_ops = {
        .init_dev               = pmac_ide_init_dev,
        .set_pio_mode           = pmac_ide_set_pio_mode,
        .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_selectproc,
        .cable_detect           = pmac_ide_cable_detect,
 };
 
@@ -984,7 +1000,6 @@ static const struct ide_port_ops pmac_ide_port_ops = {
        .init_dev               = pmac_ide_init_dev,
        .set_pio_mode           = pmac_ide_set_pio_mode,
        .set_dma_mode           = pmac_ide_set_dma_mode,
-       .selectproc             = pmac_ide_selectproc,
 };
 
 static const struct ide_dma_ops pmac_dma_ops;
@@ -1021,15 +1036,18 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
        pmif->broken_dma = pmif->broken_dma_warn = 0;
        if (of_device_is_compatible(np, "shasta-ata")) {
                pmif->kind = controller_sh_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA6;
        } else if (of_device_is_compatible(np, "kauai-ata")) {
                pmif->kind = controller_un_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA5;
        } else if (of_device_is_compatible(np, "K2-UATA")) {
                pmif->kind = controller_k2_ata6;
-               d.port_ops = &pmac_ide_ata6_port_ops;
+               d.tp_ops = &pmac_ata6_tp_ops;
+               d.port_ops = &pmac_ide_ata4_port_ops;
                d.udma_mask = ATA_UDMA5;
        } else if (of_device_is_compatible(np, "keylargo-ata")) {
                if (strcmp(np->name, "ata-4") == 0) {
@@ -1455,7 +1473,7 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
                                       "switching to PIO on Ohare chipset\n", drive->name);
                                pmif->broken_dma_warn = 1;
                        }
-                       goto use_pio_instead;
+                       return 0;
                }
                while (cur_len) {
                        unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
@@ -1463,7 +1481,7 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
                        if (count++ >= MAX_DCMDS) {
                                printk(KERN_WARNING "%s: DMA table too small\n",
                                       drive->name);
-                               goto use_pio_instead;
+                               return 0;
                        }
                        st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
                        st_le16(&table->req_count, tc);
@@ -1492,9 +1510,6 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 
        printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
 
-use_pio_instead:
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 
@@ -1510,10 +1525,8 @@ static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
        u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 
-       if (pmac_ide_build_dmatable(drive, cmd) == 0) {
-               ide_map_sg(drive, cmd);
+       if (pmac_ide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
        /* Apple adds 60ns to wrDataSetup on reads */
        if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
@@ -1522,8 +1535,6 @@ static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
                (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
        }
 
-       drive->waiting_for_dma = 1;
-
        return 0;
 }
 
@@ -1558,12 +1569,9 @@ pmac_ide_dma_end (ide_drive_t *drive)
        volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
        u32 dstat;
 
-       drive->waiting_for_dma = 0;
        dstat = readl(&dma->status);
        writel(((RUN|WAKE|DEAD) << 16), &dma->control);
 
-       ide_destroy_dmatable(drive);
-
        /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
         * in theory, but with ATAPI decices doing buffer underruns, that would
         * cause us to disable DMA, which isn't what we want
@@ -1650,7 +1658,6 @@ static const struct ide_dma_ops pmac_dma_ops = {
        .dma_start              = pmac_ide_dma_start,
        .dma_end                = pmac_ide_dma_end,
        .dma_test_irq           = pmac_ide_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = pmac_ide_dma_lost_irq,
 };
 
index 2a43a2f496337181e48c86700a403dc4f40ac50e..d007e7f665980e46b49f8ec7e5285a0caa0ac60b 100644 (file)
@@ -99,9 +99,9 @@ static const struct ide_tp_ops q40ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
index 08c4fa35e9b19481df1ac94b4772599b2fe57036..c9a1349868911eb583de495f20e1c73fbf030e1b 100644 (file)
@@ -90,13 +90,15 @@ static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
  * This routine is invoked to prepare for access to a given drive.
  */
 
-static void qd65xx_select(ide_drive_t *drive)
+static void qd65xx_dev_select(ide_drive_t *drive)
 {
        u8 index = ((   (QD_TIMREG(drive)) & 0x80 ) >> 7) |
                        (QD_TIMREG(drive) & 0x02);
 
        if (timings[index] != QD_TIMING(drive))
                outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+
+       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
 }
 
 /*
@@ -309,20 +311,33 @@ static void __init qd6580_init_dev(ide_drive_t *drive)
        drive->drive_data = (drive->dn & 1) ? t2 : t1;
 }
 
+static const struct ide_tp_ops qd65xx_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = qd65xx_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
+};
+
 static const struct ide_port_ops qd6500_port_ops = {
        .init_dev               = qd6500_init_dev,
        .set_pio_mode           = qd6500_set_pio_mode,
-       .selectproc             = qd65xx_select,
 };
 
 static const struct ide_port_ops qd6580_port_ops = {
        .init_dev               = qd6580_init_dev,
        .set_pio_mode           = qd6580_set_pio_mode,
-       .selectproc             = qd65xx_select,
 };
 
 static const struct ide_port_info qd65xx_port_info __initdata = {
        .name                   = DRV_NAME,
+       .tp_ops                 = &qd65xx_tp_ops,
        .chipset                = ide_qd65xx,
        .host_flags             = IDE_HFLAG_IO_32BIT |
                                  IDE_HFLAG_NO_DMA,
index 1c3a82914999fa7aba1c533c3571736551cd3c57..d467478d68da96839efd99b665b552e2f7512bbc 100644 (file)
@@ -115,8 +115,7 @@ static u8 sc1200_udma_filter(ide_drive_t *drive)
                if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
                    (mateid[ATA_ID_UDMA_MODES] & 7))
                        goto out;
-               if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
-                   (mateid[ATA_ID_MWDMA_MODES] & 7))
+               if (mateid[ATA_ID_MWDMA_MODES] & 7)
                        mask = 0;
        }
 out:
@@ -183,9 +182,6 @@ static int sc1200_dma_end(ide_drive_t *drive)
        outb(dma_stat|0x1b, dma_base+2);        /* clear the INTR & ERROR bits */
        outb(inb(dma_base)&~1, dma_base);       /* !! DO THIS HERE !! stop DMA */
 
-       drive->waiting_for_dma = 0;
-       ide_destroy_dmatable(drive);            /* purge DMA mappings */
-
        return (dma_stat & 7) != 4;             /* verify good DMA status */
 }
 
@@ -291,7 +287,6 @@ static const struct ide_dma_ops sc1200_dma_ops = {
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 0cc137cfe76d57f60577de9a8043ea29cb475d31..6d8dbd9c10bc11e99b28b486d5c74d220d8a9a14 100644 (file)
@@ -148,17 +148,8 @@ static u8 scc_dma_sff_read_status(ide_hwif_t *hwif)
        return (u8)in_be32((void *)(hwif->dma_base + 4));
 }
 
-static void scc_set_irq(ide_hwif_t *hwif, int on)
+static void scc_write_devctl(ide_hwif_t *hwif, u8 ctl)
 {
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
        out_be32((void *)hwif->io_ports.ctl_addr, ctl);
        eieio();
        in_be32((void *)(hwif->dma_base + 0x01c));
@@ -321,10 +312,8 @@ static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        u8 dma_stat;
 
        /* fall back to pio! */
-       if (ide_build_dmatable(drive, cmd) == 0) {
-               ide_map_sg(drive, cmd);
+       if (ide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
        /* PRD table */
        out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma);
@@ -337,7 +326,7 @@ static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 
        /* clear INTR & ERROR flags */
        out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6);
-       drive->waiting_for_dma = 1;
+
        return 0;
 }
 
@@ -356,7 +345,6 @@ static int __scc_dma_end(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat, dma_cmd;
 
-       drive->waiting_for_dma = 0;
        /* get DMA command mode */
        dma_cmd = scc_ide_inb(hwif->dma_base);
        /* stop DMA */
@@ -365,8 +353,6 @@ static int __scc_dma_end(ide_drive_t *drive)
        dma_stat = scc_dma_sff_read_status(hwif);
        /* clear the INTR & ERROR bits */
        scc_ide_outb(dma_stat | 6, hwif->dma_base + 4);
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
        /* verify good DMA status */
        wmb();
        return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
@@ -670,10 +656,6 @@ static void scc_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
        if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA)
-               out_be32((void *)io_ports->data_addr,
-                        (tf->hob_data << 8) | tf->data);
-
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                scc_ide_outb(tf->hob_feature, io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
@@ -706,18 +688,11 @@ static void scc_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
        struct ide_io_ports *io_ports = &drive->hwif->io_ports;
        struct ide_taskfile *tf = &cmd->tf;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
-               u16 data = (u16)in_be32((void *)io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       scc_ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       scc_ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = scc_ide_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = scc_ide_inb(io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = scc_ide_inb(io_ports->nsect_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
@@ -730,18 +705,18 @@ static void scc_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf->device = scc_ide_inb(io_ports->device_addr);
 
        if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               scc_ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+               scc_ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = scc_ide_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = scc_ide_inb(io_ports->feature_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = scc_ide_inb(io_ports->nsect_addr);
+                       tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = scc_ide_inb(io_ports->lbal_addr);
+                       tf->hob_lbal  = scc_ide_inb(io_ports->lbal_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = scc_ide_inb(io_ports->lbam_addr);
+                       tf->hob_lbam  = scc_ide_inb(io_ports->lbam_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = scc_ide_inb(io_ports->lbah_addr);
+                       tf->hob_lbah  = scc_ide_inb(io_ports->lbah_addr);
        }
 }
 
@@ -848,9 +823,9 @@ static const struct ide_tp_ops scc_tp_ops = {
        .exec_command           = scc_exec_command,
        .read_status            = scc_read_status,
        .read_altstatus         = scc_read_altstatus,
+       .write_devctl           = scc_write_devctl,
 
-       .set_irq                = scc_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = scc_tf_load,
        .tf_read                = scc_tf_read,
 
@@ -872,7 +847,6 @@ static const struct ide_dma_ops scc_dma_ops = {
        .dma_end                = scc_dma_end,
        .dma_test_irq           = scc_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
        .dma_sff_read_status    = scc_dma_sff_read_status,
 };
index b12de8346c738130cc2f4314344f64f65408c153..e5d2a48a84de9314133d2b54c49f63aa08f536e4 100644 (file)
@@ -258,9 +258,6 @@ static int sgiioc4_dma_end(ide_drive_t *drive)
                }
        }
 
-       drive->waiting_for_dma = 0;
-       ide_destroy_dmatable(drive);
-
        return dma_stat;
 }
 
@@ -280,10 +277,12 @@ static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
                sgiioc4_clearirq(drive);
 }
 
-static void
-sgiioc4_resetproc(ide_drive_t * drive)
+static void sgiioc4_resetproc(ide_drive_t *drive)
 {
+       struct ide_cmd *cmd = &drive->hwif->cmd;
+
        sgiioc4_dma_end(drive);
+       ide_dma_unmap_sg(drive, cmd);
        sgiioc4_clearirq(drive);
 }
 
@@ -412,7 +411,6 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
        writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4));
 
        writel(dma_direction, (void __iomem *)ioc4_dma_addr);
-       drive->waiting_for_dma = 1;
 }
 
 /* IOC4 Scatter Gather list Format                                      */
@@ -442,7 +440,7 @@ static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
                                printk(KERN_WARNING
                                       "%s: DMA table too small\n",
                                       drive->name);
-                               goto use_pio_instead;
+                               return 0;
                        } else {
                                u32 bcount =
                                    0x10000 - (cur_addr & 0xffff);
@@ -477,9 +475,6 @@ static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
                return count;
        }
 
-use_pio_instead:
-       ide_destroy_dmatable(drive);
-
        return 0;               /* revert to PIO for this request */
 }
 
@@ -488,11 +483,9 @@ static int sgiioc4_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        int ddir;
        u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 
-       if (sgiioc4_build_dmatable(drive, cmd) == 0) {
+       if (sgiioc4_build_dmatable(drive, cmd) == 0)
                /* try PIO instead of DMA */
-               ide_map_sg(drive, cmd);
                return 1;
-       }
 
        if (write)
                /* Writes TO the IOC4 FROM Main Memory */
@@ -510,9 +503,9 @@ static const struct ide_tp_ops sgiioc4_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = sgiioc4_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -533,7 +526,6 @@ static const struct ide_dma_ops sgiioc4_dma_ops = {
        .dma_end                = sgiioc4_dma_end,
        .dma_test_irq           = sgiioc4_dma_test_irq,
        .dma_lost_irq           = sgiioc4_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
 };
 
 static const struct ide_port_info sgiioc4_port_info __devinitconst = {
index 075cb1243b2a6a117e1eaa7324b3805973166417..e4973cd1fba9e8735191f73e32e3eb9575f1d97d 100644 (file)
@@ -715,7 +715,6 @@ static const struct ide_dma_ops sil_dma_ops = {
        .dma_end                = ide_dma_end,
        .dma_test_irq           = siimage_dma_test_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
index d25137b04e7a2d357bba29c7d798b864d55ad629..b0a460625335c9c469b94ea94a7d4210c305e2ab 100644 (file)
@@ -61,7 +61,8 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
        if (cmd_off == 0)
                cmd_off = 1;
 
-       if (pio > 2 || ata_id_has_iordy(drive->id))
+       if ((pio > 2 || ata_id_has_iordy(drive->id)) &&
+           !(pio > 4 && ata_id_is_cfa(drive->id)))
                iordy = 0x40;
 
        return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
@@ -189,14 +190,13 @@ static void sl82c105_dma_start(ide_drive_t *drive)
        ide_dma_start(drive);
 }
 
-static void sl82c105_dma_timeout(ide_drive_t *drive)
+static void sl82c105_dma_clear(ide_drive_t *drive)
 {
        struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
 
-       DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name));
+       DBG(("sl82c105_dma_clear(drive:%s)\n", drive->name));
 
        sl82c105_reset_host(dev);
-       ide_dma_timeout(drive);
 }
 
 static int sl82c105_dma_end(ide_drive_t *drive)
@@ -298,7 +298,7 @@ static const struct ide_dma_ops sl82c105_dma_ops = {
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = sl82c105_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = sl82c105_dma_timeout,
+       .dma_clear              = sl82c105_dma_clear,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index 427d4b3c2c636d37c3888464c3ce42b37290e7c8..b4cf42dc8a6fcf4cd155ae0bd3f7ad9868a10106 100644 (file)
@@ -187,7 +187,6 @@ static const struct ide_dma_ops tc86c001_dma_ops = {
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
index ed1496845a9395b379d5b572d6ac098ec5457ca4..4b42ca091534093a52cefdd5398ba8a6a0726cb6 100644 (file)
@@ -171,54 +171,51 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
        local_irq_restore(flags);
 }
 
-static void trm290_selectproc (ide_drive_t *drive)
+static void trm290_dev_select(ide_drive_t *drive)
 {
        trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
+
+       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
 }
 
-static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
+static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
 {
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned int count, rw;
-
        if (cmd->tf_flags & IDE_TFLAG_WRITE) {
 #ifdef TRM290_NO_DMA_WRITES
                /* always use PIO for writes */
-               trm290_prepare_drive(drive, 0); /* select PIO xfer */
                return 1;
 #endif
-               rw = 1;
-       } else
-               rw = 2;
+       }
+       return 0;
+}
+
+static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2;
 
        count = ide_build_dmatable(drive, cmd);
-       if (count == 0) {
-               ide_map_sg(drive, cmd);
+       if (count == 0)
                /* try PIO instead of DMA */
-               trm290_prepare_drive(drive, 0); /* select PIO xfer */
                return 1;
-       }
-       /* select DMA xfer */
-       trm290_prepare_drive(drive, 1);
+
        outl(hwif->dmatable_dma | rw, hwif->dma_base);
-       drive->waiting_for_dma = 1;
        /* start DMA */
        outw(count * 2 - 1, hwif->dma_base + 2);
+
        return 0;
 }
 
 static void trm290_dma_start(ide_drive_t *drive)
 {
+       trm290_prepare_drive(drive, 1);
 }
 
 static int trm290_dma_end(ide_drive_t *drive)
 {
-       u16 status;
+       u16 status = inw(drive->hwif->dma_base + 2);
 
-       drive->waiting_for_dma = 0;
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
-       status = inw(drive->hwif->dma_base + 2);
+       trm290_prepare_drive(drive, 0);
 
        return status != 0x00ff;
 }
@@ -303,8 +300,18 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
 #endif
 }
 
-static const struct ide_port_ops trm290_port_ops = {
-       .selectproc             = trm290_selectproc,
+static const struct ide_tp_ops trm290_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
+
+       .dev_select             = trm290_dev_select,
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
 };
 
 static struct ide_dma_ops trm290_dma_ops = {
@@ -314,13 +321,13 @@ static struct ide_dma_ops trm290_dma_ops = {
        .dma_end                = trm290_dma_end,
        .dma_test_irq           = trm290_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timeout            = ide_dma_timeout,
+       .dma_check              = trm290_dma_check,
 };
 
 static const struct ide_port_info trm290_chipset __devinitdata = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_trm290,
-       .port_ops       = &trm290_port_ops,
+       .tp_ops         = &trm290_tp_ops,
        .dma_ops        = &trm290_dma_ops,
        .host_flags     = IDE_HFLAG_TRM290 |
                          IDE_HFLAG_NO_ATAPI_DMA |
index 657a61890b1caef03d6ae1202fc888a16e624ff7..4cb79c4c2604e2920c435ff1c97ebe3fb236de0d 100644 (file)
@@ -92,13 +92,6 @@ static void tx4938ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
        if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               /* no endian swap */
-               __raw_writew(data, (void __iomem *)io_ports->data_addr);
-       }
-
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                tx4938ide_outb(tf->hob_feature, io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
@@ -132,20 +125,11 @@ static void tx4938ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
        struct ide_io_ports *io_ports = &hwif->io_ports;
        struct ide_taskfile *tf = &cmd->tf;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
-               u16 data;
-
-               /* no endian swap */
-               data = __raw_readw((void __iomem *)io_ports->data_addr);
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       tx4938ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       tx4938ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = tx4938ide_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = tx4938ide_inb(io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = tx4938ide_inb(io_ports->nsect_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
@@ -158,19 +142,18 @@ static void tx4938ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf->device = tx4938ide_inb(io_ports->device_addr);
 
        if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               tx4938ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+               tx4938ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature =
-                               tx4938ide_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = tx4938ide_inb(io_ports->feature_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = tx4938ide_inb(io_ports->nsect_addr);
+                       tf->hob_nsect = tx4938ide_inb(io_ports->nsect_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = tx4938ide_inb(io_ports->lbal_addr);
+                       tf->hob_lbal  = tx4938ide_inb(io_ports->lbal_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = tx4938ide_inb(io_ports->lbam_addr);
+                       tf->hob_lbam  = tx4938ide_inb(io_ports->lbam_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = tx4938ide_inb(io_ports->lbah_addr);
+                       tf->hob_lbah  = tx4938ide_inb(io_ports->lbah_addr);
        }
 }
 
@@ -204,9 +187,9 @@ static const struct ide_tp_ops tx4938ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = tx4938ide_tf_load,
        .tf_read                = tx4938ide_tf_read,
 
index e0e0a803dde38d92de14f620eb5f3fe798d1bd69..0040a9a3e26e81a1ac0712d8f2eb3434f0f6a7fe 100644 (file)
@@ -279,8 +279,6 @@ use_pio_instead:
        printk(KERN_ERR "%s: %s\n", drive->name,
                count ? "DMA table too small" : "empty DMA table?");
 
-       ide_destroy_dmatable(drive);
-
        return 0; /* revert to PIO for this request */
 }
 #else
@@ -294,10 +292,8 @@ static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
 
        /* fall back to PIO! */
-       if (tx4939ide_build_dmatable(drive, cmd) == 0) {
-               ide_map_sg(drive, cmd);
+       if (tx4939ide_build_dmatable(drive, cmd) == 0)
                return 1;
-       }
 
        /* PRD table */
        tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr);
@@ -308,8 +304,6 @@ static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
        /* clear INTR & ERROR flags */
        tx4939ide_clear_dma_status(base);
 
-       drive->waiting_for_dma = 1;
-
        tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ?
                         TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1);
 
@@ -325,8 +319,6 @@ static int tx4939ide_dma_end(ide_drive_t *drive)
        void __iomem *base = TX4939IDE_BASE(hwif);
        u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
 
-       drive->waiting_for_dma = 0;
-
        /* get DMA command mode */
        dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd);
        /* stop DMA */
@@ -335,11 +327,9 @@ static int tx4939ide_dma_end(ide_drive_t *drive)
        /* read and clear the INTR & ERROR bits */
        dma_stat = tx4939ide_clear_dma_status(base);
 
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
-       /* verify good DMA status */
        wmb();
 
+       /* verify good DMA status */
        if ((dma_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == 0 &&
            (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) ==
            (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST))
@@ -439,7 +429,7 @@ static void tx4939ide_tf_load_fixup(ide_drive_t *drive)
         * Fix ATA100 CORE System Control Register. (The write to the
         * Device/Head register may write wrong data to the System
         * Control Register)
-        * While Sys_Ctl is written here, selectproc is not needed.
+        * While Sys_Ctl is written here, dev_select() is not needed.
         */
        tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
 }
@@ -467,13 +457,6 @@ static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
        if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
                HIHI = 0xFF;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               /* no endian swap */
-               __raw_writew(data, (void __iomem *)io_ports->data_addr);
-       }
-
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
                tx4939ide_outb(tf->hob_feature, io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
@@ -509,20 +492,11 @@ static void tx4939ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
        struct ide_io_ports *io_ports = &hwif->io_ports;
        struct ide_taskfile *tf = &cmd->tf;
 
-       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
-               u16 data;
-
-               /* no endian swap */
-               data = __raw_readw((void __iomem *)io_ports->data_addr);
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
        /* be sure we're looking at the low order bits */
-       tx4939ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+       tx4939ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-       if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = tx4939ide_inb(io_ports->feature_addr);
+       if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
+               tf->error  = tx4939ide_inb(io_ports->feature_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
                tf->nsect  = tx4939ide_inb(io_ports->nsect_addr);
        if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
@@ -535,19 +509,18 @@ static void tx4939ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
                tf->device = tx4939ide_inb(io_ports->device_addr);
 
        if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               tx4939ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+               tx4939ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
 
-               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature =
-                               tx4939ide_inb(io_ports->feature_addr);
+               if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
+                       tf->hob_error = tx4939ide_inb(io_ports->feature_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = tx4939ide_inb(io_ports->nsect_addr);
+                       tf->hob_nsect = tx4939ide_inb(io_ports->nsect_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = tx4939ide_inb(io_ports->lbal_addr);
+                       tf->hob_lbal  = tx4939ide_inb(io_ports->lbal_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = tx4939ide_inb(io_ports->lbam_addr);
+                       tf->hob_lbam  = tx4939ide_inb(io_ports->lbam_addr);
                if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = tx4939ide_inb(io_ports->lbah_addr);
+                       tf->hob_lbah  = tx4939ide_inb(io_ports->lbah_addr);
        }
 }
 
@@ -581,9 +554,9 @@ static const struct ide_tp_ops tx4939ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = tx4939ide_tf_load,
        .tf_read                = tx4939ide_tf_read,
 
@@ -605,9 +578,9 @@ static const struct ide_tp_ops tx4939ide_tp_ops = {
        .exec_command           = ide_exec_command,
        .read_status            = ide_read_status,
        .read_altstatus         = ide_read_altstatus,
+       .write_devctl           = ide_write_devctl,
 
-       .set_irq                = ide_set_irq,
-
+       .dev_select             = ide_dev_select,
        .tf_load                = tx4939ide_tf_load,
        .tf_read                = ide_tf_read,
 
@@ -632,7 +605,6 @@ static const struct ide_dma_ops tx4939ide_dma_ops = {
        .dma_test_irq           = tx4939ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_timeout            = ide_dma_timeout,
        .dma_sff_read_status    = tx4939ide_dma_sff_read_status,
 };
 
index 5f9d860925a17c7f8799880ba096fe2ccd41dc3c..cd50c00ab20fd8bcf94e274caa70d14347dc15df 100644 (file)
@@ -143,7 +143,7 @@ config INPUT_APMPOWER
        ---help---
          Say Y here if you want suspend key events to trigger a user
          requested suspend through APM. This is useful on embedded
-         systems where such behviour is desired without userspace
+         systems where such behaviour is desired without userspace
          interaction. If unsure, say N.
 
          To compile this driver as a module, choose M here: the
index 1730d7331a5dff13a6841fd0009066f49cde6666..ec3db3ade1182b01ef663a946c85de10efa54023 100644 (file)
@@ -903,8 +903,6 @@ static int __init input_proc_init(void)
        if (!proc_bus_input_dir)
                return -ENOMEM;
 
-       proc_bus_input_dir->owner = THIS_MODULE;
-
        entry = proc_create("devices", 0, proc_bus_input_dir,
                            &input_devices_fileops);
        if (!entry)
index 0db8d16c5eddafd297edcf25b3387968d976d135..5e5eb88d8d1e04e48b5a0668300ecf56cbe6017d 100644 (file)
@@ -18,7 +18,7 @@
 
 /*
  * Timer function which is run every scan_ms ms when the device is opened.
- * The dev input varaible is set to the the input_dev pointer.
+ * The dev input variable is set to the the input_dev pointer.
  */
 static void gpio_mouse_scan(struct input_polled_dev *dev)
 {
index 81e6ebf323e9b9a8bdfc780afc487e690caf5c2c..55cd0fa6833984c2b025b3115b6ed81bb4adf6ef 100644 (file)
@@ -381,7 +381,7 @@ static void hgpk_disconnect(struct psmouse *psmouse)
 
 static void hgpk_recalib_work(struct work_struct *work)
 {
-       struct delayed_work *w = container_of(work, struct delayed_work, work);
+       struct delayed_work *w = to_delayed_work(work);
        struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
        struct psmouse *psmouse = priv->psmouse;
 
index 7c27c8b9b6d0e1b8d23199f584332119b541ba06..056ac77e2cf0ed6fe5624d9f62f35bbab2d57697 100644 (file)
@@ -295,7 +295,7 @@ name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
 
 
-/* Sysfs conventions report temperatures in millidegrees Celcius.
+/* Sysfs conventions report temperatures in millidegrees Celsius.
  * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
  * accuracy scheme without calibration data.  For now we won't try either;
  * userspace sees raw sensor values, and must scale/calibrate appropriately.
index 3e468d2cf730b0467c44de5403b4c7efaab58933..2d8352419c0db445c57f03d80336cf9e1458faf5 100644 (file)
@@ -1331,12 +1331,6 @@ static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
 #endif
 }
 
-static int capinc_tty_read_proc(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return 0;
-}
-
 static struct tty_driver *capinc_tty_driver;
 
 static const struct tty_operations capinc_ops = {
@@ -1358,7 +1352,6 @@ static const struct tty_operations capinc_ops = {
        .flush_buffer = capinc_tty_flush_buffer,
        .set_ldisc = capinc_tty_set_ldisc,
        .send_xchar = capinc_tty_send_xchar,
-       .read_proc = capinc_tty_read_proc,
 };
 
 static int capinc_tty_init(void)
index f4969fe0a0554ad5f567268075be2a6e90b34bb1..69e71ebe7841830bf2af1dc68b894186b776cb91 100644 (file)
@@ -118,7 +118,6 @@ static int DIVA_INIT_FUNCTION create_um_idi_proc(void)
                return (0);
 
        um_idi_proc_entry->read_proc = um_idi_proc_read;
-       um_idi_proc_entry->owner = THIS_MODULE;
 
        return (1);
 }
index 4938355c407264b389ff6e885ed835df33ae483f..1747a02a019a1bcb7ed1ac1d37c02babd2a8c99e 100644 (file)
@@ -14,13 +14,15 @@ config MISDN_DSP
        depends on MISDN
        help
          Enable support for digital audio processing capability.
+
          This module may be used for special applications that require
-         cross connecting of bchannels, conferencing, dtmf decoding
+         cross connecting of bchannels, conferencing, dtmf decoding,
          echo cancelation, tone generation, and Blowfish encryption and
-         decryption.
-         It may use hardware features if available.
+         decryption. It may use hardware features if available.
+
          E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
-         and get more informations about this module and it's usage.
+         and get more information about this module and its usage.
+
          If unsure, say 'N'.
 
 config MISDN_L1OIP
index 2ec4b28d9edc85aecf80c7007c3ea0f4038eb62a..e4ecba3d48dfcf75703aee66c5a443b9f39c2c62 100644 (file)
@@ -331,7 +331,7 @@ l1oip_4bit_alloc(int ulaw)
        /* alloc conversion tables */
        table_com = vmalloc(65536);
        table_dec = vmalloc(512);
-       if (!table_com | !table_dec) {
+       if (!table_com || !table_dec) {
                l1oip_4bit_free();
                return -ENOMEM;
        }
index 556aeca0d860c835c9467bbfa9578bd61d0292dc..d9db17624f129fc88a3d1e50f49d69661e39ba99 100644 (file)
@@ -100,7 +100,7 @@ config LEDS_HP6XX
        tristate "LED Support for the HP Jornada 6xx"
        depends on LEDS_CLASS && SH_HP6XX
        help
-         This option enables led support for the handheld
+         This option enables LED support for the handheld
          HP Jornada 620/660/680/690.
 
 config LEDS_PCA9532
@@ -108,7 +108,7 @@ config LEDS_PCA9532
        depends on LEDS_CLASS && I2C && INPUT && EXPERIMENTAL
        help
          This option enables support for NXP pca9532
-         led controller. It is generally only usefull
+         LED controller. It is generally only useful
          as a platform driver
 
 config LEDS_GPIO
@@ -144,7 +144,7 @@ config LEDS_CLEVO_MAIL
                Positivo Mobile (Clevo M5x0V)
 
          If your model is not listed here you can try the "nodetect"
-         module paramter.
+         module parameter.
 
          To compile this driver as a module, choose M here: the
          module will be called leds-clevo-mail.
index 76ec7498e2d5eee3e8d762ec71f2c8c7e54bafd7..bd3b431c9710eccc207228b6daacc049c3e04463 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * pca9532.c - 16-bit Led dimmer
  *
- * Copyright (C) 2008 Riku Voipio <riku.voipio@movial.fi>
+ * Copyright (C) 2008 Riku Voipio
  *
  * 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
@@ -367,7 +367,7 @@ static void __exit pca9532_exit(void)
        i2c_del_driver(&pca9532_driver);
 }
 
-MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>");
+MODULE_AUTHOR("Riku Voipio");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("PCA 9532 LED dimmer");
 
index 60156dfdc608cf5e8d45e40ec34a51d09a084664..4845fb3cf74bd8911dc3a48b8370c722be688512 100644 (file)
@@ -152,8 +152,8 @@ static void unmap_switcher(void)
  * code.  We have to check that the range is below the pfn_limit the Launcher
  * gave us.  We have to make sure that addr + len doesn't give us a false
  * positive by overflowing, too. */
-int lguest_address_ok(const struct lguest *lg,
-                     unsigned long addr, unsigned long len)
+bool lguest_address_ok(const struct lguest *lg,
+                      unsigned long addr, unsigned long len)
 {
        return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
 }
index 415fab0125acd8e465e1fe2e6fe8241d75894868..6e99adbe1946e8810951460872fdd59d79985ebf 100644 (file)
@@ -34,7 +34,7 @@ static int idt_type(u32 lo, u32 hi)
 }
 
 /* An IDT entry can't be used unless the "present" bit is set. */
-static int idt_present(u32 lo, u32 hi)
+static bool idt_present(u32 lo, u32 hi)
 {
        return (hi & 0x8000);
 }
@@ -60,7 +60,8 @@ static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
  * We set up the stack just like the CPU does for a real interrupt, so it's
  * identical for the Guest (and the standard "iret" instruction will undo
  * it). */
-static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, int has_err)
+static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
+                               bool has_err)
 {
        unsigned long gstack, origstack;
        u32 eflags, ss, irq_enable;
@@ -184,7 +185,7 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
                /* set_guest_interrupt() takes the interrupt descriptor and a
                 * flag to say whether this interrupt pushes an error code onto
                 * the stack as well: virtual interrupts never do. */
-               set_guest_interrupt(cpu, idt->a, idt->b, 0);
+               set_guest_interrupt(cpu, idt->a, idt->b, false);
        }
 
        /* Every time we deliver an interrupt, we update the timestamp in the
@@ -244,26 +245,26 @@ void free_interrupts(void)
 /*H:220 Now we've got the routines to deliver interrupts, delivering traps like
  * page fault is easy.  The only trick is that Intel decided that some traps
  * should have error codes: */
-static int has_err(unsigned int trap)
+static bool has_err(unsigned int trap)
 {
        return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
 }
 
 /* deliver_trap() returns true if it could deliver the trap. */
-int deliver_trap(struct lg_cpu *cpu, unsigned int num)
+bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
 {
        /* Trap numbers are always 8 bit, but we set an impossible trap number
         * for traps inside the Switcher, so check that here. */
        if (num >= ARRAY_SIZE(cpu->arch.idt))
-               return 0;
+               return false;
 
        /* Early on the Guest hasn't set the IDT entries (or maybe it put a
         * bogus one in): if we fail here, the Guest will be killed. */
        if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b))
-               return 0;
+               return false;
        set_guest_interrupt(cpu, cpu->arch.idt[num].a,
                            cpu->arch.idt[num].b, has_err(num));
-       return 1;
+       return true;
 }
 
 /*H:250 Here's the hard part: returning to the Host every time a trap happens
@@ -279,18 +280,19 @@ int deliver_trap(struct lg_cpu *cpu, unsigned int num)
  *
  * This routine indicates if a particular trap number could be delivered
  * directly. */
-static int direct_trap(unsigned int num)
+static bool direct_trap(unsigned int num)
 {
        /* Hardware interrupts don't go to the Guest at all (except system
         * call). */
        if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num))
-               return 0;
+               return false;
 
        /* The Host needs to see page faults (for shadow paging and to save the
         * fault address), general protection faults (in/out emulation) and
-        * device not available (TS handling), and of course, the hypercall
-        * trap. */
-       return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;
+        * device not available (TS handling), invalid opcode fault (kvm hcall),
+        * and of course, the hypercall trap. */
+       return num != 14 && num != 13 && num != 7 &&
+                       num != 6 && num != LGUEST_TRAP_ENTRY;
 }
 /*:*/
 
index f2c641e0bdde508887809176774badcc31519622..ac8a4a3741b831e36d5ca499f85424e90b9d1335 100644 (file)
@@ -109,8 +109,8 @@ struct lguest
 extern struct mutex lguest_lock;
 
 /* core.c: */
-int lguest_address_ok(const struct lguest *lg,
-                     unsigned long addr, unsigned long len);
+bool lguest_address_ok(const struct lguest *lg,
+                      unsigned long addr, unsigned long len);
 void __lgread(struct lg_cpu *, void *, unsigned long, unsigned);
 void __lgwrite(struct lg_cpu *, unsigned long, const void *, unsigned);
 
@@ -140,7 +140,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user);
 
 /* interrupts_and_traps.c: */
 void maybe_do_interrupt(struct lg_cpu *cpu);
-int deliver_trap(struct lg_cpu *cpu, unsigned int num);
+bool deliver_trap(struct lg_cpu *cpu, unsigned int num);
 void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i,
                          u32 low, u32 hi);
 void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages);
@@ -173,7 +173,7 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu);
 void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
                   unsigned long vaddr, pte_t val);
 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages);
-int demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
+bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
 void pin_page(struct lg_cpu *cpu, unsigned long vaddr);
 unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr);
 void page_table_guest_data_init(struct lg_cpu *cpu);
index 8132533d71f9384e3e73aca8092b02295cd75024..df44d962626d327ba26a3b1a2aa83a2bba383390 100644 (file)
@@ -161,7 +161,7 @@ static void set_status(struct virtio_device *vdev, u8 status)
 
        /* We set the status. */
        to_lgdev(vdev)->desc->status = status;
-       hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+       kvm_hypercall1(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset);
 }
 
 static void lg_set_status(struct virtio_device *vdev, u8 status)
@@ -209,7 +209,7 @@ static void lg_notify(struct virtqueue *vq)
         * virtqueue structure. */
        struct lguest_vq_info *lvq = vq->priv;
 
-       hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0);
+       kvm_hypercall1(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT);
 }
 
 /* An extern declaration inside a C file is bad form.  Don't do it. */
index 576a8318221c9dfe47dc28a660565094c9ef7753..a059cf9980f711b97d2009545b574e63cf79fddc 100644 (file)
@@ -199,7 +199,7 @@ static void check_gpgd(struct lg_cpu *cpu, pgd_t gpgd)
  *
  * If we fixed up the fault (ie. we mapped the address), this routine returns
  * true.  Otherwise, it was a real fault and we need to tell the Guest. */
-int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
+bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
 {
        pgd_t gpgd;
        pgd_t *spgd;
@@ -211,7 +211,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
        gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
        if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
-               return 0;
+               return false;
 
        /* Now look at the matching shadow entry. */
        spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
@@ -222,7 +222,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
                 * simple for this corner case. */
                if (!ptepage) {
                        kill_guest(cpu, "out of memory allocating pte page");
-                       return 0;
+                       return false;
                }
                /* We check that the Guest pgd is OK. */
                check_gpgd(cpu, gpgd);
@@ -238,16 +238,16 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
 
        /* If this page isn't in the Guest page tables, we can't page it in. */
        if (!(pte_flags(gpte) & _PAGE_PRESENT))
-               return 0;
+               return false;
 
        /* Check they're not trying to write to a page the Guest wants
         * read-only (bit 2 of errcode == write). */
        if ((errcode & 2) && !(pte_flags(gpte) & _PAGE_RW))
-               return 0;
+               return false;
 
        /* User access to a kernel-only page? (bit 3 == user access) */
        if ((errcode & 4) && !(pte_flags(gpte) & _PAGE_USER))
-               return 0;
+               return false;
 
        /* Check that the Guest PTE flags are OK, and the page number is below
         * the pfn_limit (ie. not mapping the Launcher binary). */
@@ -283,7 +283,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
         * manipulated, the result returned and the code complete.  A small
         * delay and a trace of alliteration are the only indications the Guest
         * has that a page fault occurred at all. */
-       return 1;
+       return true;
 }
 
 /*H:360
@@ -296,7 +296,7 @@ int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
  *
  * This is a quick version which answers the question: is this virtual address
  * mapped by the shadow page tables, and is it writable? */
-static int page_writable(struct lg_cpu *cpu, unsigned long vaddr)
+static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
 {
        pgd_t *spgd;
        unsigned long flags;
@@ -304,7 +304,7 @@ static int page_writable(struct lg_cpu *cpu, unsigned long vaddr)
        /* Look at the current top level entry: is it present? */
        spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
        if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
-               return 0;
+               return false;
 
        /* Check the flags on the pte entry itself: it must be present and
         * writable. */
@@ -373,8 +373,10 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
        /* First step: get the top-level Guest page table entry. */
        gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
-       if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
+       if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) {
                kill_guest(cpu, "Bad address %#lx", vaddr);
+               return -1UL;
+       }
 
        gpte = lgread(cpu, gpte_addr(gpgd, vaddr), pte_t);
        if (!(pte_flags(gpte) & _PAGE_PRESENT))
index ec6aa3f1c36b349464e946375de109cc606c82a2..4f15439b7f1288c8f0f9462e42e76db4471c199c 100644 (file)
@@ -45,7 +45,7 @@
  * "Task State Segment" which controls all kinds of delicate things.  The
  * LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the
  * the Guest can't be trusted to deal with double faults. */
-static int ignored_gdt(unsigned int num)
+static bool ignored_gdt(unsigned int num)
 {
        return (num == GDT_ENTRY_TSS
                || num == GDT_ENTRY_LGUEST_CS
index bf7942327bda5c2f122889e9881e1b7d90acaf44..a6b717644be0d50efc2f257e52e9e543cc545833 100644 (file)
@@ -290,6 +290,57 @@ static int emulate_insn(struct lg_cpu *cpu)
        return 1;
 }
 
+/* Our hypercalls mechanism used to be based on direct software interrupts.
+ * After Anthony's "Refactor hypercall infrastructure" kvm patch, we decided to
+ * change over to using kvm hypercalls.
+ *
+ * KVM_HYPERCALL is actually a "vmcall" instruction, which generates an invalid
+ * opcode fault (fault 6) on non-VT cpus, so the easiest solution seemed to be
+ * an *emulation approach*: if the fault was really produced by an hypercall
+ * (is_hypercall() does exactly this check), we can just call the corresponding
+ * hypercall host implementation function.
+ *
+ * But these invalid opcode faults are notably slower than software interrupts.
+ * So we implemented the *patching (or rewriting) approach*: every time we hit
+ * the KVM_HYPERCALL opcode in Guest code, we patch it to the old "int 0x1f"
+ * opcode, so next time the Guest calls this hypercall it will use the
+ * faster trap mechanism.
+ *
+ * Matias even benchmarked it to convince you: this shows the average cycle
+ * cost of a hypercall.  For each alternative solution mentioned above we've
+ * made 5 runs of the benchmark:
+ *
+ * 1) direct software interrupt: 2915, 2789, 2764, 2721, 2898
+ * 2) emulation technique: 3410, 3681, 3466, 3392, 3780
+ * 3) patching (rewrite) technique: 2977, 2975, 2891, 2637, 2884
+ *
+ * One two-line function is worth a 20% hypercall speed boost!
+ */
+static void rewrite_hypercall(struct lg_cpu *cpu)
+{
+       /* This are the opcodes we use to patch the Guest.  The opcode for "int
+        * $0x1f" is "0xcd 0x1f" but vmcall instruction is 3 bytes long, so we
+        * complete the sequence with a NOP (0x90). */
+       u8 insn[3] = {0xcd, 0x1f, 0x90};
+
+       __lgwrite(cpu, guest_pa(cpu, cpu->regs->eip), insn, sizeof(insn));
+}
+
+static bool is_hypercall(struct lg_cpu *cpu)
+{
+       u8 insn[3];
+
+       /* This must be the Guest kernel trying to do something.
+        * The bottom two bits of the CS segment register are the privilege
+        * level. */
+       if ((cpu->regs->cs & 3) != GUEST_PL)
+               return false;
+
+       /* Is it a vmcall? */
+       __lgread(cpu, insn, guest_pa(cpu, cpu->regs->eip), sizeof(insn));
+       return insn[0] == 0x0f && insn[1] == 0x01 && insn[2] == 0xc1;
+}
+
 /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
 void lguest_arch_handle_trap(struct lg_cpu *cpu)
 {
@@ -337,7 +388,7 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
                break;
        case 32 ... 255:
                /* These values mean a real interrupt occurred, in which case
-                * the Host handler has already been run.  We just do a
+                * the Host handler has already been run. We just do a
                 * friendly check if another process should now be run, then
                 * return to run the Guest again */
                cond_resched();
@@ -347,6 +398,15 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
                 * up the pointer now to indicate a hypercall is pending. */
                cpu->hcall = (struct hcall_args *)cpu->regs;
                return;
+       case 6:
+               /* kvm hypercalls trigger an invalid opcode fault (6).
+                * We need to check if ring == GUEST_PL and
+                * faulting instruction == vmcall. */
+               if (is_hypercall(cpu)) {
+                       rewrite_hypercall(cpu);
+                       return;
+               }
+               break;
        }
 
        /* We didn't handle the trap, so it needs to go to the Guest. */
index 2281b5098e95455cd1a6d60af7354f7728888185..36e0675be9f72fe5793687c85c3ed0d7db67efae 100644 (file)
@@ -121,6 +121,7 @@ config MD_RAID10
 config MD_RAID456
        tristate "RAID-4/RAID-5/RAID-6 mode"
        depends on BLK_DEV_MD
+       select MD_RAID6_PQ
        select ASYNC_MEMCPY
        select ASYNC_XOR
        ---help---
@@ -151,34 +152,8 @@ config MD_RAID456
 
          If unsure, say Y.
 
-config MD_RAID5_RESHAPE
-       bool "Support adding drives to a raid-5 array"
-       depends on MD_RAID456
-       default y
-       ---help---
-         A RAID-5 set can be expanded by adding extra drives. This
-         requires "restriping" the array which means (almost) every
-         block must be written to a different place.
-
-          This option allows such restriping to be done while the array
-         is online.
-
-         You will need mdadm version 2.4.1 or later to use this
-         feature safely.  During the early stage of reshape there is
-         a critical section where live data is being over-written.  A
-         crash during this time needs extra care for recovery.  The
-         newer mdadm takes a copy of the data in the critical section
-         and will restore it, if necessary, after a crash.
-
-         The mdadm usage is e.g.
-              mdadm --grow /dev/md1 --raid-disks=6
-         to grow '/dev/md1' to having 6 disks.
-
-         Note: The array can only be expanded, not contracted.
-         There should be enough spares already present to make the new
-         array workable.
-
-         If unsure, say Y.
+config MD_RAID6_PQ
+       tristate
 
 config MD_MULTIPATH
        tristate "Multipath I/O support"
index 72880b7e28d9c464655c471a1d4bb85d1df0fab5..45cc5951d9287030df73363a20659482aa55414d 100644 (file)
@@ -2,20 +2,21 @@
 # Makefile for the kernel software RAID and LVM drivers.
 #
 
-dm-mod-objs    := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
+dm-mod-y       += dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
                   dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o
-dm-multipath-objs := dm-path-selector.o dm-mpath.o
-dm-snapshot-objs := dm-snap.o dm-exception-store.o dm-snap-transient.o \
+dm-multipath-y += dm-path-selector.o dm-mpath.o
+dm-snapshot-y  += dm-snap.o dm-exception-store.o dm-snap-transient.o \
                    dm-snap-persistent.o
-dm-mirror-objs := dm-raid1.o
-md-mod-objs     := md.o bitmap.o
-raid456-objs   := raid5.o raid6algos.o raid6recov.o raid6tables.o \
+dm-mirror-y    += dm-raid1.o
+md-mod-y       += md.o bitmap.o
+raid456-y      += raid5.o
+raid6_pq-y     += raid6algos.o raid6recov.o raid6tables.o \
                   raid6int1.o raid6int2.o raid6int4.o \
                   raid6int8.o raid6int16.o raid6int32.o \
                   raid6altivec1.o raid6altivec2.o raid6altivec4.o \
                   raid6altivec8.o \
                   raid6mmx.o raid6sse1.o raid6sse2.o
-hostprogs-y    := mktables
+hostprogs-y    += mktables
 
 # Note: link order is important.  All raid personalities
 # and must come before md.o, as they each initialise 
@@ -26,6 +27,7 @@ obj-$(CONFIG_MD_LINEAR)               += linear.o
 obj-$(CONFIG_MD_RAID0)         += raid0.o
 obj-$(CONFIG_MD_RAID1)         += raid1.o
 obj-$(CONFIG_MD_RAID10)                += raid10.o
+obj-$(CONFIG_MD_RAID6_PQ)      += raid6_pq.o
 obj-$(CONFIG_MD_RAID456)       += raid456.o
 obj-$(CONFIG_MD_MULTIPATH)     += multipath.o
 obj-$(CONFIG_MD_FAULTY)                += faulty.o
index 719943763391263c7a4ab98ad0201244ce1d3d62..f8a9f7ab2cb8ac71884b87fb512a281db3c86789 100644 (file)
@@ -16,6 +16,7 @@
  * wait if count gets too high, wake when it drops to half.
  */
 
+#include <linux/blkdev.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -26,8 +27,8 @@
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/buffer_head.h>
-#include <linux/raid/md.h>
-#include <linux/raid/bitmap.h>
+#include "md.h"
+#include "bitmap.h"
 
 /* debug macros */
 
@@ -111,9 +112,10 @@ static int bitmap_checkpage(struct bitmap *bitmap, unsigned long page, int creat
        unsigned char *mappage;
 
        if (page >= bitmap->pages) {
-               printk(KERN_ALERT
-                       "%s: invalid bitmap page request: %lu (> %lu)\n",
-                       bmname(bitmap), page, bitmap->pages-1);
+               /* This can happen if bitmap_start_sync goes beyond
+                * End-of-device while looking for a whole page.
+                * It is harmless.
+                */
                return -EINVAL;
        }
 
@@ -265,7 +267,6 @@ static mdk_rdev_t *next_active_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
        list_for_each_continue_rcu(pos, &mddev->disks) {
                rdev = list_entry(pos, mdk_rdev_t, same_set);
                if (rdev->raid_disk >= 0 &&
-                   test_bit(In_sync, &rdev->flags) &&
                    !test_bit(Faulty, &rdev->flags)) {
                        /* this is a usable devices */
                        atomic_inc(&rdev->nr_pending);
@@ -297,7 +298,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
                                    + size/512 > 0)
                                        /* bitmap runs in to metadata */
                                        goto bad_alignment;
-                               if (rdev->data_offset + mddev->size*2
+                               if (rdev->data_offset + mddev->dev_sectors
                                    > rdev->sb_start + bitmap->offset)
                                        /* data runs in to bitmap */
                                        goto bad_alignment;
@@ -570,7 +571,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
        else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO ||
                 le32_to_cpu(sb->version) > BITMAP_MAJOR_HI)
                reason = "unrecognized superblock version";
-       else if (chunksize < PAGE_SIZE)
+       else if (chunksize < 512)
                reason = "bitmap chunksize too small";
        else if ((1 << ffz(~chunksize)) != chunksize)
                reason = "bitmap chunksize not a power of 2";
@@ -1306,6 +1307,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
                PRINTK(KERN_DEBUG "dec write-behind count %d/%d\n",
                  atomic_read(&bitmap->behind_writes), bitmap->max_write_behind);
        }
+       if (bitmap->mddev->degraded)
+               /* Never clear bits or update events_cleared when degraded */
+               success = 0;
 
        while (sectors) {
                int blocks;
@@ -1345,8 +1349,8 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
        }
 }
 
-int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks,
-                       int degraded)
+static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks,
+                              int degraded)
 {
        bitmap_counter_t *bmc;
        int rv;
@@ -1374,6 +1378,29 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks,
        return rv;
 }
 
+int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks,
+                     int degraded)
+{
+       /* bitmap_start_sync must always report on multiples of whole
+        * pages, otherwise resync (which is very PAGE_SIZE based) will
+        * get confused.
+        * So call __bitmap_start_sync repeatedly (if needed) until
+        * At least PAGE_SIZE>>9 blocks are covered.
+        * Return the 'or' of the result.
+        */
+       int rv = 0;
+       int blocks1;
+
+       *blocks = 0;
+       while (*blocks < (PAGE_SIZE>>9)) {
+               rv |= __bitmap_start_sync(bitmap, offset,
+                                         &blocks1, degraded);
+               offset += blocks1;
+               *blocks += blocks1;
+       }
+       return rv;
+}
+
 void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted)
 {
        bitmap_counter_t *bmc;
@@ -1443,6 +1470,8 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
        wait_event(bitmap->mddev->recovery_wait,
                   atomic_read(&bitmap->mddev->recovery_active) == 0);
 
+       bitmap->mddev->curr_resync_completed = bitmap->mddev->curr_resync;
+       set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags);
        sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1);
        s = 0;
        while (s < sector && s < bitmap->mddev->resync_max_sectors) {
index d4509be0fe67f78ecb91c0a5981d28ab9edd31cc..345098b4ca77ac77400c00e7598f2398bec04a06 100644 (file)
@@ -52,6 +52,16 @@ static inline void bio_list_add(struct bio_list *bl, struct bio *bio)
        bl->tail = bio;
 }
 
+static inline void bio_list_add_head(struct bio_list *bl, struct bio *bio)
+{
+       bio->bi_next = bl->head;
+
+       bl->head = bio;
+
+       if (!bl->tail)
+               bl->tail = bio;
+}
+
 static inline void bio_list_merge(struct bio_list *bl, struct bio_list *bl2)
 {
        if (!bl2->head)
index d3ec217847d68c9ca2b6d20ca4e9d2eb9cefc3f3..3a8cfa2645c72f6539170f2ab2d3242bb4a6fa58 100644 (file)
  * functions in this file help the target record and restore the
  * original bio state.
  */
+
+struct dm_bio_vec_details {
+#if PAGE_SIZE < 65536
+       __u16 bv_len;
+       __u16 bv_offset;
+#else
+       unsigned bv_len;
+       unsigned bv_offset;
+#endif
+};
+
 struct dm_bio_details {
        sector_t bi_sector;
        struct block_device *bi_bdev;
        unsigned int bi_size;
        unsigned short bi_idx;
        unsigned long bi_flags;
+       struct dm_bio_vec_details bi_io_vec[BIO_MAX_PAGES];
 };
 
 static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
 {
+       unsigned i;
+
        bd->bi_sector = bio->bi_sector;
        bd->bi_bdev = bio->bi_bdev;
        bd->bi_size = bio->bi_size;
        bd->bi_idx = bio->bi_idx;
        bd->bi_flags = bio->bi_flags;
+
+       for (i = 0; i < bio->bi_vcnt; i++) {
+               bd->bi_io_vec[i].bv_len = bio->bi_io_vec[i].bv_len;
+               bd->bi_io_vec[i].bv_offset = bio->bi_io_vec[i].bv_offset;
+       }
 }
 
 static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
 {
+       unsigned i;
+
        bio->bi_sector = bd->bi_sector;
        bio->bi_bdev = bd->bi_bdev;
        bio->bi_size = bd->bi_size;
        bio->bi_idx = bd->bi_idx;
        bio->bi_flags = bd->bi_flags;
+
+       for (i = 0; i < bio->bi_vcnt; i++) {
+               bio->bi_io_vec[i].bv_len = bd->bi_io_vec[i].bv_len;
+               bio->bi_io_vec[i].bv_offset = bd->bi_io_vec[i].bv_offset;
+       }
 }
 
 #endif
index bfefd079a9557b24c4d9d4f91646c1d5f2661942..53394e863c749db9444ab4ae4780b06a61afb8f1 100644 (file)
@@ -1156,8 +1156,7 @@ bad_ivmode:
        crypto_free_ablkcipher(tfm);
 bad_cipher:
        /* Must zero key material before freeing */
-       memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
-       kfree(cc);
+       kzfree(cc);
        return -EINVAL;
 }
 
@@ -1183,8 +1182,7 @@ static void crypt_dtr(struct dm_target *ti)
        dm_put_device(ti, cc->dev);
 
        /* Must zero key material before freeing */
-       memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
-       kfree(cc);
+       kzfree(cc);
 }
 
 static int crypt_map(struct dm_target *ti, struct bio *bio,
index dccbfb0e010fafc7b3470f06de29132b18124e57..a2e26c24214150cac23e92acf1391a212d60271b 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "dm-exception-store.h"
 
+#include <linux/ctype.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
 
 #define DM_MSG_PREFIX "snapshot exception stores"
 
+static LIST_HEAD(_exception_store_types);
+static DEFINE_SPINLOCK(_lock);
+
+static struct dm_exception_store_type *__find_exception_store_type(const char *name)
+{
+       struct dm_exception_store_type *type;
+
+       list_for_each_entry(type, &_exception_store_types, list)
+               if (!strcmp(name, type->name))
+                       return type;
+
+       return NULL;
+}
+
+static struct dm_exception_store_type *_get_exception_store_type(const char *name)
+{
+       struct dm_exception_store_type *type;
+
+       spin_lock(&_lock);
+
+       type = __find_exception_store_type(name);
+
+       if (type && !try_module_get(type->module))
+               type = NULL;
+
+       spin_unlock(&_lock);
+
+       return type;
+}
+
+/*
+ * get_type
+ * @type_name
+ *
+ * Attempt to retrieve the dm_exception_store_type by name.  If not already
+ * available, attempt to load the appropriate module.
+ *
+ * Exstore modules are named "dm-exstore-" followed by the 'type_name'.
+ * Modules may contain multiple types.
+ * This function will first try the module "dm-exstore-<type_name>",
+ * then truncate 'type_name' on the last '-' and try again.
+ *
+ * For example, if type_name was "clustered-shared", it would search
+ * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'.
+ *
+ * 'dm-exception-store-<type_name>' is too long of a name in my
+ * opinion, which is why I've chosen to have the files
+ * containing exception store implementations be 'dm-exstore-<type_name>'.
+ * If you want your module to be autoloaded, you will follow this
+ * naming convention.
+ *
+ * Returns: dm_exception_store_type* on success, NULL on failure
+ */
+static struct dm_exception_store_type *get_type(const char *type_name)
+{
+       char *p, *type_name_dup;
+       struct dm_exception_store_type *type;
+
+       type = _get_exception_store_type(type_name);
+       if (type)
+               return type;
+
+       type_name_dup = kstrdup(type_name, GFP_KERNEL);
+       if (!type_name_dup) {
+               DMERR("No memory left to attempt load for \"%s\"", type_name);
+               return NULL;
+       }
+
+       while (request_module("dm-exstore-%s", type_name_dup) ||
+              !(type = _get_exception_store_type(type_name))) {
+               p = strrchr(type_name_dup, '-');
+               if (!p)
+                       break;
+               p[0] = '\0';
+       }
+
+       if (!type)
+               DMWARN("Module for exstore type \"%s\" not found.", type_name);
+
+       kfree(type_name_dup);
+
+       return type;
+}
+
+static void put_type(struct dm_exception_store_type *type)
+{
+       spin_lock(&_lock);
+       module_put(type->module);
+       spin_unlock(&_lock);
+}
+
+int dm_exception_store_type_register(struct dm_exception_store_type *type)
+{
+       int r = 0;
+
+       spin_lock(&_lock);
+       if (!__find_exception_store_type(type->name))
+               list_add(&type->list, &_exception_store_types);
+       else
+               r = -EEXIST;
+       spin_unlock(&_lock);
+
+       return r;
+}
+EXPORT_SYMBOL(dm_exception_store_type_register);
+
+int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
+{
+       spin_lock(&_lock);
+
+       if (!__find_exception_store_type(type->name)) {
+               spin_unlock(&_lock);
+               return -EINVAL;
+       }
+
+       list_del(&type->list);
+
+       spin_unlock(&_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(dm_exception_store_type_unregister);
+
+/*
+ * Round a number up to the nearest 'size' boundary.  size must
+ * be a power of 2.
+ */
+static ulong round_up(ulong n, ulong size)
+{
+       size--;
+       return (n + size) & ~size;
+}
+
+static int set_chunk_size(struct dm_exception_store *store,
+                         const char *chunk_size_arg, char **error)
+{
+       unsigned long chunk_size_ulong;
+       char *value;
+
+       chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
+       if (*chunk_size_arg == '\0' || *value != '\0') {
+               *error = "Invalid chunk size";
+               return -EINVAL;
+       }
+
+       if (!chunk_size_ulong) {
+               store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
+               return 0;
+       }
+
+       /*
+        * Chunk size must be multiple of page size.  Silently
+        * round up if it's not.
+        */
+       chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9);
+
+       /* Check chunk_size is a power of 2 */
+       if (!is_power_of_2(chunk_size_ulong)) {
+               *error = "Chunk size is not a power of 2";
+               return -EINVAL;
+       }
+
+       /* Validate the chunk size against the device block size */
+       if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) {
+               *error = "Chunk size is not a multiple of device blocksize";
+               return -EINVAL;
+       }
+
+       store->chunk_size = chunk_size_ulong;
+       store->chunk_mask = chunk_size_ulong - 1;
+       store->chunk_shift = ffs(chunk_size_ulong) - 1;
+
+       return 0;
+}
+
+int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
+                             unsigned *args_used,
+                             struct dm_exception_store **store)
+{
+       int r = 0;
+       struct dm_exception_store_type *type;
+       struct dm_exception_store *tmp_store;
+       char persistent;
+
+       if (argc < 3) {
+               ti->error = "Insufficient exception store arguments";
+               return -EINVAL;
+       }
+
+       tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
+       if (!tmp_store) {
+               ti->error = "Exception store allocation failed";
+               return -ENOMEM;
+       }
+
+       persistent = toupper(*argv[1]);
+       if (persistent != 'P' && persistent != 'N') {
+               ti->error = "Persistent flag is not P or N";
+               return -EINVAL;
+       }
+
+       type = get_type(argv[1]);
+       if (!type) {
+               ti->error = "Exception store type not recognised";
+               r = -EINVAL;
+               goto bad_type;
+       }
+
+       tmp_store->type = type;
+       tmp_store->ti = ti;
+
+       r = dm_get_device(ti, argv[0], 0, 0,
+                         FMODE_READ | FMODE_WRITE, &tmp_store->cow);
+       if (r) {
+               ti->error = "Cannot get COW device";
+               goto bad_cow;
+       }
+
+       r = set_chunk_size(tmp_store, argv[2], &ti->error);
+       if (r)
+               goto bad_cow;
+
+       r = type->ctr(tmp_store, 0, NULL);
+       if (r) {
+               ti->error = "Exception store type constructor failed";
+               goto bad_ctr;
+       }
+
+       *args_used = 3;
+       *store = tmp_store;
+       return 0;
+
+bad_ctr:
+       dm_put_device(ti, tmp_store->cow);
+bad_cow:
+       put_type(type);
+bad_type:
+       kfree(tmp_store);
+       return r;
+}
+EXPORT_SYMBOL(dm_exception_store_create);
+
+void dm_exception_store_destroy(struct dm_exception_store *store)
+{
+       store->type->dtr(store);
+       dm_put_device(store->ti, store->cow);
+       put_type(store->type);
+       kfree(store);
+}
+EXPORT_SYMBOL(dm_exception_store_destroy);
+
 int dm_exception_store_init(void)
 {
        int r;
index bb9f33d5daa2169127d96fd9ebfcbe41d1cc819b..0a2e6e7f67b3c5b6ac4c4cbd7dc2ca6811eaa30c 100644 (file)
@@ -37,11 +37,18 @@ struct dm_snap_exception {
  * Abstraction to handle the meta/layout of exception stores (the
  * COW device).
  */
-struct dm_exception_store {
+struct dm_exception_store;
+struct dm_exception_store_type {
+       const char *name;
+       struct module *module;
+
+       int (*ctr) (struct dm_exception_store *store,
+                   unsigned argc, char **argv);
+
        /*
         * Destroys this object when you've finished with it.
         */
-       void (*destroy) (struct dm_exception_store *store);
+       void (*dtr) (struct dm_exception_store *store);
 
        /*
         * The target shouldn't read the COW device until this is
@@ -72,8 +79,9 @@ struct dm_exception_store {
         */
        void (*drop_snapshot) (struct dm_exception_store *store);
 
-       int (*status) (struct dm_exception_store *store, status_type_t status,
-                      char *result, unsigned int maxlen);
+       unsigned (*status) (struct dm_exception_store *store,
+                           status_type_t status, char *result,
+                           unsigned maxlen);
 
        /*
         * Return how full the snapshot is.
@@ -82,7 +90,21 @@ struct dm_exception_store {
                               sector_t *numerator,
                               sector_t *denominator);
 
-       struct dm_snapshot *snap;
+       /* For internal device-mapper use only. */
+       struct list_head list;
+};
+
+struct dm_exception_store {
+       struct dm_exception_store_type *type;
+       struct dm_target *ti;
+
+       struct dm_dev *cow;
+
+       /* Size of data blocks saved - must be a power of 2 */
+       chunk_t chunk_size;
+       chunk_t chunk_mask;
+       chunk_t chunk_shift;
+
        void *context;
 };
 
@@ -129,6 +151,28 @@ static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
 
 #  endif
 
+/*
+ * Return the number of sectors in the device.
+ */
+static inline sector_t get_dev_size(struct block_device *bdev)
+{
+       return bdev->bd_inode->i_size >> SECTOR_SHIFT;
+}
+
+static inline chunk_t sector_to_chunk(struct dm_exception_store *store,
+                                     sector_t sector)
+{
+       return (sector & ~store->chunk_mask) >> store->chunk_shift;
+}
+
+int dm_exception_store_type_register(struct dm_exception_store_type *type);
+int dm_exception_store_type_unregister(struct dm_exception_store_type *type);
+
+int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
+                             unsigned *args_used,
+                             struct dm_exception_store **store);
+void dm_exception_store_destroy(struct dm_exception_store *store);
+
 int dm_exception_store_init(void);
 void dm_exception_store_exit(void);
 
@@ -141,8 +185,4 @@ void dm_persistent_snapshot_exit(void);
 int dm_transient_snapshot_init(void);
 void dm_transient_snapshot_exit(void);
 
-int dm_create_persistent(struct dm_exception_store *store);
-
-int dm_create_transient(struct dm_exception_store *store);
-
 #endif /* _LINUX_DM_EXCEPTION_STORE */
index 36e2b5e46a6b644f0e9902b57b29c0666541d733..e73aabd61cd78abdbc63996704c177e6aea399d1 100644 (file)
@@ -370,16 +370,13 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
        while (1) {
                set_current_state(TASK_UNINTERRUPTIBLE);
 
-               if (!atomic_read(&io.count) || signal_pending(current))
+               if (!atomic_read(&io.count))
                        break;
 
                io_schedule();
        }
        set_current_state(TASK_RUNNING);
 
-       if (atomic_read(&io.count))
-               return -EINTR;
-
        if (error_bits)
                *error_bits = io.error_bits;
 
index 737961f275c196f9b6aa41957dd08c72457c597b..be233bc4d91787a2729ef8ca740a946ddc782332 100644 (file)
 
 #define DM_MSG_PREFIX "dirty region log"
 
-struct dm_dirty_log_internal {
-       struct dm_dirty_log_type *type;
-
-       struct list_head list;
-       long use;
-};
-
 static LIST_HEAD(_log_types);
 static DEFINE_SPINLOCK(_lock);
 
-static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name)
+static struct dm_dirty_log_type *__find_dirty_log_type(const char *name)
 {
-       struct dm_dirty_log_internal *log_type;
+       struct dm_dirty_log_type *log_type;
 
        list_for_each_entry(log_type, &_log_types, list)
-               if (!strcmp(name, log_type->type->name))
+               if (!strcmp(name, log_type->name))
                        return log_type;
 
        return NULL;
 }
 
-static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name)
+static struct dm_dirty_log_type *_get_dirty_log_type(const char *name)
 {
-       struct dm_dirty_log_internal *log_type;
+       struct dm_dirty_log_type *log_type;
 
        spin_lock(&_lock);
 
        log_type = __find_dirty_log_type(name);
-       if (log_type) {
-               if (!log_type->use && !try_module_get(log_type->type->module))
-                       log_type = NULL;
-               else
-                       log_type->use++;
-       }
+       if (log_type && !try_module_get(log_type->module))
+               log_type = NULL;
 
        spin_unlock(&_lock);
 
@@ -76,14 +65,14 @@ static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name)
 static struct dm_dirty_log_type *get_type(const char *type_name)
 {
        char *p, *type_name_dup;
-       struct dm_dirty_log_internal *log_type;
+       struct dm_dirty_log_type *log_type;
 
        if (!type_name)
                return NULL;
 
        log_type = _get_dirty_log_type(type_name);
        if (log_type)
-               return log_type->type;
+               return log_type;
 
        type_name_dup = kstrdup(type_name, GFP_KERNEL);
        if (!type_name_dup) {
@@ -105,56 +94,33 @@ static struct dm_dirty_log_type *get_type(const char *type_name)
 
        kfree(type_name_dup);
 
-       return log_type ? log_type->type : NULL;
+       return log_type;
 }
 
 static void put_type(struct dm_dirty_log_type *type)
 {
-       struct dm_dirty_log_internal *log_type;
-
        if (!type)
                return;
 
        spin_lock(&_lock);
-       log_type = __find_dirty_log_type(type->name);
-       if (!log_type)
+       if (!__find_dirty_log_type(type->name))
                goto out;
 
-       if (!--log_type->use)
-               module_put(type->module);
-
-       BUG_ON(log_type->use < 0);
+       module_put(type->module);
 
 out:
        spin_unlock(&_lock);
 }
 
-static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type)
-{
-       struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type),
-                                                        GFP_KERNEL);
-
-       if (log_type)
-               log_type->type = type;
-
-       return log_type;
-}
-
 int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
 {
-       struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type);
        int r = 0;
 
-       if (!log_type)
-               return -ENOMEM;
-
        spin_lock(&_lock);
        if (!__find_dirty_log_type(type->name))
-               list_add(&log_type->list, &_log_types);
-       else {
-               kfree(log_type);
+               list_add(&type->list, &_log_types);
+       else
                r = -EEXIST;
-       }
        spin_unlock(&_lock);
 
        return r;
@@ -163,25 +129,16 @@ EXPORT_SYMBOL(dm_dirty_log_type_register);
 
 int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
 {
-       struct dm_dirty_log_internal *log_type;
-
        spin_lock(&_lock);
 
-       log_type = __find_dirty_log_type(type->name);
-       if (!log_type) {
+       if (!__find_dirty_log_type(type->name)) {
                spin_unlock(&_lock);
                return -EINVAL;
        }
 
-       if (log_type->use) {
-               spin_unlock(&_lock);
-               return -ETXTBSY;
-       }
-
-       list_del(&log_type->list);
+       list_del(&type->list);
 
        spin_unlock(&_lock);
-       kfree(log_type);
 
        return 0;
 }
index 96ea226155b10e3dbb560b3faa8c2211ec11f41f..42c04f04a0c4c84e28bb1cd05e56a19370d5e565 100644 (file)
@@ -17,9 +17,7 @@
 
 struct ps_internal {
        struct path_selector_type pst;
-
        struct list_head list;
-       long use;
 };
 
 #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
@@ -45,12 +43,8 @@ static struct ps_internal *get_path_selector(const char *name)
 
        down_read(&_ps_lock);
        psi = __find_path_selector_type(name);
-       if (psi) {
-               if ((psi->use == 0) && !try_module_get(psi->pst.module))
-                       psi = NULL;
-               else
-                       psi->use++;
-       }
+       if (psi && !try_module_get(psi->pst.module))
+               psi = NULL;
        up_read(&_ps_lock);
 
        return psi;
@@ -84,11 +78,7 @@ void dm_put_path_selector(struct path_selector_type *pst)
        if (!psi)
                goto out;
 
-       if (--psi->use == 0)
-               module_put(psi->pst.module);
-
-       BUG_ON(psi->use < 0);
-
+       module_put(psi->pst.module);
 out:
        up_read(&_ps_lock);
 }
@@ -136,11 +126,6 @@ int dm_unregister_path_selector(struct path_selector_type *pst)
                return -EINVAL;
        }
 
-       if (psi->use) {
-               up_write(&_ps_lock);
-               return -ETXTBSY;
-       }
-
        list_del(&psi->list);
 
        up_write(&_ps_lock);
index 4d6bc101962e1965a1b98e0cc1e87363be4bcc3a..536ef0bef154e507aae4f738c01c52e7d166d798 100644 (file)
@@ -145,6 +145,8 @@ struct dm_raid1_read_record {
        struct dm_bio_details details;
 };
 
+static struct kmem_cache *_dm_raid1_read_record_cache;
+
 /*
  * Every mirror should look like this one.
  */
@@ -586,6 +588,9 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
        int state;
        struct bio *bio;
        struct bio_list sync, nosync, recover, *this_list = NULL;
+       struct bio_list requeue;
+       struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
+       region_t region;
 
        if (!writes->head)
                return;
@@ -596,10 +601,18 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
        bio_list_init(&sync);
        bio_list_init(&nosync);
        bio_list_init(&recover);
+       bio_list_init(&requeue);
 
        while ((bio = bio_list_pop(writes))) {
-               state = dm_rh_get_state(ms->rh,
-                                       dm_rh_bio_to_region(ms->rh, bio), 1);
+               region = dm_rh_bio_to_region(ms->rh, bio);
+
+               if (log->type->is_remote_recovering &&
+                   log->type->is_remote_recovering(log, region)) {
+                       bio_list_add(&requeue, bio);
+                       continue;
+               }
+
+               state = dm_rh_get_state(ms->rh, region, 1);
                switch (state) {
                case DM_RH_CLEAN:
                case DM_RH_DIRTY:
@@ -618,6 +631,16 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
                bio_list_add(this_list, bio);
        }
 
+       /*
+        * Add bios that are delayed due to remote recovery
+        * back on to the write queue
+        */
+       if (unlikely(requeue.head)) {
+               spin_lock_irq(&ms->lock);
+               bio_list_merge(&ms->writes, &requeue);
+               spin_unlock_irq(&ms->lock);
+       }
+
        /*
         * Increment the pending counts for any regions that will
         * be written to (writes to recover regions are going to
@@ -764,9 +787,9 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
        atomic_set(&ms->suspend, 0);
        atomic_set(&ms->default_mirror, DEFAULT_MIRROR);
 
-       len = sizeof(struct dm_raid1_read_record);
-       ms->read_record_pool = mempool_create_kmalloc_pool(MIN_READ_RECORDS,
-                                                          len);
+       ms->read_record_pool = mempool_create_slab_pool(MIN_READ_RECORDS,
+                                               _dm_raid1_read_record_cache);
+
        if (!ms->read_record_pool) {
                ti->error = "Error creating mirror read_record_pool";
                kfree(ms);
@@ -1279,16 +1302,31 @@ static int __init dm_mirror_init(void)
 {
        int r;
 
+       _dm_raid1_read_record_cache = KMEM_CACHE(dm_raid1_read_record, 0);
+       if (!_dm_raid1_read_record_cache) {
+               DMERR("Can't allocate dm_raid1_read_record cache");
+               r = -ENOMEM;
+               goto bad_cache;
+       }
+
        r = dm_register_target(&mirror_target);
-       if (r < 0)
+       if (r < 0) {
                DMERR("Failed to register mirror target");
+               goto bad_target;
+       }
+
+       return 0;
 
+bad_target:
+       kmem_cache_destroy(_dm_raid1_read_record_cache);
+bad_cache:
        return r;
 }
 
 static void __exit dm_mirror_exit(void)
 {
        dm_unregister_target(&mirror_target);
+       kmem_cache_destroy(_dm_raid1_read_record_cache);
 }
 
 /* Module hooks */
index 936b34e0959fdd5cdeaa6eddc51dee888fb05447..e75c6dd76a9adfb3b374aa9cc6d48a2db14596be 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include "dm-exception-store.h"
-#include "dm-snap.h"
 
 #include <linux/mm.h>
 #include <linux/pagemap.h>
@@ -89,7 +88,7 @@ struct commit_callback {
  * The top level structure for a persistent exception store.
  */
 struct pstore {
-       struct dm_snapshot *snap;       /* up pointer to my snapshot */
+       struct dm_exception_store *store;
        int version;
        int valid;
        uint32_t exceptions_per_area;
@@ -141,7 +140,7 @@ static int alloc_area(struct pstore *ps)
        int r = -ENOMEM;
        size_t len;
 
-       len = ps->snap->chunk_size << SECTOR_SHIFT;
+       len = ps->store->chunk_size << SECTOR_SHIFT;
 
        /*
         * Allocate the chunk_size block of memory that will hold
@@ -163,9 +162,12 @@ static int alloc_area(struct pstore *ps)
 
 static void free_area(struct pstore *ps)
 {
-       vfree(ps->area);
+       if (ps->area)
+               vfree(ps->area);
        ps->area = NULL;
-       vfree(ps->zero_area);
+
+       if (ps->zero_area)
+               vfree(ps->zero_area);
        ps->zero_area = NULL;
 }
 
@@ -189,9 +191,9 @@ static void do_metadata(struct work_struct *work)
 static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata)
 {
        struct dm_io_region where = {
-               .bdev = ps->snap->cow->bdev,
-               .sector = ps->snap->chunk_size * chunk,
-               .count = ps->snap->chunk_size,
+               .bdev = ps->store->cow->bdev,
+               .sector = ps->store->chunk_size * chunk,
+               .count = ps->store->chunk_size,
        };
        struct dm_io_request io_req = {
                .bi_rw = rw,
@@ -247,15 +249,15 @@ static int area_io(struct pstore *ps, int rw)
 
 static void zero_memory_area(struct pstore *ps)
 {
-       memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
+       memset(ps->area, 0, ps->store->chunk_size << SECTOR_SHIFT);
 }
 
 static int zero_disk_area(struct pstore *ps, chunk_t area)
 {
        struct dm_io_region where = {
-               .bdev = ps->snap->cow->bdev,
-               .sector = ps->snap->chunk_size * area_location(ps, area),
-               .count = ps->snap->chunk_size,
+               .bdev = ps->store->cow->bdev,
+               .sector = ps->store->chunk_size * area_location(ps, area),
+               .count = ps->store->chunk_size,
        };
        struct dm_io_request io_req = {
                .bi_rw = WRITE,
@@ -278,15 +280,15 @@ static int read_header(struct pstore *ps, int *new_snapshot)
        /*
         * Use default chunk size (or hardsect_size, if larger) if none supplied
         */
-       if (!ps->snap->chunk_size) {
-               ps->snap->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
-                   bdev_hardsect_size(ps->snap->cow->bdev) >> 9);
-               ps->snap->chunk_mask = ps->snap->chunk_size - 1;
-               ps->snap->chunk_shift = ffs(ps->snap->chunk_size) - 1;
+       if (!ps->store->chunk_size) {
+               ps->store->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
+                   bdev_hardsect_size(ps->store->cow->bdev) >> 9);
+               ps->store->chunk_mask = ps->store->chunk_size - 1;
+               ps->store->chunk_shift = ffs(ps->store->chunk_size) - 1;
                chunk_size_supplied = 0;
        }
 
-       ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->
+       ps->io_client = dm_io_client_create(sectors_to_pages(ps->store->
                                                             chunk_size));
        if (IS_ERR(ps->io_client))
                return PTR_ERR(ps->io_client);
@@ -317,22 +319,22 @@ static int read_header(struct pstore *ps, int *new_snapshot)
        ps->version = le32_to_cpu(dh->version);
        chunk_size = le32_to_cpu(dh->chunk_size);
 
-       if (!chunk_size_supplied || ps->snap->chunk_size == chunk_size)
+       if (!chunk_size_supplied || ps->store->chunk_size == chunk_size)
                return 0;
 
        DMWARN("chunk size %llu in device metadata overrides "
               "table chunk size of %llu.",
               (unsigned long long)chunk_size,
-              (unsigned long long)ps->snap->chunk_size);
+              (unsigned long long)ps->store->chunk_size);
 
        /* We had a bogus chunk_size. Fix stuff up. */
        free_area(ps);
 
-       ps->snap->chunk_size = chunk_size;
-       ps->snap->chunk_mask = chunk_size - 1;
-       ps->snap->chunk_shift = ffs(chunk_size) - 1;
+       ps->store->chunk_size = chunk_size;
+       ps->store->chunk_mask = chunk_size - 1;
+       ps->store->chunk_shift = ffs(chunk_size) - 1;
 
-       r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),
+       r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size),
                                ps->io_client);
        if (r)
                return r;
@@ -349,13 +351,13 @@ static int write_header(struct pstore *ps)
 {
        struct disk_header *dh;
 
-       memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
+       memset(ps->area, 0, ps->store->chunk_size << SECTOR_SHIFT);
 
        dh = (struct disk_header *) ps->area;
        dh->magic = cpu_to_le32(SNAP_MAGIC);
        dh->valid = cpu_to_le32(ps->valid);
        dh->version = cpu_to_le32(ps->version);
-       dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);
+       dh->chunk_size = cpu_to_le32(ps->store->chunk_size);
 
        return chunk_io(ps, 0, WRITE, 1);
 }
@@ -474,18 +476,25 @@ static struct pstore *get_info(struct dm_exception_store *store)
 static void persistent_fraction_full(struct dm_exception_store *store,
                                     sector_t *numerator, sector_t *denominator)
 {
-       *numerator = get_info(store)->next_free * store->snap->chunk_size;
-       *denominator = get_dev_size(store->snap->cow->bdev);
+       *numerator = get_info(store)->next_free * store->chunk_size;
+       *denominator = get_dev_size(store->cow->bdev);
 }
 
-static void persistent_destroy(struct dm_exception_store *store)
+static void persistent_dtr(struct dm_exception_store *store)
 {
        struct pstore *ps = get_info(store);
 
        destroy_workqueue(ps->metadata_wq);
-       dm_io_client_destroy(ps->io_client);
-       vfree(ps->callbacks);
+
+       /* Created in read_header */
+       if (ps->io_client)
+               dm_io_client_destroy(ps->io_client);
        free_area(ps);
+
+       /* Allocated in persistent_read_metadata */
+       if (ps->callbacks)
+               vfree(ps->callbacks);
+
        kfree(ps);
 }
 
@@ -507,7 +516,7 @@ static int persistent_read_metadata(struct dm_exception_store *store,
        /*
         * Now we know correct chunk_size, complete the initialisation.
         */
-       ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) /
+       ps->exceptions_per_area = (ps->store->chunk_size << SECTOR_SHIFT) /
                                  sizeof(struct disk_exception);
        ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
                        sizeof(*ps->callbacks));
@@ -564,10 +573,10 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
        struct pstore *ps = get_info(store);
        uint32_t stride;
        chunk_t next_free;
-       sector_t size = get_dev_size(store->snap->cow->bdev);
+       sector_t size = get_dev_size(store->cow->bdev);
 
        /* Is there enough room ? */
-       if (size < ((ps->next_free + 1) * store->snap->chunk_size))
+       if (size < ((ps->next_free + 1) * store->chunk_size))
                return -ENOSPC;
 
        e->new_chunk = ps->next_free;
@@ -656,16 +665,17 @@ static void persistent_drop_snapshot(struct dm_exception_store *store)
                DMWARN("write header failed");
 }
 
-int dm_create_persistent(struct dm_exception_store *store)
+static int persistent_ctr(struct dm_exception_store *store,
+                         unsigned argc, char **argv)
 {
        struct pstore *ps;
 
        /* allocate the pstore */
-       ps = kmalloc(sizeof(*ps), GFP_KERNEL);
+       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
        if (!ps)
                return -ENOMEM;
 
-       ps->snap = store->snap;
+       ps->store = store;
        ps->valid = 1;
        ps->version = SNAPSHOT_DISK_VERSION;
        ps->area = NULL;
@@ -683,22 +693,77 @@ int dm_create_persistent(struct dm_exception_store *store)
                return -ENOMEM;
        }
 
-       store->destroy = persistent_destroy;
-       store->read_metadata = persistent_read_metadata;
-       store->prepare_exception = persistent_prepare_exception;
-       store->commit_exception = persistent_commit_exception;
-       store->drop_snapshot = persistent_drop_snapshot;
-       store->fraction_full = persistent_fraction_full;
        store->context = ps;
 
        return 0;
 }
 
+static unsigned persistent_status(struct dm_exception_store *store,
+                                 status_type_t status, char *result,
+                                 unsigned maxlen)
+{
+       unsigned sz = 0;
+
+       switch (status) {
+       case STATUSTYPE_INFO:
+               break;
+       case STATUSTYPE_TABLE:
+               DMEMIT(" %s P %llu", store->cow->name,
+                      (unsigned long long)store->chunk_size);
+       }
+
+       return sz;
+}
+
+static struct dm_exception_store_type _persistent_type = {
+       .name = "persistent",
+       .module = THIS_MODULE,
+       .ctr = persistent_ctr,
+       .dtr = persistent_dtr,
+       .read_metadata = persistent_read_metadata,
+       .prepare_exception = persistent_prepare_exception,
+       .commit_exception = persistent_commit_exception,
+       .drop_snapshot = persistent_drop_snapshot,
+       .fraction_full = persistent_fraction_full,
+       .status = persistent_status,
+};
+
+static struct dm_exception_store_type _persistent_compat_type = {
+       .name = "P",
+       .module = THIS_MODULE,
+       .ctr = persistent_ctr,
+       .dtr = persistent_dtr,
+       .read_metadata = persistent_read_metadata,
+       .prepare_exception = persistent_prepare_exception,
+       .commit_exception = persistent_commit_exception,
+       .drop_snapshot = persistent_drop_snapshot,
+       .fraction_full = persistent_fraction_full,
+       .status = persistent_status,
+};
+
 int dm_persistent_snapshot_init(void)
 {
-       return 0;
+       int r;
+
+       r = dm_exception_store_type_register(&_persistent_type);
+       if (r) {
+               DMERR("Unable to register persistent exception store type");
+               return r;
+       }
+
+       r = dm_exception_store_type_register(&_persistent_compat_type);
+       if (r) {
+               DMERR("Unable to register old-style persistent exception "
+                     "store type");
+               dm_exception_store_type_unregister(&_persistent_type);
+               return r;
+       }
+
+       return r;
 }
 
 void dm_persistent_snapshot_exit(void)
 {
+       dm_exception_store_type_unregister(&_persistent_type);
+       dm_exception_store_type_unregister(&_persistent_compat_type);
 }
index 7f6e2e6dcb0ddcfa78ba071af928dac0f5401682..cde5aa558e6d77b7d1130777762f8aec84c86ab1 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include "dm-exception-store.h"
-#include "dm-snap.h"
 
 #include <linux/mm.h>
 #include <linux/pagemap.h>
@@ -23,7 +22,7 @@ struct transient_c {
        sector_t next_free;
 };
 
-static void transient_destroy(struct dm_exception_store *store)
+static void transient_dtr(struct dm_exception_store *store)
 {
        kfree(store->context);
 }
@@ -39,14 +38,14 @@ static int transient_read_metadata(struct dm_exception_store *store,
 static int transient_prepare_exception(struct dm_exception_store *store,
                                       struct dm_snap_exception *e)
 {
-       struct transient_c *tc = (struct transient_c *) store->context;
-       sector_t size = get_dev_size(store->snap->cow->bdev);
+       struct transient_c *tc = store->context;
+       sector_t size = get_dev_size(store->cow->bdev);
 
-       if (size < (tc->next_free + store->snap->chunk_size))
+       if (size < (tc->next_free + store->chunk_size))
                return -1;
 
-       e->new_chunk = sector_to_chunk(store->snap, tc->next_free);
-       tc->next_free += store->snap->chunk_size;
+       e->new_chunk = sector_to_chunk(store, tc->next_free);
+       tc->next_free += store->chunk_size;
 
        return 0;
 }
@@ -64,20 +63,14 @@ static void transient_fraction_full(struct dm_exception_store *store,
                                    sector_t *numerator, sector_t *denominator)
 {
        *numerator = ((struct transient_c *) store->context)->next_free;
-       *denominator = get_dev_size(store->snap->cow->bdev);
+       *denominator = get_dev_size(store->cow->bdev);
 }
 
-int dm_create_transient(struct dm_exception_store *store)
+static int transient_ctr(struct dm_exception_store *store,
+                        unsigned argc, char **argv)
 {
        struct transient_c *tc;
 
-       store->destroy = transient_destroy;
-       store->read_metadata = transient_read_metadata;
-       store->prepare_exception = transient_prepare_exception;
-       store->commit_exception = transient_commit_exception;
-       store->drop_snapshot = NULL;
-       store->fraction_full = transient_fraction_full;
-
        tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
        if (!tc)
                return -ENOMEM;
@@ -88,11 +81,70 @@ int dm_create_transient(struct dm_exception_store *store)
        return 0;
 }
 
+static unsigned transient_status(struct dm_exception_store *store,
+                                status_type_t status, char *result,
+                                unsigned maxlen)
+{
+       unsigned sz = 0;
+
+       switch (status) {
+       case STATUSTYPE_INFO:
+               break;
+       case STATUSTYPE_TABLE:
+               DMEMIT(" %s N %llu", store->cow->name,
+                      (unsigned long long)store->chunk_size);
+       }
+
+       return sz;
+}
+
+static struct dm_exception_store_type _transient_type = {
+       .name = "transient",
+       .module = THIS_MODULE,
+       .ctr = transient_ctr,
+       .dtr = transient_dtr,
+       .read_metadata = transient_read_metadata,
+       .prepare_exception = transient_prepare_exception,
+       .commit_exception = transient_commit_exception,
+       .fraction_full = transient_fraction_full,
+       .status = transient_status,
+};
+
+static struct dm_exception_store_type _transient_compat_type = {
+       .name = "N",
+       .module = THIS_MODULE,
+       .ctr = transient_ctr,
+       .dtr = transient_dtr,
+       .read_metadata = transient_read_metadata,
+       .prepare_exception = transient_prepare_exception,
+       .commit_exception = transient_commit_exception,
+       .fraction_full = transient_fraction_full,
+       .status = transient_status,
+};
+
 int dm_transient_snapshot_init(void)
 {
-       return 0;
+       int r;
+
+       r = dm_exception_store_type_register(&_transient_type);
+       if (r) {
+               DMWARN("Unable to register transient exception store type");
+               return r;
+       }
+
+       r = dm_exception_store_type_register(&_transient_compat_type);
+       if (r) {
+               DMWARN("Unable to register old-style transient "
+                      "exception store type");
+               dm_exception_store_type_unregister(&_transient_type);
+               return r;
+       }
+
+       return r;
 }
 
 void dm_transient_snapshot_exit(void)
 {
+       dm_exception_store_type_unregister(&_transient_type);
+       dm_exception_store_type_unregister(&_transient_compat_type);
 }
index 65ff82ff124e29a3c7cfedf276df89646fcbc2ac..981a0413068f8028c90e7da039cf5d48fcc27b9b 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/blkdev.h>
-#include <linux/ctype.h>
 #include <linux/device-mapper.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
@@ -20,9 +19,9 @@
 #include <linux/vmalloc.h>
 #include <linux/log2.h>
 #include <linux/dm-kcopyd.h>
+#include <linux/workqueue.h>
 
 #include "dm-exception-store.h"
-#include "dm-snap.h"
 #include "dm-bio-list.h"
 
 #define DM_MSG_PREFIX "snapshots"
  */
 #define MIN_IOS 256
 
+#define DM_TRACKED_CHUNK_HASH_SIZE     16
+#define DM_TRACKED_CHUNK_HASH(x)       ((unsigned long)(x) & \
+                                        (DM_TRACKED_CHUNK_HASH_SIZE - 1))
+
+struct exception_table {
+       uint32_t hash_mask;
+       unsigned hash_shift;
+       struct list_head *table;
+};
+
+struct dm_snapshot {
+       struct rw_semaphore lock;
+
+       struct dm_dev *origin;
+
+       /* List of snapshots per Origin */
+       struct list_head list;
+
+       /* You can't use a snapshot if this is 0 (e.g. if full) */
+       int valid;
+
+       /* Origin writes don't trigger exceptions until this is set */
+       int active;
+
+       mempool_t *pending_pool;
+
+       atomic_t pending_exceptions_count;
+
+       struct exception_table pending;
+       struct exception_table complete;
+
+       /*
+        * pe_lock protects all pending_exception operations and access
+        * as well as the snapshot_bios list.
+        */
+       spinlock_t pe_lock;
+
+       /* The on disk metadata handler */
+       struct dm_exception_store *store;
+
+       struct dm_kcopyd_client *kcopyd_client;
+
+       /* Queue of snapshot writes for ksnapd to flush */
+       struct bio_list queued_bios;
+       struct work_struct queued_bios_work;
+
+       /* Chunks with outstanding reads */
+       mempool_t *tracked_chunk_pool;
+       spinlock_t tracked_chunk_lock;
+       struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
+};
+
 static struct workqueue_struct *ksnapd;
 static void flush_queued_bios(struct work_struct *work);
 
+static sector_t chunk_to_sector(struct dm_exception_store *store,
+                               chunk_t chunk)
+{
+       return chunk << store->chunk_shift;
+}
+
+static int bdev_equal(struct block_device *lhs, struct block_device *rhs)
+{
+       /*
+        * There is only ever one instance of a particular block
+        * device so we can compare pointers safely.
+        */
+       return lhs == rhs;
+}
+
 struct dm_snap_pending_exception {
        struct dm_snap_exception e;
 
@@ -476,11 +542,11 @@ static int init_hash_tables(struct dm_snapshot *s)
         * Calculate based on the size of the original volume or
         * the COW volume...
         */
-       cow_dev_size = get_dev_size(s->cow->bdev);
+       cow_dev_size = get_dev_size(s->store->cow->bdev);
        origin_dev_size = get_dev_size(s->origin->bdev);
        max_buckets = calc_max_buckets();
 
-       hash_size = min(origin_dev_size, cow_dev_size) >> s->chunk_shift;
+       hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift;
        hash_size = min(hash_size, max_buckets);
 
        hash_size = rounddown_pow_of_two(hash_size);
@@ -504,58 +570,6 @@ static int init_hash_tables(struct dm_snapshot *s)
        return 0;
 }
 
-/*
- * Round a number up to the nearest 'size' boundary.  size must
- * be a power of 2.
- */
-static ulong round_up(ulong n, ulong size)
-{
-       size--;
-       return (n + size) & ~size;
-}
-
-static int set_chunk_size(struct dm_snapshot *s, const char *chunk_size_arg,
-                         char **error)
-{
-       unsigned long chunk_size;
-       char *value;
-
-       chunk_size = simple_strtoul(chunk_size_arg, &value, 10);
-       if (*chunk_size_arg == '\0' || *value != '\0') {
-               *error = "Invalid chunk size";
-               return -EINVAL;
-       }
-
-       if (!chunk_size) {
-               s->chunk_size = s->chunk_mask = s->chunk_shift = 0;
-               return 0;
-       }
-
-       /*
-        * Chunk size must be multiple of page size.  Silently
-        * round up if it's not.
-        */
-       chunk_size = round_up(chunk_size, PAGE_SIZE >> 9);
-
-       /* Check chunk_size is a power of 2 */
-       if (!is_power_of_2(chunk_size)) {
-               *error = "Chunk size is not a power of 2";
-               return -EINVAL;
-       }
-
-       /* Validate the chunk size against the device block size */
-       if (chunk_size % (bdev_hardsect_size(s->cow->bdev) >> 9)) {
-               *error = "Chunk size is not a multiple of device blocksize";
-               return -EINVAL;
-       }
-
-       s->chunk_size = chunk_size;
-       s->chunk_mask = chunk_size - 1;
-       s->chunk_shift = ffs(chunk_size) - 1;
-
-       return 0;
-}
-
 /*
  * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
  */
@@ -564,91 +578,68 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        struct dm_snapshot *s;
        int i;
        int r = -EINVAL;
-       char persistent;
        char *origin_path;
-       char *cow_path;
+       struct dm_exception_store *store;
+       unsigned args_used;
 
        if (argc != 4) {
                ti->error = "requires exactly 4 arguments";
                r = -EINVAL;
-               goto bad1;
+               goto bad_args;
        }
 
        origin_path = argv[0];
-       cow_path = argv[1];
-       persistent = toupper(*argv[2]);
+       argv++;
+       argc--;
 
-       if (persistent != 'P' && persistent != 'N') {
-               ti->error = "Persistent flag is not P or N";
+       r = dm_exception_store_create(ti, argc, argv, &args_used, &store);
+       if (r) {
+               ti->error = "Couldn't create exception store";
                r = -EINVAL;
-               goto bad1;
+               goto bad_args;
        }
 
+       argv += args_used;
+       argc -= args_used;
+
        s = kmalloc(sizeof(*s), GFP_KERNEL);
-       if (s == NULL) {
+       if (!s) {
                ti->error = "Cannot allocate snapshot context private "
                    "structure";
                r = -ENOMEM;
-               goto bad1;
+               goto bad_snap;
        }
 
        r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
        if (r) {
                ti->error = "Cannot get origin device";
-               goto bad2;
-       }
-
-       r = dm_get_device(ti, cow_path, 0, 0,
-                         FMODE_READ | FMODE_WRITE, &s->cow);
-       if (r) {
-               dm_put_device(ti, s->origin);
-               ti->error = "Cannot get COW device";
-               goto bad2;
+               goto bad_origin;
        }
 
-       r = set_chunk_size(s, argv[3], &ti->error);
-       if (r)
-               goto bad3;
-
-       s->type = persistent;
-
+       s->store = store;
        s->valid = 1;
        s->active = 0;
        atomic_set(&s->pending_exceptions_count, 0);
        init_rwsem(&s->lock);
        spin_lock_init(&s->pe_lock);
-       s->ti = ti;
 
        /* Allocate hash table for COW data */
        if (init_hash_tables(s)) {
                ti->error = "Unable to allocate hash table space";
                r = -ENOMEM;
-               goto bad3;
-       }
-
-       s->store.snap = s;
-
-       if (persistent == 'P')
-               r = dm_create_persistent(&s->store);
-       else
-               r = dm_create_transient(&s->store);
-
-       if (r) {
-               ti->error = "Couldn't create exception store";
-               r = -EINVAL;
-               goto bad4;
+               goto bad_hash_tables;
        }
 
        r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
        if (r) {
                ti->error = "Could not create kcopyd client";
-               goto bad5;
+               goto bad_kcopyd;
        }
 
        s->pending_pool = mempool_create_slab_pool(MIN_IOS, pending_cache);
        if (!s->pending_pool) {
                ti->error = "Could not allocate mempool for pending exceptions";
-               goto bad6;
+               goto bad_pending_pool;
        }
 
        s->tracked_chunk_pool = mempool_create_slab_pool(MIN_IOS,
@@ -665,7 +656,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        spin_lock_init(&s->tracked_chunk_lock);
 
        /* Metadata must only be loaded into one table at once */
-       r = s->store.read_metadata(&s->store, dm_add_exception, (void *)s);
+       r = s->store->type->read_metadata(s->store, dm_add_exception,
+                                         (void *)s);
        if (r < 0) {
                ti->error = "Failed to read snapshot metadata";
                goto bad_load_and_register;
@@ -686,34 +678,33 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ti->private = s;
-       ti->split_io = s->chunk_size;
+       ti->split_io = s->store->chunk_size;
 
        return 0;
 
- bad_load_and_register:
+bad_load_and_register:
        mempool_destroy(s->tracked_chunk_pool);
 
- bad_tracked_chunk_pool:
+bad_tracked_chunk_pool:
        mempool_destroy(s->pending_pool);
 
- bad6:
+bad_pending_pool:
        dm_kcopyd_client_destroy(s->kcopyd_client);
 
- bad5:
-       s->store.destroy(&s->store);
-
- bad4:
+bad_kcopyd:
        exit_exception_table(&s->pending, pending_cache);
        exit_exception_table(&s->complete, exception_cache);
 
- bad3:
-       dm_put_device(ti, s->cow);
+bad_hash_tables:
        dm_put_device(ti, s->origin);
 
- bad2:
+bad_origin:
        kfree(s);
 
- bad1:
+bad_snap:
+       dm_exception_store_destroy(store);
+
+bad_args:
        return r;
 }
 
@@ -724,8 +715,6 @@ static void __free_exceptions(struct dm_snapshot *s)
 
        exit_exception_table(&s->pending, pending_cache);
        exit_exception_table(&s->complete, exception_cache);
-
-       s->store.destroy(&s->store);
 }
 
 static void snapshot_dtr(struct dm_target *ti)
@@ -761,7 +750,8 @@ static void snapshot_dtr(struct dm_target *ti)
        mempool_destroy(s->pending_pool);
 
        dm_put_device(ti, s->origin);
-       dm_put_device(ti, s->cow);
+
+       dm_exception_store_destroy(s->store);
 
        kfree(s);
 }
@@ -820,12 +810,12 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
        else if (err == -ENOMEM)
                DMERR("Invalidating snapshot: Unable to allocate exception.");
 
-       if (s->store.drop_snapshot)
-               s->store.drop_snapshot(&s->store);
+       if (s->store->type->drop_snapshot)
+               s->store->type->drop_snapshot(s->store);
 
        s->valid = 0;
 
-       dm_table_event(s->ti->table);
+       dm_table_event(s->store->ti->table);
 }
 
 static void get_pending_exception(struct dm_snap_pending_exception *pe)
@@ -943,8 +933,8 @@ static void copy_callback(int read_err, unsigned long write_err, void *context)
 
        else
                /* Update the metadata if we are persistent */
-               s->store.commit_exception(&s->store, &pe->e, commit_callback,
-                                         pe);
+               s->store->type->commit_exception(s->store, &pe->e,
+                                                commit_callback, pe);
 }
 
 /*
@@ -960,11 +950,11 @@ static void start_copy(struct dm_snap_pending_exception *pe)
        dev_size = get_dev_size(bdev);
 
        src.bdev = bdev;
-       src.sector = chunk_to_sector(s, pe->e.old_chunk);
-       src.count = min(s->chunk_size, dev_size - src.sector);
+       src.sector = chunk_to_sector(s->store, pe->e.old_chunk);
+       src.count = min(s->store->chunk_size, dev_size - src.sector);
 
-       dest.bdev = s->cow->bdev;
-       dest.sector = chunk_to_sector(s, pe->e.new_chunk);
+       dest.bdev = s->store->cow->bdev;
+       dest.sector = chunk_to_sector(s->store, pe->e.new_chunk);
        dest.count = src.count;
 
        /* Hand over to kcopyd */
@@ -972,6 +962,17 @@ static void start_copy(struct dm_snap_pending_exception *pe)
                    &src, 1, &dest, 0, copy_callback, pe);
 }
 
+static struct dm_snap_pending_exception *
+__lookup_pending_exception(struct dm_snapshot *s, chunk_t chunk)
+{
+       struct dm_snap_exception *e = lookup_exception(&s->pending, chunk);
+
+       if (!e)
+               return NULL;
+
+       return container_of(e, struct dm_snap_pending_exception, e);
+}
+
 /*
  * Looks to see if this snapshot already has a pending exception
  * for this chunk, otherwise it allocates a new one and inserts
@@ -981,40 +982,15 @@ static void start_copy(struct dm_snap_pending_exception *pe)
  * this.
  */
 static struct dm_snap_pending_exception *
-__find_pending_exception(struct dm_snapshot *s, struct bio *bio)
+__find_pending_exception(struct dm_snapshot *s,
+                        struct dm_snap_pending_exception *pe, chunk_t chunk)
 {
-       struct dm_snap_exception *e;
-       struct dm_snap_pending_exception *pe;
-       chunk_t chunk = sector_to_chunk(s, bio->bi_sector);
+       struct dm_snap_pending_exception *pe2;
 
-       /*
-        * Is there a pending exception for this already ?
-        */
-       e = lookup_exception(&s->pending, chunk);
-       if (e) {
-               /* cast the exception to a pending exception */
-               pe = container_of(e, struct dm_snap_pending_exception, e);
-               goto out;
-       }
-
-       /*
-        * Create a new pending exception, we don't want
-        * to hold the lock while we do this.
-        */
-       up_write(&s->lock);
-       pe = alloc_pending_exception(s);
-       down_write(&s->lock);
-
-       if (!s->valid) {
-               free_pending_exception(pe);
-               return NULL;
-       }
-
-       e = lookup_exception(&s->pending, chunk);
-       if (e) {
+       pe2 = __lookup_pending_exception(s, chunk);
+       if (pe2) {
                free_pending_exception(pe);
-               pe = container_of(e, struct dm_snap_pending_exception, e);
-               goto out;
+               return pe2;
        }
 
        pe->e.old_chunk = chunk;
@@ -1024,7 +1000,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
        atomic_set(&pe->ref_count, 0);
        pe->started = 0;
 
-       if (s->store.prepare_exception(&s->store, &pe->e)) {
+       if (s->store->type->prepare_exception(s->store, &pe->e)) {
                free_pending_exception(pe);
                return NULL;
        }
@@ -1032,17 +1008,18 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
        get_pending_exception(pe);
        insert_exception(&s->pending, &pe->e);
 
- out:
        return pe;
 }
 
 static void remap_exception(struct dm_snapshot *s, struct dm_snap_exception *e,
                            struct bio *bio, chunk_t chunk)
 {
-       bio->bi_bdev = s->cow->bdev;
-       bio->bi_sector = chunk_to_sector(s, dm_chunk_number(e->new_chunk) +
-                        (chunk - e->old_chunk)) +
-                        (bio->bi_sector & s->chunk_mask);
+       bio->bi_bdev = s->store->cow->bdev;
+       bio->bi_sector = chunk_to_sector(s->store,
+                                        dm_chunk_number(e->new_chunk) +
+                                        (chunk - e->old_chunk)) +
+                                        (bio->bi_sector &
+                                         s->store->chunk_mask);
 }
 
 static int snapshot_map(struct dm_target *ti, struct bio *bio,
@@ -1054,7 +1031,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
        chunk_t chunk;
        struct dm_snap_pending_exception *pe = NULL;
 
-       chunk = sector_to_chunk(s, bio->bi_sector);
+       chunk = sector_to_chunk(s->store, bio->bi_sector);
 
        /* Full snapshots are not usable */
        /* To get here the table must be live so s->active is always set. */
@@ -1083,11 +1060,31 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
         * writeable.
         */
        if (bio_rw(bio) == WRITE) {
-               pe = __find_pending_exception(s, bio);
+               pe = __lookup_pending_exception(s, chunk);
                if (!pe) {
-                       __invalidate_snapshot(s, -ENOMEM);
-                       r = -EIO;
-                       goto out_unlock;
+                       up_write(&s->lock);
+                       pe = alloc_pending_exception(s);
+                       down_write(&s->lock);
+
+                       if (!s->valid) {
+                               free_pending_exception(pe);
+                               r = -EIO;
+                               goto out_unlock;
+                       }
+
+                       e = lookup_exception(&s->complete, chunk);
+                       if (e) {
+                               free_pending_exception(pe);
+                               remap_exception(s, e, bio, chunk);
+                               goto out_unlock;
+                       }
+
+                       pe = __find_pending_exception(s, pe, chunk);
+                       if (!pe) {
+                               __invalidate_snapshot(s, -ENOMEM);
+                               r = -EIO;
+                               goto out_unlock;
+                       }
                }
 
                remap_exception(s, &pe->e, bio, chunk);
@@ -1137,24 +1134,25 @@ static void snapshot_resume(struct dm_target *ti)
 static int snapshot_status(struct dm_target *ti, status_type_t type,
                           char *result, unsigned int maxlen)
 {
+       unsigned sz = 0;
        struct dm_snapshot *snap = ti->private;
 
        switch (type) {
        case STATUSTYPE_INFO:
                if (!snap->valid)
-                       snprintf(result, maxlen, "Invalid");
+                       DMEMIT("Invalid");
                else {
-                       if (snap->store.fraction_full) {
+                       if (snap->store->type->fraction_full) {
                                sector_t numerator, denominator;
-                               snap->store.fraction_full(&snap->store,
-                                                         &numerator,
-                                                         &denominator);
-                               snprintf(result, maxlen, "%llu/%llu",
-                                       (unsigned long long)numerator,
-                                       (unsigned long long)denominator);
+                               snap->store->type->fraction_full(snap->store,
+                                                                &numerator,
+                                                                &denominator);
+                               DMEMIT("%llu/%llu",
+                                      (unsigned long long)numerator,
+                                      (unsigned long long)denominator);
                        }
                        else
-                               snprintf(result, maxlen, "Unknown");
+                               DMEMIT("Unknown");
                }
                break;
 
@@ -1164,10 +1162,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
                 * to make private copies if the output is to
                 * make sense.
                 */
-               snprintf(result, maxlen, "%s %s %c %llu",
-                        snap->origin->name, snap->cow->name,
-                        snap->type,
-                        (unsigned long long)snap->chunk_size);
+               DMEMIT("%s", snap->origin->name);
+               snap->store->type->status(snap->store, type, result + sz,
+                                         maxlen - sz);
                break;
        }
 
@@ -1196,14 +1193,14 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
                        goto next_snapshot;
 
                /* Nothing to do if writing beyond end of snapshot */
-               if (bio->bi_sector >= dm_table_get_size(snap->ti->table))
+               if (bio->bi_sector >= dm_table_get_size(snap->store->ti->table))
                        goto next_snapshot;
 
                /*
                 * Remember, different snapshots can have
                 * different chunk sizes.
                 */
-               chunk = sector_to_chunk(snap, bio->bi_sector);
+               chunk = sector_to_chunk(snap->store, bio->bi_sector);
 
                /*
                 * Check exception table to see if block
@@ -1217,10 +1214,28 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
                if (e)
                        goto next_snapshot;
 
-               pe = __find_pending_exception(snap, bio);
+               pe = __lookup_pending_exception(snap, chunk);
                if (!pe) {
-                       __invalidate_snapshot(snap, -ENOMEM);
-                       goto next_snapshot;
+                       up_write(&snap->lock);
+                       pe = alloc_pending_exception(snap);
+                       down_write(&snap->lock);
+
+                       if (!snap->valid) {
+                               free_pending_exception(pe);
+                               goto next_snapshot;
+                       }
+
+                       e = lookup_exception(&snap->complete, chunk);
+                       if (e) {
+                               free_pending_exception(pe);
+                               goto next_snapshot;
+                       }
+
+                       pe = __find_pending_exception(snap, pe, chunk);
+                       if (!pe) {
+                               __invalidate_snapshot(snap, -ENOMEM);
+                               goto next_snapshot;
+                       }
                }
 
                if (!primary_pe) {
@@ -1360,7 +1375,8 @@ static void origin_resume(struct dm_target *ti)
        o = __lookup_origin(dev->bdev);
        if (o)
                list_for_each_entry (snap, &o->snapshots, list)
-                       chunk_size = min_not_zero(chunk_size, snap->chunk_size);
+                       chunk_size = min_not_zero(chunk_size,
+                                                 snap->store->chunk_size);
        up_read(&_origins_lock);
 
        ti->split_io = chunk_size;
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
deleted file mode 100644 (file)
index d9e62b4..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
- *
- * This file is released under the GPL.
- */
-
-#ifndef DM_SNAPSHOT_H
-#define DM_SNAPSHOT_H
-
-#include <linux/device-mapper.h>
-#include "dm-exception-store.h"
-#include "dm-bio-list.h"
-#include <linux/blkdev.h>
-#include <linux/workqueue.h>
-
-struct exception_table {
-       uint32_t hash_mask;
-       unsigned hash_shift;
-       struct list_head *table;
-};
-
-#define DM_TRACKED_CHUNK_HASH_SIZE     16
-#define DM_TRACKED_CHUNK_HASH(x)       ((unsigned long)(x) & \
-                                        (DM_TRACKED_CHUNK_HASH_SIZE - 1))
-
-struct dm_snapshot {
-       struct rw_semaphore lock;
-       struct dm_target *ti;
-
-       struct dm_dev *origin;
-       struct dm_dev *cow;
-
-       /* List of snapshots per Origin */
-       struct list_head list;
-
-       /* Size of data blocks saved - must be a power of 2 */
-       chunk_t chunk_size;
-       chunk_t chunk_mask;
-       chunk_t chunk_shift;
-
-       /* You can't use a snapshot if this is 0 (e.g. if full) */
-       int valid;
-
-       /* Origin writes don't trigger exceptions until this is set */
-       int active;
-
-       /* Used for display of table */
-       char type;
-
-       mempool_t *pending_pool;
-
-       atomic_t pending_exceptions_count;
-
-       struct exception_table pending;
-       struct exception_table complete;
-
-       /*
-        * pe_lock protects all pending_exception operations and access
-        * as well as the snapshot_bios list.
-        */
-       spinlock_t pe_lock;
-
-       /* The on disk metadata handler */
-       struct dm_exception_store store;
-
-       struct dm_kcopyd_client *kcopyd_client;
-
-       /* Queue of snapshot writes for ksnapd to flush */
-       struct bio_list queued_bios;
-       struct work_struct queued_bios_work;
-
-       /* Chunks with outstanding reads */
-       mempool_t *tracked_chunk_pool;
-       spinlock_t tracked_chunk_lock;
-       struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
-};
-
-/*
- * Return the number of sectors in the device.
- */
-static inline sector_t get_dev_size(struct block_device *bdev)
-{
-       return bdev->bd_inode->i_size >> SECTOR_SHIFT;
-}
-
-static inline chunk_t sector_to_chunk(struct dm_snapshot *s, sector_t sector)
-{
-       return (sector & ~s->chunk_mask) >> s->chunk_shift;
-}
-
-static inline sector_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk)
-{
-       return chunk << s->chunk_shift;
-}
-
-static inline int bdev_equal(struct block_device *lhs, struct block_device *rhs)
-{
-       /*
-        * There is only ever one instance of a particular block
-        * device so we can compare pointers safely.
-        */
-       return lhs == rhs;
-}
-
-#endif
index 2fd66c30f7f8b02fd699f7b3c5cab52bd6f4d89d..e8361b191b9b223baef941bfc14212dc052d127f 100644 (file)
@@ -399,28 +399,30 @@ static int check_device_area(struct dm_dev_internal *dd, sector_t start,
 }
 
 /*
- * This upgrades the mode on an already open dm_dev.  Being
+ * This upgrades the mode on an already open dm_dev, being
  * careful to leave things as they were if we fail to reopen the
- * device.
+ * device and not to touch the existing bdev field in case
+ * it is accessed concurrently inside dm_table_any_congested().
  */
 static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
                        struct mapped_device *md)
 {
        int r;
-       struct dm_dev_internal dd_copy;
-       dev_t dev = dd->dm_dev.bdev->bd_dev;
+       struct dm_dev_internal dd_new, dd_old;
 
-       dd_copy = *dd;
+       dd_new = dd_old = *dd;
+
+       dd_new.dm_dev.mode |= new_mode;
+       dd_new.dm_dev.bdev = NULL;
+
+       r = open_dev(&dd_new, dd->dm_dev.bdev->bd_dev, md);
+       if (r)
+               return r;
 
        dd->dm_dev.mode |= new_mode;
-       dd->dm_dev.bdev = NULL;
-       r = open_dev(dd, dev, md);
-       if (!r)
-               close_dev(&dd_copy, md);
-       else
-               *dd = dd_copy;
+       close_dev(&dd_old, md);
 
-       return r;
+       return 0;
 }
 
 /*
index 7decf10006e41cf9b3372544fa60eff54d195923..04feccf2a997947968260029419e7813cb222553 100644 (file)
 
 #define DM_MSG_PREFIX "target"
 
-struct tt_internal {
-       struct target_type tt;
-
-       struct list_head list;
-       long use;
-};
-
 static LIST_HEAD(_targets);
 static DECLARE_RWSEM(_lock);
 
 #define DM_MOD_NAME_SIZE 32
 
-static inline struct tt_internal *__find_target_type(const char *name)
+static inline struct target_type *__find_target_type(const char *name)
 {
-       struct tt_internal *ti;
+       struct target_type *tt;
 
-       list_for_each_entry (ti, &_targets, list)
-               if (!strcmp(name, ti->tt.name))
-                       return ti;
+       list_for_each_entry(tt, &_targets, list)
+               if (!strcmp(name, tt->name))
+                       return tt;
 
        return NULL;
 }
 
-static struct tt_internal *get_target_type(const char *name)
+static struct target_type *get_target_type(const char *name)
 {
-       struct tt_internal *ti;
+       struct target_type *tt;
 
        down_read(&_lock);
 
-       ti = __find_target_type(name);
-       if (ti) {
-               if ((ti->use == 0) && !try_module_get(ti->tt.module))
-                       ti = NULL;
-               else
-                       ti->use++;
-       }
+       tt = __find_target_type(name);
+       if (tt && !try_module_get(tt->module))
+               tt = NULL;
 
        up_read(&_lock);
-       return ti;
+       return tt;
 }
 
 static void load_module(const char *name)
@@ -62,92 +51,59 @@ static void load_module(const char *name)
 
 struct target_type *dm_get_target_type(const char *name)
 {
-       struct tt_internal *ti = get_target_type(name);
+       struct target_type *tt = get_target_type(name);
 
-       if (!ti) {
+       if (!tt) {
                load_module(name);
-               ti = get_target_type(name);
+               tt = get_target_type(name);
        }
 
-       return ti ? &ti->tt : NULL;
+       return tt;
 }
 
-void dm_put_target_type(struct target_type *t)
+void dm_put_target_type(struct target_type *tt)
 {
-       struct tt_internal *ti = (struct tt_internal *) t;
-
        down_read(&_lock);
-       if (--ti->use == 0)
-               module_put(ti->tt.module);
-
-       BUG_ON(ti->use < 0);
+       module_put(tt->module);
        up_read(&_lock);
-
-       return;
-}
-
-static struct tt_internal *alloc_target(struct target_type *t)
-{
-       struct tt_internal *ti = kzalloc(sizeof(*ti), GFP_KERNEL);
-
-       if (ti)
-               ti->tt = *t;
-
-       return ti;
 }
 
-
 int dm_target_iterate(void (*iter_func)(struct target_type *tt,
                                        void *param), void *param)
 {
-       struct tt_internal *ti;
+       struct target_type *tt;
 
        down_read(&_lock);
-       list_for_each_entry (ti, &_targets, list)
-               iter_func(&ti->tt, param);
+       list_for_each_entry(tt, &_targets, list)
+               iter_func(tt, param);
        up_read(&_lock);
 
        return 0;
 }
 
-int dm_register_target(struct target_type *t)
+int dm_register_target(struct target_type *tt)
 {
        int rv = 0;
-       struct tt_internal *ti = alloc_target(t);
-
-       if (!ti)
-               return -ENOMEM;
 
        down_write(&_lock);
-       if (__find_target_type(t->name))
+       if (__find_target_type(tt->name))
                rv = -EEXIST;
        else
-               list_add(&ti->list, &_targets);
+               list_add(&tt->list, &_targets);
 
        up_write(&_lock);
-       if (rv)
-               kfree(ti);
        return rv;
 }
 
-void dm_unregister_target(struct target_type *t)
+void dm_unregister_target(struct target_type *tt)
 {
-       struct tt_internal *ti;
-
        down_write(&_lock);
-       if (!(ti = __find_target_type(t->name))) {
-               DMCRIT("Unregistering unrecognised target: %s", t->name);
-               BUG();
-       }
-
-       if (ti->use) {
-               DMCRIT("Attempt to unregister target still in use: %s",
-                      t->name);
+       if (!__find_target_type(tt->name)) {
+               DMCRIT("Unregistering unrecognised target: %s", tt->name);
                BUG();
        }
 
-       list_del(&ti->list);
-       kfree(ti);
+       list_del(&tt->list);
 
        up_write(&_lock);
 }
@@ -156,17 +112,17 @@ void dm_unregister_target(struct target_type *t)
  * io-err: always fails an io, useful for bringing
  * up LVs that have holes in them.
  */
-static int io_err_ctr(struct dm_target *ti, unsigned int argc, char **args)
+static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
 {
        return 0;
 }
 
-static void io_err_dtr(struct dm_target *ti)
+static void io_err_dtr(struct dm_target *tt)
 {
        /* empty */
 }
 
-static int io_err_map(struct dm_target *ti, struct bio *bio,
+static int io_err_map(struct dm_target *tt, struct bio *bio,
                      union map_info *map_context)
 {
        return -EIO;
index 8d40f27cce894e4a3c489a7d84d321fb39b363d6..788ba96a6256aaed6de8625d306cc4d5e33a82f9 100644 (file)
@@ -99,19 +99,9 @@ union map_info *dm_get_mapinfo(struct bio *bio)
 /*
  * Work processed by per-device workqueue.
  */
-struct dm_wq_req {
-       enum {
-               DM_WQ_FLUSH_DEFERRED,
-       } type;
-       struct work_struct work;
-       struct mapped_device *md;
-       void *context;
-};
-
 struct mapped_device {
        struct rw_semaphore io_lock;
        struct mutex suspend_lock;
-       spinlock_t pushback_lock;
        rwlock_t map_lock;
        atomic_t holders;
        atomic_t open_count;
@@ -129,8 +119,9 @@ struct mapped_device {
         */
        atomic_t pending;
        wait_queue_head_t wait;
+       struct work_struct work;
        struct bio_list deferred;
-       struct bio_list pushback;
+       spinlock_t deferred_lock;
 
        /*
         * Processing queue (flush/barriers)
@@ -453,7 +444,9 @@ static int queue_io(struct mapped_device *md, struct bio *bio)
                return 1;
        }
 
+       spin_lock_irq(&md->deferred_lock);
        bio_list_add(&md->deferred, bio);
+       spin_unlock_irq(&md->deferred_lock);
 
        up_write(&md->io_lock);
        return 0;               /* deferred successfully */
@@ -537,16 +530,14 @@ static void dec_pending(struct dm_io *io, int error)
                if (io->error == DM_ENDIO_REQUEUE) {
                        /*
                         * Target requested pushing back the I/O.
-                        * This must be handled before the sleeper on
-                        * suspend queue merges the pushback list.
                         */
-                       spin_lock_irqsave(&md->pushback_lock, flags);
+                       spin_lock_irqsave(&md->deferred_lock, flags);
                        if (__noflush_suspending(md))
-                               bio_list_add(&md->pushback, io->bio);
+                               bio_list_add(&md->deferred, io->bio);
                        else
                                /* noflush suspend was interrupted. */
                                io->error = -EIO;
-                       spin_unlock_irqrestore(&md->pushback_lock, flags);
+                       spin_unlock_irqrestore(&md->deferred_lock, flags);
                }
 
                end_io_acct(io);
@@ -834,20 +825,22 @@ static int __clone_and_map(struct clone_info *ci)
 }
 
 /*
- * Split the bio into several clones.
+ * Split the bio into several clones and submit it to targets.
  */
-static int __split_bio(struct mapped_device *md, struct bio *bio)
+static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
 {
        struct clone_info ci;
        int error = 0;
 
        ci.map = dm_get_table(md);
-       if (unlikely(!ci.map))
-               return -EIO;
+       if (unlikely(!ci.map)) {
+               bio_io_error(bio);
+               return;
+       }
        if (unlikely(bio_barrier(bio) && !dm_table_barrier_ok(ci.map))) {
                dm_table_put(ci.map);
                bio_endio(bio, -EOPNOTSUPP);
-               return 0;
+               return;
        }
        ci.md = md;
        ci.bio = bio;
@@ -867,8 +860,6 @@ static int __split_bio(struct mapped_device *md, struct bio *bio)
        /* drop the extra reference count */
        dec_pending(ci.io, error);
        dm_table_put(ci.map);
-
-       return 0;
 }
 /*-----------------------------------------------------------------
  * CRUD END
@@ -959,8 +950,9 @@ static int dm_request(struct request_queue *q, struct bio *bio)
                down_read(&md->io_lock);
        }
 
-       r = __split_bio(md, bio);
+       __split_and_process_bio(md, bio);
        up_read(&md->io_lock);
+       return 0;
 
 out_req:
        if (r < 0)
@@ -1074,6 +1066,8 @@ out:
 
 static struct block_device_operations dm_blk_dops;
 
+static void dm_wq_work(struct work_struct *work);
+
 /*
  * Allocate and initialise a blank device with a given minor.
  */
@@ -1101,7 +1095,7 @@ static struct mapped_device *alloc_dev(int minor)
 
        init_rwsem(&md->io_lock);
        mutex_init(&md->suspend_lock);
-       spin_lock_init(&md->pushback_lock);
+       spin_lock_init(&md->deferred_lock);
        rwlock_init(&md->map_lock);
        atomic_set(&md->holders, 1);
        atomic_set(&md->open_count, 0);
@@ -1118,6 +1112,7 @@ static struct mapped_device *alloc_dev(int minor)
        md->queue->backing_dev_info.congested_fn = dm_any_congested;
        md->queue->backing_dev_info.congested_data = md;
        blk_queue_make_request(md->queue, dm_request);
+       blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL);
        blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
        md->queue->unplug_fn = dm_unplug_all;
        blk_queue_merge_bvec(md->queue, dm_merge_bvec);
@@ -1140,6 +1135,7 @@ static struct mapped_device *alloc_dev(int minor)
 
        atomic_set(&md->pending, 0);
        init_waitqueue_head(&md->wait);
+       INIT_WORK(&md->work, dm_wq_work);
        init_waitqueue_head(&md->eventq);
 
        md->disk->major = _major;
@@ -1379,18 +1375,24 @@ void dm_put(struct mapped_device *md)
 }
 EXPORT_SYMBOL_GPL(dm_put);
 
-static int dm_wait_for_completion(struct mapped_device *md)
+static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
 {
        int r = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       dm_unplug_all(md->queue);
+
+       add_wait_queue(&md->wait, &wait);
 
        while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
+               set_current_state(interruptible);
 
                smp_mb();
                if (!atomic_read(&md->pending))
                        break;
 
-               if (signal_pending(current)) {
+               if (interruptible == TASK_INTERRUPTIBLE &&
+                   signal_pending(current)) {
                        r = -EINTR;
                        break;
                }
@@ -1399,67 +1401,40 @@ static int dm_wait_for_completion(struct mapped_device *md)
        }
        set_current_state(TASK_RUNNING);
 
+       remove_wait_queue(&md->wait, &wait);
+
        return r;
 }
 
 /*
  * Process the deferred bios
  */
-static void __flush_deferred_io(struct mapped_device *md)
+static void dm_wq_work(struct work_struct *work)
 {
+       struct mapped_device *md = container_of(work, struct mapped_device,
+                                               work);
        struct bio *c;
 
-       while ((c = bio_list_pop(&md->deferred))) {
-               if (__split_bio(md, c))
-                       bio_io_error(c);
-       }
-
-       clear_bit(DMF_BLOCK_IO, &md->flags);
-}
+       down_write(&md->io_lock);
 
-static void __merge_pushback_list(struct mapped_device *md)
-{
-       unsigned long flags;
+next_bio:
+       spin_lock_irq(&md->deferred_lock);
+       c = bio_list_pop(&md->deferred);
+       spin_unlock_irq(&md->deferred_lock);
 
-       spin_lock_irqsave(&md->pushback_lock, flags);
-       clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
-       bio_list_merge_head(&md->deferred, &md->pushback);
-       bio_list_init(&md->pushback);
-       spin_unlock_irqrestore(&md->pushback_lock, flags);
-}
+       if (c) {
+               __split_and_process_bio(md, c);
+               goto next_bio;
+       }
 
-static void dm_wq_work(struct work_struct *work)
-{
-       struct dm_wq_req *req = container_of(work, struct dm_wq_req, work);
-       struct mapped_device *md = req->md;
+       clear_bit(DMF_BLOCK_IO, &md->flags);
 
-       down_write(&md->io_lock);
-       switch (req->type) {
-       case DM_WQ_FLUSH_DEFERRED:
-               __flush_deferred_io(md);
-               break;
-       default:
-               DMERR("dm_wq_work: unrecognised work type %d", req->type);
-               BUG();
-       }
        up_write(&md->io_lock);
 }
 
-static void dm_wq_queue(struct mapped_device *md, int type, void *context,
-                       struct dm_wq_req *req)
-{
-       req->type = type;
-       req->md = md;
-       req->context = context;
-       INIT_WORK(&req->work, dm_wq_work);
-       queue_work(md->wq, &req->work);
-}
-
-static void dm_queue_flush(struct mapped_device *md, int type, void *context)
+static void dm_queue_flush(struct mapped_device *md)
 {
-       struct dm_wq_req req;
-
-       dm_wq_queue(md, type, context, &req);
+       queue_work(md->wq, &md->work);
        flush_workqueue(md->wq);
 }
 
@@ -1534,7 +1509,6 @@ static void unlock_fs(struct mapped_device *md)
 int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
 {
        struct dm_table *map = NULL;
-       DECLARE_WAITQUEUE(wait, current);
        int r = 0;
        int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0;
        int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0;
@@ -1584,28 +1558,22 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
        down_write(&md->io_lock);
        set_bit(DMF_BLOCK_IO, &md->flags);
 
-       add_wait_queue(&md->wait, &wait);
        up_write(&md->io_lock);
 
-       /* unplug */
-       if (map)
-               dm_table_unplug_all(map);
-
        /*
         * Wait for the already-mapped ios to complete.
         */
-       r = dm_wait_for_completion(md);
+       r = dm_wait_for_completion(md, TASK_INTERRUPTIBLE);
 
        down_write(&md->io_lock);
-       remove_wait_queue(&md->wait, &wait);
 
        if (noflush)
-               __merge_pushback_list(md);
+               clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
        up_write(&md->io_lock);
 
        /* were we interrupted ? */
        if (r < 0) {
-               dm_queue_flush(md, DM_WQ_FLUSH_DEFERRED, NULL);
+               dm_queue_flush(md);
 
                unlock_fs(md);
                goto out; /* pushback list is already flushed, so skip flush */
@@ -1645,7 +1613,7 @@ int dm_resume(struct mapped_device *md)
        if (r)
                goto out;
 
-       dm_queue_flush(md, DM_WQ_FLUSH_DEFERRED, NULL);
+       dm_queue_flush(md);
 
        unlock_fs(md);
 
index 20194e000c5afcda9e10965d17c945b0df5d7171..b48397c0abbd44b253c37ce56db3647f7513eb9f 100644 (file)
@@ -60,7 +60,7 @@ int dm_table_barrier_ok(struct dm_table *t);
 int dm_target_init(void);
 void dm_target_exit(void);
 struct target_type *dm_get_target_type(const char *name);
-void dm_put_target_type(struct target_type *t);
+void dm_put_target_type(struct target_type *tt);
 int dm_target_iterate(void (*iter_func)(struct target_type *tt,
                                        void *param), void *param);
 
index 86d9adf90e791857efdf674117168398b40735a1..8695809b24b05f049c13a3dc667bf2a02d9b4ba6 100644 (file)
 #define        ModeShift       5
 
 #define MaxFault       50
-#include <linux/raid/md.h>
+#include <linux/blkdev.h>
+#include <linux/raid/md_u.h>
+#include "md.h"
+#include <linux/seq_file.h>
 
 
 static void faulty_fail(struct bio *bio, int error)
@@ -280,6 +283,17 @@ static int reconfig(mddev_t *mddev, int layout, int chunk_size)
        return 0;
 }
 
+static sector_t faulty_size(mddev_t *mddev, sector_t sectors, int raid_disks)
+{
+       WARN_ONCE(raid_disks,
+                 "%s does not support generic reshape\n", __func__);
+
+       if (sectors == 0)
+               return mddev->dev_sectors;
+
+       return sectors;
+}
+
 static int run(mddev_t *mddev)
 {
        mdk_rdev_t *rdev;
@@ -298,7 +312,7 @@ static int run(mddev_t *mddev)
        list_for_each_entry(rdev, &mddev->disks, same_set)
                conf->rdev = rdev;
 
-       mddev->array_sectors = mddev->size * 2;
+       md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
        mddev->private = conf;
 
        reconfig(mddev, mddev->layout, -1);
@@ -325,6 +339,7 @@ static struct mdk_personality faulty_personality =
        .stop           = stop,
        .status         = status,
        .reconfig       = reconfig,
+       .size           = faulty_size,
 };
 
 static int __init raid_init(void)
index 09658b218474a3a8f676995f02e59fdfa10693b0..7a36e38393a1e9ff24defd03c756138a9f5da903 100644 (file)
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 */
 
-#include <linux/raid/linear.h>
+#include <linux/blkdev.h>
+#include <linux/raid/md_u.h>
+#include <linux/seq_file.h>
+#include "md.h"
+#include "linear.h"
 
 /*
  * find which device holds a particular offset 
@@ -97,6 +101,16 @@ static int linear_congested(void *data, int bits)
        return ret;
 }
 
+static sector_t linear_size(mddev_t *mddev, sector_t sectors, int raid_disks)
+{
+       linear_conf_t *conf = mddev_to_conf(mddev);
+
+       WARN_ONCE(sectors || raid_disks,
+                 "%s does not support generic reshape\n", __func__);
+
+       return conf->array_sectors;
+}
+
 static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
 {
        linear_conf_t *conf;
@@ -135,8 +149,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
                    mddev->queue->max_sectors > (PAGE_SIZE>>9))
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
-               disk->num_sectors = rdev->size * 2;
-               conf->array_sectors += rdev->size * 2;
+               disk->num_sectors = rdev->sectors;
+               conf->array_sectors += rdev->sectors;
 
                cnt++;
        }
@@ -249,7 +263,7 @@ static int linear_run (mddev_t *mddev)
        if (!conf)
                return 1;
        mddev->private = conf;
-       mddev->array_sectors = conf->array_sectors;
+       md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
 
        blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
        mddev->queue->unplug_fn = linear_unplug;
@@ -283,7 +297,7 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
        newconf->prev = mddev_to_conf(mddev);
        mddev->private = newconf;
        mddev->raid_disks++;
-       mddev->array_sectors = newconf->array_sectors;
+       md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
        set_capacity(mddev->gendisk, mddev->array_sectors);
        return 0;
 }
@@ -381,6 +395,7 @@ static struct mdk_personality linear_personality =
        .stop           = linear_stop,
        .status         = linear_status,
        .hot_add_disk   = linear_add,
+       .size           = linear_size,
 };
 
 static int __init linear_init (void)
similarity index 95%
rename from include/linux/raid/linear.h
rename to drivers/md/linear.h
index f38b9c586afbc38c2a3187ac479735b14ad5fffb..bf8179587f950b2ace4eba54a73abaf4960463ab 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _LINEAR_H
 #define _LINEAR_H
 
-#include <linux/raid/md.h>
-
 struct dev_info {
        mdk_rdev_t      *rdev;
        sector_t        num_sectors;
index a307f87eb90ee361ea6c36b2cbdd94c8886dfdec..ed5727c089a9403b2ad10bb7e581beae5b0d36ac 100644 (file)
@@ -33,9 +33,9 @@
 */
 
 #include <linux/kthread.h>
-#include <linux/raid/md.h>
-#include <linux/raid/bitmap.h>
+#include <linux/blkdev.h>
 #include <linux/sysctl.h>
+#include <linux/seq_file.h>
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 #include <linux/poll.h>
 #include <linux/ctype.h>
 #include <linux/reboot.h>
 #include <linux/file.h>
 #include <linux/delay.h>
-
-#define MAJOR_NR MD_MAJOR
-
-/* 63 partitions with the alternate major number (mdp) */
-#define MdpMinorShift 6
+#include <linux/raid/md_p.h>
+#include <linux/raid/md_u.h>
+#include "md.h"
+#include "bitmap.h"
 
 #define DEBUG 0
 #define dprintk(x...) ((void)(DEBUG && printk(x)))
@@ -202,12 +201,68 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
                )
 
 
-static int md_fail_request(struct request_queue *q, struct bio *bio)
+/* Rather than calling directly into the personality make_request function,
+ * IO requests come here first so that we can check if the device is
+ * being suspended pending a reconfiguration.
+ * We hold a refcount over the call to ->make_request.  By the time that
+ * call has finished, the bio has been linked into some internal structure
+ * and so is visible to ->quiesce(), so we don't need the refcount any more.
+ */
+static int md_make_request(struct request_queue *q, struct bio *bio)
 {
-       bio_io_error(bio);
-       return 0;
+       mddev_t *mddev = q->queuedata;
+       int rv;
+       if (mddev == NULL || mddev->pers == NULL) {
+               bio_io_error(bio);
+               return 0;
+       }
+       rcu_read_lock();
+       if (mddev->suspended) {
+               DEFINE_WAIT(__wait);
+               for (;;) {
+                       prepare_to_wait(&mddev->sb_wait, &__wait,
+                                       TASK_UNINTERRUPTIBLE);
+                       if (!mddev->suspended)
+                               break;
+                       rcu_read_unlock();
+                       schedule();
+                       rcu_read_lock();
+               }
+               finish_wait(&mddev->sb_wait, &__wait);
+       }
+       atomic_inc(&mddev->active_io);
+       rcu_read_unlock();
+       rv = mddev->pers->make_request(q, bio);
+       if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
+               wake_up(&mddev->sb_wait);
+
+       return rv;
+}
+
+static void mddev_suspend(mddev_t *mddev)
+{
+       BUG_ON(mddev->suspended);
+       mddev->suspended = 1;
+       synchronize_rcu();
+       wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0);
+       mddev->pers->quiesce(mddev, 1);
+       md_unregister_thread(mddev->thread);
+       mddev->thread = NULL;
+       /* we now know that no code is executing in the personality module,
+        * except possibly the tail end of a ->bi_end_io function, but that
+        * is certain to complete before the module has a chance to get
+        * unloaded
+        */
+}
+
+static void mddev_resume(mddev_t *mddev)
+{
+       mddev->suspended = 0;
+       wake_up(&mddev->sb_wait);
+       mddev->pers->quiesce(mddev, 0);
 }
 
+
 static inline mddev_t *mddev_get(mddev_t *mddev)
 {
        atomic_inc(&mddev->active);
@@ -310,6 +365,7 @@ static mddev_t * mddev_find(dev_t unit)
        init_timer(&new->safemode_timer);
        atomic_set(&new->active, 1);
        atomic_set(&new->openers, 0);
+       atomic_set(&new->active_io, 0);
        spin_lock_init(&new->write_lock);
        init_waitqueue_head(&new->sb_wait);
        init_waitqueue_head(&new->recovery_wait);
@@ -326,6 +382,11 @@ static inline int mddev_lock(mddev_t * mddev)
        return mutex_lock_interruptible(&mddev->reconfig_mutex);
 }
 
+static inline int mddev_is_locked(mddev_t *mddev)
+{
+       return mutex_is_locked(&mddev->reconfig_mutex);
+}
+
 static inline int mddev_trylock(mddev_t * mddev)
 {
        return mutex_trylock(&mddev->reconfig_mutex);
@@ -409,7 +470,7 @@ static void free_disk_sb(mdk_rdev_t * rdev)
                rdev->sb_loaded = 0;
                rdev->sb_page = NULL;
                rdev->sb_start = 0;
-               rdev->size = 0;
+               rdev->sectors = 0;
        }
 }
 
@@ -775,9 +836,9 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
                else 
                        ret = 0;
        }
-       rdev->size = calc_num_sectors(rdev, sb->chunk_size) / 2;
+       rdev->sectors = calc_num_sectors(rdev, sb->chunk_size);
 
-       if (rdev->size < sb->size && sb->level > 1)
+       if (rdev->sectors < sb->size * 2 && sb->level > 1)
                /* "this cannot possibly happen" ... */
                ret = -EINVAL;
 
@@ -812,7 +873,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->clevel[0] = 0;
                mddev->layout = sb->layout;
                mddev->raid_disks = sb->raid_disks;
-               mddev->size = sb->size;
+               mddev->dev_sectors = sb->size * 2;
                mddev->events = ev1;
                mddev->bitmap_offset = 0;
                mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
@@ -926,7 +987,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
 
        sb->ctime = mddev->ctime;
        sb->level = mddev->level;
-       sb->size  = mddev->size;
+       sb->size = mddev->dev_sectors / 2;
        sb->raid_disks = mddev->raid_disks;
        sb->md_minor = mddev->md_minor;
        sb->not_persistent = 0;
@@ -1024,7 +1085,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
 static unsigned long long
 super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
 {
-       if (num_sectors && num_sectors < rdev->mddev->size * 2)
+       if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
                return 0; /* component must fit device */
        if (rdev->mddev->bitmap_offset)
                return 0; /* can't move bitmap */
@@ -1180,16 +1241,17 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
                        ret = 0;
        }
        if (minor_version)
-               rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2;
+               rdev->sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+                       le64_to_cpu(sb->data_offset);
        else
-               rdev->size = rdev->sb_start / 2;
-       if (rdev->size < le64_to_cpu(sb->data_size)/2)
+               rdev->sectors = rdev->sb_start;
+       if (rdev->sectors < le64_to_cpu(sb->data_size))
                return -EINVAL;
-       rdev->size = le64_to_cpu(sb->data_size)/2;
+       rdev->sectors = le64_to_cpu(sb->data_size);
        if (le32_to_cpu(sb->chunksize))
-               rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1);
+               rdev->sectors &= ~((sector_t)le32_to_cpu(sb->chunksize) - 1);
 
-       if (le64_to_cpu(sb->size) > rdev->size*2)
+       if (le64_to_cpu(sb->size) > rdev->sectors)
                return -EINVAL;
        return ret;
 }
@@ -1216,7 +1278,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->clevel[0] = 0;
                mddev->layout = le32_to_cpu(sb->layout);
                mddev->raid_disks = le32_to_cpu(sb->raid_disks);
-               mddev->size = le64_to_cpu(sb->size)/2;
+               mddev->dev_sectors = le64_to_cpu(sb->size);
                mddev->events = ev1;
                mddev->bitmap_offset = 0;
                mddev->default_bitmap_offset = 1024 >> 9;
@@ -1312,7 +1374,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors));
 
        sb->raid_disks = cpu_to_le32(mddev->raid_disks);
-       sb->size = cpu_to_le64(mddev->size<<1);
+       sb->size = cpu_to_le64(mddev->dev_sectors);
 
        if (mddev->bitmap && mddev->bitmap_file == NULL) {
                sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
@@ -1320,10 +1382,15 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        }
 
        if (rdev->raid_disk >= 0 &&
-           !test_bit(In_sync, &rdev->flags) &&
-           rdev->recovery_offset > 0) {
-               sb->feature_map |= cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
-               sb->recovery_offset = cpu_to_le64(rdev->recovery_offset);
+           !test_bit(In_sync, &rdev->flags)) {
+               if (mddev->curr_resync_completed > rdev->recovery_offset)
+                       rdev->recovery_offset = mddev->curr_resync_completed;
+               if (rdev->recovery_offset > 0) {
+                       sb->feature_map |=
+                               cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
+                       sb->recovery_offset =
+                               cpu_to_le64(rdev->recovery_offset);
+               }
        }
 
        if (mddev->reshape_position != MaxSector) {
@@ -1365,7 +1432,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
 {
        struct mdp_superblock_1 *sb;
        sector_t max_sectors;
-       if (num_sectors && num_sectors < rdev->mddev->size * 2)
+       if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
                return 0; /* component must fit device */
        if (rdev->sb_start < rdev->data_offset) {
                /* minor versions 1 and 2; superblock before data */
@@ -1381,7 +1448,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
                sector_t sb_start;
                sb_start = (rdev->bdev->bd_inode->i_size >> 9) - 8*2;
                sb_start &= ~(sector_t)(4*2 - 1);
-               max_sectors = rdev->size * 2 + sb_start - rdev->sb_start;
+               max_sectors = rdev->sectors + sb_start - rdev->sb_start;
                if (!num_sectors || num_sectors > max_sectors)
                        num_sectors = max_sectors;
                rdev->sb_start = sb_start;
@@ -1433,6 +1500,38 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
 
 static LIST_HEAD(pending_raid_disks);
 
+static void md_integrity_check(mdk_rdev_t *rdev, mddev_t *mddev)
+{
+       struct mdk_personality *pers = mddev->pers;
+       struct gendisk *disk = mddev->gendisk;
+       struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev);
+       struct blk_integrity *bi_mddev = blk_get_integrity(disk);
+
+       /* Data integrity passthrough not supported on RAID 4, 5 and 6 */
+       if (pers && pers->level >= 4 && pers->level <= 6)
+               return;
+
+       /* If rdev is integrity capable, register profile for mddev */
+       if (!bi_mddev && bi_rdev) {
+               if (blk_integrity_register(disk, bi_rdev))
+                       printk(KERN_ERR "%s: %s Could not register integrity!\n",
+                              __func__, disk->disk_name);
+               else
+                       printk(KERN_NOTICE "Enabling data integrity on %s\n",
+                              disk->disk_name);
+               return;
+       }
+
+       /* Check that mddev and rdev have matching profiles */
+       if (blk_integrity_compare(disk, rdev->bdev->bd_disk) < 0) {
+               printk(KERN_ERR "%s: %s/%s integrity mismatch!\n", __func__,
+                      disk->disk_name, rdev->bdev->bd_disk->disk_name);
+               printk(KERN_NOTICE "Disabling data integrity on %s\n",
+                      disk->disk_name);
+               blk_integrity_unregister(disk);
+       }
+}
+
 static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
 {
        char b[BDEVNAME_SIZE];
@@ -1449,8 +1548,9 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
        if (find_rdev(mddev, rdev->bdev->bd_dev))
                return -EEXIST;
 
-       /* make sure rdev->size exceeds mddev->size */
-       if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) {
+       /* make sure rdev->sectors exceeds mddev->dev_sectors */
+       if (rdev->sectors && (mddev->dev_sectors == 0 ||
+                       rdev->sectors < mddev->dev_sectors)) {
                if (mddev->pers) {
                        /* Cannot change size, so fail
                         * If mddev->level <= 0, then we don't care
@@ -1459,7 +1559,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
                        if (mddev->level > 0)
                                return -ENOSPC;
                } else
-                       mddev->size = rdev->size;
+                       mddev->dev_sectors = rdev->sectors;
        }
 
        /* Verify rdev->desc_nr is unique.
@@ -1503,6 +1603,8 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
 
        /* May as well allow recovery to be retried once */
        mddev->recovery_disabled = 0;
+
+       md_integrity_check(rdev, mddev);
        return 0;
 
  fail:
@@ -1713,8 +1815,8 @@ static void print_sb_1(struct mdp_superblock_1 *sb)
 static void print_rdev(mdk_rdev_t *rdev, int major_version)
 {
        char b[BDEVNAME_SIZE];
-       printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n",
-               bdevname(rdev->bdev,b), (unsigned long long)rdev->size,
+       printk(KERN_INFO "md: rdev %s, Sect:%08llu F:%d S:%d DN:%u\n",
+               bdevname(rdev->bdev, b), (unsigned long long)rdev->sectors,
                test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags),
                rdev->desc_nr);
        if (rdev->sb_loaded) {
@@ -2153,7 +2255,7 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                return -EINVAL;
        if (rdev->mddev->pers && rdev->raid_disk >= 0)
                return -EBUSY;
-       if (rdev->size && rdev->mddev->external)
+       if (rdev->sectors && rdev->mddev->external)
                /* Must set offset before size, so overlap checks
                 * can be sane */
                return -EBUSY;
@@ -2167,7 +2269,7 @@ __ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store);
 static ssize_t
 rdev_size_show(mdk_rdev_t *rdev, char *page)
 {
-       return sprintf(page, "%llu\n", (unsigned long long)rdev->size);
+       return sprintf(page, "%llu\n", (unsigned long long)rdev->sectors / 2);
 }
 
 static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
@@ -2180,34 +2282,52 @@ static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
        return 1;
 }
 
+static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
+{
+       unsigned long long blocks;
+       sector_t new;
+
+       if (strict_strtoull(buf, 10, &blocks) < 0)
+               return -EINVAL;
+
+       if (blocks & 1ULL << (8 * sizeof(blocks) - 1))
+               return -EINVAL; /* sector conversion overflow */
+
+       new = blocks * 2;
+       if (new != blocks * 2)
+               return -EINVAL; /* unsigned long long to sector_t overflow */
+
+       *sectors = new;
+       return 0;
+}
+
 static ssize_t
 rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 {
-       unsigned long long size;
-       unsigned long long oldsize = rdev->size;
        mddev_t *my_mddev = rdev->mddev;
+       sector_t oldsectors = rdev->sectors;
+       sector_t sectors;
 
-       if (strict_strtoull(buf, 10, &size) < 0)
+       if (strict_blocks_to_sectors(buf, &sectors) < 0)
                return -EINVAL;
        if (my_mddev->pers && rdev->raid_disk >= 0) {
                if (my_mddev->persistent) {
-                       size = super_types[my_mddev->major_version].
-                               rdev_size_change(rdev, size * 2);
-                       if (!size)
+                       sectors = super_types[my_mddev->major_version].
+                               rdev_size_change(rdev, sectors);
+                       if (!sectors)
                                return -EBUSY;
-               } else if (!size) {
-                       size = (rdev->bdev->bd_inode->i_size >> 10);
-                       size -= rdev->data_offset/2;
-               }
+               } else if (!sectors)
+                       sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+                               rdev->data_offset;
        }
-       if (size < my_mddev->size)
+       if (sectors < my_mddev->dev_sectors)
                return -EINVAL; /* component must fit device */
 
-       rdev->size = size;
-       if (size > oldsize && my_mddev->external) {
+       rdev->sectors = sectors;
+       if (sectors > oldsectors && my_mddev->external) {
                /* need to check that all other rdevs with the same ->bdev
                 * do not overlap.  We need to unlock the mddev to avoid
-                * a deadlock.  We have already changed rdev->size, and if
+                * a deadlock.  We have already changed rdev->sectors, and if
                 * we have to change it back, we will have the lock again.
                 */
                mddev_t *mddev;
@@ -2223,9 +2343,9 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                                if (test_bit(AllReserved, &rdev2->flags) ||
                                    (rdev->bdev == rdev2->bdev &&
                                     rdev != rdev2 &&
-                                    overlaps(rdev->data_offset, rdev->size * 2,
+                                    overlaps(rdev->data_offset, rdev->sectors,
                                              rdev2->data_offset,
-                                             rdev2->size * 2))) {
+                                             rdev2->sectors))) {
                                        overlap = 1;
                                        break;
                                }
@@ -2239,11 +2359,11 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                if (overlap) {
                        /* Someone else could have slipped in a size
                         * change here, but doing so is just silly.
-                        * We put oldsize back because we *know* it is
+                        * We put oldsectors back because we *know* it is
                         * safe, and trust userspace not to race with
                         * itself
                         */
-                       rdev->size = oldsize;
+                       rdev->sectors = oldsectors;
                        return -EBUSY;
                }
        }
@@ -2547,18 +2667,101 @@ level_show(mddev_t *mddev, char *page)
 static ssize_t
 level_store(mddev_t *mddev, const char *buf, size_t len)
 {
+       char level[16];
        ssize_t rv = len;
-       if (mddev->pers)
+       struct mdk_personality *pers;
+       void *priv;
+
+       if (mddev->pers == NULL) {
+               if (len == 0)
+                       return 0;
+               if (len >= sizeof(mddev->clevel))
+                       return -ENOSPC;
+               strncpy(mddev->clevel, buf, len);
+               if (mddev->clevel[len-1] == '\n')
+                       len--;
+               mddev->clevel[len] = 0;
+               mddev->level = LEVEL_NONE;
+               return rv;
+       }
+
+       /* request to change the personality.  Need to ensure:
+        *  - array is not engaged in resync/recovery/reshape
+        *  - old personality can be suspended
+        *  - new personality will access other array.
+        */
+
+       if (mddev->sync_thread || mddev->reshape_position != MaxSector)
                return -EBUSY;
-       if (len == 0)
-               return 0;
-       if (len >= sizeof(mddev->clevel))
-               return -ENOSPC;
-       strncpy(mddev->clevel, buf, len);
-       if (mddev->clevel[len-1] == '\n')
+
+       if (!mddev->pers->quiesce) {
+               printk(KERN_WARNING "md: %s: %s does not support online personality change\n",
+                      mdname(mddev), mddev->pers->name);
+               return -EINVAL;
+       }
+
+       /* Now find the new personality */
+       if (len == 0 || len >= sizeof(level))
+               return -EINVAL;
+       strncpy(level, buf, len);
+       if (level[len-1] == '\n')
                len--;
-       mddev->clevel[len] = 0;
-       mddev->level = LEVEL_NONE;
+       level[len] = 0;
+
+       request_module("md-%s", level);
+       spin_lock(&pers_lock);
+       pers = find_pers(LEVEL_NONE, level);
+       if (!pers || !try_module_get(pers->owner)) {
+               spin_unlock(&pers_lock);
+               printk(KERN_WARNING "md: personality %s not loaded\n", level);
+               return -EINVAL;
+       }
+       spin_unlock(&pers_lock);
+
+       if (pers == mddev->pers) {
+               /* Nothing to do! */
+               module_put(pers->owner);
+               return rv;
+       }
+       if (!pers->takeover) {
+               module_put(pers->owner);
+               printk(KERN_WARNING "md: %s: %s does not support personality takeover\n",
+                      mdname(mddev), level);
+               return -EINVAL;
+       }
+
+       /* ->takeover must set new_* and/or delta_disks
+        * if it succeeds, and may set them when it fails.
+        */
+       priv = pers->takeover(mddev);
+       if (IS_ERR(priv)) {
+               mddev->new_level = mddev->level;
+               mddev->new_layout = mddev->layout;
+               mddev->new_chunk = mddev->chunk_size;
+               mddev->raid_disks -= mddev->delta_disks;
+               mddev->delta_disks = 0;
+               module_put(pers->owner);
+               printk(KERN_WARNING "md: %s: %s would not accept array\n",
+                      mdname(mddev), level);
+               return PTR_ERR(priv);
+       }
+
+       /* Looks like we have a winner */
+       mddev_suspend(mddev);
+       mddev->pers->stop(mddev);
+       module_put(mddev->pers->owner);
+       mddev->pers = pers;
+       mddev->private = priv;
+       strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
+       mddev->level = mddev->new_level;
+       mddev->layout = mddev->new_layout;
+       mddev->chunk_size = mddev->new_chunk;
+       mddev->delta_disks = 0;
+       pers->run(mddev);
+       mddev_resume(mddev);
+       set_bit(MD_CHANGE_DEVS, &mddev->flags);
+       set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+       md_wakeup_thread(mddev->thread);
        return rv;
 }
 
@@ -2586,12 +2789,18 @@ layout_store(mddev_t *mddev, const char *buf, size_t len)
        if (!*buf || (*e && *e != '\n'))
                return -EINVAL;
 
-       if (mddev->pers)
-               return -EBUSY;
-       if (mddev->reshape_position != MaxSector)
+       if (mddev->pers) {
+               int err;
+               if (mddev->pers->reconfig == NULL)
+                       return -EBUSY;
+               err = mddev->pers->reconfig(mddev, n, -1);
+               if (err)
+                       return err;
+       } else {
                mddev->new_layout = n;
-       else
-               mddev->layout = n;
+               if (mddev->reshape_position == MaxSector)
+                       mddev->layout = n;
+       }
        return len;
 }
 static struct md_sysfs_entry md_layout =
@@ -2648,19 +2857,24 @@ chunk_size_show(mddev_t *mddev, char *page)
 static ssize_t
 chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
 {
-       /* can only set chunk_size if array is not yet active */
        char *e;
        unsigned long n = simple_strtoul(buf, &e, 10);
 
        if (!*buf || (*e && *e != '\n'))
                return -EINVAL;
 
-       if (mddev->pers)
-               return -EBUSY;
-       else if (mddev->reshape_position != MaxSector)
+       if (mddev->pers) {
+               int err;
+               if (mddev->pers->reconfig == NULL)
+                       return -EBUSY;
+               err = mddev->pers->reconfig(mddev, -1, n);
+               if (err)
+                       return err;
+       } else {
                mddev->new_chunk = n;
-       else
-               mddev->chunk_size = n;
+               if (mddev->reshape_position == MaxSector)
+                       mddev->chunk_size = n;
+       }
        return len;
 }
 static struct md_sysfs_entry md_chunk_size =
@@ -2669,6 +2883,8 @@ __ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);
 static ssize_t
 resync_start_show(mddev_t *mddev, char *page)
 {
+       if (mddev->recovery_cp == MaxSector)
+               return sprintf(page, "none\n");
        return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp);
 }
 
@@ -2766,7 +2982,7 @@ array_state_show(mddev_t *mddev, char *page)
        else {
                if (list_empty(&mddev->disks) &&
                    mddev->raid_disks == 0 &&
-                   mddev->size == 0)
+                   mddev->dev_sectors == 0)
                        st = clear;
                else
                        st = inactive;
@@ -2973,7 +3189,8 @@ __ATTR(bitmap_set_bits, S_IWUSR, null_show, bitmap_store);
 static ssize_t
 size_show(mddev_t *mddev, char *page)
 {
-       return sprintf(page, "%llu\n", (unsigned long long)mddev->size);
+       return sprintf(page, "%llu\n",
+               (unsigned long long)mddev->dev_sectors / 2);
 }
 
 static int update_size(mddev_t *mddev, sector_t num_sectors);
@@ -2985,20 +3202,18 @@ size_store(mddev_t *mddev, const char *buf, size_t len)
         * not increase it (except from 0).
         * If array is active, we can try an on-line resize
         */
-       char *e;
-       int err = 0;
-       unsigned long long size = simple_strtoull(buf, &e, 10);
-       if (!*buf || *buf == '\n' ||
-           (*e && *e != '\n'))
-               return -EINVAL;
+       sector_t sectors;
+       int err = strict_blocks_to_sectors(buf, &sectors);
 
+       if (err < 0)
+               return err;
        if (mddev->pers) {
-               err = update_size(mddev, size * 2);
+               err = update_size(mddev, sectors);
                md_update_sb(mddev, 1);
        } else {
-               if (mddev->size == 0 ||
-                   mddev->size > size)
-                       mddev->size = size;
+               if (mddev->dev_sectors == 0 ||
+                   mddev->dev_sectors > sectors)
+                       mddev->dev_sectors = sectors;
                else
                        err = -ENOSPC;
        }
@@ -3251,6 +3466,8 @@ static ssize_t
 sync_speed_show(mddev_t *mddev, char *page)
 {
        unsigned long resync, dt, db;
+       if (mddev->curr_resync == 0)
+               return sprintf(page, "none\n");
        resync = mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active);
        dt = (jiffies - mddev->resync_mark) / HZ;
        if (!dt) dt++;
@@ -3263,15 +3480,15 @@ static struct md_sysfs_entry md_sync_speed = __ATTR_RO(sync_speed);
 static ssize_t
 sync_completed_show(mddev_t *mddev, char *page)
 {
-       unsigned long max_blocks, resync;
+       unsigned long max_sectors, resync;
 
        if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
-               max_blocks = mddev->resync_max_sectors;
+               max_sectors = mddev->resync_max_sectors;
        else
-               max_blocks = mddev->size << 1;
+               max_sectors = mddev->dev_sectors;
 
        resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active));
-       return sprintf(page, "%lu / %lu\n", resync, max_blocks);
+       return sprintf(page, "%lu / %lu\n", resync, max_sectors);
 }
 
 static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
@@ -3431,6 +3648,57 @@ static struct md_sysfs_entry md_reshape_position =
 __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
        reshape_position_store);
 
+static ssize_t
+array_size_show(mddev_t *mddev, char *page)
+{
+       if (mddev->external_size)
+               return sprintf(page, "%llu\n",
+                              (unsigned long long)mddev->array_sectors/2);
+       else
+               return sprintf(page, "default\n");
+}
+
+static ssize_t
+array_size_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       sector_t sectors;
+
+       if (strncmp(buf, "default", 7) == 0) {
+               if (mddev->pers)
+                       sectors = mddev->pers->size(mddev, 0, 0);
+               else
+                       sectors = mddev->array_sectors;
+
+               mddev->external_size = 0;
+       } else {
+               if (strict_blocks_to_sectors(buf, &sectors) < 0)
+                       return -EINVAL;
+               if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors)
+                       return -EINVAL;
+
+               mddev->external_size = 1;
+       }
+
+       mddev->array_sectors = sectors;
+       set_capacity(mddev->gendisk, mddev->array_sectors);
+       if (mddev->pers) {
+               struct block_device *bdev = bdget_disk(mddev->gendisk, 0);
+
+               if (bdev) {
+                       mutex_lock(&bdev->bd_inode->i_mutex);
+                       i_size_write(bdev->bd_inode,
+                                    (loff_t)mddev->array_sectors << 9);
+                       mutex_unlock(&bdev->bd_inode->i_mutex);
+                       bdput(bdev);
+               }
+       }
+
+       return len;
+}
+
+static struct md_sysfs_entry md_array_size =
+__ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show,
+       array_size_store);
 
 static struct attribute *md_default_attrs[] = {
        &md_level.attr,
@@ -3444,6 +3712,7 @@ static struct attribute *md_default_attrs[] = {
        &md_safe_delay.attr,
        &md_array_state.attr,
        &md_reshape_position.attr,
+       &md_array_size.attr,
        NULL,
 };
 
@@ -3602,10 +3871,12 @@ static int md_alloc(dev_t dev, char *name)
                mddev_put(mddev);
                return -ENOMEM;
        }
+       mddev->queue->queuedata = mddev;
+
        /* Can be unlocked because the queue is new: no concurrency */
        queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue);
 
-       blk_queue_make_request(mddev->queue, md_fail_request);
+       blk_queue_make_request(mddev->queue, md_make_request);
 
        disk = alloc_disk(1 << shift);
        if (!disk) {
@@ -3731,13 +4002,13 @@ static int do_md_run(mddev_t * mddev)
                list_for_each_entry(rdev, &mddev->disks, same_set) {
                        if (test_bit(Faulty, &rdev->flags))
                                continue;
-                       if (rdev->size < chunk_size / 1024) {
+                       if (rdev->sectors < chunk_size / 512) {
                                printk(KERN_WARNING
                                        "md: Dev %s smaller than chunk_size:"
-                                       " %lluk < %dk\n",
+                                       " %llu < %d\n",
                                        bdevname(rdev->bdev,b),
-                                       (unsigned long long)rdev->size,
-                                       chunk_size / 1024);
+                                       (unsigned long long)rdev->sectors,
+                                       chunk_size / 512);
                                return -EINVAL;
                        }
                }
@@ -3761,11 +4032,11 @@ static int do_md_run(mddev_t * mddev)
 
                /* perform some consistency tests on the device.
                 * We don't want the data to overlap the metadata,
-                * Internal Bitmap issues has handled elsewhere.
+                * Internal Bitmap issues have been handled elsewhere.
                 */
                if (rdev->data_offset < rdev->sb_start) {
-                       if (mddev->size &&
-                           rdev->data_offset + mddev->size*2
+                       if (mddev->dev_sectors &&
+                           rdev->data_offset + mddev->dev_sectors
                            > rdev->sb_start) {
                                printk("md: %s: data overlaps metadata\n",
                                       mdname(mddev));
@@ -3801,9 +4072,16 @@ static int do_md_run(mddev_t * mddev)
        }
        mddev->pers = pers;
        spin_unlock(&pers_lock);
-       mddev->level = pers->level;
+       if (mddev->level != pers->level) {
+               mddev->level = pers->level;
+               mddev->new_level = pers->level;
+       }
        strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
 
+       if (pers->level >= 4 && pers->level <= 6)
+               /* Cannot support integrity (yet) */
+               blk_integrity_unregister(mddev->gendisk);
+
        if (mddev->reshape_position != MaxSector &&
            pers->start_reshape == NULL) {
                /* This personality cannot handle reshaping... */
@@ -3843,7 +4121,9 @@ static int do_md_run(mddev_t * mddev)
        }
 
        mddev->recovery = 0;
-       mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
+       /* may be over-ridden by personality */
+       mddev->resync_max_sectors = mddev->dev_sectors;
+
        mddev->barriers_work = 1;
        mddev->ok_start_degraded = start_dirty_degraded;
 
@@ -3853,7 +4133,17 @@ static int do_md_run(mddev_t * mddev)
        err = mddev->pers->run(mddev);
        if (err)
                printk(KERN_ERR "md: pers->run() failed ...\n");
-       else if (mddev->pers->sync_request) {
+       else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) {
+               WARN_ONCE(!mddev->external_size, "%s: default size too small,"
+                         " but 'external_size' not in effect?\n", __func__);
+               printk(KERN_ERR
+                      "md: invalid array_size %llu > default size %llu\n",
+                      (unsigned long long)mddev->array_sectors / 2,
+                      (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2);
+               err = -EINVAL;
+               mddev->pers->stop(mddev);
+       }
+       if (err == 0 && mddev->pers->sync_request) {
                err = bitmap_create(mddev);
                if (err) {
                        printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
@@ -3899,16 +4189,6 @@ static int do_md_run(mddev_t * mddev)
 
        set_capacity(disk, mddev->array_sectors);
 
-       /* If we call blk_queue_make_request here, it will
-        * re-initialise max_sectors etc which may have been
-        * refined inside -> run.  So just set the bits we need to set.
-        * Most initialisation happended when we called
-        * blk_queue_make_request(..., md_fail_request)
-        * earlier.
-        */
-       mddev->queue->queuedata = mddev;
-       mddev->queue->make_request_fn = mddev->pers->make_request;
-
        /* If there is a partially-recovered drive we need to
         * start recovery here.  If we leave it to md_check_recovery,
         * it will remove the drives and not do the right thing
@@ -4038,7 +4318,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                        md_super_wait(mddev);
                        if (mddev->ro)
                                set_disk_ro(disk, 0);
-                       blk_queue_make_request(mddev->queue, md_fail_request);
+
                        mddev->pers->stop(mddev);
                        mddev->queue->merge_bvec_fn = NULL;
                        mddev->queue->unplug_fn = NULL;
@@ -4095,7 +4375,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                export_array(mddev);
 
                mddev->array_sectors = 0;
-               mddev->size = 0;
+               mddev->external_size = 0;
+               mddev->dev_sectors = 0;
                mddev->raid_disks = 0;
                mddev->recovery_cp = 0;
                mddev->resync_min = 0;
@@ -4135,6 +4416,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                printk(KERN_INFO "md: %s switched to read-only mode.\n",
                        mdname(mddev));
        err = 0;
+       blk_integrity_unregister(disk);
        md_new_event(mddev);
        sysfs_notify_dirent(mddev->sysfs_state);
 out:
@@ -4300,8 +4582,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
        info.patch_version = MD_PATCHLEVEL_VERSION;
        info.ctime         = mddev->ctime;
        info.level         = mddev->level;
-       info.size          = mddev->size;
-       if (info.size != mddev->size) /* overflow */
+       info.size          = mddev->dev_sectors / 2;
+       if (info.size != mddev->dev_sectors / 2) /* overflow */
                info.size = -1;
        info.nr_disks      = nr;
        info.raid_disks    = mddev->raid_disks;
@@ -4480,6 +4762,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                clear_bit(In_sync, &rdev->flags); /* just to be sure */
                if (info->state & (1<<MD_DISK_WRITEMOSTLY))
                        set_bit(WriteMostly, &rdev->flags);
+               else
+                       clear_bit(WriteMostly, &rdev->flags);
 
                rdev->raid_disk = -1;
                err = bind_rdev_to_array(rdev, mddev);
@@ -4543,7 +4827,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                        rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
                } else 
                        rdev->sb_start = calc_dev_sboffset(rdev->bdev);
-               rdev->size = calc_num_sectors(rdev, mddev->chunk_size) / 2;
+               rdev->sectors = calc_num_sectors(rdev, mddev->chunk_size);
 
                err = bind_rdev_to_array(rdev, mddev);
                if (err) {
@@ -4613,7 +4897,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
        else
                rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
 
-       rdev->size = calc_num_sectors(rdev, mddev->chunk_size) / 2;
+       rdev->sectors = calc_num_sectors(rdev, mddev->chunk_size);
 
        if (test_bit(Faulty, &rdev->flags)) {
                printk(KERN_WARNING 
@@ -4749,7 +5033,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
 
        mddev->level         = info->level;
        mddev->clevel[0]     = 0;
-       mddev->size          = info->size;
+       mddev->dev_sectors   = 2 * (sector_t)info->size;
        mddev->raid_disks    = info->raid_disks;
        /* don't set md_minor, it is determined by which /dev/md* was
         * openned
@@ -4788,6 +5072,17 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
        return 0;
 }
 
+void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors)
+{
+       WARN(!mddev_is_locked(mddev), "%s: unlocked mddev!\n", __func__);
+
+       if (mddev->external_size)
+               return;
+
+       mddev->array_sectors = array_sectors;
+}
+EXPORT_SYMBOL(md_set_array_sectors);
+
 static int update_size(mddev_t *mddev, sector_t num_sectors)
 {
        mdk_rdev_t *rdev;
@@ -4814,8 +5109,7 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
                 */
                return -EBUSY;
        list_for_each_entry(rdev, &mddev->disks, same_set) {
-               sector_t avail;
-               avail = rdev->size * 2;
+               sector_t avail = rdev->sectors;
 
                if (fit && (num_sectors == 0 || num_sectors > avail))
                        num_sectors = avail;
@@ -4887,12 +5181,18 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                )
                return -EINVAL;
        /* Check there is only one change */
-       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++;
-       if (cnt == 0) return 0;
-       if (cnt > 1) return -EINVAL;
+       if (info->size >= 0 && mddev->dev_sectors / 2 != 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++;
+       if (cnt == 0)
+               return 0;
+       if (cnt > 1)
+               return -EINVAL;
 
        if (mddev->layout != info->layout) {
                /* Change layout
@@ -4904,7 +5204,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                else
                        return mddev->pers->reconfig(mddev, info->layout, -1);
        }
-       if (info->size >= 0 && mddev->size != info->size)
+       if (info->size >= 0 && mddev->dev_sectors / 2 != info->size)
                rv = update_size(mddev, (sector_t)info->size * 2);
 
        if (mddev->raid_disks    != info->raid_disks)
@@ -5331,6 +5631,8 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
 
 void md_unregister_thread(mdk_thread_t *thread)
 {
+       if (!thread)
+               return;
        dprintk("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
 
        kthread_stop(thread->tsk);
@@ -5404,7 +5706,7 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
        if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
                max_blocks = mddev->resync_max_sectors >> 1;
        else
-               max_blocks = mddev->size;
+               max_blocks = mddev->dev_sectors / 2;
 
        /*
         * Should not happen.
@@ -5537,7 +5839,7 @@ struct mdstat_info {
 static int md_seq_show(struct seq_file *seq, void *v)
 {
        mddev_t *mddev = v;
-       sector_t size;
+       sector_t sectors;
        mdk_rdev_t *rdev;
        struct mdstat_info *mi = seq->private;
        struct bitmap *bitmap;
@@ -5573,7 +5875,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
                        seq_printf(seq, " %s", mddev->pers->name);
                }
 
-               size = 0;
+               sectors = 0;
                list_for_each_entry(rdev, &mddev->disks, same_set) {
                        char b[BDEVNAME_SIZE];
                        seq_printf(seq, " %s[%d]",
@@ -5585,7 +5887,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
                                continue;
                        } else if (rdev->raid_disk < 0)
                                seq_printf(seq, "(S)"); /* spare */
-                       size += rdev->size;
+                       sectors += rdev->sectors;
                }
 
                if (!list_empty(&mddev->disks)) {
@@ -5595,7 +5897,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
                                           mddev->array_sectors / 2);
                        else
                                seq_printf(seq, "\n      %llu blocks",
-                                          (unsigned long long)size);
+                                          (unsigned long long)sectors / 2);
                }
                if (mddev->persistent) {
                        if (mddev->major_version != 0 ||
@@ -5722,19 +6024,19 @@ int unregister_md_personality(struct mdk_personality *p)
        return 0;
 }
 
-static int is_mddev_idle(mddev_t *mddev)
+static int is_mddev_idle(mddev_t *mddev, int init)
 {
        mdk_rdev_t * rdev;
        int idle;
-       long curr_events;
+       int curr_events;
 
        idle = 1;
        rcu_read_lock();
        rdev_for_each_rcu(rdev, mddev) {
                struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
-               curr_events = part_stat_read(&disk->part0, sectors[0]) +
-                               part_stat_read(&disk->part0, sectors[1]) -
-                               atomic_read(&disk->sync_io);
+               curr_events = (int)part_stat_read(&disk->part0, sectors[0]) +
+                             (int)part_stat_read(&disk->part0, sectors[1]) -
+                             atomic_read(&disk->sync_io);
                /* sync IO will cause sync_io to increase before the disk_stats
                 * as sync_io is counted when a request starts, and
                 * disk_stats is counted when it completes.
@@ -5757,7 +6059,7 @@ static int is_mddev_idle(mddev_t *mddev)
                 * always make curr_events less than last_events.
                 *
                 */
-               if (curr_events - rdev->last_events > 4096) {
+               if (init || curr_events - rdev->last_events > 64) {
                        rdev->last_events = curr_events;
                        idle = 0;
                }
@@ -5980,10 +6282,10 @@ void md_do_sync(mddev_t *mddev)
                        j = mddev->recovery_cp;
 
        } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
-               max_sectors = mddev->size << 1;
+               max_sectors = mddev->dev_sectors;
        else {
                /* recovery follows the physical size of devices */
-               max_sectors = mddev->size << 1;
+               max_sectors = mddev->dev_sectors;
                j = MaxSector;
                list_for_each_entry(rdev, &mddev->disks, same_set)
                        if (rdev->raid_disk >= 0 &&
@@ -6000,7 +6302,7 @@ void md_do_sync(mddev_t *mddev)
               "(but not more than %d KB/sec) for %s.\n",
               speed_max(mddev), desc);
 
-       is_mddev_idle(mddev); /* this also initializes IO event counters */
+       is_mddev_idle(mddev, 1); /* this initializes IO event counters */
 
        io_sectors = 0;
        for (m = 0; m < SYNC_MARKS; m++) {
@@ -6040,6 +6342,18 @@ void md_do_sync(mddev_t *mddev)
                }
                if (kthread_should_stop())
                        goto interrupted;
+
+               if (mddev->curr_resync > mddev->curr_resync_completed &&
+                   (mddev->curr_resync - mddev->curr_resync_completed)
+                   > (max_sectors >> 4)) {
+                       /* time to update curr_resync_completed */
+                       blk_unplug(mddev->queue);
+                       wait_event(mddev->recovery_wait,
+                                  atomic_read(&mddev->recovery_active) == 0);
+                       mddev->curr_resync_completed =
+                               mddev->curr_resync;
+                       set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+               }
                sectors = mddev->pers->sync_request(mddev, j, &skipped,
                                                  currspeed < speed_min(mddev));
                if (sectors == 0) {
@@ -6102,7 +6416,7 @@ void md_do_sync(mddev_t *mddev)
 
                if (currspeed > speed_min(mddev)) {
                        if ((currspeed > speed_max(mddev)) ||
-                                       !is_mddev_idle(mddev)) {
+                                       !is_mddev_idle(mddev, 0)) {
                                msleep(500);
                                goto repeat;
                        }
@@ -6173,6 +6487,8 @@ static int remove_and_add_spares(mddev_t *mddev)
        mdk_rdev_t *rdev;
        int spares = 0;
 
+       mddev->curr_resync_completed = 0;
+
        list_for_each_entry(rdev, &mddev->disks, same_set)
                if (rdev->raid_disk >= 0 &&
                    !test_bit(Blocked, &rdev->flags) &&
@@ -6327,6 +6643,9 @@ void md_check_recovery(mddev_t *mddev)
                                        sysfs_notify(&mddev->kobj, NULL,
                                                     "degraded");
                        }
+                       if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+                           mddev->pers->finish_reshape)
+                               mddev->pers->finish_reshape(mddev);
                        md_update_sb(mddev, 1);
 
                        /* if array is no-longer degraded, then any saved_raid_disk
@@ -6470,13 +6789,13 @@ static void md_geninit(void)
 
 static int __init md_init(void)
 {
-       if (register_blkdev(MAJOR_NR, "md"))
+       if (register_blkdev(MD_MAJOR, "md"))
                return -1;
        if ((mdp_major=register_blkdev(0, "mdp"))<=0) {
-               unregister_blkdev(MAJOR_NR, "md");
+               unregister_blkdev(MD_MAJOR, "md");
                return -1;
        }
-       blk_register_region(MKDEV(MAJOR_NR, 0), 1UL<<MINORBITS, THIS_MODULE,
+       blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE,
                            md_probe, NULL, NULL);
        blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE,
                            md_probe, NULL, NULL);
@@ -6562,10 +6881,10 @@ static __exit void md_exit(void)
        mddev_t *mddev;
        struct list_head *tmp;
 
-       blk_unregister_region(MKDEV(MAJOR_NR,0), 1U << MINORBITS);
+       blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS);
        blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS);
 
-       unregister_blkdev(MAJOR_NR,"md");
+       unregister_blkdev(MD_MAJOR,"md");
        unregister_blkdev(mdp_major, "mdp");
        unregister_reboot_notifier(&md_notifier);
        unregister_sysctl_table(raid_table_header);
similarity index 83%
rename from include/linux/raid/md_k.h
rename to drivers/md/md.h
index 9743e4dbc9188031b0c180584df4c5e6ba898513..e9b7f54c24d653f68daacd28cc0c386252669627 100644 (file)
 #ifndef _MD_K_H
 #define _MD_K_H
 
-/* and dm-bio-list.h is not under include/linux because.... ??? */
-#include "../../../drivers/md/dm-bio-list.h"
-
 #ifdef CONFIG_BLOCK
 
-#define        LEVEL_MULTIPATH         (-4)
-#define        LEVEL_LINEAR            (-1)
-#define        LEVEL_FAULTY            (-5)
-
-/* we need a value for 'no level specified' and 0
- * means 'raid0', so we need something else.  This is
- * for internal use only
- */
-#define        LEVEL_NONE              (-1000000)
-
 #define MaxSector (~(sector_t)0)
 
 typedef struct mddev_s mddev_t;
@@ -49,9 +36,9 @@ struct mdk_rdev_s
 {
        struct list_head same_set;      /* RAID devices within the same set */
 
-       sector_t size;                  /* Device size (in blocks) */
+       sector_t sectors;               /* Device size (in 512bytes sectors) */
        mddev_t *mddev;                 /* RAID array if running */
-       long last_events;               /* IO event timestamp */
+       int last_events;                /* IO event timestamp */
 
        struct block_device *bdev;      /* block device handle */
 
@@ -132,6 +119,8 @@ struct mddev_s
 #define MD_CHANGE_CLEAN 1      /* transition to or from 'clean' */
 #define MD_CHANGE_PENDING 2    /* superblock update in progress */
 
+       int                             suspended;
+       atomic_t                        active_io;
        int                             ro;
 
        struct gendisk                  *gendisk;
@@ -155,8 +144,11 @@ struct mddev_s
        char                            clevel[16];
        int                             raid_disks;
        int                             max_disks;
-       sector_t                        size; /* used size of component devices */
+       sector_t                        dev_sectors;    /* used size of
+                                                        * component devices */
        sector_t                        array_sectors; /* exported array size */
+       int                             external_size; /* size managed
+                                                       * externally */
        __u64                           events;
 
        char                            uuid[16];
@@ -172,6 +164,13 @@ struct mddev_s
        struct mdk_thread_s             *thread;        /* management thread */
        struct mdk_thread_s             *sync_thread;   /* doing resync or reconstruct */
        sector_t                        curr_resync;    /* last block scheduled */
+       /* As resync requests can complete out of order, we cannot easily track
+        * how much resync has been completed.  So we occasionally pause until
+        * everything completes, then set curr_resync_completed to curr_resync.
+        * As such it may be well behind the real resync mark, but it is a value
+        * we are certain of.
+        */
+       sector_t                        curr_resync_completed;
        unsigned long                   resync_mark;    /* a recent timestamp */
        sector_t                        resync_mark_cnt;/* blocks written at resync_mark */
        sector_t                        curr_mark_cnt; /* blocks scheduled now */
@@ -315,8 +314,10 @@ struct mdk_personality
        int (*spare_active) (mddev_t *mddev);
        sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster);
        int (*resize) (mddev_t *mddev, sector_t sectors);
+       sector_t (*size) (mddev_t *mddev, sector_t sectors, int raid_disks);
        int (*check_reshape) (mddev_t *mddev);
        int (*start_reshape) (mddev_t *mddev);
+       void (*finish_reshape) (mddev_t *mddev);
        int (*reconfig) (mddev_t *mddev, int layout, int chunk_size);
        /* quiesce moves between quiescence states
         * 0 - fully active
@@ -324,6 +325,16 @@ struct mdk_personality
         * others - reserved
         */
        void (*quiesce) (mddev_t *mddev, int state);
+       /* takeover is used to transition an array from one
+        * personality to another.  The new personality must be able
+        * to handle the data in the current layout.
+        * e.g. 2drive raid1 -> 2drive raid5
+        *      ndrive raid5 -> degraded n+1drive raid6 with special layout
+        * If the takeover succeeds, a new 'private' structure is returned.
+        * This needs to be installed and then ->run used to activate the
+        * array.
+        */
+       void *(*takeover) (mddev_t *mddev);
 };
 
 
@@ -400,3 +411,26 @@ static inline void safe_put_page(struct page *p)
 #endif /* CONFIG_BLOCK */
 #endif
 
+
+extern int register_md_personality(struct mdk_personality *p);
+extern int unregister_md_personality(struct mdk_personality *p);
+extern mdk_thread_t * md_register_thread(void (*run) (mddev_t *mddev),
+                               mddev_t *mddev, const char *name);
+extern void md_unregister_thread(mdk_thread_t *thread);
+extern void md_wakeup_thread(mdk_thread_t *thread);
+extern void md_check_recovery(mddev_t *mddev);
+extern void md_write_start(mddev_t *mddev, struct bio *bi);
+extern void md_write_end(mddev_t *mddev);
+extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
+extern void md_error(mddev_t *mddev, mdk_rdev_t *rdev);
+
+extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
+                          sector_t sector, int size, struct page *page);
+extern void md_super_wait(mddev_t *mddev);
+extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
+                       struct page *page, int rw);
+extern void md_do_sync(mddev_t *mddev);
+extern void md_new_event(mddev_t *mddev);
+extern int md_allow_write(mddev_t *mddev);
+extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
+extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors);
index b61d5767aae7c61c3960a09e16c26becb3a1712f..3b1500843bbac2dfa85daaeb85058480294080d4 100644 (file)
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
        uint8_t v;
        uint8_t exptbl[256], invtbl[256];
 
-       printf("#include \"raid6.h\"\n");
+       printf("#include <linux/raid/pq.h>\n");
 
        /* Compute multiplication table */
        printf("\nconst u8  __attribute__((aligned(256)))\n"
@@ -76,6 +76,9 @@ int main(int argc, char *argv[])
                printf("\t},\n");
        }
        printf("};\n");
+       printf("#ifdef __KERNEL__\n");
+       printf("EXPORT_SYMBOL(raid6_gfmul);\n");
+       printf("#endif\n");
 
        /* Compute power-of-2 table (exponent) */
        v = 1;
@@ -92,6 +95,9 @@ int main(int argc, char *argv[])
                }
        }
        printf("};\n");
+       printf("#ifdef __KERNEL__\n");
+       printf("EXPORT_SYMBOL(raid6_gfexp);\n");
+       printf("#endif\n");
 
        /* Compute inverse table x^-1 == x^254 */
        printf("\nconst u8 __attribute__((aligned(256)))\n"
@@ -104,6 +110,9 @@ int main(int argc, char *argv[])
                }
        }
        printf("};\n");
+       printf("#ifdef __KERNEL__\n");
+       printf("EXPORT_SYMBOL(raid6_gfinv);\n");
+       printf("#endif\n");
 
        /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
        printf("\nconst u8 __attribute__((aligned(256)))\n"
@@ -115,6 +124,9 @@ int main(int argc, char *argv[])
                               (j == 7) ? '\n' : ' ');
        }
        printf("};\n");
+       printf("#ifdef __KERNEL__\n");
+       printf("EXPORT_SYMBOL(raid6_gfexi);\n");
+       printf("#endif\n");
 
        return 0;
 }
index f6d08f2416716f7207fe49aba23d154a5eb41fae..41ced0cbe823c7275cc2f79172cc9913385fcd2f 100644 (file)
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/raid/multipath.h>
+#include <linux/blkdev.h>
+#include <linux/raid/md_u.h>
+#include <linux/seq_file.h>
+#include "md.h"
+#include "multipath.h"
 
 #define MAX_WORK_PER_DISK 128
 
@@ -402,6 +406,14 @@ static void multipathd (mddev_t *mddev)
        spin_unlock_irqrestore(&conf->device_lock, flags);
 }
 
+static sector_t multipath_size(mddev_t *mddev, sector_t sectors, int raid_disks)
+{
+       WARN_ONCE(sectors || raid_disks,
+                 "%s does not support generic reshape\n", __func__);
+
+       return mddev->dev_sectors;
+}
+
 static int multipath_run (mddev_t *mddev)
 {
        multipath_conf_t *conf;
@@ -498,7 +510,7 @@ static int multipath_run (mddev_t *mddev)
        /*
         * Ok, everything is just fine now
         */
-       mddev->array_sectors = mddev->size * 2;
+       md_set_array_sectors(mddev, multipath_size(mddev, 0, 0));
 
        mddev->queue->unplug_fn = multipath_unplug;
        mddev->queue->backing_dev_info.congested_fn = multipath_congested;
@@ -543,6 +555,7 @@ static struct mdk_personality multipath_personality =
        .error_handler  = multipath_error,
        .hot_add_disk   = multipath_add_disk,
        .hot_remove_disk= multipath_remove_disk,
+       .size           = multipath_size,
 };
 
 static int __init multipath_init (void)
similarity index 96%
rename from include/linux/raid/multipath.h
rename to drivers/md/multipath.h
index 6f53fc177a47359b1490ba5b999e9d2b34e7bb2e..6fa70b400cdae6347fa07dedc2c80a5c16cabc90 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _MULTIPATH_H
 #define _MULTIPATH_H
 
-#include <linux/raid/md.h>
-
 struct multipath_info {
        mdk_rdev_t      *rdev;
 };
index c605ba8055863d2d0ede52e9fe7e9c4e374bd9d3..c08d7559be5531fb01bedb55e4663a0e40092607 100644 (file)
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 */
 
-#include <linux/raid/raid0.h>
+#include <linux/blkdev.h>
+#include <linux/seq_file.h>
+#include "md.h"
+#include "raid0.h"
 
 static void raid0_unplug(struct request_queue *q)
 {
@@ -73,16 +76,15 @@ static int create_strip_zones (mddev_t *mddev)
                list_for_each_entry(rdev2, &mddev->disks, same_set) {
                        printk(KERN_INFO "raid0:   comparing %s(%llu)",
                               bdevname(rdev1->bdev,b),
-                              (unsigned long long)rdev1->size);
+                              (unsigned long long)rdev1->sectors);
                        printk(KERN_INFO " with %s(%llu)\n",
                               bdevname(rdev2->bdev,b),
-                              (unsigned long long)rdev2->size);
+                              (unsigned long long)rdev2->sectors);
                        if (rdev2 == rdev1) {
                                printk(KERN_INFO "raid0:   END\n");
                                break;
                        }
-                       if (rdev2->size == rdev1->size)
-                       {
+                       if (rdev2->sectors == rdev1->sectors) {
                                /*
                                 * Not unique, don't count it as a new
                                 * group
@@ -145,7 +147,7 @@ static int create_strip_zones (mddev_t *mddev)
                    mddev->queue->max_sectors > (PAGE_SIZE>>9))
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
-               if (!smallest || (rdev1->size <smallest->size))
+               if (!smallest || (rdev1->sectors < smallest->sectors))
                        smallest = rdev1;
                cnt++;
        }
@@ -155,10 +157,10 @@ static int create_strip_zones (mddev_t *mddev)
                goto abort;
        }
        zone->nb_dev = cnt;
-       zone->sectors = smallest->size * cnt * 2;
+       zone->sectors = smallest->sectors * cnt;
        zone->zone_start = 0;
 
-       current_start = smallest->size * 2;
+       current_start = smallest->sectors;
        curr_zone_start = zone->sectors;
 
        /* now do the other zones */
@@ -177,29 +179,29 @@ static int create_strip_zones (mddev_t *mddev)
                        rdev = conf->strip_zone[0].dev[j];
                        printk(KERN_INFO "raid0: checking %s ...",
                                bdevname(rdev->bdev, b));
-                       if (rdev->size > current_start / 2) {
-                               printk(KERN_INFO " contained as device %d\n",
-                                       c);
-                               zone->dev[c] = rdev;
-                               c++;
-                               if (!smallest || (rdev->size <smallest->size)) {
-                                       smallest = rdev;
-                                       printk(KERN_INFO "  (%llu) is smallest!.\n",
-                                               (unsigned long long)rdev->size);
-                               }
-                       } else
+                       if (rdev->sectors <= current_start) {
                                printk(KERN_INFO " nope.\n");
+                               continue;
+                       }
+                       printk(KERN_INFO " contained as device %d\n", c);
+                       zone->dev[c] = rdev;
+                       c++;
+                       if (!smallest || rdev->sectors < smallest->sectors) {
+                               smallest = rdev;
+                               printk(KERN_INFO "  (%llu) is smallest!.\n",
+                                       (unsigned long long)rdev->sectors);
+                       }
                }
 
                zone->nb_dev = c;
-               zone->sectors = (smallest->size * 2 - current_start) * c;
+               zone->sectors = (smallest->sectors - current_start) * c;
                printk(KERN_INFO "raid0: zone->nb_dev: %d, sectors: %llu\n",
                        zone->nb_dev, (unsigned long long)zone->sectors);
 
                zone->zone_start = curr_zone_start;
                curr_zone_start += zone->sectors;
 
-               current_start = smallest->size * 2;
+               current_start = smallest->sectors;
                printk(KERN_INFO "raid0: current zone start: %llu\n",
                        (unsigned long long)current_start);
        }
@@ -261,12 +263,25 @@ static int raid0_mergeable_bvec(struct request_queue *q,
                return max;
 }
 
+static sector_t raid0_size(mddev_t *mddev, sector_t sectors, int raid_disks)
+{
+       sector_t array_sectors = 0;
+       mdk_rdev_t *rdev;
+
+       WARN_ONCE(sectors || raid_disks,
+                 "%s does not support generic reshape\n", __func__);
+
+       list_for_each_entry(rdev, &mddev->disks, same_set)
+               array_sectors += rdev->sectors;
+
+       return array_sectors;
+}
+
 static int raid0_run (mddev_t *mddev)
 {
        unsigned  cur=0, i=0, nb_zone;
        s64 sectors;
        raid0_conf_t *conf;
-       mdk_rdev_t *rdev;
 
        if (mddev->chunk_size == 0) {
                printk(KERN_ERR "md/raid0: non-zero chunk size required.\n");
@@ -291,16 +306,14 @@ static int raid0_run (mddev_t *mddev)
                goto out_free_conf;
 
        /* calculate array device size */
-       mddev->array_sectors = 0;
-       list_for_each_entry(rdev, &mddev->disks, same_set)
-               mddev->array_sectors += rdev->size * 2;
+       md_set_array_sectors(mddev, raid0_size(mddev, 0, 0));
 
        printk(KERN_INFO "raid0 : md_size is %llu sectors.\n",
                (unsigned long long)mddev->array_sectors);
        printk(KERN_INFO "raid0 : conf->spacing is %llu sectors.\n",
                (unsigned long long)conf->spacing);
        {
-               sector_t s = mddev->array_sectors;
+               sector_t s = raid0_size(mddev, 0, 0);
                sector_t space = conf->spacing;
                int round;
                conf->sector_shift = 0;
@@ -509,6 +522,7 @@ static struct mdk_personality raid0_personality=
        .run            = raid0_run,
        .stop           = raid0_stop,
        .status         = raid0_status,
+       .size           = raid0_size,
 };
 
 static int __init raid0_init (void)
similarity index 96%
rename from include/linux/raid/raid0.h
rename to drivers/md/raid0.h
index fd42aa87c39186791d1a06481fecb6ddd7c03326..824b12eb1d4f50086e8a4dba48d711563362640c 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _RAID0_H
 #define _RAID0_H
 
-#include <linux/raid/md.h>
-
 struct strip_zone
 {
        sector_t zone_start;    /* Zone offset in md_dev (in sectors) */
index e2466425d9cad798edf40858183404408b319e3d..b4f4badc0068991290515b1281cdaddd898893ce 100644 (file)
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include "dm-bio-list.h"
 #include <linux/delay.h>
-#include <linux/raid/raid1.h>
-#include <linux/raid/bitmap.h>
+#include <linux/blkdev.h>
+#include <linux/seq_file.h>
+#include "md.h"
+#include "dm-bio-list.h"
+#include "raid1.h"
+#include "bitmap.h"
 
 #define DEBUG 0
 #if DEBUG
@@ -1723,7 +1726,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                        return 0;
        }
 
-       max_sector = mddev->size << 1;
+       max_sector = mddev->dev_sectors;
        if (sector_nr >= max_sector) {
                /* If we aborted, we need to abort the
                 * sync on the 'current' bitmap chunk (there will
@@ -1919,6 +1922,14 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        return nr_sectors;
 }
 
+static sector_t raid1_size(mddev_t *mddev, sector_t sectors, int raid_disks)
+{
+       if (sectors)
+               return sectors;
+
+       return mddev->dev_sectors;
+}
+
 static int run(mddev_t *mddev)
 {
        conf_t *conf;
@@ -2048,7 +2059,7 @@ static int run(mddev_t *mddev)
        /*
         * Ok, everything is just fine now
         */
-       mddev->array_sectors = mddev->size * 2;
+       md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
 
        mddev->queue->unplug_fn = raid1_unplug;
        mddev->queue->backing_dev_info.congested_fn = raid1_congested;
@@ -2089,6 +2100,9 @@ static int stop(mddev_t *mddev)
                /* need to kick something here to make sure I/O goes? */
        }
 
+       raise_barrier(conf);
+       lower_barrier(conf);
+
        md_unregister_thread(mddev->thread);
        mddev->thread = NULL;
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
@@ -2110,15 +2124,17 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors)
         * any io in the removed space completes, but it hardly seems
         * worth it.
         */
-       mddev->array_sectors = sectors;
+       md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0));
+       if (mddev->array_sectors > raid1_size(mddev, sectors, 0))
+               return -EINVAL;
        set_capacity(mddev->gendisk, mddev->array_sectors);
        mddev->changed = 1;
-       if (mddev->array_sectors / 2 > mddev->size &&
+       if (sectors > mddev->dev_sectors &&
            mddev->recovery_cp == MaxSector) {
-               mddev->recovery_cp = mddev->size << 1;
+               mddev->recovery_cp = mddev->dev_sectors;
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        }
-       mddev->size = mddev->array_sectors / 2;
+       mddev->dev_sectors = sectors;
        mddev->resync_max_sectors = sectors;
        return 0;
 }
@@ -2264,6 +2280,7 @@ static struct mdk_personality raid1_personality =
        .spare_active   = raid1_spare_active,
        .sync_request   = sync_request,
        .resize         = raid1_resize,
+       .size           = raid1_size,
        .check_reshape  = raid1_reshape,
        .quiesce        = raid1_quiesce,
 };
similarity index 99%
rename from include/linux/raid/raid1.h
rename to drivers/md/raid1.h
index 0a9ba7c3302e2393e881244983a3397807e29dfb..1620eea3d57c50231729c04c98e6996c086b00c5 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _RAID1_H
 #define _RAID1_H
 
-#include <linux/raid/md.h>
-
 typedef struct mirror_info mirror_info_t;
 
 struct mirror_info {
index 7301631abe0453a4791dec55ba0eff84912876c3..e293d92641acc2b61c5767d3b343702fd65a509b 100644 (file)
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include "dm-bio-list.h"
 #include <linux/delay.h>
-#include <linux/raid/raid10.h>
-#include <linux/raid/bitmap.h>
+#include <linux/blkdev.h>
+#include <linux/seq_file.h>
+#include "md.h"
+#include "dm-bio-list.h"
+#include "raid10.h"
+#include "bitmap.h"
 
 /*
  * RAID10 provides a combination of RAID0 and RAID1 functionality.
@@ -1695,7 +1698,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                        return 0;
 
  skipped:
-       max_sector = mddev->size << 1;
+       max_sector = mddev->dev_sectors;
        if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
                max_sector = mddev->resync_max_sectors;
        if (sector_nr >= max_sector) {
@@ -2020,6 +2023,25 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        goto skipped;
 }
 
+static sector_t
+raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks)
+{
+       sector_t size;
+       conf_t *conf = mddev_to_conf(mddev);
+
+       if (!raid_disks)
+               raid_disks = mddev->raid_disks;
+       if (!sectors)
+               sectors = mddev->dev_sectors;
+
+       size = sectors >> conf->chunk_shift;
+       sector_div(size, conf->far_copies);
+       size = size * raid_disks;
+       sector_div(size, conf->near_copies);
+
+       return size << conf->chunk_shift;
+}
+
 static int run(mddev_t *mddev)
 {
        conf_t *conf;
@@ -2076,7 +2098,7 @@ static int run(mddev_t *mddev)
        conf->far_offset = fo;
        conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
        conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
-       size = mddev->size >> (conf->chunk_shift-1);
+       size = mddev->dev_sectors >> conf->chunk_shift;
        sector_div(size, fc);
        size = size * conf->raid_disks;
        sector_div(size, nc);
@@ -2089,7 +2111,7 @@ static int run(mddev_t *mddev)
         */
        stride += conf->raid_disks - 1;
        sector_div(stride, conf->raid_disks);
-       mddev->size = stride  << (conf->chunk_shift-1);
+       mddev->dev_sectors = stride << conf->chunk_shift;
 
        if (fo)
                stride = 1;
@@ -2171,8 +2193,8 @@ static int run(mddev_t *mddev)
        /*
         * Ok, everything is just fine now
         */
-       mddev->array_sectors = size << conf->chunk_shift;
-       mddev->resync_max_sectors = size << conf->chunk_shift;
+       md_set_array_sectors(mddev, raid10_size(mddev, 0, 0));
+       mddev->resync_max_sectors = raid10_size(mddev, 0, 0);
 
        mddev->queue->unplug_fn = raid10_unplug;
        mddev->queue->backing_dev_info.congested_fn = raid10_congested;
@@ -2208,6 +2230,9 @@ static int stop(mddev_t *mddev)
 {
        conf_t *conf = mddev_to_conf(mddev);
 
+       raise_barrier(conf, 0);
+       lower_barrier(conf);
+
        md_unregister_thread(mddev->thread);
        mddev->thread = NULL;
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
@@ -2255,6 +2280,7 @@ static struct mdk_personality raid10_personality =
        .spare_active   = raid10_spare_active,
        .sync_request   = sync_request,
        .quiesce        = raid10_quiesce,
+       .size           = raid10_size,
 };
 
 static int __init raid_init(void)
similarity index 99%
rename from include/linux/raid/raid10.h
rename to drivers/md/raid10.h
index e9091cfeb286c2a9b0d30dc57e6748933bb3a9ee..244dbe507a54fa893a6731f57c56de1dca2a3b70 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _RAID10_H
 #define _RAID10_H
 
-#include <linux/raid/md.h>
-
 typedef struct mirror_info mirror_info_t;
 
 struct mirror_info {
index a5ba080d303b93bb3a4d764ea621f4bf9bc191d0..3bbc6d647044c6b6d782427a1e3e35a146bc0751 100644 (file)
  * miss any bits.
  */
 
+#include <linux/blkdev.h>
 #include <linux/kthread.h>
-#include "raid6.h"
-
-#include <linux/raid/bitmap.h>
+#include <linux/raid/pq.h>
 #include <linux/async_tx.h>
+#include <linux/seq_file.h>
+#include "md.h"
+#include "raid5.h"
+#include "bitmap.h"
 
 /*
  * Stripe cache
 
 #define printk_rl(args...) ((void) (printk_ratelimit() && printk(args)))
 
-#if !RAID6_USE_EMPTY_ZERO_PAGE
-/* In .bss so it's zeroed */
-const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
-#endif
-
 /*
  * We maintain a biased count of active stripes in the bottom 16 bits of
  * bi_phys_segments, and a count of processed stripes in the upper 16 bits
@@ -130,12 +128,42 @@ static inline void raid5_set_bi_hw_segments(struct bio *bio, unsigned int cnt)
        bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16);
 }
 
+/* Find first data disk in a raid6 stripe */
+static inline int raid6_d0(struct stripe_head *sh)
+{
+       if (sh->ddf_layout)
+               /* ddf always start from first device */
+               return 0;
+       /* md starts just after Q block */
+       if (sh->qd_idx == sh->disks - 1)
+               return 0;
+       else
+               return sh->qd_idx + 1;
+}
 static inline int raid6_next_disk(int disk, int raid_disks)
 {
        disk++;
        return (disk < raid_disks) ? disk : 0;
 }
 
+/* When walking through the disks in a raid5, starting at raid6_d0,
+ * We need to map each disk to a 'slot', where the data disks are slot
+ * 0 .. raid_disks-3, the parity disk is raid_disks-2 and the Q disk
+ * is raid_disks-1.  This help does that mapping.
+ */
+static int raid6_idx_to_slot(int idx, struct stripe_head *sh,
+                            int *count, int syndrome_disks)
+{
+       int slot;
+
+       if (idx == sh->pd_idx)
+               return syndrome_disks;
+       if (idx == sh->qd_idx)
+               return syndrome_disks + 1;
+       slot = (*count)++;
+       return slot;
+}
+
 static void return_io(struct bio *return_bi)
 {
        struct bio *bi = return_bi;
@@ -193,6 +221,7 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
                }
        }
 }
+
 static void release_stripe(struct stripe_head *sh)
 {
        raid5_conf_t *conf = sh->raid_conf;
@@ -270,9 +299,11 @@ static int grow_buffers(struct stripe_head *sh, int num)
        return 0;
 }
 
-static void raid5_build_block(struct stripe_head *sh, int i);
+static void raid5_build_block(struct stripe_head *sh, int i, int previous);
+static void stripe_set_idx(sector_t stripe, raid5_conf_t *conf, int previous,
+                           struct stripe_head *sh);
 
-static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int disks)
+static void init_stripe(struct stripe_head *sh, sector_t sector, int previous)
 {
        raid5_conf_t *conf = sh->raid_conf;
        int i;
@@ -287,11 +318,12 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int
 
        remove_hash(sh);
 
+       sh->generation = conf->generation - previous;
+       sh->disks = previous ? conf->previous_raid_disks : conf->raid_disks;
        sh->sector = sector;
-       sh->pd_idx = pd_idx;
+       stripe_set_idx(sector, conf, previous, sh);
        sh->state = 0;
 
-       sh->disks = disks;
 
        for (i = sh->disks; i--; ) {
                struct r5dev *dev = &sh->dev[i];
@@ -305,12 +337,13 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int
                        BUG();
                }
                dev->flags = 0;
-               raid5_build_block(sh, i);
+               raid5_build_block(sh, i, previous);
        }
        insert_hash(conf, sh);
 }
 
-static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, int disks)
+static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector,
+                                        short generation)
 {
        struct stripe_head *sh;
        struct hlist_node *hn;
@@ -318,7 +351,7 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, in
        CHECK_DEVLOCK();
        pr_debug("__find_stripe, sector %llu\n", (unsigned long long)sector);
        hlist_for_each_entry(sh, hn, stripe_hash(conf, sector), hash)
-               if (sh->sector == sector && sh->disks == disks)
+               if (sh->sector == sector && sh->generation == generation)
                        return sh;
        pr_debug("__stripe %llu not in cache\n", (unsigned long long)sector);
        return NULL;
@@ -327,8 +360,9 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, in
 static void unplug_slaves(mddev_t *mddev);
 static void raid5_unplug_device(struct request_queue *q);
 
-static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int disks,
-                                            int pd_idx, int noblock)
+static struct stripe_head *
+get_active_stripe(raid5_conf_t *conf, sector_t sector,
+                 int previous, int noblock)
 {
        struct stripe_head *sh;
 
@@ -340,7 +374,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
                wait_event_lock_irq(conf->wait_for_stripe,
                                    conf->quiesce == 0,
                                    conf->device_lock, /* nothing */);
-               sh = __find_stripe(conf, sector, disks);
+               sh = __find_stripe(conf, sector, conf->generation - previous);
                if (!sh) {
                        if (!conf->inactive_blocked)
                                sh = get_free_stripe(conf);
@@ -358,10 +392,11 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
                                        );
                                conf->inactive_blocked = 0;
                        } else
-                               init_stripe(sh, sector, pd_idx, disks);
+                               init_stripe(sh, sector, previous);
                } else {
                        if (atomic_read(&sh->count)) {
-                         BUG_ON(!list_empty(&sh->lru));
+                               BUG_ON(!list_empty(&sh->lru)
+                                   && !test_bit(STRIPE_EXPANDING, &sh->state));
                        } else {
                                if (!test_bit(STRIPE_HANDLE, &sh->state))
                                        atomic_inc(&conf->active_stripes);
@@ -895,8 +930,10 @@ static int grow_stripes(raid5_conf_t *conf, int num)
        struct kmem_cache *sc;
        int devs = conf->raid_disks;
 
-       sprintf(conf->cache_name[0], "raid5-%s", mdname(conf->mddev));
-       sprintf(conf->cache_name[1], "raid5-%s-alt", mdname(conf->mddev));
+       sprintf(conf->cache_name[0],
+               "raid%d-%s", conf->level, mdname(conf->mddev));
+       sprintf(conf->cache_name[1],
+               "raid%d-%s-alt", conf->level, mdname(conf->mddev));
        conf->active_name = 0;
        sc = kmem_cache_create(conf->cache_name[conf->active_name],
                               sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
@@ -911,7 +948,6 @@ static int grow_stripes(raid5_conf_t *conf, int num)
        return 0;
 }
 
-#ifdef CONFIG_MD_RAID5_RESHAPE
 static int resize_stripes(raid5_conf_t *conf, int newsize)
 {
        /* Make all the stripes able to hold 'newsize' devices.
@@ -1036,7 +1072,6 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
        conf->pool_size = newsize;
        return err;
 }
-#endif
 
 static int drop_one_stripe(raid5_conf_t *conf)
 {
@@ -1066,7 +1101,7 @@ static void shrink_stripes(raid5_conf_t *conf)
 
 static void raid5_end_read_request(struct bio * bi, int error)
 {
-       struct stripe_head *sh = bi->bi_private;
+       struct stripe_head *sh = bi->bi_private;
        raid5_conf_t *conf = sh->raid_conf;
        int disks = sh->disks, i;
        int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
@@ -1148,7 +1183,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
 
 static void raid5_end_write_request(struct bio *bi, int error)
 {
-       struct stripe_head *sh = bi->bi_private;
+       struct stripe_head *sh = bi->bi_private;
        raid5_conf_t *conf = sh->raid_conf;
        int disks = sh->disks, i;
        int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
@@ -1176,9 +1211,9 @@ static void raid5_end_write_request(struct bio *bi, int error)
 }
 
 
-static sector_t compute_blocknr(struct stripe_head *sh, int i);
+static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous);
        
-static void raid5_build_block(struct stripe_head *sh, int i)
+static void raid5_build_block(struct stripe_head *sh, int i, int previous)
 {
        struct r5dev *dev = &sh->dev[i];
 
@@ -1194,7 +1229,7 @@ static void raid5_build_block(struct stripe_head *sh, int i)
        dev->req.bi_private = sh;
 
        dev->flags = 0;
-       dev->sector = compute_blocknr(sh, i);
+       dev->sector = compute_blocknr(sh, i, previous);
 }
 
 static void error(mddev_t *mddev, mdk_rdev_t *rdev)
@@ -1227,15 +1262,23 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
  * Input: a 'big' sector number,
  * Output: index of the data and parity disk, and the sector # in them.
  */
-static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
-                       unsigned int data_disks, unsigned int * dd_idx,
-                       unsigned int * pd_idx, raid5_conf_t *conf)
+static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector,
+                                    int previous, int *dd_idx,
+                                    struct stripe_head *sh)
 {
        long stripe;
        unsigned long chunk_number;
        unsigned int chunk_offset;
+       int pd_idx, qd_idx;
+       int ddf_layout = 0;
        sector_t new_sector;
-       int sectors_per_chunk = conf->chunk_size >> 9;
+       int algorithm = previous ? conf->prev_algo
+                                : conf->algorithm;
+       int sectors_per_chunk = previous ? (conf->prev_chunk >> 9)
+                                        : (conf->chunk_size >> 9);
+       int raid_disks = previous ? conf->previous_raid_disks
+                                 : conf->raid_disks;
+       int data_disks = raid_disks - conf->max_degraded;
 
        /* First compute the information on this sector */
 
@@ -1259,68 +1302,170 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
        /*
         * Select the parity disk based on the user selected algorithm.
         */
+       pd_idx = qd_idx = ~0;
        switch(conf->level) {
        case 4:
-               *pd_idx = data_disks;
+               pd_idx = data_disks;
                break;
        case 5:
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
-                       *pd_idx = data_disks - stripe % raid_disks;
-                       if (*dd_idx >= *pd_idx)
+                       pd_idx = data_disks - stripe % raid_disks;
+                       if (*dd_idx >= pd_idx)
                                (*dd_idx)++;
                        break;
                case ALGORITHM_RIGHT_ASYMMETRIC:
-                       *pd_idx = stripe % raid_disks;
-                       if (*dd_idx >= *pd_idx)
+                       pd_idx = stripe % raid_disks;
+                       if (*dd_idx >= pd_idx)
                                (*dd_idx)++;
                        break;
                case ALGORITHM_LEFT_SYMMETRIC:
-                       *pd_idx = data_disks - stripe % raid_disks;
-                       *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks;
+                       pd_idx = data_disks - stripe % raid_disks;
+                       *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
                        break;
                case ALGORITHM_RIGHT_SYMMETRIC:
-                       *pd_idx = stripe % raid_disks;
-                       *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks;
+                       pd_idx = stripe % raid_disks;
+                       *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
+                       break;
+               case ALGORITHM_PARITY_0:
+                       pd_idx = 0;
+                       (*dd_idx)++;
+                       break;
+               case ALGORITHM_PARITY_N:
+                       pd_idx = data_disks;
                        break;
                default:
                        printk(KERN_ERR "raid5: unsupported algorithm %d\n",
-                               conf->algorithm);
+                               algorithm);
+                       BUG();
                }
                break;
        case 6:
 
-               /**** FIX THIS ****/
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
-                       *pd_idx = raid_disks - 1 - (stripe % raid_disks);
-                       if (*pd_idx == raid_disks-1)
-                               (*dd_idx)++;    /* Q D D D P */
-                       else if (*dd_idx >= *pd_idx)
+                       pd_idx = raid_disks - 1 - (stripe % raid_disks);
+                       qd_idx = pd_idx + 1;
+                       if (pd_idx == raid_disks-1) {
+                               (*dd_idx)++;    /* Q D D D P */
+                               qd_idx = 0;
+                       } else if (*dd_idx >= pd_idx)
                                (*dd_idx) += 2; /* D D P Q D */
                        break;
                case ALGORITHM_RIGHT_ASYMMETRIC:
-                       *pd_idx = stripe % raid_disks;
-                       if (*pd_idx == raid_disks-1)
-                               (*dd_idx)++;    /* Q D D D P */
-                       else if (*dd_idx >= *pd_idx)
+                       pd_idx = stripe % raid_disks;
+                       qd_idx = pd_idx + 1;
+                       if (pd_idx == raid_disks-1) {
+                               (*dd_idx)++;    /* Q D D D P */
+                               qd_idx = 0;
+                       } else if (*dd_idx >= pd_idx)
                                (*dd_idx) += 2; /* D D P Q D */
                        break;
                case ALGORITHM_LEFT_SYMMETRIC:
-                       *pd_idx = raid_disks - 1 - (stripe % raid_disks);
-                       *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
+                       pd_idx = raid_disks - 1 - (stripe % raid_disks);
+                       qd_idx = (pd_idx + 1) % raid_disks;
+                       *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks;
                        break;
                case ALGORITHM_RIGHT_SYMMETRIC:
-                       *pd_idx = stripe % raid_disks;
-                       *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
+                       pd_idx = stripe % raid_disks;
+                       qd_idx = (pd_idx + 1) % raid_disks;
+                       *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks;
+                       break;
+
+               case ALGORITHM_PARITY_0:
+                       pd_idx = 0;
+                       qd_idx = 1;
+                       (*dd_idx) += 2;
+                       break;
+               case ALGORITHM_PARITY_N:
+                       pd_idx = data_disks;
+                       qd_idx = data_disks + 1;
                        break;
+
+               case ALGORITHM_ROTATING_ZERO_RESTART:
+                       /* Exactly the same as RIGHT_ASYMMETRIC, but or
+                        * of blocks for computing Q is different.
+                        */
+                       pd_idx = stripe % raid_disks;
+                       qd_idx = pd_idx + 1;
+                       if (pd_idx == raid_disks-1) {
+                               (*dd_idx)++;    /* Q D D D P */
+                               qd_idx = 0;
+                       } else if (*dd_idx >= pd_idx)
+                               (*dd_idx) += 2; /* D D P Q D */
+                       ddf_layout = 1;
+                       break;
+
+               case ALGORITHM_ROTATING_N_RESTART:
+                       /* Same a left_asymmetric, by first stripe is
+                        * D D D P Q  rather than
+                        * Q D D D P
+                        */
+                       pd_idx = raid_disks - 1 - ((stripe + 1) % raid_disks);
+                       qd_idx = pd_idx + 1;
+                       if (pd_idx == raid_disks-1) {
+                               (*dd_idx)++;    /* Q D D D P */
+                               qd_idx = 0;
+                       } else if (*dd_idx >= pd_idx)
+                               (*dd_idx) += 2; /* D D P Q D */
+                       ddf_layout = 1;
+                       break;
+
+               case ALGORITHM_ROTATING_N_CONTINUE:
+                       /* Same as left_symmetric but Q is before P */
+                       pd_idx = raid_disks - 1 - (stripe % raid_disks);
+                       qd_idx = (pd_idx + raid_disks - 1) % raid_disks;
+                       *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
+                       ddf_layout = 1;
+                       break;
+
+               case ALGORITHM_LEFT_ASYMMETRIC_6:
+                       /* RAID5 left_asymmetric, with Q on last device */
+                       pd_idx = data_disks - stripe % (raid_disks-1);
+                       if (*dd_idx >= pd_idx)
+                               (*dd_idx)++;
+                       qd_idx = raid_disks - 1;
+                       break;
+
+               case ALGORITHM_RIGHT_ASYMMETRIC_6:
+                       pd_idx = stripe % (raid_disks-1);
+                       if (*dd_idx >= pd_idx)
+                               (*dd_idx)++;
+                       qd_idx = raid_disks - 1;
+                       break;
+
+               case ALGORITHM_LEFT_SYMMETRIC_6:
+                       pd_idx = data_disks - stripe % (raid_disks-1);
+                       *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1);
+                       qd_idx = raid_disks - 1;
+                       break;
+
+               case ALGORITHM_RIGHT_SYMMETRIC_6:
+                       pd_idx = stripe % (raid_disks-1);
+                       *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1);
+                       qd_idx = raid_disks - 1;
+                       break;
+
+               case ALGORITHM_PARITY_0_6:
+                       pd_idx = 0;
+                       (*dd_idx)++;
+                       qd_idx = raid_disks - 1;
+                       break;
+
+
                default:
                        printk(KERN_CRIT "raid6: unsupported algorithm %d\n",
-                              conf->algorithm);
+                              algorithm);
+                       BUG();
                }
                break;
        }
 
+       if (sh) {
+               sh->pd_idx = pd_idx;
+               sh->qd_idx = qd_idx;
+               sh->ddf_layout = ddf_layout;
+       }
        /*
         * Finally, compute the new sector number
         */
@@ -1329,17 +1474,21 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
 }
 
 
-static sector_t compute_blocknr(struct stripe_head *sh, int i)
+static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous)
 {
        raid5_conf_t *conf = sh->raid_conf;
        int raid_disks = sh->disks;
        int data_disks = raid_disks - conf->max_degraded;
        sector_t new_sector = sh->sector, check;
-       int sectors_per_chunk = conf->chunk_size >> 9;
+       int sectors_per_chunk = previous ? (conf->prev_chunk >> 9)
+                                        : (conf->chunk_size >> 9);
+       int algorithm = previous ? conf->prev_algo
+                                : conf->algorithm;
        sector_t stripe;
        int chunk_offset;
-       int chunk_number, dummy1, dummy2, dd_idx = i;
+       int chunk_number, dummy1, dd_idx = i;
        sector_t r_sector;
+       struct stripe_head sh2;
 
 
        chunk_offset = sector_div(new_sector, sectors_per_chunk);
@@ -1351,7 +1500,7 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
        switch(conf->level) {
        case 4: break;
        case 5:
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
                case ALGORITHM_RIGHT_ASYMMETRIC:
                        if (i > sh->pd_idx)
@@ -1363,19 +1512,27 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
                                i += raid_disks;
                        i -= (sh->pd_idx + 1);
                        break;
+               case ALGORITHM_PARITY_0:
+                       i -= 1;
+                       break;
+               case ALGORITHM_PARITY_N:
+                       break;
                default:
                        printk(KERN_ERR "raid5: unsupported algorithm %d\n",
-                              conf->algorithm);
+                              algorithm);
+                       BUG();
                }
                break;
        case 6:
-               if (i == raid6_next_disk(sh->pd_idx, raid_disks))
+               if (i == sh->qd_idx)
                        return 0; /* It is the Q disk */
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
                case ALGORITHM_RIGHT_ASYMMETRIC:
-                       if (sh->pd_idx == raid_disks-1)
-                               i--;    /* Q D D D P */
+               case ALGORITHM_ROTATING_ZERO_RESTART:
+               case ALGORITHM_ROTATING_N_RESTART:
+                       if (sh->pd_idx == raid_disks-1)
+                               i--;    /* Q D D D P */
                        else if (i > sh->pd_idx)
                                i -= 2; /* D D P Q D */
                        break;
@@ -1390,9 +1547,35 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
                                i -= (sh->pd_idx + 2);
                        }
                        break;
+               case ALGORITHM_PARITY_0:
+                       i -= 2;
+                       break;
+               case ALGORITHM_PARITY_N:
+                       break;
+               case ALGORITHM_ROTATING_N_CONTINUE:
+                       if (sh->pd_idx == 0)
+                               i--;    /* P D D D Q */
+                       else if (i > sh->pd_idx)
+                               i -= 2; /* D D Q P D */
+                       break;
+               case ALGORITHM_LEFT_ASYMMETRIC_6:
+               case ALGORITHM_RIGHT_ASYMMETRIC_6:
+                       if (i > sh->pd_idx)
+                               i--;
+                       break;
+               case ALGORITHM_LEFT_SYMMETRIC_6:
+               case ALGORITHM_RIGHT_SYMMETRIC_6:
+                       if (i < sh->pd_idx)
+                               i += data_disks + 1;
+                       i -= (sh->pd_idx + 1);
+                       break;
+               case ALGORITHM_PARITY_0_6:
+                       i -= 1;
+                       break;
                default:
                        printk(KERN_CRIT "raid6: unsupported algorithm %d\n",
-                              conf->algorithm);
+                              algorithm);
+                       BUG();
                }
                break;
        }
@@ -1400,8 +1583,10 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
        chunk_number = stripe * data_disks + i;
        r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset;
 
-       check = raid5_compute_sector(r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf);
-       if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) {
+       check = raid5_compute_sector(conf, r_sector,
+                                    previous, &dummy1, &sh2);
+       if (check != sh->sector || dummy1 != dd_idx || sh2.pd_idx != sh->pd_idx
+               || sh2.qd_idx != sh->qd_idx) {
                printk(KERN_ERR "compute_blocknr: map not correct\n");
                return 0;
        }
@@ -1468,14 +1653,16 @@ static void copy_data(int frombio, struct bio *bio,
 
 static void compute_parity6(struct stripe_head *sh, int method)
 {
-       raid6_conf_t *conf = sh->raid_conf;
-       int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = sh->disks, count;
+       raid5_conf_t *conf = sh->raid_conf;
+       int i, pd_idx, qd_idx, d0_idx, disks = sh->disks, count;
+       int syndrome_disks = sh->ddf_layout ? disks : (disks - 2);
        struct bio *chosen;
        /**** FIX THIS: This could be very bad if disks is close to 256 ****/
-       void *ptrs[disks];
+       void *ptrs[syndrome_disks+2];
 
-       qd_idx = raid6_next_disk(pd_idx, disks);
-       d0_idx = raid6_next_disk(qd_idx, disks);
+       pd_idx = sh->pd_idx;
+       qd_idx = sh->qd_idx;
+       d0_idx = raid6_d0(sh);
 
        pr_debug("compute_parity, stripe %llu, method %d\n",
                (unsigned long long)sh->sector, method);
@@ -1513,24 +1700,29 @@ static void compute_parity6(struct stripe_head *sh, int method)
                        set_bit(R5_UPTODATE, &sh->dev[i].flags);
                }
 
-//     switch(method) {
-//     case RECONSTRUCT_WRITE:
-//     case CHECK_PARITY:
-//     case UPDATE_PARITY:
-               /* Note that unlike RAID-5, the ordering of the disks matters greatly. */
-               /* FIX: Is this ordering of drives even remotely optimal? */
-               count = 0;
-               i = d0_idx;
-               do {
-                       ptrs[count++] = page_address(sh->dev[i].page);
-                       if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags))
-                               printk("block %d/%d not uptodate on parity calc\n", i,count);
-                       i = raid6_next_disk(i, disks);
-               } while ( i != d0_idx );
-//             break;
-//     }
-
-       raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs);
+       /* Note that unlike RAID-5, the ordering of the disks matters greatly.*/
+
+       for (i = 0; i < disks; i++)
+               ptrs[i] = (void *)raid6_empty_zero_page;
+
+       count = 0;
+       i = d0_idx;
+       do {
+               int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks);
+
+               ptrs[slot] = page_address(sh->dev[i].page);
+               if (slot < syndrome_disks &&
+                   !test_bit(R5_UPTODATE, &sh->dev[i].flags)) {
+                       printk(KERN_ERR "block %d/%d not uptodate "
+                              "on parity calc\n", i, count);
+                       BUG();
+               }
+
+               i = raid6_next_disk(i, disks);
+       } while (i != d0_idx);
+       BUG_ON(count != syndrome_disks);
+
+       raid6_call.gen_syndrome(syndrome_disks+2, STRIPE_SIZE, ptrs);
 
        switch(method) {
        case RECONSTRUCT_WRITE:
@@ -1552,8 +1744,7 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
 {
        int i, count, disks = sh->disks;
        void *ptr[MAX_XOR_BLOCKS], *dest, *p;
-       int pd_idx = sh->pd_idx;
-       int qd_idx = raid6_next_disk(pd_idx, disks);
+       int qd_idx = sh->qd_idx;
 
        pr_debug("compute_block_1, stripe %llu, idx %d\n",
                (unsigned long long)sh->sector, dd_idx);
@@ -1589,63 +1780,65 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
 static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
 {
        int i, count, disks = sh->disks;
-       int pd_idx = sh->pd_idx;
-       int qd_idx = raid6_next_disk(pd_idx, disks);
-       int d0_idx = raid6_next_disk(qd_idx, disks);
-       int faila, failb;
+       int syndrome_disks = sh->ddf_layout ? disks : disks-2;
+       int d0_idx = raid6_d0(sh);
+       int faila = -1, failb = -1;
+       /**** FIX THIS: This could be very bad if disks is close to 256 ****/
+       void *ptrs[syndrome_disks+2];
 
-       /* faila and failb are disk numbers relative to d0_idx */
-       /* pd_idx become disks-2 and qd_idx become disks-1 */
-       faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx;
-       failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx;
+       for (i = 0; i < disks ; i++)
+               ptrs[i] = (void *)raid6_empty_zero_page;
+       count = 0;
+       i = d0_idx;
+       do {
+               int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks);
+
+               ptrs[slot] = page_address(sh->dev[i].page);
+
+               if (i == dd_idx1)
+                       faila = slot;
+               if (i == dd_idx2)
+                       failb = slot;
+               i = raid6_next_disk(i, disks);
+       } while (i != d0_idx);
+       BUG_ON(count != syndrome_disks);
 
        BUG_ON(faila == failb);
        if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; }
 
        pr_debug("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n",
-              (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb);
+                (unsigned long long)sh->sector, dd_idx1, dd_idx2,
+                faila, failb);
 
-       if ( failb == disks-1 ) {
+       if (failb == syndrome_disks+1) {
                /* Q disk is one of the missing disks */
-               if ( faila == disks-2 ) {
+               if (faila == syndrome_disks) {
                        /* Missing P+Q, just recompute */
                        compute_parity6(sh, UPDATE_PARITY);
                        return;
                } else {
                        /* We're missing D+Q; recompute D from P */
-                       compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0);
+                       compute_block_1(sh, ((dd_idx1 == sh->qd_idx) ?
+                                            dd_idx2 : dd_idx1),
+                                       0);
                        compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */
                        return;
                }
        }
 
-       /* We're missing D+P or D+D; build pointer table */
-       {
-               /**** FIX THIS: This could be very bad if disks is close to 256 ****/
-               void *ptrs[disks];
-
-               count = 0;
-               i = d0_idx;
-               do {
-                       ptrs[count++] = page_address(sh->dev[i].page);
-                       i = raid6_next_disk(i, disks);
-                       if (i != dd_idx1 && i != dd_idx2 &&
-                           !test_bit(R5_UPTODATE, &sh->dev[i].flags))
-                               printk("compute_2 with missing block %d/%d\n", count, i);
-               } while ( i != d0_idx );
-
-               if ( failb == disks-2 ) {
-                       /* We're missing D+P. */
-                       raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs);
-               } else {
-                       /* We're missing D+D. */
-                       raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs);
-               }
-
-               /* Both the above update both missing blocks */
-               set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags);
-               set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags);
+       /* We're missing D+P or D+D; */
+       if (failb == syndrome_disks) {
+               /* We're missing D+P. */
+               raid6_datap_recov(syndrome_disks+2, STRIPE_SIZE, faila, ptrs);
+       } else {
+               /* We're missing D+D. */
+               raid6_2data_recov(syndrome_disks+2, STRIPE_SIZE, faila, failb,
+                                 ptrs);
        }
+
+       /* Both the above update both missing blocks */
+       set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags);
+       set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags);
 }
 
 static void
@@ -1800,17 +1993,21 @@ static int page_is_zero(struct page *p)
                memcmp(a, a+4, STRIPE_SIZE-4)==0);
 }
 
-static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
+static void stripe_set_idx(sector_t stripe, raid5_conf_t *conf, int previous,
+                           struct stripe_head *sh)
 {
-       int sectors_per_chunk = conf->chunk_size >> 9;
-       int pd_idx, dd_idx;
+       int sectors_per_chunk =
+               previous ? (conf->prev_chunk >> 9)
+                        : (conf->chunk_size >> 9);
+       int dd_idx;
        int chunk_offset = sector_div(stripe, sectors_per_chunk);
+       int disks = previous ? conf->previous_raid_disks : conf->raid_disks;
 
-       raid5_compute_sector(stripe * (disks - conf->max_degraded)
+       raid5_compute_sector(conf,
+                            stripe * (disks - conf->max_degraded)
                             *sectors_per_chunk + chunk_offset,
-                            disks, disks - conf->max_degraded,
-                            &dd_idx, &pd_idx, conf);
-       return pd_idx;
+                            previous,
+                            &dd_idx, sh);
 }
 
 static void
@@ -2181,7 +2378,7 @@ static void handle_stripe_dirtying6(raid5_conf_t *conf,
                struct r6_state *r6s, int disks)
 {
        int rcw = 0, must_compute = 0, pd_idx = sh->pd_idx, i;
-       int qd_idx = r6s->qd_idx;
+       int qd_idx = sh->qd_idx;
        for (i = disks; i--; ) {
                struct r5dev *dev = &sh->dev[i];
                /* Would I have to read this buffer for reconstruct_write */
@@ -2371,7 +2568,7 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
        int update_p = 0, update_q = 0;
        struct r5dev *dev;
        int pd_idx = sh->pd_idx;
-       int qd_idx = r6s->qd_idx;
+       int qd_idx = sh->qd_idx;
 
        set_bit(STRIPE_HANDLE, &sh->state);
 
@@ -2467,17 +2664,14 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
        struct dma_async_tx_descriptor *tx = NULL;
        clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
        for (i = 0; i < sh->disks; i++)
-               if (i != sh->pd_idx && (!r6s || i != r6s->qd_idx)) {
-                       int dd_idx, pd_idx, j;
+               if (i != sh->pd_idx && i != sh->qd_idx) {
+                       int dd_idx, j;
                        struct stripe_head *sh2;
 
-                       sector_t bn = compute_blocknr(sh, i);
-                       sector_t s = raid5_compute_sector(bn, conf->raid_disks,
-                                               conf->raid_disks -
-                                               conf->max_degraded, &dd_idx,
-                                               &pd_idx, conf);
-                       sh2 = get_active_stripe(conf, s, conf->raid_disks,
-                                               pd_idx, 1);
+                       sector_t bn = compute_blocknr(sh, i, 1);
+                       sector_t s = raid5_compute_sector(conf, bn, 0,
+                                                         &dd_idx, NULL);
+                       sh2 = get_active_stripe(conf, s, 0, 1);
                        if (sh2 == NULL)
                                /* so far only the early blocks of this stripe
                                 * have been requested.  When later blocks
@@ -2500,8 +2694,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
                        set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
                        for (j = 0; j < conf->raid_disks; j++)
                                if (j != sh2->pd_idx &&
-                                   (!r6s || j != raid6_next_disk(sh2->pd_idx,
-                                                                sh2->disks)) &&
+                                   (!r6s || j != sh2->qd_idx) &&
                                    !test_bit(R5_Expanded, &sh2->dev[j].flags))
                                        break;
                        if (j == conf->raid_disks) {
@@ -2750,6 +2943,23 @@ static bool handle_stripe5(struct stripe_head *sh)
 
        /* Finish reconstruct operations initiated by the expansion process */
        if (sh->reconstruct_state == reconstruct_state_result) {
+               struct stripe_head *sh2
+                       = get_active_stripe(conf, sh->sector, 1, 1);
+               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
+                       /* sh cannot be written until sh2 has been read.
+                        * so arrange for sh to be delayed a little
+                        */
+                       set_bit(STRIPE_DELAYED, &sh->state);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
+                                             &sh2->state))
+                               atomic_inc(&conf->preread_active_stripes);
+                       release_stripe(sh2);
+                       goto unlock;
+               }
+               if (sh2)
+                       release_stripe(sh2);
+
                sh->reconstruct_state = reconstruct_state_idle;
                clear_bit(STRIPE_EXPANDING, &sh->state);
                for (i = conf->raid_disks; i--; ) {
@@ -2763,8 +2973,7 @@ static bool handle_stripe5(struct stripe_head *sh)
            !sh->reconstruct_state) {
                /* Need to write out all blocks after computing parity */
                sh->disks = conf->raid_disks;
-               sh->pd_idx = stripe_to_pdidx(sh->sector, conf,
-                       conf->raid_disks);
+               stripe_set_idx(sh->sector, conf, 0, sh);
                schedule_reconstruction5(sh, &s, 1, 1);
        } else if (s.expanded && !sh->reconstruct_state && s.locked == 0) {
                clear_bit(STRIPE_EXPAND_READY, &sh->state);
@@ -2796,20 +3005,19 @@ static bool handle_stripe5(struct stripe_head *sh)
 
 static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
 {
-       raid6_conf_t *conf = sh->raid_conf;
+       raid5_conf_t *conf = sh->raid_conf;
        int disks = sh->disks;
        struct bio *return_bi = NULL;
-       int i, pd_idx = sh->pd_idx;
+       int i, pd_idx = sh->pd_idx, qd_idx = sh->qd_idx;
        struct stripe_head_state s;
        struct r6_state r6s;
        struct r5dev *dev, *pdev, *qdev;
        mdk_rdev_t *blocked_rdev = NULL;
 
-       r6s.qd_idx = raid6_next_disk(pd_idx, disks);
        pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
                "pd_idx=%d, qd_idx=%d\n",
               (unsigned long long)sh->sector, sh->state,
-              atomic_read(&sh->count), pd_idx, r6s.qd_idx);
+              atomic_read(&sh->count), pd_idx, qd_idx);
        memset(&s, 0, sizeof(s));
 
        spin_lock(&sh->lock);
@@ -2920,9 +3128,9 @@ static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
        pdev = &sh->dev[pd_idx];
        r6s.p_failed = (s.failed >= 1 && r6s.failed_num[0] == pd_idx)
                || (s.failed >= 2 && r6s.failed_num[1] == pd_idx);
-       qdev = &sh->dev[r6s.qd_idx];
-       r6s.q_failed = (s.failed >= 1 && r6s.failed_num[0] == r6s.qd_idx)
-               || (s.failed >= 2 && r6s.failed_num[1] == r6s.qd_idx);
+       qdev = &sh->dev[qd_idx];
+       r6s.q_failed = (s.failed >= 1 && r6s.failed_num[0] == qd_idx)
+               || (s.failed >= 2 && r6s.failed_num[1] == qd_idx);
 
        if ( s.written &&
             ( r6s.p_failed || ((test_bit(R5_Insync, &pdev->flags)
@@ -2980,10 +3188,26 @@ static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
                }
 
        if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state)) {
+               struct stripe_head *sh2
+                       = get_active_stripe(conf, sh->sector, 1, 1);
+               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
+                       /* sh cannot be written until sh2 has been read.
+                        * so arrange for sh to be delayed a little
+                        */
+                       set_bit(STRIPE_DELAYED, &sh->state);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
+                                             &sh2->state))
+                               atomic_inc(&conf->preread_active_stripes);
+                       release_stripe(sh2);
+                       goto unlock;
+               }
+               if (sh2)
+                       release_stripe(sh2);
+
                /* Need to write out all blocks after computing P&Q */
                sh->disks = conf->raid_disks;
-               sh->pd_idx = stripe_to_pdidx(sh->sector, conf,
-                                            conf->raid_disks);
+               stripe_set_idx(sh->sector, conf, 0, sh);
                compute_parity6(sh, RECONSTRUCT_WRITE);
                for (i = conf->raid_disks ; i-- ;  ) {
                        set_bit(R5_LOCKED, &sh->dev[i].flags);
@@ -3134,6 +3358,8 @@ static int raid5_mergeable_bvec(struct request_queue *q,
        if ((bvm->bi_rw & 1) == WRITE)
                return biovec->bv_len; /* always allow writes to be mergeable */
 
+       if (mddev->new_chunk < mddev->chunk_size)
+               chunk_sectors = mddev->new_chunk >> 9;
        max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
        if (max < 0) max = 0;
        if (max <= biovec->bv_len && bio_sectors == 0)
@@ -3149,6 +3375,8 @@ static int in_chunk_boundary(mddev_t *mddev, struct bio *bio)
        unsigned int chunk_sectors = mddev->chunk_size >> 9;
        unsigned int bio_sectors = bio->bi_size >> 9;
 
+       if (mddev->new_chunk < mddev->chunk_size)
+               chunk_sectors = mddev->new_chunk >> 9;
        return  chunk_sectors >=
                ((sector & (chunk_sectors - 1)) + bio_sectors);
 }
@@ -3255,9 +3483,7 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio)
 {
        mddev_t *mddev = q->queuedata;
        raid5_conf_t *conf = mddev_to_conf(mddev);
-       const unsigned int raid_disks = conf->raid_disks;
-       const unsigned int data_disks = raid_disks - conf->max_degraded;
-       unsigned int dd_idx, pd_idx;
+       unsigned int dd_idx;
        struct bio* align_bi;
        mdk_rdev_t *rdev;
 
@@ -3266,7 +3492,7 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio)
                return 0;
        }
        /*
-        * use bio_clone to make a copy of the bio
+        * use bio_clone to make a copy of the bio
         */
        align_bi = bio_clone(raid_bio, GFP_NOIO);
        if (!align_bi)
@@ -3280,12 +3506,9 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio)
        /*
         *      compute position
         */
-       align_bi->bi_sector =  raid5_compute_sector(raid_bio->bi_sector,
-                                       raid_disks,
-                                       data_disks,
-                                       &dd_idx,
-                                       &pd_idx,
-                                       conf);
+       align_bi->bi_sector =  raid5_compute_sector(conf, raid_bio->bi_sector,
+                                                   0,
+                                                   &dd_idx, NULL);
 
        rcu_read_lock();
        rdev = rcu_dereference(conf->disks[dd_idx].rdev);
@@ -3377,7 +3600,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
 {
        mddev_t *mddev = q->queuedata;
        raid5_conf_t *conf = mddev_to_conf(mddev);
-       unsigned int dd_idx, pd_idx;
+       int dd_idx;
        sector_t new_sector;
        sector_t logical_sector, last_sector;
        struct stripe_head *sh;
@@ -3400,7 +3623,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
        if (rw == READ &&
             mddev->reshape_position == MaxSector &&
             chunk_aligned_read(q,bi))
-               return 0;
+               return 0;
 
        logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
        last_sector = bi->bi_sector + (bi->bi_size>>9);
@@ -3410,26 +3633,31 @@ static int make_request(struct request_queue *q, struct bio * bi)
        for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
                DEFINE_WAIT(w);
                int disks, data_disks;
+               int previous;
 
        retry:
+               previous = 0;
+               disks = conf->raid_disks;
                prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
-               if (likely(conf->expand_progress == MaxSector))
-                       disks = conf->raid_disks;
-               else {
-                       /* spinlock is needed as expand_progress may be
+               if (unlikely(conf->reshape_progress != MaxSector)) {
+                       /* spinlock is needed as reshape_progress may be
                         * 64bit on a 32bit platform, and so it might be
                         * possible to see a half-updated value
-                        * Ofcourse expand_progress could change after
+                        * Ofcourse reshape_progress could change after
                         * the lock is dropped, so once we get a reference
                         * to the stripe that we think it is, we will have
                         * to check again.
                         */
                        spin_lock_irq(&conf->device_lock);
-                       disks = conf->raid_disks;
-                       if (logical_sector >= conf->expand_progress)
+                       if (mddev->delta_disks < 0
+                           ? logical_sector < conf->reshape_progress
+                           : logical_sector >= conf->reshape_progress) {
                                disks = conf->previous_raid_disks;
-                       else {
-                               if (logical_sector >= conf->expand_lo) {
+                               previous = 1;
+                       } else {
+                               if (mddev->delta_disks < 0
+                                   ? logical_sector < conf->reshape_safe
+                                   : logical_sector >= conf->reshape_safe) {
                                        spin_unlock_irq(&conf->device_lock);
                                        schedule();
                                        goto retry;
@@ -3439,15 +3667,17 @@ static int make_request(struct request_queue *q, struct bio * bi)
                }
                data_disks = disks - conf->max_degraded;
 
-               new_sector = raid5_compute_sector(logical_sector, disks, data_disks,
-                                                 &dd_idx, &pd_idx, conf);
+               new_sector = raid5_compute_sector(conf, logical_sector,
+                                                 previous,
+                                                 &dd_idx, NULL);
                pr_debug("raid5: make_request, sector %llu logical %llu\n",
                        (unsigned long long)new_sector, 
                        (unsigned long long)logical_sector);
 
-               sh = get_active_stripe(conf, new_sector, disks, pd_idx, (bi->bi_rw&RWA_MASK));
+               sh = get_active_stripe(conf, new_sector, previous,
+                                      (bi->bi_rw&RWA_MASK));
                if (sh) {
-                       if (unlikely(conf->expand_progress != MaxSector)) {
+                       if (unlikely(previous)) {
                                /* expansion might have moved on while waiting for a
                                 * stripe, so we must do the range check again.
                                 * Expansion could still move past after this
@@ -3458,8 +3688,9 @@ static int make_request(struct request_queue *q, struct bio * bi)
                                 */
                                int must_retry = 0;
                                spin_lock_irq(&conf->device_lock);
-                               if (logical_sector <  conf->expand_progress &&
-                                   disks == conf->previous_raid_disks)
+                               if (mddev->delta_disks < 0
+                                   ? logical_sector >= conf->reshape_progress
+                                   : logical_sector < conf->reshape_progress)
                                        /* mismatch, need to try again */
                                        must_retry = 1;
                                spin_unlock_irq(&conf->device_lock);
@@ -3514,6 +3745,8 @@ static int make_request(struct request_queue *q, struct bio * bi)
        return 0;
 }
 
+static sector_t raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks);
+
 static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped)
 {
        /* reshaping is quite different to recovery/resync so it is
@@ -3527,61 +3760,118 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
         */
        raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
        struct stripe_head *sh;
-       int pd_idx;
        sector_t first_sector, last_sector;
        int raid_disks = conf->previous_raid_disks;
        int data_disks = raid_disks - conf->max_degraded;
        int new_data_disks = conf->raid_disks - conf->max_degraded;
        int i;
        int dd_idx;
-       sector_t writepos, safepos, gap;
-
-       if (sector_nr == 0 &&
-           conf->expand_progress != 0) {
-               /* restarting in the middle, skip the initial sectors */
-               sector_nr = conf->expand_progress;
+       sector_t writepos, readpos, safepos;
+       sector_t stripe_addr;
+       int reshape_sectors;
+       struct list_head stripes;
+
+       if (sector_nr == 0) {
+               /* If restarting in the middle, skip the initial sectors */
+               if (mddev->delta_disks < 0 &&
+                   conf->reshape_progress < raid5_size(mddev, 0, 0)) {
+                       sector_nr = raid5_size(mddev, 0, 0)
+                               - conf->reshape_progress;
+               } else if (mddev->delta_disks > 0 &&
+                          conf->reshape_progress > 0)
+                       sector_nr = conf->reshape_progress;
                sector_div(sector_nr, new_data_disks);
-               *skipped = 1;
-               return sector_nr;
+               if (sector_nr) {
+                       *skipped = 1;
+                       return sector_nr;
+               }
        }
 
+       /* We need to process a full chunk at a time.
+        * If old and new chunk sizes differ, we need to process the
+        * largest of these
+        */
+       if (mddev->new_chunk > mddev->chunk_size)
+               reshape_sectors = mddev->new_chunk / 512;
+       else
+               reshape_sectors = mddev->chunk_size / 512;
+
        /* we update the metadata when there is more than 3Meg
         * in the block range (that is rather arbitrary, should
         * probably be time based) or when the data about to be
         * copied would over-write the source of the data at
         * the front of the range.
-        * i.e. one new_stripe forward from expand_progress new_maps
-        * to after where expand_lo old_maps to
+        * i.e. one new_stripe along from reshape_progress new_maps
+        * to after where reshape_safe old_maps to
         */
-       writepos = conf->expand_progress +
-               conf->chunk_size/512*(new_data_disks);
+       writepos = conf->reshape_progress;
        sector_div(writepos, new_data_disks);
-       safepos = conf->expand_lo;
+       readpos = conf->reshape_progress;
+       sector_div(readpos, data_disks);
+       safepos = conf->reshape_safe;
        sector_div(safepos, data_disks);
-       gap = conf->expand_progress - conf->expand_lo;
+       if (mddev->delta_disks < 0) {
+               writepos -= reshape_sectors;
+               readpos += reshape_sectors;
+               safepos += reshape_sectors;
+       } else {
+               writepos += reshape_sectors;
+               readpos -= reshape_sectors;
+               safepos -= reshape_sectors;
+       }
 
-       if (writepos >= safepos ||
-           gap > (new_data_disks)*3000*2 /*3Meg*/) {
+       /* 'writepos' is the most advanced device address we might write.
+        * 'readpos' is the least advanced device address we might read.
+        * 'safepos' is the least address recorded in the metadata as having
+        *     been reshaped.
+        * If 'readpos' is behind 'writepos', then there is no way that we can
+        * ensure safety in the face of a crash - that must be done by userspace
+        * making a backup of the data.  So in that case there is no particular
+        * rush to update metadata.
+        * Otherwise if 'safepos' is behind 'writepos', then we really need to
+        * update the metadata to advance 'safepos' to match 'readpos' so that
+        * we can be safe in the event of a crash.
+        * So we insist on updating metadata if safepos is behind writepos and
+        * readpos is beyond writepos.
+        * In any case, update the metadata every 10 seconds.
+        * Maybe that number should be configurable, but I'm not sure it is
+        * worth it.... maybe it could be a multiple of safemode_delay???
+        */
+       if ((mddev->delta_disks < 0
+            ? (safepos > writepos && readpos < writepos)
+            : (safepos < writepos && readpos > writepos)) ||
+           time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
                /* Cannot proceed until we've updated the superblock... */
                wait_event(conf->wait_for_overlap,
                           atomic_read(&conf->reshape_stripes)==0);
-               mddev->reshape_position = conf->expand_progress;
+               mddev->reshape_position = conf->reshape_progress;
+               conf->reshape_checkpoint = jiffies;
                set_bit(MD_CHANGE_DEVS, &mddev->flags);
                md_wakeup_thread(mddev->thread);
                wait_event(mddev->sb_wait, mddev->flags == 0 ||
                           kthread_should_stop());
                spin_lock_irq(&conf->device_lock);
-               conf->expand_lo = mddev->reshape_position;
+               conf->reshape_safe = mddev->reshape_position;
                spin_unlock_irq(&conf->device_lock);
                wake_up(&conf->wait_for_overlap);
        }
 
-       for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) {
+       if (mddev->delta_disks < 0) {
+               BUG_ON(conf->reshape_progress == 0);
+               stripe_addr = writepos;
+               BUG_ON((mddev->dev_sectors &
+                       ~((sector_t)reshape_sectors - 1))
+                      - reshape_sectors - stripe_addr
+                      != sector_nr);
+       } else {
+               BUG_ON(writepos != sector_nr + reshape_sectors);
+               stripe_addr = sector_nr;
+       }
+       INIT_LIST_HEAD(&stripes);
+       for (i = 0; i < reshape_sectors; i += STRIPE_SECTORS) {
                int j;
                int skipped = 0;
-               pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks);
-               sh = get_active_stripe(conf, sector_nr+i,
-                                      conf->raid_disks, pd_idx, 0);
+               sh = get_active_stripe(conf, stripe_addr+i, 0, 0);
                set_bit(STRIPE_EXPANDING, &sh->state);
                atomic_inc(&conf->reshape_stripes);
                /* If any of this stripe is beyond the end of the old
@@ -3592,10 +3882,10 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                        if (j == sh->pd_idx)
                                continue;
                        if (conf->level == 6 &&
-                           j == raid6_next_disk(sh->pd_idx, sh->disks))
+                           j == sh->qd_idx)
                                continue;
-                       s = compute_blocknr(sh, j);
-                       if (s < mddev->array_sectors) {
+                       s = compute_blocknr(sh, j, 0);
+                       if (s < raid5_size(mddev, 0, 0)) {
                                skipped = 1;
                                continue;
                        }
@@ -3607,10 +3897,13 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                        set_bit(STRIPE_EXPAND_READY, &sh->state);
                        set_bit(STRIPE_HANDLE, &sh->state);
                }
-               release_stripe(sh);
+               list_add(&sh->lru, &stripes);
        }
        spin_lock_irq(&conf->device_lock);
-       conf->expand_progress = (sector_nr + i) * new_data_disks;
+       if (mddev->delta_disks < 0)
+               conf->reshape_progress -= reshape_sectors * new_data_disks;
+       else
+               conf->reshape_progress += reshape_sectors * new_data_disks;
        spin_unlock_irq(&conf->device_lock);
        /* Ok, those stripe are ready. We can start scheduling
         * reads on the source stripes.
@@ -3618,46 +3911,50 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
         * block on the destination stripes.
         */
        first_sector =
-               raid5_compute_sector(sector_nr*(new_data_disks),
-                                    raid_disks, data_disks,
-                                    &dd_idx, &pd_idx, conf);
+               raid5_compute_sector(conf, stripe_addr*(new_data_disks),
+                                    1, &dd_idx, NULL);
        last_sector =
-               raid5_compute_sector((sector_nr+conf->chunk_size/512)
-                                    *(new_data_disks) -1,
-                                    raid_disks, data_disks,
-                                    &dd_idx, &pd_idx, conf);
-       if (last_sector >= (mddev->size<<1))
-               last_sector = (mddev->size<<1)-1;
+               raid5_compute_sector(conf, ((stripe_addr+conf->chunk_size/512)
+                                           *(new_data_disks) - 1),
+                                    1, &dd_idx, NULL);
+       if (last_sector >= mddev->dev_sectors)
+               last_sector = mddev->dev_sectors - 1;
        while (first_sector <= last_sector) {
-               pd_idx = stripe_to_pdidx(first_sector, conf,
-                                        conf->previous_raid_disks);
-               sh = get_active_stripe(conf, first_sector,
-                                      conf->previous_raid_disks, pd_idx, 0);
+               sh = get_active_stripe(conf, first_sector, 1, 0);
                set_bit(STRIPE_EXPAND_SOURCE, &sh->state);
                set_bit(STRIPE_HANDLE, &sh->state);
                release_stripe(sh);
                first_sector += STRIPE_SECTORS;
        }
+       /* Now that the sources are clearly marked, we can release
+        * the destination stripes
+        */
+       while (!list_empty(&stripes)) {
+               sh = list_entry(stripes.next, struct stripe_head, lru);
+               list_del_init(&sh->lru);
+               release_stripe(sh);
+       }
        /* If this takes us to the resync_max point where we have to pause,
         * then we need to write out the superblock.
         */
-       sector_nr += conf->chunk_size>>9;
+       sector_nr += reshape_sectors;
        if (sector_nr >= mddev->resync_max) {
                /* Cannot proceed until we've updated the superblock... */
                wait_event(conf->wait_for_overlap,
                           atomic_read(&conf->reshape_stripes) == 0);
-               mddev->reshape_position = conf->expand_progress;
+               mddev->reshape_position = conf->reshape_progress;
+               conf->reshape_checkpoint = jiffies;
                set_bit(MD_CHANGE_DEVS, &mddev->flags);
                md_wakeup_thread(mddev->thread);
                wait_event(mddev->sb_wait,
                           !test_bit(MD_CHANGE_DEVS, &mddev->flags)
                           || kthread_should_stop());
                spin_lock_irq(&conf->device_lock);
-               conf->expand_lo = mddev->reshape_position;
+               conf->reshape_safe = mddev->reshape_position;
                spin_unlock_irq(&conf->device_lock);
                wake_up(&conf->wait_for_overlap);
        }
-       return conf->chunk_size>>9;
+       return reshape_sectors;
 }
 
 /* FIXME go_faster isn't used */
@@ -3665,9 +3962,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
 {
        raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
        struct stripe_head *sh;
-       int pd_idx;
-       int raid_disks = conf->raid_disks;
-       sector_t max_sector = mddev->size << 1;
+       sector_t max_sector = mddev->dev_sectors;
        int sync_blocks;
        int still_degraded = 0;
        int i;
@@ -3675,6 +3970,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
        if (sector_nr >= max_sector) {
                /* just being told to finish up .. nothing much to do */
                unplug_slaves(mddev);
+
                if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
                        end_reshape(conf);
                        return 0;
@@ -3705,7 +4001,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
         */
        if (mddev->degraded >= conf->max_degraded &&
            test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
-               sector_t rv = (mddev->size << 1) - sector_nr;
+               sector_t rv = mddev->dev_sectors - sector_nr;
                *skipped = 1;
                return rv;
        }
@@ -3721,10 +4017,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
 
        bitmap_cond_end_sync(mddev->bitmap, sector_nr);
 
-       pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks);
-       sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1);
+       sh = get_active_stripe(conf, sector_nr, 0, 1);
        if (sh == NULL) {
-               sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0);
+               sh = get_active_stripe(conf, sector_nr, 0, 0);
                /* make sure we don't swamp the stripe cache if someone else
                 * is trying to get access
                 */
@@ -3766,19 +4061,15 @@ static int  retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
         * it will be only one 'dd_idx' and only need one call to raid5_compute_sector.
         */
        struct stripe_head *sh;
-       int dd_idx, pd_idx;
+       int dd_idx;
        sector_t sector, logical_sector, last_sector;
        int scnt = 0;
        int remaining;
        int handled = 0;
 
        logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
-       sector = raid5_compute_sector(  logical_sector,
-                                       conf->raid_disks,
-                                       conf->raid_disks - conf->max_degraded,
-                                       &dd_idx,
-                                       &pd_idx,
-                                       conf);
+       sector = raid5_compute_sector(conf, logical_sector,
+                                     0, &dd_idx, NULL);
        last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
 
        for (; logical_sector < last_sector;
@@ -3790,7 +4081,7 @@ static int  retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
                        /* already done this stripe */
                        continue;
 
-               sh = get_active_stripe(conf, sector, conf->raid_disks, pd_idx, 1);
+               sh = get_active_stripe(conf, sector, 0, 1);
 
                if (!sh) {
                        /* failed to get a stripe - must wait */
@@ -3992,89 +4283,69 @@ static struct attribute_group raid5_attrs_group = {
        .attrs = raid5_attrs,
 };
 
-static int run(mddev_t *mddev)
+static sector_t
+raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks)
+{
+       raid5_conf_t *conf = mddev_to_conf(mddev);
+
+       if (!sectors)
+               sectors = mddev->dev_sectors;
+       if (!raid_disks) {
+               /* size is defined by the smallest of previous and new size */
+               if (conf->raid_disks < conf->previous_raid_disks)
+                       raid_disks = conf->raid_disks;
+               else
+                       raid_disks = conf->previous_raid_disks;
+       }
+
+       sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
+       sectors &= ~((sector_t)mddev->new_chunk/512 - 1);
+       return sectors * (raid_disks - conf->max_degraded);
+}
+
+static raid5_conf_t *setup_conf(mddev_t *mddev)
 {
        raid5_conf_t *conf;
        int raid_disk, memory;
        mdk_rdev_t *rdev;
        struct disk_info *disk;
-       int working_disks = 0;
 
-       if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) {
+       if (mddev->new_level != 5
+           && mddev->new_level != 4
+           && mddev->new_level != 6) {
                printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n",
-                      mdname(mddev), mddev->level);
-               return -EIO;
+                      mdname(mddev), mddev->new_level);
+               return ERR_PTR(-EIO);
        }
-
-       if (mddev->chunk_size < PAGE_SIZE) {
-               printk(KERN_ERR "md/raid5: chunk_size must be at least "
-                      "PAGE_SIZE but %d < %ld\n",
-                      mddev->chunk_size, PAGE_SIZE);
-               return -EINVAL;
+       if ((mddev->new_level == 5
+            && !algorithm_valid_raid5(mddev->new_layout)) ||
+           (mddev->new_level == 6
+            && !algorithm_valid_raid6(mddev->new_layout))) {
+               printk(KERN_ERR "raid5: %s: layout %d not supported\n",
+                      mdname(mddev), mddev->new_layout);
+               return ERR_PTR(-EIO);
        }
-
-       if (mddev->reshape_position != MaxSector) {
-               /* Check that we can continue the reshape.
-                * Currently only disks can change, it must
-                * increase, and we must be past the point where
-                * a stripe over-writes itself
-                */
-               sector_t here_new, here_old;
-               int old_disks;
-               int max_degraded = (mddev->level == 5 ? 1 : 2);
-
-               if (mddev->new_level != mddev->level ||
-                   mddev->new_layout != mddev->layout ||
-                   mddev->new_chunk != mddev->chunk_size) {
-                       printk(KERN_ERR "raid5: %s: unsupported reshape "
-                              "required - aborting.\n",
-                              mdname(mddev));
-                       return -EINVAL;
-               }
-               if (mddev->delta_disks <= 0) {
-                       printk(KERN_ERR "raid5: %s: unsupported reshape "
-                              "(reduce disks) required - aborting.\n",
-                              mdname(mddev));
-                       return -EINVAL;
-               }
-               old_disks = mddev->raid_disks - mddev->delta_disks;
-               /* reshape_position must be on a new-stripe boundary, and one
-                * further up in new geometry must map after here in old
-                * geometry.
-                */
-               here_new = mddev->reshape_position;
-               if (sector_div(here_new, (mddev->chunk_size>>9)*
-                              (mddev->raid_disks - max_degraded))) {
-                       printk(KERN_ERR "raid5: reshape_position not "
-                              "on a stripe boundary\n");
-                       return -EINVAL;
-               }
-               /* here_new is the stripe we will write to */
-               here_old = mddev->reshape_position;
-               sector_div(here_old, (mddev->chunk_size>>9)*
-                          (old_disks-max_degraded));
-               /* here_old is the first stripe that we might need to read
-                * from */
-               if (here_new >= here_old) {
-                       /* Reading from the same stripe as writing to - bad */
-                       printk(KERN_ERR "raid5: reshape_position too early for "
-                              "auto-recovery - aborting.\n");
-                       return -EINVAL;
-               }
-               printk(KERN_INFO "raid5: reshape will continue\n");
-               /* OK, we should be able to continue; */
+       if (mddev->new_level == 6 && mddev->raid_disks < 4) {
+               printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
+                      mdname(mddev), mddev->raid_disks);
+               return ERR_PTR(-EINVAL);
        }
 
+       if (!mddev->new_chunk || mddev->new_chunk % PAGE_SIZE) {
+               printk(KERN_ERR "raid5: invalid chunk size %d for %s\n",
+                       mddev->new_chunk, mdname(mddev));
+               return ERR_PTR(-EINVAL);
+       }
 
-       mddev->private = kzalloc(sizeof (raid5_conf_t), GFP_KERNEL);
-       if ((conf = mddev->private) == NULL)
+       conf = kzalloc(sizeof(raid5_conf_t), GFP_KERNEL);
+       if (conf == NULL)
                goto abort;
-       if (mddev->reshape_position == MaxSector) {
-               conf->previous_raid_disks = conf->raid_disks = mddev->raid_disks;
-       } else {
-               conf->raid_disks = mddev->raid_disks;
+
+       conf->raid_disks = mddev->raid_disks;
+       if (mddev->reshape_position == MaxSector)
+               conf->previous_raid_disks = mddev->raid_disks;
+       else
                conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks;
-       }
 
        conf->disks = kzalloc(conf->raid_disks * sizeof(struct disk_info),
                              GFP_KERNEL);
@@ -4086,13 +4357,12 @@ static int run(mddev_t *mddev)
        if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
                goto abort;
 
-       if (mddev->level == 6) {
+       if (mddev->new_level == 6) {
                conf->spare_page = alloc_page(GFP_KERNEL);
                if (!conf->spare_page)
                        goto abort;
        }
        spin_lock_init(&conf->device_lock);
-       mddev->queue->queue_lock = &conf->device_lock;
        init_waitqueue_head(&conf->wait_for_stripe);
        init_waitqueue_head(&conf->wait_for_overlap);
        INIT_LIST_HEAD(&conf->handle_list);
@@ -4121,47 +4391,134 @@ static int run(mddev_t *mddev)
                        printk(KERN_INFO "raid5: device %s operational as raid"
                                " disk %d\n", bdevname(rdev->bdev,b),
                                raid_disk);
-                       working_disks++;
                } else
                        /* Cannot rely on bitmap to complete recovery */
                        conf->fullsync = 1;
        }
 
-       /*
-        * 0 for a fully functional array, 1 or 2 for a degraded array.
-        */
-       mddev->degraded = conf->raid_disks - working_disks;
-       conf->mddev = mddev;
-       conf->chunk_size = mddev->chunk_size;
-       conf->level = mddev->level;
+       conf->chunk_size = mddev->new_chunk;
+       conf->level = mddev->new_level;
        if (conf->level == 6)
                conf->max_degraded = 2;
        else
                conf->max_degraded = 1;
-       conf->algorithm = mddev->layout;
+       conf->algorithm = mddev->new_layout;
        conf->max_nr_stripes = NR_STRIPES;
-       conf->expand_progress = mddev->reshape_position;
-
-       /* device size must be a multiple of chunk size */
-       mddev->size &= ~(mddev->chunk_size/1024 -1);
-       mddev->resync_max_sectors = mddev->size << 1;
+       conf->reshape_progress = mddev->reshape_position;
+       if (conf->reshape_progress != MaxSector) {
+               conf->prev_chunk = mddev->chunk_size;
+               conf->prev_algo = mddev->layout;
+       }
 
-       if (conf->level == 6 && conf->raid_disks < 4) {
-               printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
-                      mdname(mddev), conf->raid_disks);
+       memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
+                conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
+       if (grow_stripes(conf, conf->max_nr_stripes)) {
+               printk(KERN_ERR
+                       "raid5: couldn't allocate %dkB for buffers\n", memory);
                goto abort;
-       }
-       if (!conf->chunk_size || conf->chunk_size % 4) {
-               printk(KERN_ERR "raid5: invalid chunk size %d for %s\n",
-                       conf->chunk_size, mdname(mddev));
+       } else
+               printk(KERN_INFO "raid5: allocated %dkB for %s\n",
+                       memory, mdname(mddev));
+
+       conf->thread = md_register_thread(raid5d, mddev, "%s_raid5");
+       if (!conf->thread) {
+               printk(KERN_ERR
+                      "raid5: couldn't allocate thread for %s\n",
+                      mdname(mddev));
                goto abort;
        }
-       if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) {
-               printk(KERN_ERR 
-                       "raid5: unsupported parity algorithm %d for %s\n",
-                       conf->algorithm, mdname(mddev));
-               goto abort;
+
+       return conf;
+
+ abort:
+       if (conf) {
+               shrink_stripes(conf);
+               safe_put_page(conf->spare_page);
+               kfree(conf->disks);
+               kfree(conf->stripe_hashtbl);
+               kfree(conf);
+               return ERR_PTR(-EIO);
+       } else
+               return ERR_PTR(-ENOMEM);
+}
+
+static int run(mddev_t *mddev)
+{
+       raid5_conf_t *conf;
+       int working_disks = 0;
+       mdk_rdev_t *rdev;
+
+       if (mddev->reshape_position != MaxSector) {
+               /* Check that we can continue the reshape.
+                * Currently only disks can change, it must
+                * increase, and we must be past the point where
+                * a stripe over-writes itself
+                */
+               sector_t here_new, here_old;
+               int old_disks;
+               int max_degraded = (mddev->level == 6 ? 2 : 1);
+
+               if (mddev->new_level != mddev->level) {
+                       printk(KERN_ERR "raid5: %s: unsupported reshape "
+                              "required - aborting.\n",
+                              mdname(mddev));
+                       return -EINVAL;
+               }
+               old_disks = mddev->raid_disks - mddev->delta_disks;
+               /* reshape_position must be on a new-stripe boundary, and one
+                * further up in new geometry must map after here in old
+                * geometry.
+                */
+               here_new = mddev->reshape_position;
+               if (sector_div(here_new, (mddev->new_chunk>>9)*
+                              (mddev->raid_disks - max_degraded))) {
+                       printk(KERN_ERR "raid5: reshape_position not "
+                              "on a stripe boundary\n");
+                       return -EINVAL;
+               }
+               /* here_new is the stripe we will write to */
+               here_old = mddev->reshape_position;
+               sector_div(here_old, (mddev->chunk_size>>9)*
+                          (old_disks-max_degraded));
+               /* here_old is the first stripe that we might need to read
+                * from */
+               if (here_new >= here_old) {
+                       /* Reading from the same stripe as writing to - bad */
+                       printk(KERN_ERR "raid5: reshape_position too early for "
+                              "auto-recovery - aborting.\n");
+                       return -EINVAL;
+               }
+               printk(KERN_INFO "raid5: reshape will continue\n");
+               /* OK, we should be able to continue; */
+       } else {
+               BUG_ON(mddev->level != mddev->new_level);
+               BUG_ON(mddev->layout != mddev->new_layout);
+               BUG_ON(mddev->chunk_size != mddev->new_chunk);
+               BUG_ON(mddev->delta_disks != 0);
        }
+
+       if (mddev->private == NULL)
+               conf = setup_conf(mddev);
+       else
+               conf = mddev->private;
+
+       if (IS_ERR(conf))
+               return PTR_ERR(conf);
+
+       mddev->thread = conf->thread;
+       conf->thread = NULL;
+       mddev->private = conf;
+
+       /*
+        * 0 for a fully functional array, 1 or 2 for a degraded array.
+        */
+       list_for_each_entry(rdev, &mddev->disks, same_set)
+               if (rdev->raid_disk >= 0 &&
+                   test_bit(In_sync, &rdev->flags))
+                       working_disks++;
+
+       mddev->degraded = conf->raid_disks - working_disks;
+
        if (mddev->degraded > conf->max_degraded) {
                printk(KERN_ERR "raid5: not enough operational devices for %s"
                        " (%d/%d failed)\n",
@@ -4169,6 +4526,10 @@ static int run(mddev_t *mddev)
                goto abort;
        }
 
+       /* device size must be a multiple of chunk size */
+       mddev->dev_sectors &= ~(mddev->chunk_size / 512 - 1);
+       mddev->resync_max_sectors = mddev->dev_sectors;
+
        if (mddev->degraded > 0 &&
            mddev->recovery_cp != MaxSector) {
                if (mddev->ok_start_degraded)
@@ -4184,43 +4545,22 @@ static int run(mddev_t *mddev)
                }
        }
 
-       {
-               mddev->thread = md_register_thread(raid5d, mddev, "%s_raid5");
-               if (!mddev->thread) {
-                       printk(KERN_ERR 
-                               "raid5: couldn't allocate thread for %s\n",
-                               mdname(mddev));
-                       goto abort;
-               }
-       }
-       memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
-                conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
-       if (grow_stripes(conf, conf->max_nr_stripes)) {
-               printk(KERN_ERR 
-                       "raid5: couldn't allocate %dkB for buffers\n", memory);
-               shrink_stripes(conf);
-               md_unregister_thread(mddev->thread);
-               goto abort;
-       } else
-               printk(KERN_INFO "raid5: allocated %dkB for %s\n",
-                       memory, mdname(mddev));
-
        if (mddev->degraded == 0)
                printk("raid5: raid level %d set %s active with %d out of %d"
-                       " devices, algorithm %d\n", conf->level, mdname(mddev), 
-                       mddev->raid_disks-mddev->degraded, mddev->raid_disks,
-                       conf->algorithm);
+                      " devices, algorithm %d\n", conf->level, mdname(mddev),
+                      mddev->raid_disks-mddev->degraded, mddev->raid_disks,
+                      mddev->new_layout);
        else
                printk(KERN_ALERT "raid5: raid level %d set %s active with %d"
                        " out of %d devices, algorithm %d\n", conf->level,
                        mdname(mddev), mddev->raid_disks - mddev->degraded,
-                       mddev->raid_disks, conf->algorithm);
+                       mddev->raid_disks, mddev->new_layout);
 
        print_raid5_conf(conf);
 
-       if (conf->expand_progress != MaxSector) {
+       if (conf->reshape_progress != MaxSector) {
                printk("...ok start reshape thread\n");
-               conf->expand_lo = conf->expand_progress;
+               conf->reshape_safe = conf->reshape_progress;
                atomic_set(&conf->reshape_stripes, 0);
                clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
@@ -4247,18 +4587,22 @@ static int run(mddev_t *mddev)
                       "raid5: failed to create sysfs attributes for %s\n",
                       mdname(mddev));
 
+       mddev->queue->queue_lock = &conf->device_lock;
+
        mddev->queue->unplug_fn = raid5_unplug_device;
        mddev->queue->backing_dev_info.congested_data = mddev;
        mddev->queue->backing_dev_info.congested_fn = raid5_congested;
 
-       mddev->array_sectors = 2 * mddev->size * (conf->previous_raid_disks -
-                                           conf->max_degraded);
+       md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
 
        blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
 
        return 0;
 abort:
+       md_unregister_thread(mddev->thread);
+       mddev->thread = NULL;
        if (conf) {
+               shrink_stripes(conf);
                print_raid5_conf(conf);
                safe_put_page(conf->spare_page);
                kfree(conf->disks);
@@ -4396,6 +4740,10 @@ static int raid5_remove_disk(mddev_t *mddev, int number)
        print_raid5_conf(conf);
        rdev = p->rdev;
        if (rdev) {
+               if (number >= conf->raid_disks &&
+                   conf->reshape_progress == MaxSector)
+                       clear_bit(In_sync, &rdev->flags);
+
                if (test_bit(In_sync, &rdev->flags) ||
                    atomic_read(&rdev->nr_pending)) {
                        err = -EBUSY;
@@ -4405,7 +4753,8 @@ static int raid5_remove_disk(mddev_t *mddev, int number)
                 * isn't possible.
                 */
                if (!test_bit(Faulty, &rdev->flags) &&
-                   mddev->degraded <= conf->max_degraded) {
+                   mddev->degraded <= conf->max_degraded &&
+                   number < conf->raid_disks) {
                        err = -EBUSY;
                        goto abort;
                }
@@ -4472,36 +4821,48 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
         * any io in the removed space completes, but it hardly seems
         * worth it.
         */
-       raid5_conf_t *conf = mddev_to_conf(mddev);
-
        sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
-       mddev->array_sectors = sectors * (mddev->raid_disks
-                                         - conf->max_degraded);
+       md_set_array_sectors(mddev, raid5_size(mddev, sectors,
+                                              mddev->raid_disks));
+       if (mddev->array_sectors >
+           raid5_size(mddev, sectors, mddev->raid_disks))
+               return -EINVAL;
        set_capacity(mddev->gendisk, mddev->array_sectors);
        mddev->changed = 1;
-       if (sectors/2  > mddev->size && mddev->recovery_cp == MaxSector) {
-               mddev->recovery_cp = mddev->size << 1;
+       if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) {
+               mddev->recovery_cp = mddev->dev_sectors;
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        }
-       mddev->size = sectors /2;
+       mddev->dev_sectors = sectors;
        mddev->resync_max_sectors = sectors;
        return 0;
 }
 
-#ifdef CONFIG_MD_RAID5_RESHAPE
 static int raid5_check_reshape(mddev_t *mddev)
 {
        raid5_conf_t *conf = mddev_to_conf(mddev);
-       int err;
 
-       if (mddev->delta_disks < 0 ||
-           mddev->new_level != mddev->level)
-               return -EINVAL; /* Cannot shrink array or change level yet */
-       if (mddev->delta_disks == 0)
-               return 0; /* nothing to do */
+       if (mddev->delta_disks == 0 &&
+           mddev->new_layout == mddev->layout &&
+           mddev->new_chunk == mddev->chunk_size)
+               return -EINVAL; /* nothing to do */
        if (mddev->bitmap)
                /* Cannot grow a bitmap yet */
                return -EBUSY;
+       if (mddev->degraded > conf->max_degraded)
+               return -EINVAL;
+       if (mddev->delta_disks < 0) {
+               /* We might be able to shrink, but the devices must
+                * be made bigger first.
+                * For raid6, 4 is the minimum size.
+                * Otherwise 2 is the minimum
+                */
+               int min = 2;
+               if (mddev->level == 6)
+                       min = 4;
+               if (mddev->raid_disks + mddev->delta_disks < min)
+                       return -EINVAL;
+       }
 
        /* Can only proceed if there are plenty of stripe_heads.
         * We need a minimum of one full stripe,, and for sensible progress
@@ -4514,18 +4875,12 @@ static int raid5_check_reshape(mddev_t *mddev)
        if ((mddev->chunk_size / STRIPE_SIZE) * 4 > conf->max_nr_stripes ||
            (mddev->new_chunk / STRIPE_SIZE) * 4 > conf->max_nr_stripes) {
                printk(KERN_WARNING "raid5: reshape: not enough stripes.  Needed %lu\n",
-                      (mddev->chunk_size / STRIPE_SIZE)*4);
+                      (max(mddev->chunk_size, mddev->new_chunk)
+                       / STRIPE_SIZE)*4);
                return -ENOSPC;
        }
 
-       err = resize_stripes(conf, conf->raid_disks + mddev->delta_disks);
-       if (err)
-               return err;
-
-       if (mddev->degraded > conf->max_degraded)
-               return -EINVAL;
-       /* looks like we might be able to manage this */
-       return 0;
+       return resize_stripes(conf, conf->raid_disks + mddev->delta_disks);
 }
 
 static int raid5_start_reshape(mddev_t *mddev)
@@ -4550,12 +4905,31 @@ static int raid5_start_reshape(mddev_t *mddev)
                 */
                return -EINVAL;
 
+       /* Refuse to reduce size of the array.  Any reductions in
+        * array size must be through explicit setting of array_size
+        * attribute.
+        */
+       if (raid5_size(mddev, 0, conf->raid_disks + mddev->delta_disks)
+           < mddev->array_sectors) {
+               printk(KERN_ERR "md: %s: array size must be reduced "
+                      "before number of disks\n", mdname(mddev));
+               return -EINVAL;
+       }
+
        atomic_set(&conf->reshape_stripes, 0);
        spin_lock_irq(&conf->device_lock);
        conf->previous_raid_disks = conf->raid_disks;
        conf->raid_disks += mddev->delta_disks;
-       conf->expand_progress = 0;
-       conf->expand_lo = 0;
+       conf->prev_chunk = conf->chunk_size;
+       conf->chunk_size = mddev->new_chunk;
+       conf->prev_algo = conf->algorithm;
+       conf->algorithm = mddev->new_layout;
+       if (mddev->delta_disks < 0)
+               conf->reshape_progress = raid5_size(mddev, 0, 0);
+       else
+               conf->reshape_progress = 0;
+       conf->reshape_safe = conf->reshape_progress;
+       conf->generation++;
        spin_unlock_irq(&conf->device_lock);
 
        /* Add some new drives, as many as will fit.
@@ -4580,9 +4954,12 @@ static int raid5_start_reshape(mddev_t *mddev)
                                break;
                }
 
-       spin_lock_irqsave(&conf->device_lock, flags);
-       mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices;
-       spin_unlock_irqrestore(&conf->device_lock, flags);
+       if (mddev->delta_disks > 0) {
+               spin_lock_irqsave(&conf->device_lock, flags);
+               mddev->degraded = (conf->raid_disks - conf->previous_raid_disks)
+                       - added_devices;
+               spin_unlock_irqrestore(&conf->device_lock, flags);
+       }
        mddev->raid_disks = conf->raid_disks;
        mddev->reshape_position = 0;
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
@@ -4597,52 +4974,86 @@ static int raid5_start_reshape(mddev_t *mddev)
                mddev->recovery = 0;
                spin_lock_irq(&conf->device_lock);
                mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks;
-               conf->expand_progress = MaxSector;
+               conf->reshape_progress = MaxSector;
                spin_unlock_irq(&conf->device_lock);
                return -EAGAIN;
        }
+       conf->reshape_checkpoint = jiffies;
        md_wakeup_thread(mddev->sync_thread);
        md_new_event(mddev);
        return 0;
 }
-#endif
 
+/* This is called from the reshape thread and should make any
+ * changes needed in 'conf'
+ */
 static void end_reshape(raid5_conf_t *conf)
 {
-       struct block_device *bdev;
 
        if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
-               conf->mddev->array_sectors = 2 * conf->mddev->size *
-                       (conf->raid_disks - conf->max_degraded);
-               set_capacity(conf->mddev->gendisk, conf->mddev->array_sectors);
-               conf->mddev->changed = 1;
-
-               bdev = bdget_disk(conf->mddev->gendisk, 0);
-               if (bdev) {
-                       mutex_lock(&bdev->bd_inode->i_mutex);
-                       i_size_write(bdev->bd_inode,
-                                    (loff_t)conf->mddev->array_sectors << 9);
-                       mutex_unlock(&bdev->bd_inode->i_mutex);
-                       bdput(bdev);
-               }
+
                spin_lock_irq(&conf->device_lock);
-               conf->expand_progress = MaxSector;
+               conf->previous_raid_disks = conf->raid_disks;
+               conf->reshape_progress = MaxSector;
                spin_unlock_irq(&conf->device_lock);
-               conf->mddev->reshape_position = MaxSector;
+               wake_up(&conf->wait_for_overlap);
 
                /* read-ahead size must cover two whole stripes, which is
                 * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
                 */
                {
-                       int data_disks = conf->previous_raid_disks - conf->max_degraded;
-                       int stripe = data_disks *
-                               (conf->mddev->chunk_size / PAGE_SIZE);
+                       int data_disks = conf->raid_disks - conf->max_degraded;
+                       int stripe = data_disks * (conf->chunk_size
+                                                  / PAGE_SIZE);
                        if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
                                conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
                }
        }
 }
 
+/* This is called from the raid5d thread with mddev_lock held.
+ * It makes config changes to the device.
+ */
+static void raid5_finish_reshape(mddev_t *mddev)
+{
+       struct block_device *bdev;
+       raid5_conf_t *conf = mddev_to_conf(mddev);
+
+       if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
+
+               if (mddev->delta_disks > 0) {
+                       md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
+                       set_capacity(mddev->gendisk, mddev->array_sectors);
+                       mddev->changed = 1;
+
+                       bdev = bdget_disk(mddev->gendisk, 0);
+                       if (bdev) {
+                               mutex_lock(&bdev->bd_inode->i_mutex);
+                               i_size_write(bdev->bd_inode,
+                                            (loff_t)mddev->array_sectors << 9);
+                               mutex_unlock(&bdev->bd_inode->i_mutex);
+                               bdput(bdev);
+                       }
+               } else {
+                       int d;
+                       mddev->degraded = conf->raid_disks;
+                       for (d = 0; d < conf->raid_disks ; d++)
+                               if (conf->disks[d].rdev &&
+                                   test_bit(In_sync,
+                                            &conf->disks[d].rdev->flags))
+                                       mddev->degraded--;
+                       for (d = conf->raid_disks ;
+                            d < conf->raid_disks - mddev->delta_disks;
+                            d++)
+                               raid5_remove_disk(mddev, d);
+               }
+               mddev->layout = conf->algorithm;
+               mddev->chunk_size = conf->chunk_size;
+               mddev->reshape_position = MaxSector;
+               mddev->delta_disks = 0;
+       }
+}
+
 static void raid5_quiesce(mddev_t *mddev, int state)
 {
        raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -4672,6 +5083,212 @@ static void raid5_quiesce(mddev_t *mddev, int state)
        }
 }
 
+
+static void *raid5_takeover_raid1(mddev_t *mddev)
+{
+       int chunksect;
+
+       if (mddev->raid_disks != 2 ||
+           mddev->degraded > 1)
+               return ERR_PTR(-EINVAL);
+
+       /* Should check if there are write-behind devices? */
+
+       chunksect = 64*2; /* 64K by default */
+
+       /* The array must be an exact multiple of chunksize */
+       while (chunksect && (mddev->array_sectors & (chunksect-1)))
+               chunksect >>= 1;
+
+       if ((chunksect<<9) < STRIPE_SIZE)
+               /* array size does not allow a suitable chunk size */
+               return ERR_PTR(-EINVAL);
+
+       mddev->new_level = 5;
+       mddev->new_layout = ALGORITHM_LEFT_SYMMETRIC;
+       mddev->new_chunk = chunksect << 9;
+
+       return setup_conf(mddev);
+}
+
+static void *raid5_takeover_raid6(mddev_t *mddev)
+{
+       int new_layout;
+
+       switch (mddev->layout) {
+       case ALGORITHM_LEFT_ASYMMETRIC_6:
+               new_layout = ALGORITHM_LEFT_ASYMMETRIC;
+               break;
+       case ALGORITHM_RIGHT_ASYMMETRIC_6:
+               new_layout = ALGORITHM_RIGHT_ASYMMETRIC;
+               break;
+       case ALGORITHM_LEFT_SYMMETRIC_6:
+               new_layout = ALGORITHM_LEFT_SYMMETRIC;
+               break;
+       case ALGORITHM_RIGHT_SYMMETRIC_6:
+               new_layout = ALGORITHM_RIGHT_SYMMETRIC;
+               break;
+       case ALGORITHM_PARITY_0_6:
+               new_layout = ALGORITHM_PARITY_0;
+               break;
+       case ALGORITHM_PARITY_N:
+               new_layout = ALGORITHM_PARITY_N;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+       mddev->new_level = 5;
+       mddev->new_layout = new_layout;
+       mddev->delta_disks = -1;
+       mddev->raid_disks -= 1;
+       return setup_conf(mddev);
+}
+
+
+static int raid5_reconfig(mddev_t *mddev, int new_layout, int new_chunk)
+{
+       /* For a 2-drive array, the layout and chunk size can be changed
+        * immediately as not restriping is needed.
+        * For larger arrays we record the new value - after validation
+        * to be used by a reshape pass.
+        */
+       raid5_conf_t *conf = mddev_to_conf(mddev);
+
+       if (new_layout >= 0 && !algorithm_valid_raid5(new_layout))
+               return -EINVAL;
+       if (new_chunk > 0) {
+               if (new_chunk & (new_chunk-1))
+                       /* not a power of 2 */
+                       return -EINVAL;
+               if (new_chunk < PAGE_SIZE)
+                       return -EINVAL;
+               if (mddev->array_sectors & ((new_chunk>>9)-1))
+                       /* not factor of array size */
+                       return -EINVAL;
+       }
+
+       /* They look valid */
+
+       if (mddev->raid_disks == 2) {
+
+               if (new_layout >= 0) {
+                       conf->algorithm = new_layout;
+                       mddev->layout = mddev->new_layout = new_layout;
+               }
+               if (new_chunk > 0) {
+                       conf->chunk_size = new_chunk;
+                       mddev->chunk_size = mddev->new_chunk = new_chunk;
+               }
+               set_bit(MD_CHANGE_DEVS, &mddev->flags);
+               md_wakeup_thread(mddev->thread);
+       } else {
+               if (new_layout >= 0)
+                       mddev->new_layout = new_layout;
+               if (new_chunk > 0)
+                       mddev->new_chunk = new_chunk;
+       }
+       return 0;
+}
+
+static int raid6_reconfig(mddev_t *mddev, int new_layout, int new_chunk)
+{
+       if (new_layout >= 0 && !algorithm_valid_raid6(new_layout))
+               return -EINVAL;
+       if (new_chunk > 0) {
+               if (new_chunk & (new_chunk-1))
+                       /* not a power of 2 */
+                       return -EINVAL;
+               if (new_chunk < PAGE_SIZE)
+                       return -EINVAL;
+               if (mddev->array_sectors & ((new_chunk>>9)-1))
+                       /* not factor of array size */
+                       return -EINVAL;
+       }
+
+       /* They look valid */
+
+       if (new_layout >= 0)
+               mddev->new_layout = new_layout;
+       if (new_chunk > 0)
+               mddev->new_chunk = new_chunk;
+
+       return 0;
+}
+
+static void *raid5_takeover(mddev_t *mddev)
+{
+       /* raid5 can take over:
+        *  raid0 - if all devices are the same - make it a raid4 layout
+        *  raid1 - if there are two drives.  We need to know the chunk size
+        *  raid4 - trivial - just use a raid4 layout.
+        *  raid6 - Providing it is a *_6 layout
+        *
+        * For now, just do raid1
+        */
+
+       if (mddev->level == 1)
+               return raid5_takeover_raid1(mddev);
+       if (mddev->level == 4) {
+               mddev->new_layout = ALGORITHM_PARITY_N;
+               mddev->new_level = 5;
+               return setup_conf(mddev);
+       }
+       if (mddev->level == 6)
+               return raid5_takeover_raid6(mddev);
+
+       return ERR_PTR(-EINVAL);
+}
+
+
+static struct mdk_personality raid5_personality;
+
+static void *raid6_takeover(mddev_t *mddev)
+{
+       /* Currently can only take over a raid5.  We map the
+        * personality to an equivalent raid6 personality
+        * with the Q block at the end.
+        */
+       int new_layout;
+
+       if (mddev->pers != &raid5_personality)
+               return ERR_PTR(-EINVAL);
+       if (mddev->degraded > 1)
+               return ERR_PTR(-EINVAL);
+       if (mddev->raid_disks > 253)
+               return ERR_PTR(-EINVAL);
+       if (mddev->raid_disks < 3)
+               return ERR_PTR(-EINVAL);
+
+       switch (mddev->layout) {
+       case ALGORITHM_LEFT_ASYMMETRIC:
+               new_layout = ALGORITHM_LEFT_ASYMMETRIC_6;
+               break;
+       case ALGORITHM_RIGHT_ASYMMETRIC:
+               new_layout = ALGORITHM_RIGHT_ASYMMETRIC_6;
+               break;
+       case ALGORITHM_LEFT_SYMMETRIC:
+               new_layout = ALGORITHM_LEFT_SYMMETRIC_6;
+               break;
+       case ALGORITHM_RIGHT_SYMMETRIC:
+               new_layout = ALGORITHM_RIGHT_SYMMETRIC_6;
+               break;
+       case ALGORITHM_PARITY_0:
+               new_layout = ALGORITHM_PARITY_0_6;
+               break;
+       case ALGORITHM_PARITY_N:
+               new_layout = ALGORITHM_PARITY_N;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+       mddev->new_level = 6;
+       mddev->new_layout = new_layout;
+       mddev->delta_disks = 1;
+       mddev->raid_disks += 1;
+       return setup_conf(mddev);
+}
+
+
 static struct mdk_personality raid6_personality =
 {
        .name           = "raid6",
@@ -4687,11 +5304,13 @@ static struct mdk_personality raid6_personality =
        .spare_active   = raid5_spare_active,
        .sync_request   = sync_request,
        .resize         = raid5_resize,
-#ifdef CONFIG_MD_RAID5_RESHAPE
+       .size           = raid5_size,
        .check_reshape  = raid5_check_reshape,
        .start_reshape  = raid5_start_reshape,
-#endif
+       .finish_reshape = raid5_finish_reshape,
        .quiesce        = raid5_quiesce,
+       .takeover       = raid6_takeover,
+       .reconfig       = raid6_reconfig,
 };
 static struct mdk_personality raid5_personality =
 {
@@ -4708,11 +5327,13 @@ static struct mdk_personality raid5_personality =
        .spare_active   = raid5_spare_active,
        .sync_request   = sync_request,
        .resize         = raid5_resize,
-#ifdef CONFIG_MD_RAID5_RESHAPE
+       .size           = raid5_size,
        .check_reshape  = raid5_check_reshape,
        .start_reshape  = raid5_start_reshape,
-#endif
+       .finish_reshape = raid5_finish_reshape,
        .quiesce        = raid5_quiesce,
+       .takeover       = raid5_takeover,
+       .reconfig       = raid5_reconfig,
 };
 
 static struct mdk_personality raid4_personality =
@@ -4730,20 +5351,15 @@ static struct mdk_personality raid4_personality =
        .spare_active   = raid5_spare_active,
        .sync_request   = sync_request,
        .resize         = raid5_resize,
-#ifdef CONFIG_MD_RAID5_RESHAPE
+       .size           = raid5_size,
        .check_reshape  = raid5_check_reshape,
        .start_reshape  = raid5_start_reshape,
-#endif
+       .finish_reshape = raid5_finish_reshape,
        .quiesce        = raid5_quiesce,
 };
 
 static int __init raid5_init(void)
 {
-       int e;
-
-       e = raid6_select_algo();
-       if ( e )
-               return e;
        register_md_personality(&raid6_personality);
        register_md_personality(&raid5_personality);
        register_md_personality(&raid4_personality);
similarity index 81%
rename from include/linux/raid/raid5.h
rename to drivers/md/raid5.h
index 3b2672792457ff08b991acb78e619f3daa3dab6e..52ba99954decf0ceee11bc30da2213a7c6619983 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _RAID5_H
 #define _RAID5_H
 
-#include <linux/raid/md.h>
 #include <linux/raid/xor.h>
 
 /*
@@ -197,15 +196,19 @@ enum reconstruct_states {
 
 struct stripe_head {
        struct hlist_node       hash;
-       struct list_head        lru;                    /* inactive_list or handle_list */
-       struct raid5_private_data       *raid_conf;
-       sector_t                sector;                 /* sector of this row */
-       int                     pd_idx;                 /* parity disk index */
-       unsigned long           state;                  /* state flags */
-       atomic_t                count;                  /* nr of active thread/requests */
+       struct list_head        lru;          /* inactive_list or handle_list */
+       struct raid5_private_data *raid_conf;
+       short                   generation;     /* increments with every
+                                                * reshape */
+       sector_t                sector;         /* sector of this row */
+       short                   pd_idx;         /* parity disk index */
+       short                   qd_idx;         /* 'Q' disk index for raid6 */
+       short                   ddf_layout;/* use DDF ordering to calculate Q */
+       unsigned long           state;          /* state flags */
+       atomic_t                count;        /* nr of active thread/requests */
        spinlock_t              lock;
        int                     bm_seq; /* sequence number for bitmap flushes */
-       int                     disks;                  /* disks in stripe */
+       int                     disks;          /* disks in stripe */
        enum check_states       check_state;
        enum reconstruct_states reconstruct_state;
        /* stripe_operations
@@ -238,7 +241,7 @@ struct stripe_head_state {
 
 /* r6_state - extra state data only relevant to r6 */
 struct r6_state {
-       int p_failed, q_failed, qd_idx, failed_num[2];
+       int p_failed, q_failed, failed_num[2];
 };
 
 /* Flags */
@@ -268,6 +271,8 @@ struct r6_state {
 #define READ_MODIFY_WRITE      2
 /* not a write method, but a compute_parity mode */
 #define        CHECK_PARITY            3
+/* Additional compute_parity mode -- updates the parity w/o LOCKING */
+#define UPDATE_PARITY          4
 
 /*
  * Stripe state
@@ -319,7 +324,7 @@ struct r6_state {
  * PREREAD_ACTIVE is set, else we set DELAYED which will send it to the delayed queue.
  * HANDLE gets cleared if stripe_handle leave nothing locked.
  */
+
 
 struct disk_info {
        mdk_rdev_t      *rdev;
@@ -334,12 +339,21 @@ struct raid5_private_data {
        int                     raid_disks;
        int                     max_nr_stripes;
 
-       /* used during an expand */
-       sector_t                expand_progress;        /* MaxSector when no expand happening */
-       sector_t                expand_lo; /* from here up to expand_progress it out-of-bounds
-                                           * as we haven't flushed the metadata yet
-                                           */
+       /* reshape_progress is the leading edge of a 'reshape'
+        * It has value MaxSector when no reshape is happening
+        * If delta_disks < 0, it is the last sector we started work on,
+        * else is it the next sector to work on.
+        */
+       sector_t                reshape_progress;
+       /* reshape_safe is the trailing edge of a reshape.  We know that
+        * before (or after) this address, all reshape has completed.
+        */
+       sector_t                reshape_safe;
        int                     previous_raid_disks;
+       int                     prev_chunk, prev_algo;
+       short                   generation; /* increments with every reshape */
+       unsigned long           reshape_checkpoint; /* Time we last updated
+                                                    * metadata */
 
        struct list_head        handle_list; /* stripes needing handling */
        struct list_head        hold_list; /* preread ready stripes */
@@ -385,6 +399,11 @@ struct raid5_private_data {
        int                     pool_size; /* number of disks in stripeheads in pool */
        spinlock_t              device_lock;
        struct disk_info        *disks;
+
+       /* When taking over an array from a different personality, we store
+        * the new thread here until we fully activate the array.
+        */
+       struct mdk_thread_s     *thread;
 };
 
 typedef struct raid5_private_data raid5_conf_t;
@@ -394,9 +413,62 @@ typedef struct raid5_private_data raid5_conf_t;
 /*
  * Our supported algorithms
  */
-#define ALGORITHM_LEFT_ASYMMETRIC      0
-#define ALGORITHM_RIGHT_ASYMMETRIC     1
-#define ALGORITHM_LEFT_SYMMETRIC       2
-#define ALGORITHM_RIGHT_SYMMETRIC      3
+#define ALGORITHM_LEFT_ASYMMETRIC      0 /* Rotating Parity N with Data Restart */
+#define ALGORITHM_RIGHT_ASYMMETRIC     1 /* Rotating Parity 0 with Data Restart */
+#define ALGORITHM_LEFT_SYMMETRIC       2 /* Rotating Parity N with Data Continuation */
+#define ALGORITHM_RIGHT_SYMMETRIC      3 /* Rotating Parity 0 with Data Continuation */
+
+/* Define non-rotating (raid4) algorithms.  These allow
+ * conversion of raid4 to raid5.
+ */
+#define ALGORITHM_PARITY_0             4 /* P or P,Q are initial devices */
+#define ALGORITHM_PARITY_N             5 /* P or P,Q are final devices. */
+
+/* DDF RAID6 layouts differ from md/raid6 layouts in two ways.
+ * Firstly, the exact positioning of the parity block is slightly
+ * different between the 'LEFT_*' modes of md and the "_N_*" modes
+ * of DDF.
+ * Secondly, or order of datablocks over which the Q syndrome is computed
+ * is different.
+ * Consequently we have different layouts for DDF/raid6 than md/raid6.
+ * These layouts are from the DDFv1.2 spec.
+ * Interestingly DDFv1.2-Errata-A does not specify N_CONTINUE but
+ * leaves RLQ=3 as 'Vendor Specific'
+ */
+
+#define ALGORITHM_ROTATING_ZERO_RESTART        8 /* DDF PRL=6 RLQ=1 */
+#define ALGORITHM_ROTATING_N_RESTART   9 /* DDF PRL=6 RLQ=2 */
+#define ALGORITHM_ROTATING_N_CONTINUE  10 /*DDF PRL=6 RLQ=3 */
+
+
+/* For every RAID5 algorithm we define a RAID6 algorithm
+ * with exactly the same layout for data and parity, and
+ * with the Q block always on the last device (N-1).
+ * This allows trivial conversion from RAID5 to RAID6
+ */
+#define ALGORITHM_LEFT_ASYMMETRIC_6    16
+#define ALGORITHM_RIGHT_ASYMMETRIC_6   17
+#define ALGORITHM_LEFT_SYMMETRIC_6     18
+#define ALGORITHM_RIGHT_SYMMETRIC_6    19
+#define ALGORITHM_PARITY_0_6           20
+#define ALGORITHM_PARITY_N_6           ALGORITHM_PARITY_N
+
+static inline int algorithm_valid_raid5(int layout)
+{
+       return (layout >= 0) &&
+               (layout <= 5);
+}
+static inline int algorithm_valid_raid6(int layout)
+{
+       return (layout >= 0 && layout <= 5)
+               ||
+               (layout == 8 || layout == 10)
+               ||
+               (layout >= 16 && layout <= 20);
+}
 
+static inline int algorithm_is_DDF(int layout)
+{
+       return layout >= 8 && layout <= 10;
+}
 #endif
index 21987e3dbe6c0ce4199fcc25f3e81506c337713f..866215ac7f2554f86733cc900f4b902b3f60bc76 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
  * Algorithm list and algorithm selection for RAID-6
  */
 
-#include "raid6.h"
+#include <linux/raid/pq.h>
 #ifndef __KERNEL__
 #include <sys/mman.h>
 #include <stdio.h>
+#else
+#if !RAID6_USE_EMPTY_ZERO_PAGE
+/* In .bss so it's zeroed */
+const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
+EXPORT_SYMBOL(raid6_empty_zero_page);
+#endif
 #endif
 
 struct raid6_calls raid6_call;
+EXPORT_SYMBOL_GPL(raid6_call);
 
 /* Various routine sets */
 extern const struct raid6_calls raid6_intx1;
@@ -79,6 +86,7 @@ const struct raid6_calls * const raid6_algos[] = {
 #else
 /* Need more time to be stable in userspace */
 #define RAID6_TIME_JIFFIES_LG2 9
+#define time_before(x, y) ((x) < (y))
 #endif
 
 /* Try to pick the best algorithm */
@@ -152,3 +160,12 @@ int __init raid6_select_algo(void)
 
        return best ? 0 : -EINVAL;
 }
+
+static void raid6_exit(void)
+{
+       do { } while (0);
+}
+
+subsys_initcall(raid6_select_algo);
+module_exit(raid6_exit);
+MODULE_LICENSE("GPL");
index b9afd35b8812cf46c1994a37b99f4e8935680614..699dfeee494459afdd1ba2ff3b7a7e90c063b12f 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
@@ -22,7 +22,7 @@
  * bracked this with preempt_disable/enable or in a lock)
  */
 
-#include "raid6.h"
+#include <linux/raid/pq.h>
 
 #ifdef CONFIG_ALTIVEC
 
index ad004cee0e261c414e989fec6e9ae4e7a7884011..f9bf9cba357fd1202b6bef088a7e26b49fed6ab2 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
@@ -18,7 +18,7 @@
  * This file is postprocessed using unroll.pl
  */
 
-#include "raid6.h"
+#include <linux/raid/pq.h>
 
 /*
  * This is the C data type to use
index d4e4a1bd70ad2f0841a8dd4036a167dfd1e9a3c0..e7f6c13132bfd12e2f145a337ed954659198d971 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
@@ -18,7 +18,7 @@
 
 #if defined(__i386__) && !defined(__arch_um__)
 
-#include "raid6.h"
+#include <linux/raid/pq.h>
 #include "raid6x86.h"
 
 /* Shared with raid6sse1.c */
index a8c4d9451bd901da3172447f7bd00536ceec794a..2609f00e0d61ed8c5b80347704c4bf6d9fbae29f 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
@@ -18,7 +18,7 @@
  * the syndrome.)
  */
 
-#include "raid6.h"
+#include <linux/raid/pq.h>
 
 /* Recover two failed data blocks. */
 void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
@@ -63,9 +63,7 @@ void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
                p++; q++;
        }
 }
-
-
-
+EXPORT_SYMBOL_GPL(raid6_2data_recov);
 
 /* Recover failure of one data block plus the P block */
 void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
@@ -97,9 +95,10 @@ void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
                q++; dq++;
        }
 }
+EXPORT_SYMBOL_GPL(raid6_datap_recov);
 
-
-#ifndef __KERNEL__             /* Testing only */
+#ifndef __KERNEL__
+/* Testing only */
 
 /* Recover two failed blocks. */
 void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
index 0666237276ff37283e06aacc8980340eada56840..b274dd5eab8f1a39aa3706e0d012bfeb8cef92f2 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
@@ -23,7 +23,7 @@
 
 #if defined(__i386__) && !defined(__arch_um__)
 
-#include "raid6.h"
+#include <linux/raid/pq.h>
 #include "raid6x86.h"
 
 /* Defined in raid6mmx.c */
index b034ad8680397e0ab62eff5d55ddf6f5820979eb..6ed6c6c0389f47aef453c8708defd7f01e4d1c8f 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
@@ -19,7 +19,7 @@
 
 #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
 
-#include "raid6.h"
+#include <linux/raid/pq.h>
 #include "raid6x86.h"
 
 static const struct raid6_sse_constants {
index 78e0396adf2ac28ab8cc23f0427303b10d2207b2..58ffdf4f51619caa05253d5d42abb520ae5c8e20 100644 (file)
@@ -5,7 +5,7 @@
 
 CC      = gcc
 OPTFLAGS = -O2                 # Adjust as desired
-CFLAGS  = -I.. -g $(OPTFLAGS)
+CFLAGS  = -I.. -I ../../../include -g $(OPTFLAGS)
 LD      = ld
 PERL    = perl
 AR      = ar
index 559cc41b258566d4b0437241559156fbbc574721..7a930318b17d60c406bb1d421ba406c0f3bcb139 100644 (file)
@@ -17,7 +17,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include "raid6.h"
+#include <linux/raid/pq.h>
 
 #define NDISKS         16      /* Including P and Q */
 
index 99fea7a70ca70ace27cca159e039b0ab318368ae..4c22c1568558b7c92dac1b456559d9981cc2ae3c 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
index 52c3f65b12d69362b79c8b386cf0d59c3e04bb02..607d319ce8ed8fd09a512770a3658a9206fcb453 100644 (file)
@@ -148,7 +148,7 @@ config MEDIA_TUNER_XC5000
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner XC5000 from Xceive.
-         This device is only used inside a SiP called togther with a
+         This device is only used inside a SiP called together with a
          demodulator for now.
 
 config MEDIA_TUNER_MXL5005S
index a206cee23f739073b6f6c11e76fd8257a6a9d939..a486a7f81fa9c226594e3ef0d879345ddbca4a31 100644 (file)
@@ -479,7 +479,7 @@ config DVB_TUNER_DIB0070
        default m if DVB_FE_CUSTOMISE
        help
          A driver for the silicon baseband tuner DiB0070 from DiBcom.
-         This device is only used inside a SiP called togther with a
+         This device is only used inside a SiP called together with a
          demodulator for now.
 
 comment "SEC control devices for DVB-S"
index 1e81e713df635db0e310d3419c557c5bcce56fb1..172f1f928f0271f8e64bc7daa12ea999033ee2d6 100644 (file)
@@ -74,7 +74,7 @@ static struct {
 } fw[] = {
 #define _FW_ENTRY(a, b, c)     {                                       \
                        .name   = a,                                    \
-                       .file   = 0,                                    \
+                       .file   = NULL,                                 \
                        .lock   = __RW_LOCK_UNLOCKED(fw[c].lock),       \
                        .refcnt = 0,                                    \
                        .data   = { }           }
index c3b0c8c63c7642601a2b14feceb5a1f55ff86a78..43ab0adf3b610a8927299e833c6bb3ab5f3b73ad 100644 (file)
@@ -1381,9 +1381,7 @@ static void proc_cpia_create(void)
 {
        cpia_proc_root = proc_mkdir("cpia", NULL);
 
-       if (cpia_proc_root)
-               cpia_proc_root->owner = THIS_MODULE;
-       else
+       if (!cpia_proc_root)
                LOG("Unable to initialise /proc/cpia\n");
 }
 
index 9a36b5a7de5736365f356190877a6947f2048246..7045c45da9b160030fdd07859b373708656d2ea0 100644 (file)
@@ -2037,8 +2037,6 @@ static int __init i2o_proc_fs_create(void)
        if (!i2o_proc_dir_root)
                return -1;
 
-       i2o_proc_dir_root->owner = THIS_MODULE;
-
        list_for_each_entry(c, &i2o_controllers, list)
            i2o_proc_iop_add(i2o_proc_dir_root, c);
 
index 06a2b0f7737c98f9009ea9ee4cb1986b7208ef7e..75f35dbb11dc48c9c4de183769d1801f52da35a9 100644 (file)
@@ -88,7 +88,7 @@ config MENELAUS
        help
          If you say yes here you get support for the Texas Instruments
          TWL92330/Menelaus Power Management chip. This include voltage
-         regulators, Dual slot memory card tranceivers, real-time clock
+         regulators, Dual slot memory card transceivers, real-time clock
          and other features that are often used in portable devices like
          cell phones and PDAs.
 
index 68826f1e36bccd057f938919083e6877731025c3..ec90e953adced9f0d2b3f3d4abe878d6b3511da9 100644 (file)
@@ -592,11 +592,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
        /* maybe add LDOs that are omitted on cost-reduced parts */
        if (twl_has_regulator() && !(features & TPS_SUBSET)) {
-               /*
                child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
                if (IS_ERR(child))
                        return PTR_ERR(child);
-               */
 
                child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
                if (IS_ERR(child))
index 1c484084ed4f874c78cf7ccbf555350148a2a00c..6d1ac180f6ee8013b212ff06bf6dca6ff475b1cb 100644 (file)
@@ -18,8 +18,8 @@ config ATMEL_PWM
        depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
        help
          This option enables device driver support for the PWM channels
-         on certain Atmel prcoessors.  Pulse Width Modulation is used for
-         purposes including software controlled power-efficent backlights
+         on certain Atmel processors.  Pulse Width Modulation is used for
+         purposes including software controlled power-efficient backlights
          on LCD displays, motor control, and waveform generation.
 
 config ATMEL_TCLIB
@@ -142,7 +142,7 @@ config ATMEL_SSC
        tristate "Device driver for Atmel SSC peripheral"
        depends on AVR32 || ARCH_AT91
        ---help---
-         This option enables device driver support for Atmel Syncronized
+         This option enables device driver support for Atmel Synchronized
          Serial Communication peripheral (SSC).
 
          The SSC peripheral supports a wide variety of serial frame based
@@ -165,7 +165,7 @@ config SGI_XP
        depends on (IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || X86_UV) && SMP
        select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
        select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
-       select SGI_GRU if (IA64_GENERIC || IA64_SGI_UV || X86_64) && SMP
+       select SGI_GRU if X86_64 && SMP
        ---help---
          An SGI machine can be divided into multiple Single System
          Images which act independently of each other and have
@@ -189,7 +189,7 @@ config HP_ILO
 
 config SGI_GRU
        tristate "SGI GRU driver"
-       depends on (X86_UV || IA64_SGI_UV || IA64_GENERIC) && SMP
+       depends on X86_UV && SMP
        default n
        select MMU_NOTIFIER
        ---help---
@@ -223,6 +223,16 @@ config DELL_LAPTOP
        This driver adds support for rfkill and backlight control to Dell
        laptops.
 
+config ISL29003
+       tristate "Intersil ISL29003 ambient light sensor"
+       depends on I2C && SYSFS
+       help
+         If you say yes here you get support for the Intersil ISL29003
+         ambient light sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called isl29003.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 
index bc11998305544752f67b16ab587d14e725a870e2..7871f05dcb9b8d29804dbe7e68743c01369937da 100644 (file)
@@ -18,5 +18,6 @@ obj-$(CONFIG_KGDB_TESTS)      += kgdbts.o
 obj-$(CONFIG_SGI_XP)           += sgi-xp/
 obj-$(CONFIG_SGI_GRU)          += sgi-gru/
 obj-$(CONFIG_HP_ILO)           += hpilo.o
+obj-$(CONFIG_ISL29003)         += isl29003.o
 obj-$(CONFIG_C2PORT)           += c2port/
 obj-y                          += eeprom/
index d4775528abc69b2d4c4d580d712e48862ef7d1d7..d184dfab9631c0315ef40ed58d502136dc0055e2 100644 (file)
@@ -53,6 +53,7 @@
 
 struct at24_data {
        struct at24_platform_data chip;
+       struct memory_accessor macc;
        bool use_smbus;
 
        /*
@@ -225,14 +226,11 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
                return status;
 }
 
-static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
+static ssize_t at24_read(struct at24_data *at24,
                char *buf, loff_t off, size_t count)
 {
-       struct at24_data *at24;
        ssize_t retval = 0;
 
-       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
-
        if (unlikely(!count))
                return count;
 
@@ -262,12 +260,14 @@ static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
        return retval;
 }
 
+static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct at24_data *at24;
 
-/*
- * REVISIT: export at24_bin{read,write}() to let other kernel code use
- * eeprom data. For example, it might hold a board's Ethernet address, or
- * board-specific calibration data generated on the manufacturing floor.
- */
+       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+       return at24_read(at24, buf, off, count);
+}
 
 
 /*
@@ -347,14 +347,11 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf,
        return -ETIMEDOUT;
 }
 
-static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
+static ssize_t at24_write(struct at24_data *at24,
                char *buf, loff_t off, size_t count)
 {
-       struct at24_data *at24;
        ssize_t retval = 0;
 
-       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
-
        if (unlikely(!count))
                return count;
 
@@ -384,6 +381,39 @@ static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
        return retval;
 }
 
+static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct at24_data *at24;
+
+       at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+       return at24_write(at24, buf, off, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This lets other kernel code access the eeprom data. For example, it
+ * might hold a board's Ethernet address, or board-specific calibration
+ * data generated on the manufacturing floor.
+ */
+
+static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf,
+                        off_t offset, size_t count)
+{
+       struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+       return at24_read(at24, buf, offset, count);
+}
+
+static ssize_t at24_macc_write(struct memory_accessor *macc, char *buf,
+                         off_t offset, size_t count)
+{
+       struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+       return at24_write(at24, buf, offset, count);
+}
+
 /*-------------------------------------------------------------------------*/
 
 static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
@@ -413,6 +443,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
                 * is recommended anyhow.
                 */
                chip.page_size = 1;
+
+               chip.setup = NULL;
+               chip.context = NULL;
        }
 
        if (!is_power_of_2(chip.byte_len))
@@ -463,6 +496,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
        at24->bin.read = at24_bin_read;
        at24->bin.size = chip.byte_len;
 
+       at24->macc.read = at24_macc_read;
+
        writable = !(chip.flags & AT24_FLAG_READONLY);
        if (writable) {
                if (!use_smbus || i2c_check_functionality(client->adapter,
@@ -470,6 +505,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
                        unsigned write_max = chip.page_size;
 
+                       at24->macc.write = at24_macc_write;
+
                        at24->bin.write = at24_bin_write;
                        at24->bin.attr.mode |= S_IWUSR;
 
@@ -520,6 +557,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
                at24->write_max,
                use_smbus ? ", use_smbus" : "");
 
+       /* export data to kernel code */
+       if (chip.setup)
+               chip.setup(&at24->macc, chip.context);
+
        return 0;
 
 err_clients:
index 290dbe99647a141125a4465170343c51c770ec02..6bc0dac5c1e8f425f6390495220cc4572cea8037 100644 (file)
@@ -30,6 +30,7 @@
 
 struct at25_data {
        struct spi_device       *spi;
+       struct memory_accessor  mem;
        struct mutex            lock;
        struct spi_eeprom       chip;
        struct bin_attribute    bin;
@@ -75,6 +76,13 @@ at25_ee_read(
        struct spi_transfer     t[2];
        struct spi_message      m;
 
+       if (unlikely(offset >= at25->bin.size))
+               return 0;
+       if ((offset + count) > at25->bin.size)
+               count = at25->bin.size - offset;
+       if (unlikely(!count))
+               return count;
+
        cp = command;
        *cp++ = AT25_READ;
 
@@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
        dev = container_of(kobj, struct device, kobj);
        at25 = dev_get_drvdata(dev);
 
-       if (unlikely(off >= at25->bin.size))
-               return 0;
-       if ((off + count) > at25->bin.size)
-               count = at25->bin.size - off;
-       if (unlikely(!count))
-               return count;
-
        return at25_ee_read(at25, buf, off, count);
 }
 
@@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
        unsigned                buf_size;
        u8                      *bounce;
 
+       if (unlikely(off >= at25->bin.size))
+               return -EFBIG;
+       if ((off + count) > at25->bin.size)
+               count = at25->bin.size - off;
+       if (unlikely(!count))
+               return count;
+
        /* Temp buffer starts with command and address */
        buf_size = at25->chip.page_size;
        if (buf_size > io_limit)
@@ -253,18 +261,31 @@ at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr,
        dev = container_of(kobj, struct device, kobj);
        at25 = dev_get_drvdata(dev);
 
-       if (unlikely(off >= at25->bin.size))
-               return -EFBIG;
-       if ((off + count) > at25->bin.size)
-               count = at25->bin.size - off;
-       if (unlikely(!count))
-               return count;
-
        return at25_ee_write(at25, buf, off, count);
 }
 
 /*-------------------------------------------------------------------------*/
 
+/* Let in-kernel code access the eeprom data. */
+
+static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf,
+                        off_t offset, size_t count)
+{
+       struct at25_data *at25 = container_of(mem, struct at25_data, mem);
+
+       return at25_ee_read(at25, buf, offset, count);
+}
+
+static ssize_t at25_mem_write(struct memory_accessor *mem, char *buf,
+                         off_t offset, size_t count)
+{
+       struct at25_data *at25 = container_of(mem, struct at25_data, mem);
+
+       return at25_ee_write(at25, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
 static int at25_probe(struct spi_device *spi)
 {
        struct at25_data        *at25 = NULL;
@@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi)
        at25->addrlen = addrlen;
 
        /* Export the EEPROM bytes through sysfs, since that's convenient.
+        * And maybe to other kernel code; it might hold a board's Ethernet
+        * address, or board-specific calibration data generated on the
+        * manufacturing floor.
+        *
         * Default to root-only access to the data; EEPROMs often hold data
         * that's sensitive for read and/or write, like ethernet addresses,
         * security codes, board-specific manufacturing calibrations, etc.
@@ -324,17 +349,22 @@ static int at25_probe(struct spi_device *spi)
        at25->bin.attr.name = "eeprom";
        at25->bin.attr.mode = S_IRUSR;
        at25->bin.read = at25_bin_read;
+       at25->mem.read = at25_mem_read;
 
        at25->bin.size = at25->chip.byte_len;
        if (!(chip->flags & EE_READONLY)) {
                at25->bin.write = at25_bin_write;
                at25->bin.attr.mode |= S_IWUSR;
+               at25->mem.write = at25_mem_write;
        }
 
        err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
        if (err)
                goto fail;
 
+       if (chip->setup)
+               chip->setup(&at25->mem, chip->context);
+
        dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
                (at25->bin.size < 1024)
                        ? at25->bin.size
index cf991850f01ba04b23ad40b1ded35747735b0bf4..880ccf39e23b1f70c83d26883c9a169ce76281f0 100644 (file)
@@ -209,7 +209,7 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
        /* give iLO some time to process stop request */
        for (retries = MAX_WAIT; retries > 0; retries--) {
                doorbell_set(driver_ccb);
-               udelay(1);
+               udelay(WAIT_TIME);
                if (!(ioread32(&device_ccb->send_ctrl) & (1 << CTRL_BITPOS_A))
                    &&
                    !(ioread32(&device_ccb->recv_ctrl) & (1 << CTRL_BITPOS_A)))
@@ -312,7 +312,7 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
        for (i = MAX_WAIT; i > 0; i--) {
                if (ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, NULL, NULL))
                        break;
-               udelay(1);
+               udelay(WAIT_TIME);
        }
 
        if (i) {
@@ -759,7 +759,7 @@ static void __exit ilo_exit(void)
        class_destroy(ilo_class);
 }
 
-MODULE_VERSION("1.0");
+MODULE_VERSION("1.1");
 MODULE_ALIAS(ILO_NAME);
 MODULE_DESCRIPTION(ILO_NAME);
 MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
index b64a20ef07e3cc6e7280386b5dc462233e1fd99a..03a14c82aad9bc9f0588cb3ee974ea5e2d8cd493 100644 (file)
 #define MAX_ILO_DEV    1
 /* max number of files */
 #define MAX_OPEN       (MAX_CCB * MAX_ILO_DEV)
+/* total wait time in usec */
+#define MAX_WAIT_TIME  10000
+/* per spin wait time in usec */
+#define WAIT_TIME      10
 /* spin counter for open/close delay */
-#define MAX_WAIT       10000
+#define MAX_WAIT       (MAX_WAIT_TIME / WAIT_TIME)
 
 /*
  * Per device, used to track global memory allocations.
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
new file mode 100644 (file)
index 0000000..2e2a592
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ *  isl29003.c - Linux kernel module for
+ *     Intersil ISL29003 ambient light sensor
+ *
+ *  See file:Documentation/misc-devices/isl29003
+ *
+ *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  Based on code written by
+ *     Rodolfo Giometti <giometti@linux.it>
+ *     Eurotech S.p.A. <info@eurotech.it>
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define ISL29003_DRV_NAME      "isl29003"
+#define DRIVER_VERSION         "1.0"
+
+#define ISL29003_REG_COMMAND           0x00
+#define ISL29003_ADC_ENABLED           (1 << 7)
+#define ISL29003_ADC_PD                        (1 << 6)
+#define ISL29003_TIMING_INT            (1 << 5)
+#define ISL29003_MODE_SHIFT            (2)
+#define ISL29003_MODE_MASK             (0x3 << ISL29003_MODE_SHIFT)
+#define ISL29003_RES_SHIFT             (0)
+#define ISL29003_RES_MASK              (0x3 << ISL29003_RES_SHIFT)
+
+#define ISL29003_REG_CONTROL           0x01
+#define ISL29003_INT_FLG               (1 << 5)
+#define ISL29003_RANGE_SHIFT           (2)
+#define ISL29003_RANGE_MASK            (0x3 << ISL29003_RANGE_SHIFT)
+#define ISL29003_INT_PERSISTS_SHIFT    (0)
+#define ISL29003_INT_PERSISTS_MASK     (0xf << ISL29003_INT_PERSISTS_SHIFT)
+
+#define ISL29003_REG_IRQ_THRESH_HI     0x02
+#define ISL29003_REG_IRQ_THRESH_LO     0x03
+#define ISL29003_REG_LSB_SENSOR                0x04
+#define ISL29003_REG_MSB_SENSOR                0x05
+#define ISL29003_REG_LSB_TIMER         0x06
+#define ISL29003_REG_MSB_TIMER         0x07
+
+#define ISL29003_NUM_CACHABLE_REGS     4
+
+struct isl29003_data {
+       struct i2c_client *client;
+       struct mutex lock;
+       u8 reg_cache[ISL29003_NUM_CACHABLE_REGS];
+};
+
+static int gain_range[] = {
+       1000, 4000, 16000, 64000
+};
+
+/*
+ * register access helpers
+ */
+
+static int __isl29003_read_reg(struct i2c_client *client,
+                              u32 reg, u8 mask, u8 shift)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       return (data->reg_cache[reg] & mask) >> shift;
+}
+
+static int __isl29003_write_reg(struct i2c_client *client,
+                               u32 reg, u8 mask, u8 shift, u8 val)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       int ret = 0;
+       u8 tmp;
+
+       if (reg >= ISL29003_NUM_CACHABLE_REGS)
+               return -EINVAL;
+
+       mutex_lock(&data->lock);
+
+       tmp = data->reg_cache[reg];
+       tmp &= ~mask;
+       tmp |= val << shift;
+
+       ret = i2c_smbus_write_byte_data(client, reg, tmp);
+       if (!ret)
+               data->reg_cache[reg] = tmp;
+
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+/*
+ * internally used functions
+ */
+
+/* range */
+static int isl29003_get_range(struct i2c_client *client)
+{
+       return __isl29003_read_reg(client, ISL29003_REG_CONTROL,
+               ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT);
+}
+
+static int isl29003_set_range(struct i2c_client *client, int range)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_CONTROL,
+               ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT, range);
+}
+
+/* resolution */
+static int isl29003_get_resolution(struct i2c_client *client)
+{
+       return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT);
+}
+
+static int isl29003_set_resolution(struct i2c_client *client, int res)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT, res);
+}
+
+/* mode */
+static int isl29003_get_mode(struct i2c_client *client)
+{
+       return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT);
+}
+
+static int isl29003_set_mode(struct i2c_client *client, int mode)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
+               ISL29003_RES_MASK, ISL29003_RES_SHIFT, mode);
+}
+
+/* power_state */
+static int isl29003_set_power_state(struct i2c_client *client, int state)
+{
+       return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
+                               ISL29003_ADC_ENABLED | ISL29003_ADC_PD, 0,
+                               state ? ISL29003_ADC_ENABLED : ISL29003_ADC_PD);
+}
+
+static int isl29003_get_power_state(struct i2c_client *client)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       u8 cmdreg = data->reg_cache[ISL29003_REG_COMMAND];
+       return ~cmdreg & ISL29003_ADC_PD;
+}
+
+static int isl29003_get_adc_value(struct i2c_client *client)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       int lsb, msb, range, bitdepth;
+
+       mutex_lock(&data->lock);
+       lsb = i2c_smbus_read_byte_data(client, ISL29003_REG_LSB_SENSOR);
+
+       if (lsb < 0) {
+               mutex_unlock(&data->lock);
+               return lsb;
+       }
+
+       msb = i2c_smbus_read_byte_data(client, ISL29003_REG_MSB_SENSOR);
+       mutex_unlock(&data->lock);
+
+       if (msb < 0)
+               return msb;
+
+       range = isl29003_get_range(client);
+       bitdepth = (4 - isl29003_get_resolution(client)) * 4;
+       return (((msb << 8) | lsb) * gain_range[range]) >> bitdepth;
+}
+
+/*
+ * sysfs layer
+ */
+
+/* range */
+static ssize_t isl29003_show_range(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%i\n", isl29003_get_range(client));
+}
+
+static ssize_t isl29003_store_range(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3))
+               return -EINVAL;
+
+       ret = isl29003_set_range(client, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(range, S_IWUSR | S_IRUGO,
+                  isl29003_show_range, isl29003_store_range);
+
+
+/* resolution */
+static ssize_t isl29003_show_resolution(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%d\n", isl29003_get_resolution(client));
+}
+
+static ssize_t isl29003_store_resolution(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3))
+               return -EINVAL;
+
+       ret = isl29003_set_resolution(client, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO,
+                  isl29003_show_resolution, isl29003_store_resolution);
+
+/* mode */
+static ssize_t isl29003_show_mode(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%d\n", isl29003_get_mode(client));
+}
+
+static ssize_t isl29003_store_mode(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 2))
+               return -EINVAL;
+
+       ret = isl29003_set_mode(client, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
+                  isl29003_show_mode, isl29003_store_mode);
+
+
+/* power state */
+static ssize_t isl29003_show_power_state(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%d\n", isl29003_get_power_state(client));
+}
+
+static ssize_t isl29003_store_power_state(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int ret;
+
+       if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1))
+               return -EINVAL;
+
+       ret = isl29003_set_power_state(client, val);
+       return ret ? ret : count;
+}
+
+static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
+                  isl29003_show_power_state, isl29003_store_power_state);
+
+
+/* lux */
+static ssize_t isl29003_show_lux(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       /* No LUX data if not operational */
+       if (!isl29003_get_power_state(client))
+               return -EBUSY;
+
+       return sprintf(buf, "%d\n", isl29003_get_adc_value(client));
+}
+
+static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL);
+
+static struct attribute *isl29003_attributes[] = {
+       &dev_attr_range.attr,
+       &dev_attr_resolution.attr,
+       &dev_attr_mode.attr,
+       &dev_attr_power_state.attr,
+       &dev_attr_lux.attr,
+       NULL
+};
+
+static const struct attribute_group isl29003_attr_group = {
+       .attrs = isl29003_attributes,
+};
+
+static int isl29003_init_client(struct i2c_client *client)
+{
+       struct isl29003_data *data = i2c_get_clientdata(client);
+       int i;
+
+       /* read all the registers once to fill the cache.
+        * if one of the reads fails, we consider the init failed */
+       for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
+               int v = i2c_smbus_read_byte_data(client, i);
+               if (v < 0)
+                       return -ENODEV;
+
+               data->reg_cache[i] = v;
+       }
+
+       /* set defaults */
+       isl29003_set_range(client, 0);
+       isl29003_set_resolution(client, 0);
+       isl29003_set_mode(client, 0);
+       isl29003_set_power_state(client, 0);
+
+       return 0;
+}
+
+/*
+ * I2C layer
+ */
+
+static int __devinit isl29003_probe(struct i2c_client *client,
+                                   const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct isl29003_data *data;
+       int err = 0;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+               return -EIO;
+
+       data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->client = client;
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->lock);
+
+       /* initialize the ISL29003 chip */
+       err = isl29003_init_client(client);
+       if (err)
+               goto exit_kfree;
+
+       /* register sysfs hooks */
+       err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group);
+       if (err)
+               goto exit_kfree;
+
+       dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
+       return 0;
+
+exit_kfree:
+       kfree(data);
+       return err;
+}
+
+static int __devexit isl29003_remove(struct i2c_client *client)
+{
+       sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group);
+       isl29003_set_power_state(client, 0);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int isl29003_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       return isl29003_set_power_state(client, 0);
+}
+
+static int isl29003_resume(struct i2c_client *client)
+{
+       int i;
+       struct isl29003_data *data = i2c_get_clientdata(client);
+
+       /* restore registers from cache */
+       for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++)
+               if (!i2c_smbus_write_byte_data(client, i, data->reg_cache[i]))
+                       return -EIO;
+
+       return 0;
+}
+
+#else
+#define isl29003_suspend       NULL
+#define isl29003_resume                NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id isl29003_id[] = {
+       { "isl29003", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, isl29003_id);
+
+static struct i2c_driver isl29003_driver = {
+       .driver = {
+               .name   = ISL29003_DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .suspend = isl29003_suspend,
+       .resume = isl29003_resume,
+       .probe  = isl29003_probe,
+       .remove = __devexit_p(isl29003_remove),
+       .id_table = isl29003_id,
+};
+
+static int __init isl29003_init(void)
+{
+       return i2c_add_driver(&isl29003_driver);
+}
+
+static void __exit isl29003_exit(void)
+{
+       i2c_del_driver(&isl29003_driver);
+}
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("ISL29003 ambient light sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(isl29003_init);
+module_exit(isl29003_exit);
+
index 9e9170b3599a249e4576fbb8b8d4214dead20a2a..bcd8136d2f985bab6341c0ba912fc09f2fe83d65 100644 (file)
@@ -3,5 +3,5 @@ ifdef CONFIG_SGI_GRU_DEBUG
 endif
 
 obj-$(CONFIG_SGI_GRU) := gru.o
-gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o
+gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o
 
index 48762e7b98be65a5b3758489657a5d1675cf5de0..3fde33c1e8f3b64e10192194974ec0016ea95f00 100644 (file)
 #ifndef __GRU_INSTRUCTIONS_H__
 #define __GRU_INSTRUCTIONS_H__
 
-#define gru_flush_cache_hook(p)
-#define gru_emulator_wait_hook(p, w)
+extern int gru_check_status_proc(void *cb);
+extern int gru_wait_proc(void *cb);
+extern void gru_wait_abort_proc(void *cb);
+
+
 
 /*
  * Architecture dependent functions
 #if defined(CONFIG_IA64)
 #include <linux/compiler.h>
 #include <asm/intrinsics.h>
-#define __flush_cache(p)               ia64_fc(p)
+#define __flush_cache(p)               ia64_fc((unsigned long)p)
 /* Use volatile on IA64 to ensure ordering via st4.rel */
-#define gru_ordered_store_int(p,v)                                     \
+#define gru_ordered_store_int(p, v)                                    \
                do {                                                    \
                        barrier();                                      \
                        *((volatile int *)(p)) = v; /* force st.rel */  \
                } while (0)
 #elif defined(CONFIG_X86_64)
 #define __flush_cache(p)               clflush(p)
-#define gru_ordered_store_int(p,v)                                     \
+#define gru_ordered_store_int(p, v)                                    \
                do {                                                    \
                        barrier();                                      \
                        *(int *)p = v;                                  \
@@ -558,20 +561,19 @@ extern int gru_get_cb_exception_detail(void *cb,
 
 #define GRU_EXC_STR_SIZE               256
 
-extern int gru_check_status_proc(void *cb);
-extern int gru_wait_proc(void *cb);
-extern void gru_wait_abort_proc(void *cb);
 
 /*
  * Control block definition for checking status
  */
 struct gru_control_block_status {
        unsigned int    icmd            :1;
-       unsigned int    unused1         :31;
+       unsigned int    ima             :3;
+       unsigned int    reserved0       :4;
+       unsigned int    unused1         :24;
        unsigned int    unused2         :24;
        unsigned int    istatus         :2;
        unsigned int    isubstatus      :4;
-       unsigned int    inused3         :2;
+       unsigned int    unused3         :2;
 };
 
 /* Get CB status */
index 3ee698ad85997cf2f5c32b986689d7c07a0ed607..ab118558552e96a3fea1071f406b47d88514e905 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
+#include <linux/security.h>
 #include <asm/pgtable.h>
 #include "gru.h"
 #include "grutables.h"
@@ -266,6 +267,44 @@ err:
        return 1;
 }
 
+static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
+                   int write, int atomic, unsigned long *gpa, int *pageshift)
+{
+       struct mm_struct *mm = gts->ts_mm;
+       struct vm_area_struct *vma;
+       unsigned long paddr;
+       int ret, ps;
+
+       vma = find_vma(mm, vaddr);
+       if (!vma)
+               goto inval;
+
+       /*
+        * Atomic lookup is faster & usually works even if called in non-atomic
+        * context.
+        */
+       rmb();  /* Must/check ms_range_active before loading PTEs */
+       ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &ps);
+       if (ret) {
+               if (atomic)
+                       goto upm;
+               if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, &ps))
+                       goto inval;
+       }
+       if (is_gru_paddr(paddr))
+               goto inval;
+       paddr = paddr & ~((1UL << ps) - 1);
+       *gpa = uv_soc_phys_ram_to_gpa(paddr);
+       *pageshift = ps;
+       return 0;
+
+inval:
+       return -1;
+upm:
+       return -2;
+}
+
+
 /*
  * Drop a TLB entry into the GRU. The fault is described by info in an TFH.
  *     Input:
@@ -280,10 +319,8 @@ static int gru_try_dropin(struct gru_thread_state *gts,
                          struct gru_tlb_fault_handle *tfh,
                          unsigned long __user *cb)
 {
-       struct mm_struct *mm = gts->ts_mm;
-       struct vm_area_struct *vma;
-       int pageshift, asid, write, ret;
-       unsigned long paddr, gpa, vaddr;
+       int pageshift = 0, asid, write, ret, atomic = !cb;
+       unsigned long gpa = 0, vaddr = 0;
 
        /*
         * NOTE: The GRU contains magic hardware that eliminates races between
@@ -317,28 +354,19 @@ static int gru_try_dropin(struct gru_thread_state *gts,
        if (atomic_read(&gts->ts_gms->ms_range_active))
                goto failactive;
 
-       vma = find_vma(mm, vaddr);
-       if (!vma)
+       ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift);
+       if (ret == -1)
                goto failinval;
+       if (ret == -2)
+               goto failupm;
 
-       /*
-        * Atomic lookup is faster & usually works even if called in non-atomic
-        * context.
-        */
-       rmb();  /* Must/check ms_range_active before loading PTEs */
-       ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &pageshift);
-       if (ret) {
-               if (!cb)
+       if (!(gts->ts_sizeavail & GRU_SIZEAVAIL(pageshift))) {
+               gts->ts_sizeavail |= GRU_SIZEAVAIL(pageshift);
+               if (atomic || !gru_update_cch(gts, 0)) {
+                       gts->ts_force_cch_reload = 1;
                        goto failupm;
-               if (non_atomic_pte_lookup(vma, vaddr, write, &paddr,
-                                         &pageshift))
-                       goto failinval;
+               }
        }
-       if (is_gru_paddr(paddr))
-               goto failinval;
-
-       paddr = paddr & ~((1UL << pageshift) - 1);
-       gpa = uv_soc_phys_ram_to_gpa(paddr);
        gru_cb_set_istatus_active(cb);
        tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write,
                          GRU_PAGESIZE(pageshift));
@@ -368,6 +396,7 @@ failupm:
 
 failfmm:
        /* FMM state on UPM call */
+       gru_flush_cache(tfh);
        STAT(tlb_dropin_fail_fmm);
        gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state);
        return 0;
@@ -448,6 +477,7 @@ irqreturn_t gru_intr(int irq, void *dev_id)
                        up_read(&gts->ts_mm->mmap_sem);
                } else {
                        tfh_user_polling_mode(tfh);
+                       STAT(intr_mm_lock_failed);
                }
        }
        return IRQ_HANDLED;
@@ -497,10 +527,8 @@ int gru_handle_user_call_os(unsigned long cb)
        if (!gts)
                return -EINVAL;
 
-       if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) {
-               ret = -EINVAL;
+       if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE)
                goto exit;
-       }
 
        /*
         * If force_unload is set, the UPM TLB fault is phony. The task
@@ -508,6 +536,20 @@ int gru_handle_user_call_os(unsigned long cb)
         * unload the context. The task will page fault and assign a new
         * context.
         */
+       if (gts->ts_tgid_owner == current->tgid && gts->ts_blade >= 0 &&
+                               gts->ts_blade != uv_numa_blade_id()) {
+               STAT(call_os_offnode_reference);
+               gts->ts_force_unload = 1;
+       }
+
+       /*
+        * CCH may contain stale data if ts_force_cch_reload is set.
+        */
+       if (gts->ts_gru && gts->ts_force_cch_reload) {
+               gru_update_cch(gts, 0);
+               gts->ts_force_cch_reload = 0;
+       }
+
        ret = -EAGAIN;
        cbrnum = thread_cbr_number(gts, ucbnum);
        if (gts->ts_force_unload) {
@@ -541,11 +583,13 @@ int gru_get_exception_detail(unsigned long arg)
        if (!gts)
                return -EINVAL;
 
-       if (gts->ts_gru) {
-               ucbnum = get_cb_number((void *)excdet.cb);
+       ucbnum = get_cb_number((void *)excdet.cb);
+       if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) {
+               ret = -EINVAL;
+       } else if (gts->ts_gru) {
                cbrnum = thread_cbr_number(gts, ucbnum);
                cbe = get_cbe_by_index(gts->ts_gru, cbrnum);
-               prefetchw(cbe);         /* Harmless on hardware, required for emulator */
+               prefetchw(cbe);/* Harmless on hardware, required for emulator */
                excdet.opc = cbe->opccpy;
                excdet.exopc = cbe->exopccpy;
                excdet.ecause = cbe->ecause;
@@ -567,6 +611,31 @@ int gru_get_exception_detail(unsigned long arg)
 /*
  * User request to unload a context. Content is saved for possible reload.
  */
+static int gru_unload_all_contexts(void)
+{
+       struct gru_thread_state *gts;
+       struct gru_state *gru;
+       int gid, ctxnum;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       foreach_gid(gid) {
+               gru = GID_TO_GRU(gid);
+               spin_lock(&gru->gs_lock);
+               for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) {
+                       gts = gru->gs_gts[ctxnum];
+                       if (gts && mutex_trylock(&gts->ts_ctxlock)) {
+                               spin_unlock(&gru->gs_lock);
+                               gru_unload_context(gts, 1);
+                               gru_unlock_gts(gts);
+                               spin_lock(&gru->gs_lock);
+                       }
+               }
+               spin_unlock(&gru->gs_lock);
+       }
+       return 0;
+}
+
 int gru_user_unload_context(unsigned long arg)
 {
        struct gru_thread_state *gts;
@@ -578,6 +647,9 @@ int gru_user_unload_context(unsigned long arg)
 
        gru_dbg(grudev, "gseg 0x%lx\n", req.gseg);
 
+       if (!req.gseg)
+               return gru_unload_all_contexts();
+
        gts = gru_find_lock_gts(req.gseg);
        if (!gts)
                return -EINVAL;
@@ -609,7 +681,7 @@ int gru_user_flush_tlb(unsigned long arg)
        if (!gts)
                return -EINVAL;
 
-       gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.vaddr + req.len);
+       gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.len);
        gru_unlock_gts(gts);
 
        return 0;
index c67e4e8bd62c5fd83236ff97fb0961a82db189d2..3e6e42d2f01b559c93d5396852e2830a3cc9316a 100644 (file)
@@ -45,7 +45,9 @@
 #include <asm/uv/uv_mmrs.h>
 
 struct gru_blade_state *gru_base[GRU_MAX_BLADES] __read_mostly;
-unsigned long gru_start_paddr, gru_end_paddr __read_mostly;
+unsigned long gru_start_paddr __read_mostly;
+unsigned long gru_end_paddr __read_mostly;
+unsigned int gru_max_gids __read_mostly;
 struct gru_stats_s gru_stats;
 
 /* Guaranteed user available resources on each node */
@@ -101,7 +103,7 @@ static int gru_file_mmap(struct file *file, struct vm_area_struct *vma)
                return -EPERM;
 
        if (vma->vm_start & (GRU_GSEG_PAGESIZE - 1) ||
-                               vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
+                               vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
                return -EINVAL;
 
        vma->vm_flags |=
@@ -273,8 +275,11 @@ static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr,
        gru->gs_blade_id = bid;
        gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1;
        gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1;
+       gru->gs_asid_limit = MAX_ASID;
        gru_tgh_flush_init(gru);
-       gru_dbg(grudev, "bid %d, nid %d, gru %x, vaddr %p (0x%lx)\n",
+       if (gru->gs_gid >= gru_max_gids)
+               gru_max_gids = gru->gs_gid + 1;
+       gru_dbg(grudev, "bid %d, nid %d, gid %d, vaddr %p (0x%lx)\n",
                bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr,
                gru->gs_gru_base_paddr);
        gru_kservices_init(gru);
@@ -295,7 +300,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
        for_each_online_node(nid) {
                bid = uv_node_to_blade_id(nid);
                pnode = uv_node_to_pnode(nid);
-               if (gru_base[bid])
+               if (bid < 0 || gru_base[bid])
                        continue;
                page = alloc_pages_node(nid, GFP_KERNEL, order);
                if (!page)
@@ -308,11 +313,11 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
                dsrbytes = 0;
                cbrs = 0;
                for (gru = gru_base[bid]->bs_grus, chip = 0;
-                               chip < GRU_CHIPLETS_PER_BLADE;
+                               chip < GRU_CHIPLETS_PER_BLADE;
                                chip++, gru++) {
                        paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip);
                        vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip);
-                       gru_init_chiplet(gru, paddr, vaddr, bid, nid, chip);
+                       gru_init_chiplet(gru, paddr, vaddr, nid, bid, chip);
                        n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE;
                        cbrs = max(cbrs, n);
                        n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES;
@@ -370,26 +375,26 @@ static int __init gru_init(void)
        void *gru_start_vaddr;
 
        if (!is_uv_system())
-               return 0;
+               return -ENODEV;
 
 #if defined CONFIG_IA64
        gru_start_paddr = 0xd000000000UL; /* ZZZZZZZZZZZZZZZZZZZ fixme */
 #else
        gru_start_paddr = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR) &
                                0x7fffffffffffUL;
-
 #endif
        gru_start_vaddr = __va(gru_start_paddr);
-       gru_end_paddr = gru_start_paddr + MAX_NUMNODES * GRU_SIZE;
+       gru_end_paddr = gru_start_paddr + GRU_MAX_BLADES * GRU_SIZE;
        printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n",
               gru_start_paddr, gru_end_paddr);
        irq = get_base_irq();
        for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) {
                ret = request_irq(irq + chip, gru_intr, 0, id, NULL);
-               /* TODO: fix irq handling on x86. For now ignore failures because
+               /* TODO: fix irq handling on x86. For now ignore failure because
                 * interrupts are not required & not yet fully supported */
                if (ret) {
-                       printk("!!!WARNING: GRU ignoring request failure!!!\n");
+                       printk(KERN_WARNING
+                              "!!!WARNING: GRU ignoring request failure!!!\n");
                        ret = 0;
                }
                if (ret) {
@@ -435,7 +440,7 @@ exit1:
 
 static void __exit gru_exit(void)
 {
-       int i, bid;
+       int i, bid, gid;
        int order = get_order(sizeof(struct gru_state) *
                              GRU_CHIPLETS_PER_BLADE);
 
@@ -445,6 +450,9 @@ static void __exit gru_exit(void)
        for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++)
                free_irq(IRQ_GRU + i, NULL);
 
+       foreach_gid(gid)
+               gru_kservices_exit(GID_TO_GRU(gid));
+
        for (bid = 0; bid < GRU_MAX_BLADES; bid++)
                free_pages((unsigned long)gru_base[bid], order);
 
@@ -469,7 +477,11 @@ struct vm_operations_struct gru_vm_ops = {
        .fault          = gru_fault,
 };
 
+#ifndef MODULE
 fs_initcall(gru_init);
+#else
+module_init(gru_init);
+#endif
 module_exit(gru_exit);
 
 module_param(gru_options, ulong, 0644);
diff --git a/drivers/misc/sgi-gru/gruhandles.c b/drivers/misc/sgi-gru/gruhandles.c
new file mode 100644 (file)
index 0000000..9b7ccb3
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *              GRU KERNEL MCS INSTRUCTIONS
+ *
+ *  Copyright (c) 2008 Silicon Graphics, Inc.  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.  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
+ */
+
+#include <linux/kernel.h>
+#include "gru.h"
+#include "grulib.h"
+#include "grutables.h"
+
+/* 10 sec */
+#ifdef CONFIG_IA64
+#include <asm/processor.h>
+#define GRU_OPERATION_TIMEOUT  (((cycles_t) local_cpu_data->itc_freq)*10)
+#else
+#include <asm/tsc.h>
+#define GRU_OPERATION_TIMEOUT  ((cycles_t) tsc_khz*10*1000)
+#endif
+
+/* Extract the status field from a kernel handle */
+#define GET_MSEG_HANDLE_STATUS(h)      (((*(unsigned long *)(h)) >> 16) & 3)
+
+struct mcs_op_statistic mcs_op_statistics[mcsop_last];
+
+static void update_mcs_stats(enum mcs_op op, unsigned long clks)
+{
+       atomic_long_inc(&mcs_op_statistics[op].count);
+       atomic_long_add(clks, &mcs_op_statistics[op].total);
+       if (mcs_op_statistics[op].max < clks)
+               mcs_op_statistics[op].max = clks;
+}
+
+static void start_instruction(void *h)
+{
+       unsigned long *w0 = h;
+
+       wmb();          /* setting CMD bit must be last */
+       *w0 = *w0 | 1;
+       gru_flush_cache(h);
+}
+
+static int wait_instruction_complete(void *h, enum mcs_op opc)
+{
+       int status;
+       cycles_t start_time = get_cycles();
+
+       while (1) {
+               cpu_relax();
+               status = GET_MSEG_HANDLE_STATUS(h);
+               if (status != CCHSTATUS_ACTIVE)
+                       break;
+               if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time))
+                       panic("GRU %p is malfunctioning\n", h);
+       }
+       if (gru_options & OPT_STATS)
+               update_mcs_stats(opc, get_cycles() - start_time);
+       return status;
+}
+
+int cch_allocate(struct gru_context_configuration_handle *cch,
+               int asidval, int sizeavail, unsigned long cbrmap,
+               unsigned long dsrmap)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               cch->asid[i] = (asidval++);
+               cch->sizeavail[i] = sizeavail;
+       }
+       cch->dsr_allocation_map = dsrmap;
+       cch->cbr_allocation_map = cbrmap;
+       cch->opc = CCHOP_ALLOCATE;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_allocate);
+}
+
+int cch_start(struct gru_context_configuration_handle *cch)
+{
+       cch->opc = CCHOP_START;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_start);
+}
+
+int cch_interrupt(struct gru_context_configuration_handle *cch)
+{
+       cch->opc = CCHOP_INTERRUPT;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_interrupt);
+}
+
+int cch_deallocate(struct gru_context_configuration_handle *cch)
+{
+       cch->opc = CCHOP_DEALLOCATE;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_deallocate);
+}
+
+int cch_interrupt_sync(struct gru_context_configuration_handle
+                                    *cch)
+{
+       cch->opc = CCHOP_INTERRUPT_SYNC;
+       start_instruction(cch);
+       return wait_instruction_complete(cch, cchop_interrupt_sync);
+}
+
+int tgh_invalidate(struct gru_tlb_global_handle *tgh,
+                                unsigned long vaddr, unsigned long vaddrmask,
+                                int asid, int pagesize, int global, int n,
+                                unsigned short ctxbitmap)
+{
+       tgh->vaddr = vaddr;
+       tgh->asid = asid;
+       tgh->pagesize = pagesize;
+       tgh->n = n;
+       tgh->global = global;
+       tgh->vaddrmask = vaddrmask;
+       tgh->ctxbitmap = ctxbitmap;
+       tgh->opc = TGHOP_TLBINV;
+       start_instruction(tgh);
+       return wait_instruction_complete(tgh, tghop_invalidate);
+}
+
+void tfh_write_only(struct gru_tlb_fault_handle *tfh,
+                                 unsigned long pfn, unsigned long vaddr,
+                                 int asid, int dirty, int pagesize)
+{
+       tfh->fillasid = asid;
+       tfh->fillvaddr = vaddr;
+       tfh->pfn = pfn;
+       tfh->dirty = dirty;
+       tfh->pagesize = pagesize;
+       tfh->opc = TFHOP_WRITE_ONLY;
+       start_instruction(tfh);
+}
+
+void tfh_write_restart(struct gru_tlb_fault_handle *tfh,
+                                    unsigned long paddr, int gaa,
+                                    unsigned long vaddr, int asid, int dirty,
+                                    int pagesize)
+{
+       tfh->fillasid = asid;
+       tfh->fillvaddr = vaddr;
+       tfh->pfn = paddr >> GRU_PADDR_SHIFT;
+       tfh->gaa = gaa;
+       tfh->dirty = dirty;
+       tfh->pagesize = pagesize;
+       tfh->opc = TFHOP_WRITE_RESTART;
+       start_instruction(tfh);
+}
+
+void tfh_restart(struct gru_tlb_fault_handle *tfh)
+{
+       tfh->opc = TFHOP_RESTART;
+       start_instruction(tfh);
+}
+
+void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh)
+{
+       tfh->opc = TFHOP_USER_POLLING_MODE;
+       start_instruction(tfh);
+}
+
+void tfh_exception(struct gru_tlb_fault_handle *tfh)
+{
+       tfh->opc = TFHOP_EXCEPTION;
+       start_instruction(tfh);
+}
+
index b63018d60fe1a56b22e0cc2c02cc43b650dba7f6..1ed74d7508c8bb14181c181a07925d04041c6283 100644 (file)
@@ -489,170 +489,28 @@ enum gru_cbr_state {
  *      64m                    26      8
  *     ...
  */
-#define GRU_PAGESIZE(sh)       ((((sh) > 20 ? (sh) + 2: (sh)) >> 1) - 6)
+#define GRU_PAGESIZE(sh)       ((((sh) > 20 ? (sh) + 2 : (sh)) >> 1) - 6)
 #define GRU_SIZEAVAIL(sh)      (1UL << GRU_PAGESIZE(sh))
 
 /* minimum TLB purge count to ensure a full purge */
 #define GRUMAXINVAL            1024UL
 
-
-/* Extract the status field from a kernel handle */
-#define GET_MSEG_HANDLE_STATUS(h)      (((*(unsigned long *)(h)) >> 16) & 3)
-
-static inline void start_instruction(void *h)
-{
-       unsigned long *w0 = h;
-
-       wmb();          /* setting CMD bit must be last */
-       *w0 = *w0 | 1;
-       gru_flush_cache(h);
-}
-
-static inline int wait_instruction_complete(void *h)
-{
-       int status;
-
-       do {
-               cpu_relax();
-               barrier();
-               status = GET_MSEG_HANDLE_STATUS(h);
-       } while (status == CCHSTATUS_ACTIVE);
-       return status;
-}
-
-#if defined CONFIG_IA64
-static inline void cch_allocate_set_asids(
-                 struct gru_context_configuration_handle *cch, int asidval)
-{
-       int i;
-
-       for (i = 0; i <= RGN_HPAGE; i++) {  /*  assume HPAGE is last region */
-               cch->asid[i] = (asidval++);
-#if 0
-               /* ZZZ hugepages not supported yet */
-               if (i == RGN_HPAGE)
-                       cch->sizeavail[i] = GRU_SIZEAVAIL(hpage_shift);
-               else
-#endif
-                       cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT);
-       }
-}
-#elif defined CONFIG_X86_64
-static inline void cch_allocate_set_asids(
-                 struct gru_context_configuration_handle *cch, int asidval)
-{
-       int i;
-
-       for (i = 0; i < 8; i++) {
-               cch->asid[i] = asidval++;
-               cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT) |
-                       GRU_SIZEAVAIL(21);
-       }
-}
-#endif
-
-static inline int cch_allocate(struct gru_context_configuration_handle *cch,
-                              int asidval, unsigned long cbrmap,
-                              unsigned long dsrmap)
-{
-       cch_allocate_set_asids(cch, asidval);
-       cch->dsr_allocation_map = dsrmap;
-       cch->cbr_allocation_map = cbrmap;
-       cch->opc = CCHOP_ALLOCATE;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_start(struct gru_context_configuration_handle *cch)
-{
-       cch->opc = CCHOP_START;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_interrupt(struct gru_context_configuration_handle *cch)
-{
-       cch->opc = CCHOP_INTERRUPT;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_deallocate(struct gru_context_configuration_handle *cch)
-{
-       cch->opc = CCHOP_DEALLOCATE;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int cch_interrupt_sync(struct gru_context_configuration_handle
-                                    *cch)
-{
-       cch->opc = CCHOP_INTERRUPT_SYNC;
-       start_instruction(cch);
-       return wait_instruction_complete(cch);
-}
-
-static inline int tgh_invalidate(struct gru_tlb_global_handle *tgh,
-                                unsigned long vaddr, unsigned long vaddrmask,
-                                int asid, int pagesize, int global, int n,
-                                unsigned short ctxbitmap)
-{
-       tgh->vaddr = vaddr;
-       tgh->asid = asid;
-       tgh->pagesize = pagesize;
-       tgh->n = n;
-       tgh->global = global;
-       tgh->vaddrmask = vaddrmask;
-       tgh->ctxbitmap = ctxbitmap;
-       tgh->opc = TGHOP_TLBINV;
-       start_instruction(tgh);
-       return wait_instruction_complete(tgh);
-}
-
-static inline void tfh_write_only(struct gru_tlb_fault_handle *tfh,
-                                 unsigned long pfn, unsigned long vaddr,
-                                 int asid, int dirty, int pagesize)
-{
-       tfh->fillasid = asid;
-       tfh->fillvaddr = vaddr;
-       tfh->pfn = pfn;
-       tfh->dirty = dirty;
-       tfh->pagesize = pagesize;
-       tfh->opc = TFHOP_WRITE_ONLY;
-       start_instruction(tfh);
-}
-
-static inline void tfh_write_restart(struct gru_tlb_fault_handle *tfh,
-                                    unsigned long paddr, int gaa,
-                                    unsigned long vaddr, int asid, int dirty,
-                                    int pagesize)
-{
-       tfh->fillasid = asid;
-       tfh->fillvaddr = vaddr;
-       tfh->pfn = paddr >> GRU_PADDR_SHIFT;
-       tfh->gaa = gaa;
-       tfh->dirty = dirty;
-       tfh->pagesize = pagesize;
-       tfh->opc = TFHOP_WRITE_RESTART;
-       start_instruction(tfh);
-}
-
-static inline void tfh_restart(struct gru_tlb_fault_handle *tfh)
-{
-       tfh->opc = TFHOP_RESTART;
-       start_instruction(tfh);
-}
-
-static inline void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh)
-{
-       tfh->opc = TFHOP_USER_POLLING_MODE;
-       start_instruction(tfh);
-}
-
-static inline void tfh_exception(struct gru_tlb_fault_handle *tfh)
-{
-       tfh->opc = TFHOP_EXCEPTION;
-       start_instruction(tfh);
-}
+int cch_allocate(struct gru_context_configuration_handle *cch,
+       int asidval, int sizeavail, unsigned long cbrmap, unsigned long dsrmap);
+
+int cch_start(struct gru_context_configuration_handle *cch);
+int cch_interrupt(struct gru_context_configuration_handle *cch);
+int cch_deallocate(struct gru_context_configuration_handle *cch);
+int cch_interrupt_sync(struct gru_context_configuration_handle *cch);
+int tgh_invalidate(struct gru_tlb_global_handle *tgh, unsigned long vaddr,
+       unsigned long vaddrmask, int asid, int pagesize, int global, int n,
+       unsigned short ctxbitmap);
+void tfh_write_only(struct gru_tlb_fault_handle *tfh, unsigned long pfn,
+       unsigned long vaddr, int asid, int dirty, int pagesize);
+void tfh_write_restart(struct gru_tlb_fault_handle *tfh, unsigned long paddr,
+       int gaa, unsigned long vaddr, int asid, int dirty, int pagesize);
+void tfh_restart(struct gru_tlb_fault_handle *tfh);
+void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh);
+void tfh_exception(struct gru_tlb_fault_handle *tfh);
 
 #endif /* __GRUHANDLES_H__ */
index 880c55dfb66266dfd53cae3dea2492b986ff5744..d8bd7d84a7cf7117ca1e3f409b718e16a8ba1151 100644 (file)
  */
 
 /* Blade percpu resources PERMANENTLY reserved for kernel use */
-#define GRU_NUM_KERNEL_CBR      1
+#define GRU_NUM_KERNEL_CBR     1
 #define GRU_NUM_KERNEL_DSR_BYTES 256
+#define GRU_NUM_KERNEL_DSR_CL  (GRU_NUM_KERNEL_DSR_BYTES /             \
+                                       GRU_CACHE_LINE_BYTES)
 #define KERNEL_CTXNUM           15
 
 /* GRU instruction attributes for all instructions */
@@ -94,7 +96,6 @@ struct message_header {
        char    fill;
 };
 
-#define QLINES(mq)     ((mq) + offsetof(struct message_queue, qlines))
 #define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h]))
 
 static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr)
@@ -122,7 +123,7 @@ int gru_get_cb_exception_detail(void *cb,
        struct gru_control_block_extended *cbe;
 
        cbe = get_cbe(GRUBASE(cb), get_cb_number(cb));
-       prefetchw(cbe);         /* Harmless on hardware, required for emulator */
+       prefetchw(cbe); /* Harmless on hardware, required for emulator */
        excdet->opc = cbe->opccpy;
        excdet->exopc = cbe->exopccpy;
        excdet->ecause = cbe->ecause;
@@ -250,7 +251,8 @@ static inline void restore_present2(void *p, int val)
  * Create a message queue.
  *     qlines - message queue size in cache lines. Includes 2-line header.
  */
-int gru_create_message_queue(void *p, unsigned int bytes)
+int gru_create_message_queue(struct gru_message_queue_desc *mqd,
+               void *p, unsigned int bytes, int nasid, int vector, int apicid)
 {
        struct message_queue *mq = p;
        unsigned int qlines;
@@ -265,6 +267,12 @@ int gru_create_message_queue(void *p, unsigned int bytes)
        mq->hstatus[0] = 0;
        mq->hstatus[1] = 1;
        mq->head = gru_mesq_head(2, qlines / 2 + 1);
+       mqd->mq = mq;
+       mqd->mq_gpa = uv_gpa(mq);
+       mqd->qlines = qlines;
+       mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid);
+       mqd->interrupt_vector = vector;
+       mqd->interrupt_apicid = apicid;
        return 0;
 }
 EXPORT_SYMBOL_GPL(gru_create_message_queue);
@@ -277,8 +285,8 @@ EXPORT_SYMBOL_GPL(gru_create_message_queue);
  *             -1 - if mesq sent successfully but queue not full
  *             >0 - unexpected error. MQE_xxx returned
  */
-static int send_noop_message(void *cb,
-                               unsigned long mq, void *mesg)
+static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd,
+                               void *mesg)
 {
        const struct message_header noop_header = {
                                        .present = MQS_NOOP, .lines = 1};
@@ -289,7 +297,7 @@ static int send_noop_message(void *cb,
        STAT(mesq_noop);
        save_mhdr = *mhdr;
        *mhdr = noop_header;
-       gru_mesq(cb, mq, gru_get_tri(mhdr), 1, IMA);
+       gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), 1, IMA);
        ret = gru_wait(cb);
 
        if (ret) {
@@ -313,7 +321,7 @@ static int send_noop_message(void *cb,
                        break;
                case CBSS_PUT_NACKED:
                        STAT(mesq_noop_put_nacked);
-                       m = mq + (gru_get_amo_value_head(cb) << 6);
+                       m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
                        gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, 1, 1,
                                                IMA);
                        if (gru_wait(cb) == CBS_IDLE)
@@ -333,30 +341,20 @@ static int send_noop_message(void *cb,
 /*
  * Handle a gru_mesq full.
  */
-static int send_message_queue_full(void *cb,
-                          unsigned long mq, void *mesg, int lines)
+static int send_message_queue_full(void *cb, struct gru_message_queue_desc *mqd,
+                               void *mesg, int lines)
 {
        union gru_mesqhead mqh;
        unsigned int limit, head;
        unsigned long avalue;
-       int half, qlines, save;
+       int half, qlines;
 
        /* Determine if switching to first/second half of q */
        avalue = gru_get_amo_value(cb);
        head = gru_get_amo_value_head(cb);
        limit = gru_get_amo_value_limit(cb);
 
-       /*
-        * Fetch "qlines" from the queue header. Since the queue may be
-        * in memory that can't be accessed using socket addresses, use
-        * the GRU to access the data. Use DSR space from the message.
-        */
-       save = *(int *)mesg;
-       gru_vload(cb, QLINES(mq), gru_get_tri(mesg), XTYPE_W, 1, 1, IMA);
-       if (gru_wait(cb) != CBS_IDLE)
-               goto cberr;
-       qlines = *(int *)mesg;
-       *(int *)mesg = save;
+       qlines = mqd->qlines;
        half = (limit != qlines);
 
        if (half)
@@ -365,7 +363,7 @@ static int send_message_queue_full(void *cb,
                mqh = gru_mesq_head(2, qlines / 2 + 1);
 
        /* Try to get lock for switching head pointer */
-       gru_gamir(cb, EOP_IR_CLR, HSTATUS(mq, half), XTYPE_DW, IMA);
+       gru_gamir(cb, EOP_IR_CLR, HSTATUS(mqd->mq_gpa, half), XTYPE_DW, IMA);
        if (gru_wait(cb) != CBS_IDLE)
                goto cberr;
        if (!gru_get_amo_value(cb)) {
@@ -375,8 +373,8 @@ static int send_message_queue_full(void *cb,
 
        /* Got the lock. Send optional NOP if queue not full, */
        if (head != limit) {
-               if (send_noop_message(cb, mq, mesg)) {
-                       gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half),
+               if (send_noop_message(cb, mqd, mesg)) {
+                       gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half),
                                        XTYPE_DW, IMA);
                        if (gru_wait(cb) != CBS_IDLE)
                                goto cberr;
@@ -387,14 +385,16 @@ static int send_message_queue_full(void *cb,
        }
 
        /* Then flip queuehead to other half of queue. */
-       gru_gamer(cb, EOP_ERR_CSWAP, mq, XTYPE_DW, mqh.val, avalue, IMA);
+       gru_gamer(cb, EOP_ERR_CSWAP, mqd->mq_gpa, XTYPE_DW, mqh.val, avalue,
+                                                       IMA);
        if (gru_wait(cb) != CBS_IDLE)
                goto cberr;
 
        /* If not successfully in swapping queue head, clear the hstatus lock */
        if (gru_get_amo_value(cb) != avalue) {
                STAT(mesq_qf_switch_head_failed);
-               gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), XTYPE_DW, IMA);
+               gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half), XTYPE_DW,
+                                                       IMA);
                if (gru_wait(cb) != CBS_IDLE)
                        goto cberr;
        }
@@ -404,15 +404,25 @@ cberr:
        return MQE_UNEXPECTED_CB_ERR;
 }
 
+/*
+ * Send a cross-partition interrupt to the SSI that contains the target
+ * message queue. Normally, the interrupt is automatically delivered by hardware
+ * but some error conditions require explicit delivery.
+ */
+static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
+{
+       if (mqd->interrupt_vector)
+               uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid,
+                               mqd->interrupt_vector);
+}
+
 
 /*
  * Handle a gru_mesq failure. Some of these failures are software recoverable
  * or retryable.
  */
-static int send_message_failure(void *cb,
-                               unsigned long mq,
-                               void *mesg,
-                               int lines)
+static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
+                               void *mesg, int lines)
 {
        int substatus, ret = 0;
        unsigned long m;
@@ -429,7 +439,7 @@ static int send_message_failure(void *cb,
                break;
        case CBSS_QLIMIT_REACHED:
                STAT(mesq_send_qlimit_reached);
-               ret = send_message_queue_full(cb, mq, mesg, lines);
+               ret = send_message_queue_full(cb, mqd, mesg, lines);
                break;
        case CBSS_AMO_NACKED:
                STAT(mesq_send_amo_nacked);
@@ -437,12 +447,14 @@ static int send_message_failure(void *cb,
                break;
        case CBSS_PUT_NACKED:
                STAT(mesq_send_put_nacked);
-               m =mq + (gru_get_amo_value_head(cb) << 6);
+               m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
                gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
-               if (gru_wait(cb) == CBS_IDLE)
+               if (gru_wait(cb) == CBS_IDLE) {
                        ret = MQE_OK;
-               else
+                       send_message_queue_interrupt(mqd);
+               } else {
                        ret = MQE_UNEXPECTED_CB_ERR;
+               }
                break;
        default:
                BUG();
@@ -452,12 +464,12 @@ static int send_message_failure(void *cb,
 
 /*
  * Send a message to a message queue
- *     cb      GRU control block to use to send message
- *     mq      message queue
+ *     mqd     message queue descriptor
  *     mesg    message. ust be vaddr within a GSEG
  *     bytes   message size (<= 2 CL)
  */
-int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes)
+int gru_send_message_gpa(struct gru_message_queue_desc *mqd, void *mesg,
+                               unsigned int bytes)
 {
        struct message_header *mhdr;
        void *cb;
@@ -481,10 +493,10 @@ int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes)
 
        do {
                ret = MQE_OK;
-               gru_mesq(cb, mq, gru_get_tri(mhdr), clines, IMA);
+               gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), clines, IMA);
                istatus = gru_wait(cb);
                if (istatus != CBS_IDLE)
-                       ret = send_message_failure(cb, mq, dsr, clines);
+                       ret = send_message_failure(cb, mqd, dsr, clines);
        } while (ret == MQIE_AGAIN);
        gru_free_cpu_resources(cb, dsr);
 
@@ -497,9 +509,9 @@ EXPORT_SYMBOL_GPL(gru_send_message_gpa);
 /*
  * Advance the receive pointer for the queue to the next message.
  */
-void gru_free_message(void *rmq, void *mesg)
+void gru_free_message(struct gru_message_queue_desc *mqd, void *mesg)
 {
-       struct message_queue *mq = rmq;
+       struct message_queue *mq = mqd->mq;
        struct message_header *mhdr = mq->next;
        void *next, *pnext;
        int half = -1;
@@ -529,16 +541,16 @@ EXPORT_SYMBOL_GPL(gru_free_message);
  * present. User must call next_message() to move to next message.
  *     rmq     message queue
  */
-void *gru_get_next_message(void *rmq)
+void *gru_get_next_message(struct gru_message_queue_desc *mqd)
 {
-       struct message_queue *mq = rmq;
+       struct message_queue *mq = mqd->mq;
        struct message_header *mhdr = mq->next;
        int present = mhdr->present;
 
        /* skip NOOP messages */
        STAT(mesq_receive);
        while (present == MQS_NOOP) {
-               gru_free_message(rmq, mhdr);
+               gru_free_message(mqd, mhdr);
                mhdr = mq->next;
                present = mhdr->present;
        }
@@ -576,7 +588,7 @@ int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa,
        if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr))
                return MQE_BUG_NO_RESOURCES;
        gru_bcopy(cb, src_gpa, dest_gpa, gru_get_tri(dsr),
-                 XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_BYTES, IMA);
+                 XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_CL, IMA);
        ret = gru_wait(cb);
        gru_free_cpu_resources(cb, dsr);
        return ret;
@@ -611,7 +623,7 @@ static int quicktest(struct gru_state *gru)
 
        if (word0 != word1 || word0 != MAGIC) {
                printk
-                   ("GRU quicktest err: gru %d, found 0x%lx, expected 0x%lx\n",
+                   ("GRU quicktest err: gid %d, found 0x%lx, expected 0x%lx\n",
                     gru->gs_gid, word1, MAGIC);
                BUG();          /* ZZZ should not be fatal */
        }
@@ -660,15 +672,15 @@ int gru_kservices_init(struct gru_state *gru)
        cch->tlb_int_enable = 0;
        cch->tfm_done_bit_enable = 0;
        cch->unmap_enable = 1;
-       err = cch_allocate(cch, 0, cbr_map, dsr_map);
+       err = cch_allocate(cch, 0, 0, cbr_map, dsr_map);
        if (err) {
                gru_dbg(grudev,
-                       "Unable to allocate kernel CCH: gru %d, err %d\n",
+                       "Unable to allocate kernel CCH: gid %d, err %d\n",
                        gru->gs_gid, err);
                BUG();
        }
        if (cch_start(cch)) {
-               gru_dbg(grudev, "Unable to start kernel CCH: gru %d, err %d\n",
+               gru_dbg(grudev, "Unable to start kernel CCH: gid %d, err %d\n",
                        gru->gs_gid, err);
                BUG();
        }
@@ -678,3 +690,22 @@ int gru_kservices_init(struct gru_state *gru)
                quicktest(gru);
        return 0;
 }
+
+void gru_kservices_exit(struct gru_state *gru)
+{
+       struct gru_context_configuration_handle *cch;
+       struct gru_blade_state *bs;
+
+       bs = gru->gs_blade;
+       if (gru != &bs->bs_grus[1])
+               return;
+
+       cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM);
+       lock_cch_handle(cch);
+       if (cch_interrupt_sync(cch))
+               BUG();
+       if (cch_deallocate(cch))
+               BUG();
+       unlock_cch_handle(cch);
+}
+
index eb17e0a3ac61e4a0ff702b2edf8ebf894cb35c0f..747ed315d56f41998cec48f1a66057b144afe35c 100644 (file)
  *     - gru_create_message_queue() needs interrupt vector info
  */
 
+struct gru_message_queue_desc {
+       void            *mq;                    /* message queue vaddress */
+       unsigned long   mq_gpa;                 /* global address of mq */
+       int             qlines;                 /* queue size in CL */
+       int             interrupt_vector;       /* interrupt vector */
+       int             interrupt_pnode;        /* pnode for interrupt */
+       int             interrupt_apicid;       /* lapicid for interrupt */
+};
+
 /*
  * Initialize a user allocated chunk of memory to be used as
  * a message queue. The caller must ensure that the queue is
  * to manage the queue.
  *
  *  Input:
- *     p       pointer to user allocated memory.
+ *     mqd     pointer to message queue descriptor
+ *     p       pointer to user allocated mesq memory.
  *     bytes   size of message queue in bytes
+ *      vector interrupt vector (zero if no interrupts)
+ *      nasid  nasid of blade where interrupt is delivered
+ *      apicid apicid of cpu for interrupt
  *
  *  Errors:
  *     0       OK
  *     >0      error
  */
-extern int gru_create_message_queue(void *p, unsigned int bytes);
+extern int gru_create_message_queue(struct gru_message_queue_desc *mqd,
+               void *p, unsigned int bytes, int nasid, int vector, int apicid);
 
 /*
  * Send a message to a message queue.
@@ -68,7 +82,7 @@ extern int gru_create_message_queue(void *p, unsigned int bytes);
  *
  *
  *   Input:
- *     xmq     message queue - must be a UV global physical address
+ *     mqd     pointer to message queue descriptor
  *     mesg    pointer to message. Must be 64-bit aligned
  *     bytes   size of message in bytes
  *
@@ -77,8 +91,8 @@ extern int gru_create_message_queue(void *p, unsigned int bytes);
  *     >0      Send failure - see error codes below
  *
  */
-extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg,
-                                               unsigned int bytes);
+extern int gru_send_message_gpa(struct gru_message_queue_desc *mqd,
+                       void *mesg, unsigned int bytes);
 
 /* Status values for gru_send_message() */
 #define MQE_OK                 0       /* message sent successfully */
@@ -94,10 +108,11 @@ extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg,
  * API extensions may allow for out-of-order freeing.
  *
  *   Input
- *     mq      message queue
+ *     mqd     pointer to message queue descriptor
  *     mesq    message being freed
  */
-extern void gru_free_message(void *mq, void *mesq);
+extern void gru_free_message(struct gru_message_queue_desc *mqd,
+                            void *mesq);
 
 /*
  * Get next message from message queue. Returns pointer to
@@ -106,13 +121,13 @@ extern void gru_free_message(void *mq, void *mesq);
  * in order to move the queue pointers to next message.
  *
  *   Input
- *     mq      message queue
+ *     mqd     pointer to message queue descriptor
  *
  *   Output:
  *     p       pointer to message
  *     NULL    no message available
  */
-extern void *gru_get_next_message(void *mq);
+extern void *gru_get_next_message(struct gru_message_queue_desc *mqd);
 
 
 /*
index 3d2fc216bae5b561dea357cd86d1661803a0377d..ec3f7a17d221e01bd82bc23b6a64025263627c65 100644 (file)
@@ -76,10 +76,9 @@ int gru_cpu_fault_map_id(void)
 /* Hit the asid limit. Start over */
 static int gru_wrap_asid(struct gru_state *gru)
 {
-       gru_dbg(grudev, "gru %p\n", gru);
+       gru_dbg(grudev, "gid %d\n", gru->gs_gid);
        STAT(asid_wrap);
        gru->gs_asid_gen++;
-       gru_flush_all_tlb(gru);
        return MIN_ASID;
 }
 
@@ -88,19 +87,21 @@ static int gru_reset_asid_limit(struct gru_state *gru, int asid)
 {
        int i, gid, inuse_asid, limit;
 
-       gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid);
+       gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid);
        STAT(asid_next);
        limit = MAX_ASID;
        if (asid >= limit)
                asid = gru_wrap_asid(gru);
+       gru_flush_all_tlb(gru);
        gid = gru->gs_gid;
 again:
        for (i = 0; i < GRU_NUM_CCH; i++) {
                if (!gru->gs_gts[i])
                        continue;
                inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid;
-               gru_dbg(grudev, "gru %p, inuse_asid 0x%x, cxtnum %d, gts %p\n",
-                       gru, inuse_asid, i, gru->gs_gts[i]);
+               gru_dbg(grudev, "gid %d, gts %p, gms %p, inuse 0x%x, cxt %d\n",
+                       gru->gs_gid, gru->gs_gts[i], gru->gs_gts[i]->ts_gms,
+                       inuse_asid, i);
                if (inuse_asid == asid) {
                        asid += ASID_INC;
                        if (asid >= limit) {
@@ -120,8 +121,8 @@ again:
        }
        gru->gs_asid_limit = limit;
        gru->gs_asid = asid;
-       gru_dbg(grudev, "gru %p, new asid 0x%x, new_limit 0x%x\n", gru, asid,
-               limit);
+       gru_dbg(grudev, "gid %d, new asid 0x%x, new_limit 0x%x\n", gru->gs_gid,
+                                       asid, limit);
        return asid;
 }
 
@@ -130,14 +131,12 @@ static int gru_assign_asid(struct gru_state *gru)
 {
        int asid;
 
-       spin_lock(&gru->gs_asid_lock);
        gru->gs_asid += ASID_INC;
        asid = gru->gs_asid;
        if (asid >= gru->gs_asid_limit)
                asid = gru_reset_asid_limit(gru, asid);
-       spin_unlock(&gru->gs_asid_lock);
 
-       gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid);
+       gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid);
        return asid;
 }
 
@@ -215,17 +214,20 @@ static int check_gru_resources(struct gru_state *gru, int cbr_au_count,
  * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG
  * context.
  */
-static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms,
-                              int ctxnum)
+static int gru_load_mm_tracker(struct gru_state *gru,
+                                       struct gru_thread_state *gts)
 {
+       struct gru_mm_struct *gms = gts->ts_gms;
        struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid];
-       unsigned short ctxbitmap = (1 << ctxnum);
+       unsigned short ctxbitmap = (1 << gts->ts_ctxnum);
        int asid;
 
        spin_lock(&gms->ms_asid_lock);
        asid = asids->mt_asid;
 
-       if (asid == 0 || asids->mt_asid_gen != gru->gs_asid_gen) {
+       spin_lock(&gru->gs_asid_lock);
+       if (asid == 0 || (asids->mt_ctxbitmap == 0 && asids->mt_asid_gen !=
+                         gru->gs_asid_gen)) {
                asid = gru_assign_asid(gru);
                asids->mt_asid = asid;
                asids->mt_asid_gen = gru->gs_asid_gen;
@@ -233,6 +235,7 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms,
        } else {
                STAT(asid_reuse);
        }
+       spin_unlock(&gru->gs_asid_lock);
 
        BUG_ON(asids->mt_ctxbitmap & ctxbitmap);
        asids->mt_ctxbitmap |= ctxbitmap;
@@ -241,24 +244,28 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms,
        spin_unlock(&gms->ms_asid_lock);
 
        gru_dbg(grudev,
-               "gru %x, gms %p, ctxnum 0x%d, asid 0x%x, asidmap 0x%lx\n",
-               gru->gs_gid, gms, ctxnum, asid, gms->ms_asidmap[0]);
+               "gid %d, gts %p, gms %p, ctxnum %d, asid 0x%x, asidmap 0x%lx\n",
+               gru->gs_gid, gts, gms, gts->ts_ctxnum, asid,
+               gms->ms_asidmap[0]);
        return asid;
 }
 
 static void gru_unload_mm_tracker(struct gru_state *gru,
-                                 struct gru_mm_struct *gms, int ctxnum)
+                                       struct gru_thread_state *gts)
 {
+       struct gru_mm_struct *gms = gts->ts_gms;
        struct gru_mm_tracker *asids;
        unsigned short ctxbitmap;
 
        asids = &gms->ms_asids[gru->gs_gid];
-       ctxbitmap = (1 << ctxnum);
+       ctxbitmap = (1 << gts->ts_ctxnum);
        spin_lock(&gms->ms_asid_lock);
+       spin_lock(&gru->gs_asid_lock);
        BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap);
        asids->mt_ctxbitmap ^= ctxbitmap;
-       gru_dbg(grudev, "gru %x, gms %p, ctxnum 0x%d, asidmap 0x%lx\n",
-               gru->gs_gid, gms, ctxnum, gms->ms_asidmap[0]);
+       gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n",
+               gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0]);
+       spin_unlock(&gru->gs_asid_lock);
        spin_unlock(&gms->ms_asid_lock);
 }
 
@@ -319,6 +326,7 @@ static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
        gts->ts_vma = vma;
        gts->ts_tlb_int_select = -1;
        gts->ts_gms = gru_register_mmu_notifier();
+       gts->ts_sizeavail = GRU_SIZEAVAIL(PAGE_SHIFT);
        if (!gts->ts_gms)
                goto err;
 
@@ -399,7 +407,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts)
        struct gru_state *gru;
 
        gru = gts->ts_gru;
-       gru_dbg(grudev, "gts %p, gru %p\n", gts, gru);
+       gru_dbg(grudev, "gts %p, gid %d\n", gts, gru->gs_gid);
 
        spin_lock(&gru->gs_lock);
        gru->gs_gts[gts->ts_ctxnum] = NULL;
@@ -408,6 +416,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts)
        __clear_bit(gts->ts_ctxnum, &gru->gs_context_map);
        gts->ts_ctxnum = NULLCTX;
        gts->ts_gru = NULL;
+       gts->ts_blade = -1;
        spin_unlock(&gru->gs_lock);
 
        gts_drop(gts);
@@ -432,8 +441,8 @@ static inline long gru_copy_handle(void *d, void *s)
        return GRU_HANDLE_BYTES;
 }
 
-static void gru_prefetch_context(void *gseg, void *cb, void *cbe, unsigned long cbrmap,
-                               unsigned long length)
+static void gru_prefetch_context(void *gseg, void *cb, void *cbe,
+                               unsigned long cbrmap, unsigned long length)
 {
        int i, scr;
 
@@ -500,12 +509,12 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate)
        zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE);
        cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);
 
+       gru_dbg(grudev, "gts %p\n", gts);
        lock_cch_handle(cch);
        if (cch_interrupt_sync(cch))
                BUG();
-       gru_dbg(grudev, "gts %p\n", gts);
 
-       gru_unload_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum);
+       gru_unload_mm_tracker(gru, gts);
        if (savestate)
                gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr,
                                        ctxnum, gts->ts_cbr_map,
@@ -534,7 +543,7 @@ static void gru_load_context(struct gru_thread_state *gts)
        cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);
 
        lock_cch_handle(cch);
-       asid = gru_load_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum);
+       asid = gru_load_mm_tracker(gru, gts);
        cch->tfm_fault_bit_enable =
            (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
             || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
@@ -544,7 +553,8 @@ static void gru_load_context(struct gru_thread_state *gts)
                cch->tlb_int_select = gts->ts_tlb_int_select;
        }
        cch->tfm_done_bit_enable = 0;
-       err = cch_allocate(cch, asid, gts->ts_cbr_map, gts->ts_dsr_map);
+       err = cch_allocate(cch, asid, gts->ts_sizeavail, gts->ts_cbr_map,
+                               gts->ts_dsr_map);
        if (err) {
                gru_dbg(grudev,
                        "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n",
@@ -565,11 +575,12 @@ static void gru_load_context(struct gru_thread_state *gts)
 /*
  * Update fields in an active CCH:
  *     - retarget interrupts on local blade
+ *     - update sizeavail mask
  *     - force a delayed context unload by clearing the CCH asids. This
  *       forces TLB misses for new GRU instructions. The context is unloaded
  *       when the next TLB miss occurs.
  */
-static int gru_update_cch(struct gru_thread_state *gts, int int_select)
+int gru_update_cch(struct gru_thread_state *gts, int force_unload)
 {
        struct gru_context_configuration_handle *cch;
        struct gru_state *gru = gts->ts_gru;
@@ -583,9 +594,11 @@ static int gru_update_cch(struct gru_thread_state *gts, int int_select)
                        goto exit;
                if (cch_interrupt(cch))
                        BUG();
-               if (int_select >= 0) {
-                       gts->ts_tlb_int_select = int_select;
-                       cch->tlb_int_select = int_select;
+               if (!force_unload) {
+                       for (i = 0; i < 8; i++)
+                               cch->sizeavail[i] = gts->ts_sizeavail;
+                       gts->ts_tlb_int_select = gru_cpu_fault_map_id();
+                       cch->tlb_int_select = gru_cpu_fault_map_id();
                } else {
                        for (i = 0; i < 8; i++)
                                cch->asid[i] = 0;
@@ -617,7 +630,7 @@ static int gru_retarget_intr(struct gru_thread_state *gts)
 
        gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select,
                gru_cpu_fault_map_id());
-       return gru_update_cch(gts, gru_cpu_fault_map_id());
+       return gru_update_cch(gts, 0);
 }
 
 
@@ -688,7 +701,7 @@ static void gru_steal_context(struct gru_thread_state *gts)
                STAT(steal_context_failed);
        }
        gru_dbg(grudev,
-               "stole gru %x, ctxnum %d from gts %p. Need cb %d, ds %d;"
+               "stole gid %d, ctxnum %d from gts %p. Need cb %d, ds %d;"
                " avail cb %ld, ds %ld\n",
                gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map),
                hweight64(gru->gs_dsr_map));
@@ -727,6 +740,7 @@ again:
                }
                reserve_gru_resources(gru, gts);
                gts->ts_gru = gru;
+               gts->ts_blade = gru->gs_blade_id;
                gts->ts_ctxnum =
                    find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH);
                BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH);
@@ -737,7 +751,7 @@ again:
 
                STAT(assign_context);
                gru_dbg(grudev,
-                       "gseg %p, gts %p, gru %x, ctx %d, cbr %d, dsr %d\n",
+                       "gseg %p, gts %p, gid %d, ctx %d, cbr %d, dsr %d\n",
                        gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts,
                        gts->ts_gru->gs_gid, gts->ts_ctxnum,
                        gts->ts_cbr_au_count, gts->ts_dsr_au_count);
@@ -773,8 +787,8 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                return VM_FAULT_SIGBUS;
 
 again:
-       preempt_disable();
        mutex_lock(&gts->ts_ctxlock);
+       preempt_disable();
        if (gts->ts_gru) {
                if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) {
                        STAT(migrated_nopfn_unload);
index 73b0ca061bb567401cc4d30a145c9daf05e72160..ee74821b171c9eff780b0079760c29b016e05371 100644 (file)
@@ -62,7 +62,9 @@ static int statistics_show(struct seq_file *s, void *p)
        printstat(s, asid_wrap);
        printstat(s, asid_reuse);
        printstat(s, intr);
+       printstat(s, intr_mm_lock_failed);
        printstat(s, call_os);
+       printstat(s, call_os_offnode_reference);
        printstat(s, call_os_check_for_bug);
        printstat(s, call_os_wait_queue);
        printstat(s, user_flush_tlb);
@@ -120,6 +122,30 @@ static ssize_t statistics_write(struct file *file, const char __user *userbuf,
        return count;
 }
 
+static int mcs_statistics_show(struct seq_file *s, void *p)
+{
+       int op;
+       unsigned long total, count, max;
+       static char *id[] = {"cch_allocate", "cch_start", "cch_interrupt",
+               "cch_interrupt_sync", "cch_deallocate", "tgh_invalidate"};
+
+       for (op = 0; op < mcsop_last; op++) {
+               count = atomic_long_read(&mcs_op_statistics[op].count);
+               total = atomic_long_read(&mcs_op_statistics[op].total);
+               max = mcs_op_statistics[op].max;
+               seq_printf(s, "%-20s%12ld%12ld%12ld\n", id[op], count,
+                          count ? total / count : 0, max);
+       }
+       return 0;
+}
+
+static ssize_t mcs_statistics_write(struct file *file,
+                       const char __user *userbuf, size_t count, loff_t *data)
+{
+       memset(mcs_op_statistics, 0, sizeof(mcs_op_statistics));
+       return count;
+}
+
 static int options_show(struct seq_file *s, void *p)
 {
        seq_printf(s, "0x%lx\n", gru_options);
@@ -135,6 +161,7 @@ static ssize_t options_write(struct file *file, const char __user *userbuf,
        if (copy_from_user
            (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
                return -EFAULT;
+       buf[count - 1] = '\0';
        if (!strict_strtoul(buf, 10, &val))
                gru_options = val;
 
@@ -199,7 +226,7 @@ static void seq_stop(struct seq_file *file, void *data)
 
 static void *seq_start(struct seq_file *file, loff_t *gid)
 {
-       if (*gid < GRU_MAX_GRUS)
+       if (*gid < gru_max_gids)
                return gid;
        return NULL;
 }
@@ -207,7 +234,7 @@ static void *seq_start(struct seq_file *file, loff_t *gid)
 static void *seq_next(struct seq_file *file, void *data, loff_t *gid)
 {
        (*gid)++;
-       if (*gid < GRU_MAX_GRUS)
+       if (*gid < gru_max_gids)
                return gid;
        return NULL;
 }
@@ -231,6 +258,11 @@ static int statistics_open(struct inode *inode, struct file *file)
        return single_open(file, statistics_show, NULL);
 }
 
+static int mcs_statistics_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mcs_statistics_show, NULL);
+}
+
 static int options_open(struct inode *inode, struct file *file)
 {
        return single_open(file, options_show, NULL);
@@ -255,6 +287,14 @@ static const struct file_operations statistics_fops = {
        .release        = single_release,
 };
 
+static const struct file_operations mcs_statistics_fops = {
+       .open           = mcs_statistics_open,
+       .read           = seq_read,
+       .write          = mcs_statistics_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static const struct file_operations options_fops = {
        .open           = options_open,
        .read           = seq_read,
@@ -283,6 +323,7 @@ static struct proc_entry {
        struct proc_dir_entry *entry;
 } proc_files[] = {
        {"statistics", 0644, &statistics_fops},
+       {"mcs_statistics", 0644, &mcs_statistics_fops},
        {"debug_options", 0644, &options_fops},
        {"cch_status", 0444, &cch_fops},
        {"gru_status", 0444, &gru_fops},
index a78f70deeb59d47a9554b99ed0ec5803c6ea26ee..bf1eeb7553edda963bfea5b1b7f8de28cccf0b28 100644 (file)
 extern struct gru_stats_s gru_stats;
 extern struct gru_blade_state *gru_base[];
 extern unsigned long gru_start_paddr, gru_end_paddr;
+extern unsigned int gru_max_gids;
 
 #define GRU_MAX_BLADES         MAX_NUMNODES
 #define GRU_MAX_GRUS           (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE)
@@ -184,7 +185,9 @@ struct gru_stats_s {
        atomic_long_t asid_wrap;
        atomic_long_t asid_reuse;
        atomic_long_t intr;
+       atomic_long_t intr_mm_lock_failed;
        atomic_long_t call_os;
+       atomic_long_t call_os_offnode_reference;
        atomic_long_t call_os_check_for_bug;
        atomic_long_t call_os_wait_queue;
        atomic_long_t user_flush_tlb;
@@ -237,6 +240,17 @@ struct gru_stats_s {
 
 };
 
+enum mcs_op {cchop_allocate, cchop_start, cchop_interrupt, cchop_interrupt_sync,
+       cchop_deallocate, tghop_invalidate, mcsop_last};
+
+struct mcs_op_statistic {
+       atomic_long_t   count;
+       atomic_long_t   total;
+       unsigned long   max;
+};
+
+extern struct mcs_op_statistic mcs_op_statistics[mcsop_last];
+
 #define OPT_DPRINT     1
 #define OPT_STATS      2
 #define GRU_QUICKLOOK  4
@@ -278,13 +292,12 @@ struct gru_stats_s {
 /* Generate a GRU asid value from a GRU base asid & a virtual address. */
 #if defined CONFIG_IA64
 #define VADDR_HI_BIT           64
-#define GRUREGION(addr)                ((addr) >> (VADDR_HI_BIT - 3) & 3)
 #elif defined CONFIG_X86_64
 #define VADDR_HI_BIT           48
-#define GRUREGION(addr)                (0)             /* ZZZ could do better */
 #else
 #error "Unsupported architecture"
 #endif
+#define GRUREGION(addr)                ((addr) >> (VADDR_HI_BIT - 3) & 3)
 #define GRUASID(asid, addr)    ((asid) + GRUREGION(addr))
 
 /*------------------------------------------------------------------------------
@@ -297,12 +310,12 @@ struct gru_state;
  * This structure is pointed to from the mmstruct via the notifier pointer.
  * There is one of these per address space.
  */
-struct gru_mm_tracker {
-       unsigned int            mt_asid_gen;    /* ASID wrap count */
-       int                     mt_asid;        /* current base ASID for gru */
-       unsigned short          mt_ctxbitmap;   /* bitmap of contexts using
+struct gru_mm_tracker {                                /* pack to reduce size */
+       unsigned int            mt_asid_gen:24; /* ASID wrap count */
+       unsigned int            mt_asid:24;     /* current base ASID for gru */
+       unsigned short          mt_ctxbitmap:16;/* bitmap of contexts using
                                                   asid */
-};
+} __attribute__ ((packed));
 
 struct gru_mm_struct {
        struct mmu_notifier     ms_notifier;
@@ -348,6 +361,7 @@ struct gru_thread_state {
        long                    ts_user_options;/* misc user option flags */
        pid_t                   ts_tgid_owner;  /* task that is using the
                                                   context - for migration */
+       unsigned short          ts_sizeavail;   /* Pagesizes in use */
        int                     ts_tsid;        /* thread that owns the
                                                   structure */
        int                     ts_tlb_int_select;/* target cpu if interrupts
@@ -359,6 +373,9 @@ struct gru_thread_state {
                                                   required for contest */
        unsigned char           ts_cbr_au_count;/* Number of CBR resources
                                                   required for contest */
+       char                    ts_blade;       /* If >= 0, migrate context if
+                                                  ref from diferent blade */
+       char                    ts_force_cch_reload;
        char                    ts_force_unload;/* force context to be unloaded
                                                   after migration */
        char                    ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each
@@ -392,12 +409,12 @@ struct gru_state {
                                                           gru segments (64) */
        void                    *gs_gru_base_vaddr;     /* Virtual address of
                                                           gru segments (64) */
-       unsigned char           gs_gid;                 /* unique GRU number */
+       unsigned short          gs_gid;                 /* unique GRU number */
+       unsigned short          gs_blade_id;            /* blade of GRU */
        unsigned char           gs_tgh_local_shift;     /* used to pick TGH for
                                                           local flush */
        unsigned char           gs_tgh_first_remote;    /* starting TGH# for
                                                           remote flush */
-       unsigned short          gs_blade_id;            /* blade of GRU */
        spinlock_t              gs_asid_lock;           /* lock used for
                                                           assigning asids */
        spinlock_t              gs_lock;                /* lock used for
@@ -492,6 +509,10 @@ struct gru_blade_state {
                        (i) < GRU_CHIPLETS_PER_BLADE;                   \
                        (i)++, (gru)++)
 
+/* Scan all GRUs */
+#define foreach_gid(gid)                                               \
+       for ((gid) = 0; (gid) < gru_max_gids; (gid)++)
+
 /* Scan all active GTSs on a gru. Note: must hold ss_lock to use this macro. */
 #define for_each_gts_on_gru(gts, gru, ctxnum)                          \
        for ((ctxnum) = 0; (ctxnum) < GRU_NUM_CCH; (ctxnum)++)          \
@@ -578,9 +599,11 @@ extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct
 extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct
                                *vma, int tsid);
 extern void gru_unload_context(struct gru_thread_state *gts, int savestate);
+extern int gru_update_cch(struct gru_thread_state *gts, int force_unload);
 extern void gts_drop(struct gru_thread_state *gts);
 extern void gru_tgh_flush_init(struct gru_state *gru);
 extern int gru_kservices_init(struct gru_state *gru);
+extern void gru_kservices_exit(struct gru_state *gru);
 extern irqreturn_t gru_intr(int irq, void *dev_id);
 extern int gru_handle_user_call_os(unsigned long address);
 extern int gru_user_flush_tlb(unsigned long arg);
index c84496a7769176843d03b2ea680a620cf888c5be..1d125091f5e721f773e0c10597b2d5a232f18a49 100644 (file)
@@ -187,7 +187,7 @@ void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start,
        "  FLUSH gruid %d, asid 0x%x, num %ld, cbmap 0x%x\n",
                                gid, asid, num, asids->mt_ctxbitmap);
                        tgh = get_lock_tgh_handle(gru);
-                       tgh_invalidate(tgh, start, 0, asid, grupagesize, 0,
+                       tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0,
                                       num - 1, asids->mt_ctxbitmap);
                        get_unlock_tgh_handle(tgh);
                } else {
@@ -210,11 +210,10 @@ void gru_flush_all_tlb(struct gru_state *gru)
 {
        struct gru_tlb_global_handle *tgh;
 
-       gru_dbg(grudev, "gru %p, gid %d\n", gru, gru->gs_gid);
+       gru_dbg(grudev, "gid %d\n", gru->gs_gid);
        tgh = get_lock_tgh_handle(gru);
-       tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0);
+       tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0xffff);
        get_unlock_tgh_handle(tgh);
-       preempt_enable();
 }
 
 /*
index 275b78896a73622362b6b53b5776db6fe20245d5..114444cfd496ee2e5526587fc7ccc2e17248a087 100644 (file)
@@ -92,7 +92,9 @@ struct xpc_rsvd_page {
        u8 pad1[3];             /* align to next u64 in 1st 64-byte cacheline */
        union {
                unsigned long vars_pa;  /* phys address of struct xpc_vars */
-               unsigned long activate_mq_gpa; /* gru phy addr of activate_mq */
+               unsigned long activate_gru_mq_desc_gpa; /* phys addr of */
+                                                       /* activate mq's */
+                                                       /* gru mq descriptor */
        } sn;
        unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */
        u64 pad2[10];           /* align to last u64 in 2nd 64-byte cacheline */
@@ -189,7 +191,9 @@ struct xpc_gru_mq_uv {
        int irq;                /* irq raised when message is received in mq */
        int mmr_blade;          /* blade where watchlist was allocated from */
        unsigned long mmr_offset; /* offset of irq mmr located on mmr_blade */
+       unsigned long mmr_value; /* value of irq mmr located on mmr_blade */
        int watchlist_num;      /* number of watchlist allocatd by BIOS */
+       void *gru_mq_desc;      /* opaque structure used by the GRU driver */
 };
 
 /*
@@ -197,6 +201,7 @@ struct xpc_gru_mq_uv {
  * heartbeat, partition active state, and channel state. This is UV only.
  */
 struct xpc_activate_mq_msghdr_uv {
+       unsigned int gru_msg_hdr; /* FOR GRU INTERNAL USE ONLY */
        short partid;           /* sender's partid */
        u8 act_state;           /* sender's act_state at time msg sent */
        u8 type;                /* message's type */
@@ -232,7 +237,7 @@ struct xpc_activate_mq_msg_heartbeat_req_uv {
 struct xpc_activate_mq_msg_activate_req_uv {
        struct xpc_activate_mq_msghdr_uv hdr;
        unsigned long rp_gpa;
-       unsigned long activate_mq_gpa;
+       unsigned long activate_gru_mq_desc_gpa;
 };
 
 struct xpc_activate_mq_msg_deactivate_req_uv {
@@ -263,7 +268,7 @@ struct xpc_activate_mq_msg_chctl_openreply_uv {
        short ch_number;
        short remote_nentries;  /* ??? Is this needed? What is? */
        short local_nentries;   /* ??? Is this needed? What is? */
-       unsigned long local_notify_mq_gpa;
+       unsigned long notify_gru_mq_desc_gpa;
 };
 
 /*
@@ -510,8 +515,8 @@ struct xpc_channel_sn2 {
 };
 
 struct xpc_channel_uv {
-       unsigned long remote_notify_mq_gpa;     /* gru phys address of remote */
-                                               /* partition's notify mq */
+       void *cached_notify_gru_mq_desc; /* remote partition's notify mq's */
+                                        /* gru mq descriptor */
 
        struct xpc_send_msg_slot_uv *send_msg_slots;
        void *recv_msg_slots;   /* each slot will hold a xpc_notify_mq_msg_uv */
@@ -682,8 +687,12 @@ struct xpc_partition_sn2 {
 };
 
 struct xpc_partition_uv {
-       unsigned long remote_activate_mq_gpa;   /* gru phys address of remote */
-                                               /* partition's activate mq */
+       unsigned long activate_gru_mq_desc_gpa; /* phys addr of parititon's */
+                                               /* activate mq's gru mq */
+                                               /* descriptor */
+       void *cached_activate_gru_mq_desc; /* cached copy of partition's */
+                                          /* activate mq's gru mq descriptor */
+       struct mutex cached_activate_gru_mq_desc_mutex;
        spinlock_t flags_lock;  /* protect updating of flags */
        unsigned int flags;     /* general flags */
        u8 remote_act_state;    /* remote partition's act_state */
@@ -694,8 +703,9 @@ struct xpc_partition_uv {
 
 /* struct xpc_partition_uv flags */
 
-#define XPC_P_HEARTBEAT_OFFLINE_UV     0x00000001
-#define XPC_P_ENGAGED_UV               0x00000002
+#define XPC_P_HEARTBEAT_OFFLINE_UV             0x00000001
+#define XPC_P_ENGAGED_UV                       0x00000002
+#define XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV   0x00000004
 
 /* struct xpc_partition_uv act_state change requests */
 
@@ -804,6 +814,7 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int);
 extern void xpc_create_kthreads(struct xpc_channel *, int, int);
 extern void xpc_disconnect_wait(int);
 extern int (*xpc_setup_partitions_sn) (void);
+extern void (*xpc_teardown_partitions_sn) (void);
 extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *,
                                                         unsigned long *,
                                                         size_t *);
@@ -846,8 +857,8 @@ extern void (*xpc_send_chctl_openrequest) (struct xpc_channel *,
                                           unsigned long *);
 extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *);
 
-extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *,
-                                           unsigned long);
+extern enum xp_retval (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *,
+                                                     unsigned long);
 
 extern enum xp_retval (*xpc_send_payload) (struct xpc_channel *, u32, void *,
                                           u16, u8, xpc_notify_func, void *);
index 45fd653dbe311b5d5c775e8ae8ee753a04b769c7..99a2534c38a1ffa092ecc9f1334a8d12aff1a16f 100644 (file)
@@ -183,6 +183,7 @@ xpc_process_openclose_chctl_flags(struct xpc_partition *part, int ch_number,
            &part->remote_openclose_args[ch_number];
        struct xpc_channel *ch = &part->channels[ch_number];
        enum xp_retval reason;
+       enum xp_retval ret;
 
        spin_lock_irqsave(&ch->lock, irq_flags);
 
@@ -399,8 +400,13 @@ again:
                DBUG_ON(args->local_nentries == 0);
                DBUG_ON(args->remote_nentries == 0);
 
+               ret = xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa);
+               if (ret != xpSuccess) {
+                       XPC_DISCONNECT_CHANNEL(ch, ret, &irq_flags);
+                       spin_unlock_irqrestore(&ch->lock, irq_flags);
+                       return;
+               }
                ch->flags |= XPC_C_ROPENREPLY;
-               xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa);
 
                if (args->local_nentries < ch->remote_nentries) {
                        dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new "
index 6576170de9628ae9ab72fde2aace263248ad52de..1ab9fda87fabaf581fcb5bf6e6151da7b2ca1e27 100644 (file)
@@ -171,6 +171,7 @@ static struct notifier_block xpc_die_notifier = {
 };
 
 int (*xpc_setup_partitions_sn) (void);
+void (*xpc_teardown_partitions_sn) (void);
 enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie,
                                                  unsigned long *rp_pa,
                                                  size_t *len);
@@ -217,8 +218,8 @@ void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch,
 void (*xpc_send_chctl_openreply) (struct xpc_channel *ch,
                                  unsigned long *irq_flags);
 
-void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch,
-                                    unsigned long msgqueue_pa);
+enum xp_retval (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch,
+                                              unsigned long msgqueue_pa);
 
 enum xp_retval (*xpc_send_payload) (struct xpc_channel *ch, u32 flags,
                                    void *payload, u16 payload_size,
@@ -998,6 +999,7 @@ xpc_setup_partitions(void)
 static void
 xpc_teardown_partitions(void)
 {
+       xpc_teardown_partitions_sn();
        kfree(xpc_partitions);
 }
 
index 2e975762c32b42224f80234ccf4f8caddb34cfb4..eaaa964942de97e91b0c5edfd7d3a6ff12bc4ed4 100644 (file)
@@ -66,6 +66,12 @@ xpc_setup_partitions_sn_sn2(void)
        return 0;
 }
 
+static void
+xpc_teardown_partitions_sn_sn2(void)
+{
+       /* nothing needs to be done */
+}
+
 /* SH_IPI_ACCESS shub register value on startup */
 static u64 xpc_sh1_IPI_access_sn2;
 static u64 xpc_sh2_IPI_access0_sn2;
@@ -436,11 +442,12 @@ xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch)
        XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST);
 }
 
-static void
+static enum xp_retval
 xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch,
                                unsigned long msgqueue_pa)
 {
        ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa;
+       return xpSuccess;
 }
 
 /*
@@ -1737,20 +1744,20 @@ xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch)
 {
        struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
        struct xpc_msg_sn2 *msg;
-       s64 put;
+       s64 put, remote_nentries = ch->remote_nentries;
 
        /* flags are zeroed when the buffer is allocated */
-       if (ch_sn2->remote_GP.put < ch->remote_nentries)
+       if (ch_sn2->remote_GP.put < remote_nentries)
                return;
 
-       put = max(ch_sn2->w_remote_GP.put, ch->remote_nentries);
+       put = max(ch_sn2->w_remote_GP.put, remote_nentries);
        do {
                msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
-                                            (put % ch->remote_nentries) *
+                                            (put % remote_nentries) *
                                             ch->entry_size);
                DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
                DBUG_ON(!(msg->flags & XPC_M_SN2_DONE));
-               DBUG_ON(msg->number != put - ch->remote_nentries);
+               DBUG_ON(msg->number != put - remote_nentries);
                msg->flags = 0;
        } while (++put < ch_sn2->remote_GP.put);
 }
@@ -2315,6 +2322,7 @@ xpc_init_sn2(void)
        size_t buf_size;
 
        xpc_setup_partitions_sn = xpc_setup_partitions_sn_sn2;
+       xpc_teardown_partitions_sn = xpc_teardown_partitions_sn_sn2;
        xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2;
        xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_sn2;
        xpc_increment_heartbeat = xpc_increment_heartbeat_sn2;
index 29c0502a96b26fd9e9436d65f133136ccfce5410..f7fff4727edb0681840076b7c65b2a0d4b60a368 100644 (file)
 #include "../sgi-gru/grukservices.h"
 #include "xpc.h"
 
+#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+struct uv_IO_APIC_route_entry {
+       __u64   vector          :  8,
+               delivery_mode   :  3,
+               dest_mode       :  1,
+               delivery_status :  1,
+               polarity        :  1,
+               __reserved_1    :  1,
+               trigger         :  1,
+               mask            :  1,
+               __reserved_2    : 15,
+               dest            : 32;
+};
+#endif
+
 static atomic64_t xpc_heartbeat_uv;
 static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV);
 
@@ -56,26 +71,52 @@ xpc_setup_partitions_sn_uv(void)
        for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
                part_uv = &xpc_partitions[partid].sn.uv;
 
+               mutex_init(&part_uv->cached_activate_gru_mq_desc_mutex);
                spin_lock_init(&part_uv->flags_lock);
                part_uv->remote_act_state = XPC_P_AS_INACTIVE;
        }
        return 0;
 }
 
+static void
+xpc_teardown_partitions_sn_uv(void)
+{
+       short partid;
+       struct xpc_partition_uv *part_uv;
+       unsigned long irq_flags;
+
+       for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
+               part_uv = &xpc_partitions[partid].sn.uv;
+
+               if (part_uv->cached_activate_gru_mq_desc != NULL) {
+                       mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex);
+                       spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+                       part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
+                       spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+                       kfree(part_uv->cached_activate_gru_mq_desc);
+                       part_uv->cached_activate_gru_mq_desc = NULL;
+                       mutex_unlock(&part_uv->
+                                    cached_activate_gru_mq_desc_mutex);
+               }
+       }
+}
+
 static int
 xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
 {
+       int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
+
 #if defined CONFIG_X86_64
        mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset);
        if (mq->irq < 0) {
                dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
-                       mq->irq);
+                       -mq->irq);
+               return mq->irq;
        }
 
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
-       int mmr_pnode;
-       unsigned long mmr_value;
+       mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset);
 
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
        if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0)
                mq->irq = SGI_XPC_ACTIVATE;
        else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0)
@@ -83,10 +124,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
        else
                return -EINVAL;
 
-       mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
-       mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq;
-
-       uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value);
+       mq->mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq;
+       uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mq->mmr_value);
 #else
        #error not a supported configuration
 #endif
@@ -127,7 +166,7 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq)
                return ret;
        }
 #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
-       ret = sn_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address),
+       ret = sn_mq_watchlist_alloc(mq->mmr_blade, (void *)uv_gpa(mq->address),
                                    mq->order, &mq->mmr_offset);
        if (ret < 0) {
                dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n",
@@ -168,12 +207,22 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        int pg_order;
        struct page *page;
        struct xpc_gru_mq_uv *mq;
+       struct uv_IO_APIC_route_entry *mmr_value;
 
        mq = kmalloc(sizeof(struct xpc_gru_mq_uv), GFP_KERNEL);
        if (mq == NULL) {
                dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() "
                        "a xpc_gru_mq_uv structure\n");
                ret = -ENOMEM;
+               goto out_0;
+       }
+
+       mq->gru_mq_desc = kzalloc(sizeof(struct gru_message_queue_desc),
+                                 GFP_KERNEL);
+       if (mq->gru_mq_desc == NULL) {
+               dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() "
+                       "a gru_message_queue_desc structure\n");
+               ret = -ENOMEM;
                goto out_1;
        }
 
@@ -194,14 +243,6 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        }
        mq->address = page_address(page);
 
-       ret = gru_create_message_queue(mq->address, mq_size);
-       if (ret != 0) {
-               dev_err(xpc_part, "gru_create_message_queue() returned "
-                       "error=%d\n", ret);
-               ret = -EINVAL;
-               goto out_3;
-       }
-
        /* enable generation of irq when GRU mq operation occurs to this mq */
        ret = xpc_gru_mq_watchlist_alloc_uv(mq);
        if (ret != 0)
@@ -214,10 +255,20 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        ret = request_irq(mq->irq, irq_handler, 0, irq_name, NULL);
        if (ret != 0) {
                dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n",
-                       mq->irq, ret);
+                       mq->irq, -ret);
                goto out_5;
        }
 
+       mmr_value = (struct uv_IO_APIC_route_entry *)&mq->mmr_value;
+       ret = gru_create_message_queue(mq->gru_mq_desc, mq->address, mq_size,
+                                      nid, mmr_value->vector, mmr_value->dest);
+       if (ret != 0) {
+               dev_err(xpc_part, "gru_create_message_queue() returned "
+                       "error=%d\n", ret);
+               ret = -EINVAL;
+               goto out_6;
+       }
+
        /* allow other partitions to access this GRU mq */
        xp_ret = xp_expand_memprotect(xp_pa(mq->address), mq_size);
        if (xp_ret != xpSuccess) {
@@ -237,8 +288,10 @@ out_4:
 out_3:
        free_pages((unsigned long)mq->address, pg_order);
 out_2:
-       kfree(mq);
+       kfree(mq->gru_mq_desc);
 out_1:
+       kfree(mq);
+out_0:
        return ERR_PTR(ret);
 }
 
@@ -268,13 +321,14 @@ xpc_destroy_gru_mq_uv(struct xpc_gru_mq_uv *mq)
 }
 
 static enum xp_retval
-xpc_send_gru_msg(unsigned long mq_gpa, void *msg, size_t msg_size)
+xpc_send_gru_msg(struct gru_message_queue_desc *gru_mq_desc, void *msg,
+                size_t msg_size)
 {
        enum xp_retval xp_ret;
        int ret;
 
        while (1) {
-               ret = gru_send_message_gpa(mq_gpa, msg, msg_size);
+               ret = gru_send_message_gpa(gru_mq_desc, msg, msg_size);
                if (ret == MQE_OK) {
                        xp_ret = xpSuccess;
                        break;
@@ -421,7 +475,15 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
                part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV;
                part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */
                part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies;
-               part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa;
+
+               if (msg->activate_gru_mq_desc_gpa !=
+                   part_uv->activate_gru_mq_desc_gpa) {
+                       spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+                       part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
+                       spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+                       part_uv->activate_gru_mq_desc_gpa =
+                           msg->activate_gru_mq_desc_gpa;
+               }
                spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
 
                (*wakeup_hb_checker)++;
@@ -498,7 +560,7 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
                args = &part->remote_openclose_args[msg->ch_number];
                args->remote_nentries = msg->remote_nentries;
                args->local_nentries = msg->local_nentries;
-               args->local_msgqueue_pa = msg->local_notify_mq_gpa;
+               args->local_msgqueue_pa = msg->notify_gru_mq_desc_gpa;
 
                spin_lock_irqsave(&part->chctl_lock, irq_flags);
                part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY;
@@ -558,9 +620,10 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
        short partid;
        struct xpc_partition *part;
        int wakeup_hb_checker = 0;
+       int part_referenced;
 
        while (1) {
-               msg_hdr = gru_get_next_message(xpc_activate_mq_uv->address);
+               msg_hdr = gru_get_next_message(xpc_activate_mq_uv->gru_mq_desc);
                if (msg_hdr == NULL)
                        break;
 
@@ -571,14 +634,15 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
                                partid);
                } else {
                        part = &xpc_partitions[partid];
-                       if (xpc_part_ref(part)) {
-                               xpc_handle_activate_mq_msg_uv(part, msg_hdr,
-                                                           &wakeup_hb_checker);
+
+                       part_referenced = xpc_part_ref(part);
+                       xpc_handle_activate_mq_msg_uv(part, msg_hdr,
+                                                     &wakeup_hb_checker);
+                       if (part_referenced)
                                xpc_part_deref(part);
-                       }
                }
 
-               gru_free_message(xpc_activate_mq_uv->address, msg_hdr);
+               gru_free_message(xpc_activate_mq_uv->gru_mq_desc, msg_hdr);
        }
 
        if (wakeup_hb_checker)
@@ -587,22 +651,74 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static enum xp_retval
+xpc_cache_remote_gru_mq_desc_uv(struct gru_message_queue_desc *gru_mq_desc,
+                               unsigned long gru_mq_desc_gpa)
+{
+       enum xp_retval ret;
+
+       ret = xp_remote_memcpy(uv_gpa(gru_mq_desc), gru_mq_desc_gpa,
+                              sizeof(struct gru_message_queue_desc));
+       if (ret == xpSuccess)
+               gru_mq_desc->mq = NULL;
+
+       return ret;
+}
+
 static enum xp_retval
 xpc_send_activate_IRQ_uv(struct xpc_partition *part, void *msg, size_t msg_size,
                         int msg_type)
 {
        struct xpc_activate_mq_msghdr_uv *msg_hdr = msg;
+       struct xpc_partition_uv *part_uv = &part->sn.uv;
+       struct gru_message_queue_desc *gru_mq_desc;
+       unsigned long irq_flags;
+       enum xp_retval ret;
 
        DBUG_ON(msg_size > XPC_ACTIVATE_MSG_SIZE_UV);
 
        msg_hdr->type = msg_type;
-       msg_hdr->partid = XPC_PARTID(part);
+       msg_hdr->partid = xp_partition_id;
        msg_hdr->act_state = part->act_state;
        msg_hdr->rp_ts_jiffies = xpc_rsvd_page->ts_jiffies;
 
+       mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex);
+again:
+       if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV)) {
+               gru_mq_desc = part_uv->cached_activate_gru_mq_desc;
+               if (gru_mq_desc == NULL) {
+                       gru_mq_desc = kmalloc(sizeof(struct
+                                             gru_message_queue_desc),
+                                             GFP_KERNEL);
+                       if (gru_mq_desc == NULL) {
+                               ret = xpNoMemory;
+                               goto done;
+                       }
+                       part_uv->cached_activate_gru_mq_desc = gru_mq_desc;
+               }
+
+               ret = xpc_cache_remote_gru_mq_desc_uv(gru_mq_desc,
+                                                     part_uv->
+                                                     activate_gru_mq_desc_gpa);
+               if (ret != xpSuccess)
+                       goto done;
+
+               spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+               part_uv->flags |= XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
+               spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+       }
+
        /* ??? Is holding a spin_lock (ch->lock) during this call a bad idea? */
-       return xpc_send_gru_msg(part->sn.uv.remote_activate_mq_gpa, msg,
-                               msg_size);
+       ret = xpc_send_gru_msg(part_uv->cached_activate_gru_mq_desc, msg,
+                              msg_size);
+       if (ret != xpSuccess) {
+               smp_rmb();      /* ensure a fresh copy of part_uv->flags */
+               if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV))
+                       goto again;
+       }
+done:
+       mutex_unlock(&part_uv->cached_activate_gru_mq_desc_mutex);
+       return ret;
 }
 
 static void
@@ -620,7 +736,7 @@ static void
 xpc_send_activate_IRQ_ch_uv(struct xpc_channel *ch, unsigned long *irq_flags,
                         void *msg, size_t msg_size, int msg_type)
 {
-       struct xpc_partition *part = &xpc_partitions[ch->number];
+       struct xpc_partition *part = &xpc_partitions[ch->partid];
        enum xp_retval ret;
 
        ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type);
@@ -692,7 +808,8 @@ xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa,
 static int
 xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp)
 {
-       rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv->address);
+       rp->sn.activate_gru_mq_desc_gpa =
+           uv_gpa(xpc_activate_mq_uv->gru_mq_desc);
        return 0;
 }
 
@@ -787,7 +904,8 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp,
 
        part->remote_rp_pa = remote_rp_gpa; /* !!! _pa here is really _gpa */
        part->remote_rp_ts_jiffies = remote_rp->ts_jiffies;
-       part->sn.uv.remote_activate_mq_gpa = remote_rp->sn.activate_mq_gpa;
+       part->sn.uv.activate_gru_mq_desc_gpa =
+           remote_rp->sn.activate_gru_mq_desc_gpa;
 
        /*
         * ??? Is it a good idea to make this conditional on what is
@@ -795,7 +913,8 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp,
         */
        if (part->sn.uv.remote_act_state == XPC_P_AS_INACTIVE) {
                msg.rp_gpa = uv_gpa(xpc_rsvd_page);
-               msg.activate_mq_gpa = xpc_rsvd_page->sn.activate_mq_gpa;
+               msg.activate_gru_mq_desc_gpa =
+                   xpc_rsvd_page->sn.activate_gru_mq_desc_gpa;
                xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
                                           XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV);
        }
@@ -857,7 +976,8 @@ xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head)
                if (head->first == NULL)
                        head->last = NULL;
        }
-       head->n_entries++;
+       head->n_entries--;
+       BUG_ON(head->n_entries < 0);
        spin_unlock_irqrestore(&head->lock, irq_flags);
        first->next = NULL;
        return first;
@@ -876,8 +996,7 @@ xpc_put_fifo_entry_uv(struct xpc_fifo_head_uv *head,
        else
                head->first = last;
        head->last = last;
-       head->n_entries--;
-       BUG_ON(head->n_entries < 0);
+       head->n_entries++;
        spin_unlock_irqrestore(&head->lock, irq_flags);
 }
 
@@ -1037,6 +1156,12 @@ xpc_setup_msg_structures_uv(struct xpc_channel *ch)
 
        DBUG_ON(ch->flags & XPC_C_SETUP);
 
+       ch_uv->cached_notify_gru_mq_desc = kmalloc(sizeof(struct
+                                                  gru_message_queue_desc),
+                                                  GFP_KERNEL);
+       if (ch_uv->cached_notify_gru_mq_desc == NULL)
+               return xpNoMemory;
+
        ret = xpc_allocate_send_msg_slot_uv(ch);
        if (ret == xpSuccess) {
 
@@ -1060,7 +1185,8 @@ xpc_teardown_msg_structures_uv(struct xpc_channel *ch)
 
        DBUG_ON(!spin_is_locked(&ch->lock));
 
-       ch_uv->remote_notify_mq_gpa = 0;
+       kfree(ch_uv->cached_notify_gru_mq_desc);
+       ch_uv->cached_notify_gru_mq_desc = NULL;
 
        if (ch->flags & XPC_C_SETUP) {
                xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
@@ -1111,7 +1237,7 @@ xpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags)
        msg.ch_number = ch->number;
        msg.local_nentries = ch->local_nentries;
        msg.remote_nentries = ch->remote_nentries;
-       msg.local_notify_mq_gpa = uv_gpa(xpc_notify_mq_uv);
+       msg.notify_gru_mq_desc_gpa = uv_gpa(xpc_notify_mq_uv->gru_mq_desc);
        xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
                                    XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV);
 }
@@ -1128,11 +1254,15 @@ xpc_send_chctl_local_msgrequest_uv(struct xpc_partition *part, int ch_number)
        xpc_wakeup_channel_mgr(part);
 }
 
-static void
+static enum xp_retval
 xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch,
-                              unsigned long msgqueue_pa)
+                              unsigned long gru_mq_desc_gpa)
 {
-       ch->sn.uv.remote_notify_mq_gpa = msgqueue_pa;
+       struct xpc_channel_uv *ch_uv = &ch->sn.uv;
+
+       DBUG_ON(ch_uv->cached_notify_gru_mq_desc == NULL);
+       return xpc_cache_remote_gru_mq_desc_uv(ch_uv->cached_notify_gru_mq_desc,
+                                              gru_mq_desc_gpa);
 }
 
 static void
@@ -1339,7 +1469,8 @@ xpc_handle_notify_IRQ_uv(int irq, void *dev_id)
        short partid;
        struct xpc_partition *part;
 
-       while ((msg = gru_get_next_message(xpc_notify_mq_uv)) != NULL) {
+       while ((msg = gru_get_next_message(xpc_notify_mq_uv->gru_mq_desc)) !=
+              NULL) {
 
                partid = msg->hdr.partid;
                if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
@@ -1354,7 +1485,7 @@ xpc_handle_notify_IRQ_uv(int irq, void *dev_id)
                        }
                }
 
-               gru_free_message(xpc_notify_mq_uv, msg);
+               gru_free_message(xpc_notify_mq_uv->gru_mq_desc, msg);
        }
 
        return IRQ_HANDLED;
@@ -1438,7 +1569,8 @@ xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload,
        msg->hdr.msg_slot_number = msg_slot->msg_slot_number;
        memcpy(&msg->payload, payload, payload_size);
 
-       ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, msg_size);
+       ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg,
+                              msg_size);
        if (ret == xpSuccess)
                goto out_1;
 
@@ -1529,7 +1661,7 @@ xpc_received_payload_uv(struct xpc_channel *ch, void *payload)
        msg->hdr.partid = xp_partition_id;
        msg->hdr.size = 0;      /* size of zero indicates this is an ACK */
 
-       ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg,
+       ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg,
                               sizeof(struct xpc_notify_mq_msghdr_uv));
        if (ret != xpSuccess)
                XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret);
@@ -1541,6 +1673,7 @@ int
 xpc_init_uv(void)
 {
        xpc_setup_partitions_sn = xpc_setup_partitions_sn_uv;
+       xpc_teardown_partitions_sn = xpc_teardown_partitions_sn_uv;
        xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_uv;
        xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_uv;
        xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_uv;
index 78ad48718ab028e61b1d77d83e29de8efbe9930c..36a8d53ad2a2ba90cf7b5d7dd3fffb647545a1d1 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mutex.h>
+#include <linux/seq_file.h>
 #include <linux/serial_reg.h>
 #include <linux/circ_buf.h>
 #include <linux/gfp.h>
@@ -933,67 +934,64 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
        return result;
 }
 
-static int sdio_uart_read_proc(char *page, char **start, off_t off,
-                              int count, int *eof, void *data)
+static int sdio_uart_proc_show(struct seq_file *m, void *v)
 {
-       int i, len = 0;
-       off_t begin = 0;
+       int i;
 
-       len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
                       "", "", "");
-       for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) {
+       for (i = 0; i < UART_NR; i++) {
                struct sdio_uart_port *port = sdio_uart_port_get(i);
                if (port) {
-                       len += sprintf(page+len, "%d: uart:SDIO", i);
+                       seq_printf(m, "%d: uart:SDIO", i);
                        if(capable(CAP_SYS_ADMIN)) {
-                               len += sprintf(page + len, " tx:%d rx:%d",
+                               seq_printf(m, " tx:%d rx:%d",
                                               port->icount.tx, port->icount.rx);
                                if (port->icount.frame)
-                                       len += sprintf(page + len, " fe:%d",
+                                       seq_printf(m, " fe:%d",
                                                       port->icount.frame);
                                if (port->icount.parity)
-                                       len += sprintf(page + len, " pe:%d",
+                                       seq_printf(m, " pe:%d",
                                                       port->icount.parity);
                                if (port->icount.brk)
-                                       len += sprintf(page + len, " brk:%d",
+                                       seq_printf(m, " brk:%d",
                                                       port->icount.brk);
                                if (port->icount.overrun)
-                                       len += sprintf(page + len, " oe:%d",
+                                       seq_printf(m, " oe:%d",
                                                       port->icount.overrun);
                                if (port->icount.cts)
-                                       len += sprintf(page + len, " cts:%d",
+                                       seq_printf(m, " cts:%d",
                                                       port->icount.cts);
                                if (port->icount.dsr)
-                                       len += sprintf(page + len, " dsr:%d",
+                                       seq_printf(m, " dsr:%d",
                                                       port->icount.dsr);
                                if (port->icount.rng)
-                                       len += sprintf(page + len, " rng:%d",
+                                       seq_printf(m, " rng:%d",
                                                       port->icount.rng);
                                if (port->icount.dcd)
-                                       len += sprintf(page + len, " dcd:%d",
+                                       seq_printf(m, " dcd:%d",
                                                       port->icount.dcd);
                        }
-                       strcat(page, "\n");
-                       len++;
                        sdio_uart_port_put(port);
-               }
-
-               if (len + begin > off + count)
-                       goto done;
-               if (len + begin < off) {
-                       begin += len;
-                       len = 0;
+                       seq_putc(m, '\n');
                }
        }
-       *eof = 1;
+       return 0;
+}
 
-done:
-       if (off >= len + begin)
-               return 0;
-       *start = page + (off - begin);
-       return (count < begin + len - off) ? count : (begin + len - off);
+static int sdio_uart_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sdio_uart_proc_show, NULL);
 }
 
+static const struct file_operations sdio_uart_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = sdio_uart_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static const struct tty_operations sdio_uart_ops = {
        .open                   = sdio_uart_open,
        .close                  = sdio_uart_close,
@@ -1007,7 +1005,7 @@ static const struct tty_operations sdio_uart_ops = {
        .break_ctl              = sdio_uart_break_ctl,
        .tiocmget               = sdio_uart_tiocmget,
        .tiocmset               = sdio_uart_tiocmset,
-       .read_proc              = sdio_uart_read_proc,
+       .proc_fops              = &sdio_uart_proc_fops,
 };
 
 static struct tty_driver *sdio_uart_tty_driver;
index df6ce4a06cf37f42c11935ce7f4e2f5d92409758..1445ea8f10a61bf14df5b7abd25a3850c8b78693 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/leds.h>
 #include <linux/scatterlist.h>
 #include <linux/log2.h>
+#include <linux/regulator/consumer.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -523,6 +524,105 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
 }
 EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
 
+#ifdef CONFIG_REGULATOR
+
+/**
+ * mmc_regulator_get_ocrmask - return mask of supported voltages
+ * @supply: regulator to use
+ *
+ * This returns either a negative errno, or a mask of voltages that
+ * can be provided to MMC/SD/SDIO devices using the specified voltage
+ * regulator.  This would normally be called before registering the
+ * MMC host adapter.
+ */
+int mmc_regulator_get_ocrmask(struct regulator *supply)
+{
+       int                     result = 0;
+       int                     count;
+       int                     i;
+
+       count = regulator_count_voltages(supply);
+       if (count < 0)
+               return count;
+
+       for (i = 0; i < count; i++) {
+               int             vdd_uV;
+               int             vdd_mV;
+
+               vdd_uV = regulator_list_voltage(supply, i);
+               if (vdd_uV <= 0)
+                       continue;
+
+               vdd_mV = vdd_uV / 1000;
+               result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
+       }
+
+       return result;
+}
+EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
+
+/**
+ * mmc_regulator_set_ocr - set regulator to match host->ios voltage
+ * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
+ * @supply: regulator to use
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * MMC host drivers may use this to enable or disable a regulator using
+ * a particular supply voltage.  This would normally be called from the
+ * set_ios() method.
+ */
+int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
+{
+       int                     result = 0;
+       int                     min_uV, max_uV;
+       int                     enabled;
+
+       enabled = regulator_is_enabled(supply);
+       if (enabled < 0)
+               return enabled;
+
+       if (vdd_bit) {
+               int             tmp;
+               int             voltage;
+
+               /* REVISIT mmc_vddrange_to_ocrmask() may have set some
+                * bits this regulator doesn't quite support ... don't
+                * be too picky, most cards and regulators are OK with
+                * a 0.1V range goof (it's a small error percentage).
+                */
+               tmp = vdd_bit - ilog2(MMC_VDD_165_195);
+               if (tmp == 0) {
+                       min_uV = 1650 * 1000;
+                       max_uV = 1950 * 1000;
+               } else {
+                       min_uV = 1900 * 1000 + tmp * 100 * 1000;
+                       max_uV = min_uV + 100 * 1000;
+               }
+
+               /* avoid needless changes to this voltage; the regulator
+                * might not allow this operation
+                */
+               voltage = regulator_get_voltage(supply);
+               if (voltage < 0)
+                       result = voltage;
+               else if (voltage < min_uV || voltage > max_uV)
+                       result = regulator_set_voltage(supply, min_uV, max_uV);
+               else
+                       result = 0;
+
+               if (result == 0 && !enabled)
+                       result = regulator_enable(supply);
+       } else if (enabled) {
+               result = regulator_disable(supply);
+       }
+
+       return result;
+}
+EXPORT_SYMBOL(mmc_regulator_set_ocr);
+
+#endif
+
 /*
  * Mask off any voltages we don't support and select
  * the lowest voltage
index 99d4b28d52ed33673468d692f34d08421e5d1a18..6fbb246c40bbfc2f7747c64e5abbb3e4e0ea997f 100644 (file)
@@ -177,7 +177,7 @@ config MMC_SPI
        select CRC7
        select CRC_ITU_T
        help
-         Some systems accss MMC/SD/SDIO cards using a SPI controller
+         Some systems access MMC/SD/SDIO cards using a SPI controller
          instead of using a "native" MMC/SD/SDIO controller.  This has a
          disadvantage of being relatively high overhead, but a compensating
          advantage of working on many systems without dedicated MMC/SD/SDIO
index e9026cb1c5b2248962e2280628373f33f0f43e2b..572d32fdf38a0d8b421b094e931978e54b633745 100644 (file)
@@ -117,7 +117,7 @@ static int __init pxa2xx_flash_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit pxa2xx_flash_remove(struct platform_device *dev)
+static int __devexit pxa2xx_flash_remove(struct platform_device *dev)
 {
        struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
index e4226e02d63e752f552fc6f83af941243327dfed..e51c1ed7ac1810976f231062b4459a02634d8310 100644 (file)
@@ -1773,4 +1773,4 @@ module_exit(cleanup_nanddoc);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n");
+MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
index afbc3f8126db8aec3931d329971637b60eb6def8..a18e8d2f255765db492c8b1797dd99c2eaf54ece 100644 (file)
@@ -136,7 +136,7 @@ static int write_eraseblock(int ebnum)
                ops.ooblen    = use_len;
                ops.oobretlen = 0;
                ops.ooboffs   = use_offset;
-               ops.datbuf    = 0;
+               ops.datbuf    = NULL;
                ops.oobbuf    = writebuf;
                err = mtd->write_oob(mtd, addr, &ops);
                if (err || ops.oobretlen != use_len) {
@@ -189,7 +189,7 @@ static int verify_eraseblock(int ebnum)
                ops.ooblen    = use_len;
                ops.oobretlen = 0;
                ops.ooboffs   = use_offset;
-               ops.datbuf    = 0;
+               ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
                err = mtd->read_oob(mtd, addr, &ops);
                if (err || ops.oobretlen != use_len) {
@@ -216,7 +216,7 @@ static int verify_eraseblock(int ebnum)
                        ops.ooblen    = mtd->ecclayout->oobavail;
                        ops.oobretlen = 0;
                        ops.ooboffs   = 0;
-                       ops.datbuf    = 0;
+                       ops.datbuf    = NULL;
                        ops.oobbuf    = readbuf;
                        err = mtd->read_oob(mtd, addr, &ops);
                        if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
@@ -281,7 +281,7 @@ static int verify_eraseblock_in_one_go(int ebnum)
        ops.ooblen    = len;
        ops.oobretlen = 0;
        ops.ooboffs   = 0;
-       ops.datbuf    = 0;
+       ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
        err = mtd->read_oob(mtd, addr, &ops);
        if (err || ops.oobretlen != len) {
@@ -522,7 +522,7 @@ static int __init mtd_oobtest_init(void)
        ops.ooblen    = 1;
        ops.oobretlen = 0;
        ops.ooboffs   = mtd->ecclayout->oobavail;
-       ops.datbuf    = 0;
+       ops.datbuf    = NULL;
        ops.oobbuf    = writebuf;
        printk(PRINT_PREF "attempting to start write past end of OOB\n");
        printk(PRINT_PREF "an error is expected...\n");
@@ -542,7 +542,7 @@ static int __init mtd_oobtest_init(void)
        ops.ooblen    = 1;
        ops.oobretlen = 0;
        ops.ooboffs   = mtd->ecclayout->oobavail;
-       ops.datbuf    = 0;
+       ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
        printk(PRINT_PREF "attempting to start read past end of OOB\n");
        printk(PRINT_PREF "an error is expected...\n");
@@ -566,7 +566,7 @@ static int __init mtd_oobtest_init(void)
                ops.ooblen    = mtd->ecclayout->oobavail + 1;
                ops.oobretlen = 0;
                ops.ooboffs   = 0;
-               ops.datbuf    = 0;
+               ops.datbuf    = NULL;
                ops.oobbuf    = writebuf;
                printk(PRINT_PREF "attempting to write past end of device\n");
                printk(PRINT_PREF "an error is expected...\n");
@@ -586,7 +586,7 @@ static int __init mtd_oobtest_init(void)
                ops.ooblen    = mtd->ecclayout->oobavail + 1;
                ops.oobretlen = 0;
                ops.ooboffs   = 0;
-               ops.datbuf    = 0;
+               ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
                printk(PRINT_PREF "attempting to read past end of device\n");
                printk(PRINT_PREF "an error is expected...\n");
@@ -610,7 +610,7 @@ static int __init mtd_oobtest_init(void)
                ops.ooblen    = mtd->ecclayout->oobavail;
                ops.oobretlen = 0;
                ops.ooboffs   = 1;
-               ops.datbuf    = 0;
+               ops.datbuf    = NULL;
                ops.oobbuf    = writebuf;
                printk(PRINT_PREF "attempting to write past end of device\n");
                printk(PRINT_PREF "an error is expected...\n");
@@ -630,7 +630,7 @@ static int __init mtd_oobtest_init(void)
                ops.ooblen    = mtd->ecclayout->oobavail;
                ops.oobretlen = 0;
                ops.ooboffs   = 1;
-               ops.datbuf    = 0;
+               ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
                printk(PRINT_PREF "attempting to read past end of device\n");
                printk(PRINT_PREF "an error is expected...\n");
@@ -670,7 +670,7 @@ static int __init mtd_oobtest_init(void)
                        ops.ooblen    = sz;
                        ops.oobretlen = 0;
                        ops.ooboffs   = 0;
-                       ops.datbuf    = 0;
+                       ops.datbuf    = NULL;
                        ops.oobbuf    = writebuf;
                        err = mtd->write_oob(mtd, addr, &ops);
                        if (err)
@@ -698,7 +698,7 @@ static int __init mtd_oobtest_init(void)
                ops.ooblen    = mtd->ecclayout->oobavail * 2;
                ops.oobretlen = 0;
                ops.ooboffs   = 0;
-               ops.datbuf    = 0;
+               ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
                err = mtd->read_oob(mtd, addr, &ops);
                if (err)
index 645e77fdc63d878a64bea35fd9acb645cbe21ae2..79fc4530987b0fe49fda701d567569e7c44b9d85 100644 (file)
@@ -71,7 +71,7 @@ static int read_eraseblock_by_page(int ebnum)
                        ops.ooblen    = mtd->oobsize;
                        ops.oobretlen = 0;
                        ops.ooboffs   = 0;
-                       ops.datbuf    = 0;
+                       ops.datbuf    = NULL;
                        ops.oobbuf    = oobbuf;
                        ret = mtd->read_oob(mtd, addr, &ops);
                        if (ret || ops.oobretlen != mtd->oobsize) {
index f062b424704eeb9a869b656451f0b4752de7ae54..16899eee397ebf2d2c7e0a843e4a71174d04936b 100644 (file)
@@ -974,7 +974,7 @@ config ENC28J60_WRITEVERIFY
 
 config ETHOC
        tristate "OpenCores 10/100 Mbps Ethernet MAC support"
-       depends on NET_ETHERNET
+       depends on NET_ETHERNET && HAS_IOMEM
        select MII
        select PHYLIB
        help
@@ -2547,6 +2547,23 @@ config S2IO
          More specific information on configuring the driver is in 
          <file:Documentation/networking/s2io.txt>.
 
+config VXGE
+       tristate "Neterion X3100 Series 10GbE PCIe Server Adapter"
+       depends on PCI && INET
+       ---help---
+         This driver supports Neterion Inc's X3100 Series 10 GbE PCIe
+         I/O Virtualized Server Adapter.
+         More specific information on configuring the driver is in
+         <file:Documentation/networking/vxge.txt>.
+
+config VXGE_DEBUG_TRACE_ALL
+       bool "Enabling All Debug trace statments in driver"
+       default n
+       depends on VXGE
+       ---help---
+         Say Y here if you want to enabling all the debug trace statements in
+         driver. By  default only few debug trace statements are enabled.
+
 config MYRI10GE
        tristate "Myricom Myri-10G Ethernet support"
        depends on PCI && INET
index 98409c9dd445c7b16d79ab9bb543a02a91a274e1..edc9a0d6171ddd6d9643f855b61dc5b51724e0ba 100644 (file)
@@ -220,6 +220,7 @@ obj-$(CONFIG_R8169) += r8169.o
 obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
 obj-$(CONFIG_IBMVETH) += ibmveth.o
 obj-$(CONFIG_S2IO) += s2io.o
+obj-$(CONFIG_VXGE) += vxge/
 obj-$(CONFIG_MYRI10GE) += myri10ge/
 obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_SMC911X) += smc911x.o
index 9c326a50a3eecb22851cc21ecb5f3d3a3e861e5b..99610f358c40629cecf9a12dfbc2566587a5026d 100644 (file)
@@ -3444,25 +3444,12 @@ static void bond_remove_proc_entry(struct bonding *bond)
  */
 static void bond_create_proc_dir(void)
 {
-       int len = strlen(DRV_NAME);
-
-       for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir;
-            bond_proc_dir = bond_proc_dir->next) {
-               if ((bond_proc_dir->namelen == len) &&
-                   !memcmp(bond_proc_dir->name, DRV_NAME, len)) {
-                       break;
-               }
-       }
-
        if (!bond_proc_dir) {
                bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net);
-               if (bond_proc_dir) {
-                       bond_proc_dir->owner = THIS_MODULE;
-               } else {
+               if (!bond_proc_dir)
                        printk(KERN_WARNING DRV_NAME
                                ": Warning: cannot create /proc/net/%s\n",
                                DRV_NAME);
-               }
        }
 }
 
@@ -3471,25 +3458,7 @@ static void bond_create_proc_dir(void)
  */
 static void bond_destroy_proc_dir(void)
 {
-       struct proc_dir_entry *de;
-
-       if (!bond_proc_dir) {
-               return;
-       }
-
-       /* verify that the /proc dir is empty */
-       for (de = bond_proc_dir->subdir; de; de = de->next) {
-               /* ignore . and .. */
-               if (*(de->name) != '.') {
-                       break;
-               }
-       }
-
-       if (de) {
-               if (bond_proc_dir->owner == THIS_MODULE) {
-                       bond_proc_dir->owner = NULL;
-               }
-       } else {
+       if (bond_proc_dir) {
                remove_proc_entry(DRV_NAME, init_net.proc_net);
                bond_proc_dir = NULL;
        }
index 254ec62b5f58d4e13f3848040362e7660108b6d3..d8350860c0f8db5e6c622f4962586d8024c2636f 100644 (file)
@@ -559,7 +559,7 @@ static void dm9000_show_carrier(board_info_t *db,
 static void
 dm9000_poll_work(struct work_struct *w)
 {
-       struct delayed_work *dw = container_of(w, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(w);
        board_info_t *db = container_of(dw, board_info_t, phy_poll);
        struct net_device *ndev = db->ndev;
 
index db1e31f952003a1100d8954d0fc7b08bd3640eea..33fa9eee4cacbfc3a735ef1d4ad95377539a9d52 100644 (file)
@@ -8,7 +8,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/version.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
index 049b0a7e01f36b7278c984b7cf3fe47ca385fc7a..8bbe7f6179949c30b167d82cb2236394af9332c4 100644 (file)
@@ -129,7 +129,8 @@ static void mpc52xx_fec_free_rx_buffers(struct net_device *dev, struct bcom_task
                struct sk_buff *skb;
 
                skb = bcom_retrieve_buffer(s, NULL, (struct bcom_bd **)&bd);
-               dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE);
+               dma_unmap_single(dev->dev.parent, bd->skb_pa, skb->len,
+                                DMA_FROM_DEVICE);
                kfree_skb(skb);
        }
 }
@@ -150,7 +151,7 @@ static int mpc52xx_fec_alloc_rx_buffers(struct net_device *dev, struct bcom_task
                bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
 
                bd->status = FEC_RX_BUFFER_SIZE;
-               bd->skb_pa = dma_map_single(&dev->dev, skb->data,
+               bd->skb_pa = dma_map_single(dev->dev.parent, skb->data,
                                FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
 
                bcom_submit_next_buffer(rxtsk, skb);
@@ -270,15 +271,6 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
        phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
 }
 
-static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
-               struct mii_ioctl_data *mii_data, int cmd)
-{
-       if (!priv->phydev)
-               return -ENOTSUPP;
-
-       return phy_mii_ioctl(priv->phydev, mii_data, cmd);
-}
-
 static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
 {
        struct mpc52xx_fec __iomem *fec = priv->fec;
@@ -370,7 +362,7 @@ static int mpc52xx_fec_close(struct net_device *dev)
  * invariant will hold if you make sure that the netif_*_queue()
  * calls are done at the proper times.
  */
-static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct mpc52xx_fec_priv *priv = netdev_priv(dev);
        struct bcom_fec_bd *bd;
@@ -378,7 +370,7 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d
        if (bcom_queue_full(priv->tx_dmatsk)) {
                if (net_ratelimit())
                        dev_err(&dev->dev, "transmit queue overrun\n");
-               return 1;
+               return NETDEV_TX_BUSY;
        }
 
        spin_lock_irq(&priv->lock);
@@ -388,7 +380,8 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d
                bcom_prepare_next_buffer(priv->tx_dmatsk);
 
        bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC;
-       bd->skb_pa = dma_map_single(&dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+       bd->skb_pa = dma_map_single(dev->dev.parent, skb->data, skb->len,
+                                   DMA_TO_DEVICE);
 
        bcom_submit_next_buffer(priv->tx_dmatsk, skb);
 
@@ -398,7 +391,7 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d
 
        spin_unlock_irq(&priv->lock);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -430,7 +423,8 @@ static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id)
                struct bcom_fec_bd *bd;
                skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL,
                                (struct bcom_bd **)&bd);
-               dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_TO_DEVICE);
+               dma_unmap_single(dev->dev.parent, bd->skb_pa, skb->len,
+                                DMA_TO_DEVICE);
 
                dev_kfree_skb_irq(skb);
        }
@@ -455,7 +449,8 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
 
                rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status,
                                (struct bcom_bd **)&bd);
-               dma_unmap_single(&dev->dev, bd->skb_pa, rskb->len, DMA_FROM_DEVICE);
+               dma_unmap_single(dev->dev.parent, bd->skb_pa, rskb->len,
+                                DMA_FROM_DEVICE);
 
                /* Test for errors in received frame */
                if (status & BCOM_FEC_RX_BD_ERRORS) {
@@ -464,7 +459,8 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
                                bcom_prepare_next_buffer(priv->rx_dmatsk);
 
                        bd->status = FEC_RX_BUFFER_SIZE;
-                       bd->skb_pa = dma_map_single(&dev->dev, rskb->data,
+                       bd->skb_pa = dma_map_single(dev->dev.parent,
+                                       rskb->data,
                                        FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
 
                        bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
@@ -499,7 +495,7 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
                        bcom_prepare_next_buffer(priv->rx_dmatsk);
 
                bd->status = FEC_RX_BUFFER_SIZE;
-               bd->skb_pa = dma_map_single(&dev->dev, skb->data,
+               bd->skb_pa = dma_map_single(dev->dev.parent, skb->data,
                                FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
 
                bcom_submit_next_buffer(priv->rx_dmatsk, skb);
@@ -847,12 +843,20 @@ static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
 static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENODEV;
+
        return phy_ethtool_gset(priv->phydev, cmd);
 }
 
 static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENODEV;
+
        return phy_ethtool_sset(priv->phydev, cmd);
 }
 
@@ -882,9 +886,28 @@ static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 
-       return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
+       if (!priv->phydev)
+               return -ENOTSUPP;
+
+       return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
 }
 
+static const struct net_device_ops mpc52xx_fec_netdev_ops = {
+       .ndo_open = mpc52xx_fec_open,
+       .ndo_stop = mpc52xx_fec_close,
+       .ndo_start_xmit = mpc52xx_fec_start_xmit,
+       .ndo_set_multicast_list = mpc52xx_fec_set_multicast_list,
+       .ndo_set_mac_address = mpc52xx_fec_set_mac_address,
+       .ndo_validate_addr = eth_validate_addr,
+       .ndo_do_ioctl = mpc52xx_fec_ioctl,
+       .ndo_change_mtu = eth_change_mtu,
+       .ndo_tx_timeout = mpc52xx_fec_tx_timeout,
+       .ndo_get_stats = mpc52xx_fec_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = mpc52xx_fec_poll_controller,
+#endif
+};
+
 /* ======================================================================== */
 /* OF Driver                                                                */
 /* ======================================================================== */
@@ -929,22 +952,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
                return -EBUSY;
 
        /* Init ether ndev with what we have */
-       ndev->open              = mpc52xx_fec_open;
-       ndev->stop              = mpc52xx_fec_close;
-       ndev->hard_start_xmit   = mpc52xx_fec_hard_start_xmit;
-       ndev->do_ioctl          = mpc52xx_fec_ioctl;
+       ndev->netdev_ops        = &mpc52xx_fec_netdev_ops;
        ndev->ethtool_ops       = &mpc52xx_fec_ethtool_ops;
-       ndev->get_stats         = mpc52xx_fec_get_stats;
-       ndev->set_mac_address   = mpc52xx_fec_set_mac_address;
-       ndev->set_multicast_list = mpc52xx_fec_set_multicast_list;
-       ndev->tx_timeout        = mpc52xx_fec_tx_timeout;
        ndev->watchdog_timeo    = FEC_WATCHDOG_TIMEOUT;
        ndev->base_addr         = mem.start;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       ndev->poll_controller = mpc52xx_fec_poll_controller;
-#endif
-
-       priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
 
        spin_lock_init(&priv->lock);
 
index b3079a5a7f2bda4929d4a68a56ac326a11b250c7..aa1eb88c21fc725196f4ff084b073b41298a4aa3 100644 (file)
@@ -204,6 +204,7 @@ void fsl_pq_mdio_bus_name(char *name, struct device_node *np)
        snprintf(name, MII_BUS_ID_SIZE, "%s@%llx", np->name,
                (unsigned long long)taddr);
 }
+EXPORT_SYMBOL_GPL(fsl_pq_mdio_bus_name);
 
 /* Scan the bus in reverse, looking for an empty spot */
 static int fsl_pq_mdio_find_free(struct mii_bus *new_bus)
@@ -387,7 +388,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
         * The TBIPHY-only buses will find PHYs at every address,
         * so we mask them all but the TBI
         */
-       if (!of_device_is_compatible(np, "fsl,gianfar-mdio"))
+       if (of_device_is_compatible(np, "fsl,gianfar-tbi"))
                new_bus->phy_mask = ~(1 << tbiaddr);
 
        err = mdiobus_register(new_bus);
index 6a38800be3f109fd10d6a472517902c765f64572..65f55877be95c4c9e5d411e0bc23888b6d5c0a7a 100644 (file)
@@ -289,9 +289,9 @@ static int gfar_of_init(struct net_device *dev)
                id = of_get_property(phy, "reg", NULL);
 
                of_node_put(phy);
-               of_node_put(mdio);
 
                fsl_pq_mdio_bus_name(bus_name, mdio);
+               of_node_put(mdio);
                snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x",
                                bus_name, *id);
        }
index dd499d7cde2670c6b38fb59b4a39694c49660b1b..0642d52aef5ca703d29e415bb054ace303d8e4f1 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/crc32.h>
 #include <linux/workqueue.h>
 #include <linux/ethtool.h>
-#include <linux/fsl_devices.h>
 
 /* The maximum number of packets to be handled in one call of gfar_poll */
 #define GFAR_DEV_WEIGHT 64
index 881bf818bb48aac8a71672b4cd2677b2588613a4..7459b3ac77a9431a30c59f1d581d3c6ffe98fd02 100644 (file)
@@ -445,6 +445,7 @@ static const struct net_device_ops scc_netdev_ops = {
        .ndo_stop = scc_close,
        .ndo_start_xmit = scc_send_packet,
        .ndo_do_ioctl = scc_ioctl,
+       .ndo_set_mac_address = scc_set_mac_address,
 };
 
 static int __init setup_adapter(int card_base, int type, int n)
@@ -584,7 +585,6 @@ static int __init setup_adapter(int card_base, int type, int n)
                dev->irq = irq;
                dev->netdev_ops = &scc_netdev_ops;
                dev->header_ops = &ax25_header_ops;
-               dev->set_mac_address = scc_set_mac_address;
        }
        if (register_netdev(info->dev[0])) {
                printk(KERN_ERR "dmascc: could not register %s\n",
index 500a40b2afe785087c9f5ab2f93aeeb2863c0a40..b06691937ce947b980dc73360ed72afa09abd1cd 100644 (file)
@@ -55,6 +55,8 @@
 #include <asm/system.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
 
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
@@ -71,8 +73,6 @@
 #include <linux/init.h>
 
 #include <linux/yam.h>
-#include "yam9600.h"
-#include "yam1200.h"
 
 /* --------------------------------------------------------------------- */
 
@@ -82,6 +82,9 @@ static const char yam_drvinfo[] __initdata = KERN_INFO \
 
 /* --------------------------------------------------------------------- */
 
+#define FIRMWARE_9600  "yam/9600.bin"
+#define FIRMWARE_1200  "yam/1200.bin"
+
 #define YAM_9600       1
 #define YAM_1200       2
 
@@ -342,9 +345,51 @@ static int fpga_write(int iobase, unsigned char wrd)
        return 0;
 }
 
-static unsigned char *add_mcs(unsigned char *bits, int bitrate)
+/*
+ * predef should be 0 for loading user defined mcs
+ * predef should be YAM_1200 for loading predef 1200 mcs
+ * predef should be YAM_9600 for loading predef 9600 mcs
+ */
+static unsigned char *add_mcs(unsigned char *bits, int bitrate,
+                             unsigned int predef)
 {
+       const char *fw_name[2] = {FIRMWARE_9600, FIRMWARE_1200};
+       const struct firmware *fw;
+       struct platform_device *pdev;
        struct yam_mcs *p;
+       int err;
+
+       switch (predef) {
+       case 0:
+               fw = NULL;
+               break;
+       case YAM_1200:
+       case YAM_9600:
+               predef--;
+               pdev = platform_device_register_simple("yam", 0, NULL, 0);
+               if (IS_ERR(pdev)) {
+                       printk(KERN_ERR "yam: Failed to register firmware\n");
+                       return NULL;
+               }
+               err = request_firmware(&fw, fw_name[predef], &pdev->dev);
+               platform_device_unregister(pdev);
+               if (err) {
+                       printk(KERN_ERR "Failed to load firmware \"%s\"\n",
+                              fw_name[predef]);
+                       return NULL;
+               }
+               if (fw->size != YAM_FPGA_SIZE) {
+                       printk(KERN_ERR "Bogus length %zu in firmware \"%s\"\n",
+                              fw->size, fw_name[predef]);
+                       release_firmware(fw);
+                       return NULL;
+               }
+               bits = (unsigned char *)fw->data;
+               break;
+       default:
+               printk(KERN_ERR "yam: Invalid predef number %u\n", predef);
+               return NULL;
+       }
 
        /* If it already exists, replace the bit data */
        p = yam_data;
@@ -359,6 +404,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate)
        /* Allocate a new mcs */
        if ((p = kmalloc(sizeof(struct yam_mcs), GFP_KERNEL)) == NULL) {
                printk(KERN_WARNING "YAM: no memory to allocate mcs\n");
+               release_firmware(fw);
                return NULL;
        }
        memcpy(p->bits, bits, YAM_FPGA_SIZE);
@@ -366,6 +412,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate)
        p->next = yam_data;
        yam_data = p;
 
+       release_firmware(fw);
        return p->bits;
 }
 
@@ -383,9 +430,11 @@ static unsigned char *get_mcs(int bitrate)
        /* Load predefined mcs data */
        switch (bitrate) {
        case 1200:
-               return add_mcs(bits_1200, bitrate);
+               /* setting predef as YAM_1200 for loading predef 1200 mcs */
+               return add_mcs(NULL, bitrate, YAM_1200);
        default:
-               return add_mcs(bits_9600, bitrate);
+               /* setting predef as YAM_9600 for loading predef 9600 mcs */
+               return add_mcs(NULL, bitrate, YAM_9600);
        }
 }
 
@@ -936,7 +985,8 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        kfree(ym);
                        return -EINVAL;
                }
-               add_mcs(ym->bits, ym->bitrate);
+               /* setting predef as 0 for loading userdefined mcs data */
+               add_mcs(ym->bits, ym->bitrate, 0);
                kfree(ym);
                break;
 
@@ -1159,6 +1209,8 @@ static void __exit yam_cleanup_driver(void)
 MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
 MODULE_DESCRIPTION("Yam amateur radio modem driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE_1200);
+MODULE_FIRMWARE(FIRMWARE_9600);
 
 module_init(yam_init_driver);
 module_exit(yam_cleanup_driver);
diff --git a/drivers/net/hamradio/yam1200.h b/drivers/net/hamradio/yam1200.h
deleted file mode 100644 (file)
index 53ca8a3..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- *
- * File yam1k2b5.mcs converted to h format by mcs2h
- *
- * (C) F6FBB 1998
- *
- * Tue Aug 25 20:24:08 1998
- *
- */
-
-static unsigned char bits_1200[]= {
-0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xf3,0xcb,0xff,0xdb,0xfc,0xf2,
-0xff,0xf6,0xff,0x3c,0xbf,0xfd,0xbf,0xdf,0x6e,0x3f,0x6f,0xf1,0x7d,0xb4,0xfd,0xbf,
-0xdf,0x6f,0x3f,0x6f,0xf7,0x0b,0xff,0xdb,0xfd,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff,
-0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xef,0xff,0xff,0xff,
-0xfd,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xbf,
-0xff,0xff,0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfc,0xff,0xfe,0xff,0xff,0xff,0xf0,
-0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xf1,0xff,0xff,0xfe,0x7f,0xbf,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xff,0xff,0xf0,0x9f,
-0xff,0xff,0xff,0xfe,0xff,0xfd,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xff,
-0xff,0xff,0xfb,0xff,0xfb,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xf0,0x5f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xbf,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,
-0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,
-0xff,0xff,0xff,0xfd,0xff,0xbf,0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xfb,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,
-0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xf7,0xff,0xff,0xf1,0xff,0xff,0xf7,0xbf,0xe7,0xff,0xff,0xff,0xff,0xfb,
-0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdb,
-0xff,0xff,0xf5,0xa5,0xfd,0x4b,0x6e,0xef,0x33,0x32,0xdd,0xd3,0x4a,0xd6,0x92,0xfe,
-0xb3,0x3f,0xbd,0xf1,0xfa,0xdb,0xfe,0xf7,0xf6,0x96,0xbd,0xbd,0xff,0xbd,0xff,0xed,
-0x7f,0x6b,0x7f,0xfb,0xdf,0xfe,0xfb,0xfe,0x90,0xcf,0xff,0xff,0xff,0xfe,0xbe,0xef,
-0xff,0xff,0xdb,0x5f,0xf6,0xff,0xf6,0x8f,0xfd,0xa5,0xdd,0xff,0xff,0xff,0xff,0x6f,
-0x7f,0xdb,0xf1,0xfc,0xbf,0xff,0x6f,0xff,0xef,0xfc,0x5b,0x5d,0xda,0xdf,0xf4,0xff,
-0xf2,0xff,0xfd,0xbf,0xff,0xff,0xff,0xd0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
-0xff,0xfb,0xef,0xb7,0xfc,0x33,0xff,0xfb,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,
-0x0f,0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x72,0x0f,0xf1,0x6f,0xff,0xfe,0x94,0x3f,
-0xff,0xff,0xff,0x7b,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf0,
-0xf7,0xef,0xb7,0xfc,0x33,0xff,0xff,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,0x0f,
-0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x73,0x8f,0xf2,0x6f,0xff,0xfe,0x94,0x3f,0xff,
-0xff,0xff,0x7d,0x9f,0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x9e,
-0xff,0xfc,0xef,0xd3,0xfb,0xff,0x7f,0xf5,0x5f,0xfe,0x59,0xff,0xff,0xff,0xfc,0xf1,
-0xfe,0x7f,0xff,0xff,0xfa,0x17,0xff,0xe7,0xef,0xef,0xff,0xff,0x3f,0xf1,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xfc,0xea,
-0xff,0xf0,0xff,0xff,0xbf,0xf9,0x3f,0xb1,0xef,0xff,0xd7,0xff,0xfb,0xff,0xf0,0xff,
-0xff,0xf3,0xff,0xdf,0xff,0x7b,0xff,0xfd,0xff,0xf6,0xff,0xbf,0xff,0xff,0xbf,0xff,
-0xff,0xff,0xda,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x01,0x00,0x00,0x02,0x02,
-0x02,0x02,0x00,0x40,0x40,0x40,0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0x00,0x00,
-0x00,0x00,0x00,0x00,0x19,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
-0x00,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfb,0xff,0xfd,0xff,
-0xff,0x7f,0xff,0xff,0xbf,0xff,0xef,0xff,0xff,0xfd,0xff,0xff,0xf1,0xff,0xdf,0xff,
-0xff,0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xdf,
-0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xdf,0xff,0x7f,0xff,0xff,0xff,0xff,
-0xdf,0xdf,0xff,0xef,0xff,0x9e,0xef,0xff,0xff,0x7f,0xff,0xf1,0xef,0xff,0xff,0xff,
-0xf7,0xfa,0xbf,0xff,0xff,0xfe,0x47,0xef,0xff,0xbd,0xf6,0xff,0xff,0xdf,0xf5,0xf0,
-0xf0,0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x01,0x02,0x08,
-0x16,0x00,0x00,0x00,0x80,0x00,0x01,0x02,0x00,0x80,0x01,0x0c,0x02,0x00,0x00,0x01,
-0x00,0x00,0x20,0x00,0x00,0x06,0x00,0x20,0x00,0x10,0x00,0x14,0x00,0x04,0xc1,0xf0,
-0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,
-0xec,0xff,0xff,0xfa,0xff,0xbf,0xff,0x6f,0xff,0xe1,0xff,0xff,0xff,0xff,0xbd,0xfe,
-0x46,0xff,0xef,0x7f,0xcd,0xdf,0xff,0xff,0xfd,0xff,0xbd,0xff,0x7f,0x7f,0xf0,0x4f,
-0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa4,0xbc,0xcd,0x6d,0x6b,0x6f,0x5b,0xdc,0x33,
-0x5a,0xf6,0xf7,0xf6,0xb3,0x3f,0xbd,0xc1,0xfa,0x5a,0xf6,0xf6,0xb6,0xf7,0xff,0xbd,
-0xbb,0x3c,0xce,0xcf,0x34,0xef,0x33,0xbb,0xcc,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,
-0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xd6,0xff,0xfd,0xfd,0xbf,0xff,0xad,
-0xbf,0xf9,0x7f,0x6f,0xfc,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0xff,0xda,0xdb,0xfc,
-0xdb,0xff,0x76,0x8f,0xf6,0xff,0xcd,0xab,0xfe,0xfb,0xff,0xd0,0xff,0xff,0xff,0xff,
-0xfe,0xff,0x9f,0xff,0xf4,0x20,0xaf,0x6d,0x0b,0xc1,0x7b,0xff,0xff,0xff,0xcb,0xff,
-0x3f,0xf0,0xef,0x7f,0x0f,0xf1,0xc3,0x3c,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x0b,
-0x1d,0x6a,0x64,0x05,0x6b,0x99,0x01,0xff,0xfd,0xef,0xf0,0x2f,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xf4,0x00,0x2f,0xcc,0x0b,0xc3,0x7f,0xff,0xff,0xff,0x0a,0xdf,0xbf,
-0xfd,0x7f,0xff,0xff,0xf1,0xc3,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x4a,0x0e,
-0x96,0x64,0x02,0x97,0x99,0x10,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xfe,0x84,0xf9,0xd5,0x27,0xf1,0x7f,0xff,0xf8,0xeb,0xdf,0xf3,0xcf,0x3f,
-0x1f,0xff,0xf7,0x11,0xff,0xcf,0xff,0xfe,0x67,0xff,0xff,0xff,0xff,0xc4,0xff,0xff,
-0xb3,0xa1,0xff,0xf9,0xe0,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,
-0xff,0xfb,0x7f,0xe0,0xff,0xc7,0xfe,0x7f,0x3f,0xff,0xfd,0x77,0x8d,0x7f,0x0f,0xff,
-0xc3,0xff,0xf1,0xbf,0x8f,0xcf,0xff,0xff,0xdd,0x7b,0xff,0xf6,0xfa,0xf7,0xff,0x40,
-0x9f,0xf9,0x7f,0xd8,0xff,0xff,0xfa,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,
-0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x00,0x10,
-0x00,0x01,0x00,0x10,0x20,0x20,0x00,0x00,0x10,0x00,0x04,0x01,0x05,0x00,0x00,0x00,
-0x00,0x40,0x40,0x00,0x00,0x3c,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,
-0xff,0xff,0xfe,0x7f,0x7f,0xff,0xef,0xff,0xff,0xdf,0xff,0xff,0xdf,0xff,0xef,0xf7,
-0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xfc,0xfd,0xff,0x7f,
-0x7e,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0xff,0xff,
-0xff,0xff,0xfe,0xeb,0xfd,0x6f,0xff,0xf7,0xfe,0xf5,0x7f,0xff,0xff,0x7f,0xbf,0xb1,
-0xff,0xff,0x9f,0xbf,0xfb,0xff,0xfe,0xff,0xfe,0xff,0xf7,0xeb,0xdf,0xbf,0x5f,0xdd,
-0xff,0xdb,0xfd,0xd0,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x00,0x42,0x00,
-0x00,0x00,0x30,0x18,0x04,0x08,0x09,0x21,0x82,0x80,0x02,0x00,0x08,0x00,0x01,0x00,
-0x00,0x00,0x0c,0x20,0x10,0x00,0x11,0x00,0x44,0x84,0x00,0x20,0x20,0x84,0x80,0x00,
-0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xf7,0xff,0xfb,0xdd,0xf9,0xff,
-0xda,0xff,0xdc,0xdd,0xfc,0xfb,0xff,0xbf,0xfb,0x3e,0xd7,0x96,0xfe,0x61,0xf7,0xff,
-0x7f,0xff,0x3f,0xfd,0xff,0xdf,0xcf,0xf7,0xdf,0xf7,0xbf,0xfd,0xff,0xfe,0xef,0xef,
-0xfe,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf3,0xbd,0xfd,0x4b,0x74,0xcf,
-0x73,0x5b,0xcb,0x3b,0xdf,0xfe,0xf7,0xfe,0xd3,0x75,0xac,0xa1,0xfb,0xdf,0xfe,0xf7,
-0x76,0x96,0xb5,0x24,0xbd,0xa5,0xad,0x49,0x2f,0x69,0x2b,0x52,0x5b,0xbd,0xff,0xff,
-0xf0,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0xff,0xcc,
-0xa7,0xfb,0xad,0xff,0x7f,0x6f,0xff,0x6d,0x7f,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,
-0x6f,0xff,0xdb,0xff,0xdb,0xff,0xf6,0x97,0xf6,0xff,0xb5,0xb5,0xff,0xff,0xff,0xd0,
-0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa5,0xbc,0x43,0xfc,0x7c,0x03,0xe7,
-0xff,0xff,0x20,0xff,0xff,0xff,0xcc,0xfd,0x7d,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,
-0xba,0x56,0x66,0x6a,0xad,0x9a,0xa9,0x9a,0x97,0xa5,0xaa,0xbb,0xff,0xff,0xf0,0x0f,
-0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xfd,0xf7,0xfd,0x43,0xff,0xfd,0x6b,0xe7,0xff,
-0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0x3f,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,0xb5,
-0xa6,0x66,0x6a,0xad,0x9a,0xa9,0x99,0x6b,0x5a,0xaa,0xff,0xff,0xb7,0xf0,0x3f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x9c,0xf7,0xfd,0xd2,0x41,0xff,0xff,0xf2,0x7f,
-0x8f,0xff,0xff,0x3d,0xf3,0xff,0x17,0xf1,0xff,0xff,0xff,0xff,0xff,0x7f,0xdf,0xfc,
-0x8f,0x38,0xff,0xef,0x23,0xff,0xfb,0xf7,0xc8,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,
-0xff,0xfe,0xf5,0x7f,0xff,0xfd,0xff,0xe4,0xff,0xeb,0xff,0xcf,0xbf,0xfa,0xff,0xab,
-0xef,0xff,0xfb,0xff,0xf3,0xfd,0x61,0xff,0xff,0xff,0xff,0xfa,0xff,0xfb,0xfd,0x0d,
-0xff,0xfe,0xff,0x43,0x7f,0xfe,0xbf,0xd0,0xfd,0xff,0xfa,0xf0,0x3f,0xff,0xff,0xff,
-0xfe,0xf3,0xc0,0x00,0x00,0x00,0x02,0x00,0x02,0x01,0x00,0x60,0xc0,0x40,0x00,0x00,
-0x00,0x00,0x34,0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x00,
-0x00,0x03,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x3c,0xf0,0x3f,0xff,0xff,0xff,0xfe,
-0xfd,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfd,0xff,
-0xff,0xff,0xff,0xfe,0xfe,0x5f,0xff,0xff,0xcb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,
-0xff,0xff,0xfd,0xff,0xef,0xe3,0xde,0xee,0xd9,0xc5,0x93,0xff,0xff,0xfe,0xfe,0xff,
-0xfb,0xee,0xfe,0xf1,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xbf,0xf7,0xff,0xff,0x7f,
-0xaf,0xbd,0xdf,0xdf,0xfb,0xf3,0xf3,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x34,
-0x00,0x06,0x61,0x00,0x18,0x01,0xa0,0x05,0x17,0x00,0x20,0x05,0x28,0x20,0x00,0x00,
-0x05,0x00,0x41,0x00,0x00,0x40,0x00,0x09,0x00,0x01,0x20,0x86,0x82,0x08,0x40,0x03,
-0x80,0x30,0x70,0x08,0x14,0x02,0xc1,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
-0xff,0xff,0xbd,0xef,0xfb,0xff,0xff,0xfb,0x9c,0x7f,0xef,0xdf,0xff,0xbf,0xeb,0xde,
-0xff,0xc1,0x7f,0xff,0xfb,0x7f,0xff,0xff,0xff,0x5f,0xff,0xff,0xff,0xdf,0xbf,0xef,
-0x3f,0xf7,0x8f,0xef,0x7f,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbd,
-0xdf,0xef,0x7d,0x6d,0x2b,0x5a,0x5d,0xd2,0xdf,0xf6,0x92,0xb6,0xb2,0xb3,0xac,0xa1,
-0xfb,0xdf,0xfe,0xf1,0xee,0xf5,0xf6,0xbc,0x6b,0xbd,0x7d,0xaf,0x1a,0xef,0x5f,0x6b,
-0xc6,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,
-0xf6,0xff,0xf6,0xb7,0xfd,0xad,0xfd,0xbf,0xf3,0x6f,0xff,0x6f,0xff,0xdb,0xd1,0xfd,
-0xbf,0xff,0x6f,0xf5,0x6b,0xbc,0x5b,0x3c,0xda,0xef,0x16,0xaf,0x16,0xff,0xcd,0xab,
-0xff,0x6f,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xbf,0xff,0xff,
-0xff,0x6c,0x03,0x10,0xc1,0xf3,0xff,0xf3,0x3a,0xf3,0xca,0xff,0xaf,0xf1,0xff,0xff,
-0xff,0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,
-0xff,0x5f,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,
-0xea,0x0f,0x50,0xc3,0xf3,0x7f,0xff,0xf3,0xf3,0xc3,0xff,0xaf,0xf1,0xff,0xff,0xff,
-0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,0xff,
-0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xd7,0xff,0xff,0x5f,0xc1,
-0x3f,0xf7,0x5e,0xf5,0xce,0x9e,0x5f,0x3f,0x17,0xff,0xf3,0xe1,0xff,0xff,0xff,0xff,
-0xd8,0xff,0xfa,0xfe,0x67,0xff,0xfe,0xbf,0x5a,0xff,0xff,0xaf,0xf5,0xff,0xff,0xff,
-0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfd,0xff,0xf7,0xff,0xfd,0x4e,0x3d,
-0x3f,0xe7,0x0b,0xbf,0x8f,0xf9,0xff,0xeb,0xe3,0xff,0xe1,0xff,0xff,0xfc,0xff,0xc7,
-0x9f,0xff,0x3e,0x39,0xe5,0xff,0xcf,0x9b,0xf9,0xff,0xff,0xc5,0xff,0xff,0xfa,0xf0,
-0x5f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
-0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x20,
-0x00,0x01,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xf0,0x4f,
-0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xbf,
-0x3f,0xff,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf1,0xff,0xff,0xff,0xff,0xf7,0xff,0xf7,
-0xff,0xed,0xff,0xfb,0xfe,0xff,0x7f,0xff,0x7f,0xdf,0xff,0xff,0xdd,0xf0,0x3f,0xff,
-0xff,0xff,0xfe,0xf0,0xff,0xff,0xf3,0xff,0xf7,0xff,0xfe,0x5f,0xff,0xf7,0xff,0xff,
-0xdf,0xff,0xff,0xff,0xf7,0xfe,0x7b,0xf1,0xff,0xfd,0xfd,0xff,0xdf,0xdf,0xff,0x7d,
-0x73,0xf9,0xff,0xc3,0x7e,0xfe,0xff,0xef,0xd7,0xff,0xcf,0xd0,0xf0,0x6f,0xff,0xff,
-0xff,0xfe,0xf8,0x30,0x00,0x00,0x40,0x04,0x00,0x01,0x41,0x20,0x00,0x04,0x00,0x02,
-0xd5,0x09,0x00,0x02,0x80,0x02,0x01,0x00,0x00,0x00,0x0a,0x04,0x00,0x07,0x00,0x01,
-0x50,0x01,0x80,0x02,0x61,0x40,0x41,0x0c,0x14,0x08,0xc1,0xf0,0x9f,0xff,0xff,0xff,
-0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xdf,0xcb,0x5f,0xfe,0xef,0xff,0xfe,
-0xff,0x3f,0xff,0x7f,0xfd,0xc1,0xff,0xff,0x7f,0xff,0xdf,0xfd,0xfc,0xfd,0xf7,0xee,
-0xff,0xff,0x4e,0xff,0xdf,0xcf,0xdb,0xeb,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0x7f,
-0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,
-0xf7,0xfb,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0x7f,0xff,0xff,0xff,0x7f,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdd,0xff,
-0xff,0xff,0xa5,0xff,0x6f,0x6b,0xe9,0x6f,0xda,0xca,0xfb,0xdd,0xee,0xf7,0xf6,0xb2,
-0xb3,0xa4,0xa1,0x5b,0x5b,0xf6,0xd7,0xf4,0xf7,0x7b,0xbd,0xbd,0xad,0xcf,0xef,0x7f,
-0x6b,0x7f,0x3b,0xdf,0xdb,0xff,0xff,0x30,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,
-0xff,0xff,0xff,0xf6,0xfe,0x96,0xff,0xfd,0xb5,0xfd,0xbf,0xad,0x7f,0xff,0x6f,0xff,
-0xde,0xd1,0xad,0xad,0xe9,0xff,0xf1,0xec,0xef,0xde,0x3f,0xcb,0xff,0xf6,0xff,0x32,
-0xff,0xc5,0xbd,0xff,0xff,0xff,0xd0,0xbf,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xf4,
-0x28,0xbf,0xff,0xfd,0xfb,0xd3,0xff,0xff,0x42,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,
-0xc1,0xff,0x33,0xff,0xc0,0x15,0x6b,0x70,0xff,0xf0,0xf2,0x4f,0xff,0xfc,0x3e,0x97,
-0x3c,0xff,0xff,0xfd,0xef,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x78,
-0xbf,0xff,0xfd,0xf3,0xef,0x55,0xff,0x7e,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,0xc1,
-0xff,0x33,0xff,0xc0,0x15,0x6f,0xff,0x0f,0xf0,0xf0,0x0f,0xff,0xfc,0x3d,0x6b,0xc3,
-0xff,0xff,0xfe,0xf7,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,
-0xff,0x23,0xf8,0x7f,0xff,0x4e,0xff,0xff,0xff,0xfb,0xf9,0x17,0xff,0xf6,0xf1,0xff,
-0xcf,0xef,0xff,0xff,0x13,0xdf,0xe6,0x2f,0xc7,0xff,0xff,0xe7,0xc1,0xfd,0xff,0xfe,
-0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xfe,0xae,0xff,
-0xff,0x7f,0x3b,0x3f,0xfc,0x7f,0xfc,0xef,0xff,0xfc,0xe2,0x7b,0xff,0xf1,0xfd,0xed,
-0xef,0xff,0xff,0x35,0x73,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,
-0xff,0xfa,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x00,0x0c,0x04,0x01,0x40,0x40,0x00,
-0x00,0x30,0x28,0x04,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,
-0x38,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xfb,0xff,0x7f,
-0xff,0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xdf,0xdf,0xff,
-0xff,0xff,0xff,0xed,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xbf,0xbf,0xff,0xff,0xc3,
-0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xfd,0xff,0xbf,0xff,0xff,0xfd,0xff,0xff,
-0xff,0xff,0xff,0xfd,0x7b,0xff,0x7f,0xff,0xbd,0xff,0xf1,0xef,0xff,0xff,0xfd,0xdf,
-0xfd,0xfb,0xff,0xff,0xbf,0xbe,0xff,0xcd,0x7f,0xfc,0xf7,0xf7,0x6f,0xbf,0xd8,0xf0,
-0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x00,0xa0,0x00,0x00,
-0xc0,0x00,0x00,0x20,0x34,0x00,0x00,0x00,0x0c,0x81,0x00,0x20,0xa4,0x20,0x00,0x10,
-0x08,0x04,0x48,0x08,0x00,0x40,0x93,0x00,0x10,0x00,0x38,0x18,0x20,0xc1,0xf0,0x3f,
-0xff,0xff,0xff,0xfe,0xff,0xfb,0xff,0xff,0xb9,0xdf,0xfe,0xb3,0xff,0xff,0xe7,0xfd,
-0xff,0xff,0x3b,0xff,0x7f,0xff,0xbf,0xff,0xc1,0xff,0xfc,0xff,0xff,0x3f,0x77,0xfe,
-0xfe,0xcf,0xff,0xbf,0xfd,0xbf,0xff,0xfe,0xed,0xf2,0xfd,0xf7,0xff,0xf0,0x2f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,
-0xff,0xfe,0xff,0xff,0xff,0xf3,0xad,0xcf,0xef,0x70,0xc9,0x73,0x3b,0xdf,0x5b,0x4a,
-0xf6,0xb7,0xfe,0xd7,0xf5,0xbc,0xc1,0x33,0xca,0xd6,0xb7,0x6e,0xf7,0xfb,0xbd,0xc5,
-0x24,0xcf,0x6f,0x2f,0x4d,0x2b,0xba,0x5a,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,
-0xfe,0xbf,0xff,0xff,0xff,0xff,0xf6,0xf6,0xd7,0xff,0xff,0xad,0xbd,0xff,0xff,0xff,
-0xef,0xf7,0x7f,0xfc,0x5b,0xb1,0xfd,0xbd,0x75,0x6f,0xef,0x6a,0xfd,0x5b,0xfb,0xdb,
-0x3a,0xbf,0x8e,0x9f,0xff,0xbf,0xfd,0xff,0x6f,0xff,0xd0,0x6f,0xff,0xff,0xff,0xfe,
-0xff,0xbb,0xff,0xf0,0x3f,0xff,0xff,0xfd,0xfb,0x7f,0xde,0xff,0xff,0x5a,0xd6,0xbf,
-0xd8,0x2a,0xbf,0xbf,0xf1,0xe5,0xff,0xcc,0xc0,0xa9,0x70,0xff,0xf3,0x3c,0x3c,0xfd,
-0x57,0xfd,0x98,0x03,0x00,0xc3,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xff,0x3d,0xbf,0xff,0xfd,0xfb,0xff,0xdb,0xff,0xff,0x0f,0xfc,0x3f,0xd8,
-0x2a,0xbf,0xbf,0xf1,0xef,0xff,0xcc,0xc0,0x96,0xbe,0xff,0xf3,0x3f,0xff,0xfd,0x57,
-0xfd,0x99,0x0f,0xff,0xc3,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,
-0xff,0xf1,0xe7,0xff,0xff,0xf3,0x8e,0x7b,0xff,0xa8,0xff,0xdf,0x7f,0x8e,0x78,0x73,
-0xff,0xf1,0x51,0x62,0xff,0xfc,0x4b,0xff,0xf3,0xff,0x7e,0xcf,0xf9,0xff,0xfd,0xff,
-0xff,0x7f,0xff,0xe0,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,
-0xfb,0xfd,0xae,0xff,0xfc,0xfe,0x6f,0x3f,0xf8,0xfd,0x77,0xaf,0xfe,0x37,0xfe,0x7b,
-0xff,0xb1,0x8c,0xff,0xef,0xfd,0xf8,0xe7,0xbf,0xff,0xf1,0xfe,0x3e,0xf7,0xfe,0x95,
-0x3e,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,
-0x01,0x04,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x08,
-0x41,0x80,0x10,0x00,0x00,0x08,0x10,0x84,0x00,0x0c,0x04,0x02,0x61,0x00,0x00,0x81,
-0x00,0x00,0x00,0x00,0x3d,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,
-0xff,0xff,0x7f,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
-0x7f,0xbf,0xf7,0x7f,0xef,0xff,0xef,0xff,0xf7,0xfd,0xff,0xff,0xfd,0x7f,0xff,0xbe,
-0xdf,0xff,0xff,0xd9,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0x7f,0xfb,0xff,
-0xfb,0xff,0xbf,0xff,0xf3,0x7f,0xfb,0xfd,0xeb,0x7f,0xdf,0xfa,0xff,0xde,0xf0,0xed,
-0xff,0xb1,0xf7,0xf9,0x1f,0xb5,0x5b,0xfe,0x7e,0xf7,0xbe,0xfd,0x7f,0x5f,0xb5,0xf7,
-0xff,0xff,0xd0,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x01,0x00,0x07,0x42,0x01,
-0x00,0x6a,0x18,0x50,0x80,0x00,0x00,0x02,0x40,0x01,0x01,0x20,0x01,0x01,0x24,0x14,
-0x21,0x10,0x02,0x08,0x07,0x08,0x00,0x40,0x10,0x80,0x58,0x00,0x84,0x80,0x18,0x10,
-0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xff,0xdb,0xb7,0xf3,
-0xdf,0x7c,0xf8,0x74,0xff,0xff,0x6f,0x7d,0x3f,0x7e,0xec,0x7f,0xc1,0xf5,0xff,0xcf,
-0x6f,0x9f,0xf9,0xdf,0xbe,0xe5,0xe7,0xff,0xd7,0xf3,0xdd,0xfb,0xff,0xfc,0xff,0xbf,
-0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xf0,0x2f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xff,0xb4,0xcf,0xef,0x77,0x6f,0x73,
-0x3a,0x4a,0x3a,0xcb,0xd4,0xf7,0x2e,0xd6,0xbd,0xbd,0xa1,0x3b,0xdf,0xd6,0xf7,0xee,
-0xd3,0x35,0xbd,0xfb,0xbd,0xce,0xeb,0x2b,0x4d,0x2f,0xbb,0xda,0xff,0xff,0xfe,0xb0,
-0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdf,0x5f,0x36,0xaf,0x3f,0xed,0xb7,
-0xf5,0xfd,0xf3,0x2b,0xef,0x77,0xff,0xfb,0xda,0xb1,0xbd,0xa3,0x77,0x69,0x7f,0x4f,
-0xff,0xdb,0xfa,0x5b,0xff,0xf2,0xfe,0xff,0x96,0xff,0xff,0xfe,0xdf,0xff,0xd0,0xaf,
-0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x8f,0xfd,0x40,0x6f,0x9e,0x83,0x5a,0x0f,
-0xfa,0xc3,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xd0,0x00,0xfe,0xbf,0xcd,0x3f,0xf0,
-0xef,0xfc,0xc5,0x0c,0x3f,0xfd,0x68,0x0b,0xff,0xff,0xff,0xfe,0xdf,0xf0,0xff,0xff,
-0xff,0xff,0xfe,0xff,0xbb,0xff,0xfd,0x85,0xff,0xd4,0x6f,0x9f,0xc3,0x5a,0x0f,0xff,
-0xff,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xf0,0xfb,0xc2,0xbf,0xfc,0x00,0x37,0xef,
-0xfc,0xcd,0xbc,0x3f,0xff,0x0c,0xbf,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,
-0xff,0xfe,0xff,0xff,0xff,0xff,0xd9,0xf7,0xd1,0xb7,0x7e,0x7f,0xf1,0xe4,0xfd,0xff,
-0xfb,0xfb,0xff,0x5f,0xff,0x7f,0xb1,0xbc,0x0f,0x67,0xeb,0xb8,0x3f,0xff,0xe2,0xff,
-0xe9,0xff,0xfd,0xe3,0xff,0x3f,0x9f,0xc2,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,
-0xfe,0xf5,0x7f,0xff,0xf0,0x3f,0xbc,0xff,0xd5,0xf5,0xce,0x3f,0xfe,0xff,0xfe,0x6d,
-0xff,0xf1,0xbf,0x7b,0xff,0xf1,0xfd,0xff,0x4f,0xff,0x87,0xff,0xae,0xff,0xb1,0xf8,
-0xfe,0xff,0xff,0x78,0x01,0xb9,0xff,0xff,0xff,0xfa,0xf0,0x2f,0xff,0xff,0xff,0xfe,
-0xf3,0xc0,0x00,0x00,0x00,0x04,0x02,0x13,0x02,0x00,0x80,0x40,0x00,0x90,0x10,0x00,
-0x10,0x00,0x02,0x00,0x01,0x20,0x80,0x12,0x10,0x00,0x40,0x08,0x00,0x04,0x00,0x00,
-0x02,0x00,0x01,0x40,0x00,0x80,0x00,0x00,0x3c,0xf0,0xef,0xff,0xff,0xff,0xfe,0xfd,
-0x1f,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xf7,0xdf,0xf7,0xff,
-0xf7,0xfb,0xeb,0xd1,0xff,0xff,0xff,0xff,0xef,0xf7,0xff,0xff,0xfb,0xff,0xfe,0xff,
-0xff,0x7e,0xff,0xfb,0xff,0xff,0xff,0xdb,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf0,0xff,
-0xff,0xb7,0xeb,0xf7,0xdf,0xff,0xfe,0xf5,0x6b,0xe7,0xed,0xf7,0x3e,0xec,0xff,0x54,
-0xef,0x6f,0xf1,0xf5,0xaf,0x6f,0xf6,0xfd,0xff,0xdd,0x7b,0xff,0xef,0xbf,0x7f,0xff,
-0xff,0xf7,0xff,0xf3,0x5f,0xf7,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,
-0x80,0x40,0x04,0x00,0x81,0x2c,0x04,0x24,0x00,0x02,0x01,0xc8,0x02,0x00,0x02,0x24,
-0x00,0x01,0xb4,0x42,0xdc,0x44,0x02,0x15,0x90,0x02,0x03,0x48,0x39,0x10,0x02,0x24,
-0xa0,0xba,0x00,0x00,0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
-0xfe,0xfc,0xf7,0xf0,0xee,0xb6,0x5d,0xfd,0xf5,0xff,0xdb,0xf7,0x7f,0x7f,0xbe,0xff,
-0xc1,0xfe,0xbf,0xfa,0xfa,0x5f,0xff,0xad,0xff,0xef,0xff,0x7f,0xdf,0x7f,0xfe,0xbf,
-0xb7,0x94,0xbf,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xfb,0xb5,0xff,
-0xef,0x7c,0xeb,0x2b,0x52,0x5b,0x3b,0xda,0xd4,0xf3,0x36,0x96,0xb5,0xbd,0xf1,0xfb,
-0xda,0xee,0xf6,0xfe,0xd3,0x35,0xbd,0xdf,0xad,0xcf,0xef,0x7e,0xcd,0x6b,0xbb,0xdf,
-0xff,0xff,0xfd,0xb0,0xef,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xd3,0x5f,0xf6,
-0xff,0xf6,0xff,0xfd,0xad,0xfd,0xff,0x7f,0xef,0xff,0x6f,0x7f,0xdb,0xf1,0xa5,0xa3,
-0x7f,0x6f,0x6b,0x4f,0xff,0xdb,0xfb,0xcb,0xff,0xf6,0xff,0xf4,0xd7,0xfd,0xbf,0xfe,
-0xdf,0xff,0xd0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdf,0xff,0xff,0xff,
-0x3f,0x7f,0xfc,0xe5,0xff,0x20,0xfe,0xff,0xff,0xdf,0x7f,0xff,0xf1,0x7f,0xff,0xfe,
-0xff,0xf0,0x7c,0x3d,0x4f,0xf3,0xc3,0x3f,0xff,0xff,0x6f,0xc3,0xff,0x0f,0xff,0xff,
-0xaf,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0xb7,0xe0,0x0f,0xff,0xff,0x2b,
-0xff,0x7d,0xbf,0xff,0xdf,0xff,0xff,0xf8,0x9f,0x7f,0xff,0xf1,0x55,0xff,0xff,0xff,
-0xfd,0x7c,0x3c,0xff,0xf3,0xc3,0x3f,0xff,0xff,0xef,0xc3,0xff,0xdf,0xff,0xff,0xff,
-0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0x9f,0xbf,0x7f,
-0xf9,0x19,0x47,0x8e,0xe7,0x9f,0x3f,0x17,0xff,0xfc,0x81,0xc1,0x7e,0xf3,0xd9,0xf9,
-0x73,0xdf,0xf4,0x7f,0xfa,0xff,0xff,0xff,0xfb,0x7f,0x77,0xc7,0xff,0xff,0xff,0xf0,
-0x2f,0xff,0xff,0xff,0xfe,0xf5,0xf7,0xff,0xfb,0xff,0xf7,0x3f,0xfc,0xbf,0x3e,0x3f,
-0xec,0xff,0x81,0xaf,0xfe,0x4f,0xf3,0xbb,0xff,0xf0,0x7e,0xff,0x6f,0xff,0x87,0xff,
-0xbb,0xff,0xd5,0xfc,0xff,0x7f,0xfc,0x6f,0xff,0xef,0xe7,0xff,0xff,0xfa,0xf0,0x3f,
-0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
-0x00,0x30,0x10,0x60,0x20,0x00,0x08,0x00,0x01,0x20,0x80,0x00,0x10,0x00,0x04,0x00,
-0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x80,0x40,0x00,0x08,0x20,0x3c,0xf0,0x6f,0xff,
-0xff,0xff,0xfe,0xf5,0xbf,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x7f,0xfe,0x3f,0xff,
-0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xf1,0xdf,0xdf,0xff,0xff,0xff,0x7f,0xdf,0xff,
-0xfd,0xbd,0xff,0xff,0xff,0xfb,0xdf,0xff,0xff,0xff,0xff,0x5b,0xf0,0xff,0xff,0xff,
-0xff,0xfe,0xf0,0xbf,0xbf,0xbf,0xff,0xf7,0xfb,0xff,0xfe,0xee,0xfa,0xff,0xff,0xff,
-0x3d,0x3b,0xff,0xff,0xfe,0xfb,0xf1,0xff,0xbf,0x7b,0xff,0xff,0xef,0xff,0xbf,0xff,
-0xff,0xff,0xff,0xff,0xfe,0xff,0xf7,0xef,0xff,0xfb,0xd0,0xf0,0xdf,0xff,0xff,0xff,
-0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x00,0x0b,0x10,0x05,0x01,0x00,0x08,0x00,0x02,
-0x01,0x01,0x00,0x00,0x10,0x01,0xc8,0x08,0x00,0x00,0x00,0x00,0x42,0x02,0x00,0x00,
-0x00,0x80,0x02,0x00,0x00,0x40,0x24,0x80,0x00,0xc1,0xf0,0x3f,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0xf7,0xfd,0xf7,0xfa,0xef,0xee,0xf9,0xfd,0xff,0xf7,0xfe,0xbf,
-0x1f,0xfd,0x9e,0xfd,0xd1,0xef,0xff,0xf7,0x7f,0x9f,0xff,0xef,0xff,0xf6,0xff,0xfe,
-0xfe,0x7b,0xff,0xbd,0xff,0x7e,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,0xff,
-0xff,0xf7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xdf,0xfd,0xff,0xff,0xdf,0xff,
-0xff,0x5f,0xf1,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xef,0xff,
-0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfb,0xff,0xff,0xef,0xfb,0xfd,
-0xff,0xf1,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf7,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xe7,0xff,
-0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0xfb,0xff,0xfb,0xf1,
-0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7b,0xff,0xff,0xff,0x7f,0xff,0xf1,0xff,
-0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x57,0xff,0xfe,0xbf,0xfb,0xf1,0xff,0xff,
-0xfd,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xd7,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd,
-0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xef,0x2f,0xf1,0x3c,0xbf,0xbc,
-0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff,
-0x01,0xe2,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff };
diff --git a/drivers/net/hamradio/yam9600.h b/drivers/net/hamradio/yam9600.h
deleted file mode 100644 (file)
index 5ed1fe6..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- *
- * File yam111.mcs converted to h format by mcs2h
- *
- * (C) F6FBB 1998
- *
- * Tue Aug 25 20:23:03 1998
- *
- */
-
-static unsigned char bits_9600[]= {
-0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xfb,0xcb,0xff,0xdb,0xfe,0xf2,
-0xff,0xf6,0xff,0x9c,0xbf,0xfd,0xbf,0xef,0x2e,0x3f,0x6f,0xf1,0xfd,0xb4,0xfd,0xbf,
-0xff,0x6f,0xff,0x6f,0xff,0x0b,0xff,0xdb,0xff,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff,
-0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdf,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,
-0xfb,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0x7f,0xf1,0xff,0xfe,0xff,0xbf,0xbf,
-0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xf0,
-0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xf7,
-0xff,0xff,0xf7,0xef,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0x7e,0xff,0xff,
-0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0xdf,
-0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xef,0xff,0xf3,0xfb,0xfe,0xff,0xf1,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xdf,0xff,0xf0,0x7f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff,
-0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,
-0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xef,0xff,0x7f,0xff,0xef,
-0xff,0xef,0xff,0x7f,0xef,0xf1,0xff,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xff,0xbd,0xff,0xef,0x7f,0xef,0x7f,0xfb,0xdf,0xd3,0x5a,0xfe,0xd7,0xd6,
-0xf7,0x7f,0xbd,0xf1,0xbb,0x5d,0xd6,0xf7,0xfe,0x96,0xff,0xbd,0xaf,0xad,0xbf,0xef,
-0x7f,0x6b,0x7f,0xfb,0xd6,0xfe,0xf7,0xff,0x10,0xef,0xff,0xff,0xff,0xfe,0xbe,0xef,
-0xff,0xff,0xdb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xbf,0xff,0x7f,0xff,0x7f,
-0xdf,0xdb,0xf1,0xfd,0x35,0xff,0x6f,0xff,0x6f,0xff,0xdb,0xff,0xcb,0xff,0xf6,0xff,
-0xf2,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,
-0xff,0xf1,0x24,0xf0,0xff,0xff,0xcf,0xef,0x3f,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,
-0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,0xff,
-0xf1,0x00,0xf0,0xff,0xff,0xcf,0xdf,0xff,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,0xff,
-0xff,0xff,0x7d,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfe,0x7f,0xdf,0xff,0xff,0xff,0xf1,
-0xff,0xcf,0xff,0xf3,0xff,0x97,0xff,0xff,0x8f,0xe7,0xff,0xff,0xfc,0x71,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xf7,0xef,0xff,0xff,0xfc,0x7b,0xff,0xf1,0x3f,
-0xff,0xef,0xff,0xcf,0xe3,0xe3,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xbf,0xff,
-0xbf,0xff,0xda,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
-0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0x9f,0xff,
-0xff,0xff,0xf7,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xdb,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xdf,0xbf,0xf1,0xfe,0xfd,0xf7,0xff,
-0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xfd,0xf2,
-0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
-0x00,0x00,0x00,0x02,0x00,0x90,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x04,0x24,0x00,
-0x40,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0xc0,0xf0,
-0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xbf,0xff,0xff,0x6f,0xff,0xdf,0xff,0xd1,0xff,0xfe,0xff,0xff,0xff,0xff,
-0xff,0xff,0xdf,0xff,0xfb,0xff,0xfb,0xef,0xff,0xff,0xee,0xff,0xff,0x7f,0xf0,0xdf,
-0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xad,0xff,0x69,0x2a,0xed,0x6b,0xfb,0xdf,0x3a,
-0xdc,0xf4,0x96,0xee,0xb3,0x3d,0x35,0xc1,0xbb,0xdd,0xfe,0xf6,0xfe,0xd6,0xb5,0xad,
-0xbf,0xa5,0xad,0x49,0x2f,0x4f,0x2b,0xda,0x5f,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,
-0xff,0xfe,0xbf,0xff,0xff,0xfb,0x5b,0xf7,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xa5,
-0xf3,0x6f,0xf3,0x6e,0xfa,0x7b,0xd1,0xfd,0xb5,0x77,0x6f,0xe9,0x6f,0xff,0xdb,0xfb,
-0xdb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0x3f,0xfe,0xf7,0xff,0xd0,0x4f,0xff,0xff,0xff,
-0xfe,0xff,0x9f,0xff,0xff,0x0f,0xff,0xc0,0x3f,0x9c,0x03,0xff,0xff,0x8b,0xa5,0xfe,
-0x80,0x3e,0xc2,0xbf,0xac,0xb1,0x24,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xa3,
-0xff,0xfd,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0x0f,0xff,0xc0,0x3f,0xd4,0x6b,0xff,0xff,0xdb,0xff,0xfe,0x86,
-0xbf,0xc2,0xbf,0x30,0xa1,0x24,0xff,0xff,0xff,0xff,0xcc,0xff,0x0f,0xff,0xa3,0xff,
-0x05,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xfb,0xc7,0xff,0xc4,0xff,0xff,0x7f,0xff,0xec,0xfe,0x7f,0xdf,0xd8,0xb9,
-0x47,0xfc,0x36,0xc1,0xdf,0xff,0xff,0xf9,0xff,0xf3,0xff,0xf7,0xff,0xfc,0xff,0xfd,
-0x3f,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,
-0xff,0xff,0xff,0xfe,0xff,0xff,0x7e,0xbd,0x3f,0xff,0x2b,0xfe,0x2f,0xf5,0xa3,0xfc,
-0x5b,0xfe,0x61,0x9f,0x7f,0xef,0xff,0xff,0xa7,0xfb,0xff,0xff,0xfa,0xfe,0xff,0x33,
-0xf1,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x30,0x24,0x04,
-0x00,0x01,0x00,0x80,0x40,0x00,0x08,0x00,0x00,0x00,0x02,0x01,0x01,0x00,0x02,0x00,
-0x00,0x00,0x00,0x00,0x01,0x3d,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xfd,0xbd,0xff,0xfd,
-0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,0xf6,0xef,0xbf,0xf7,0xff,0x73,0xeb,
-0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xfd,0xfe,0xff,0xff,
-0xff,0xff,0xff,0xff,0xd9,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,0xbf,0x7f,0xff,0xff,
-0xff,0x7f,0xff,0xff,0xde,0xff,0xff,0xef,0xdd,0xde,0x77,0xf2,0xfb,0xed,0xe7,0xf1,
-0x73,0xfd,0xfd,0xdf,0xff,0x7d,0xbe,0xdf,0xff,0xfb,0xff,0xef,0xff,0xef,0xff,0xff,
-0xff,0xff,0xff,0xd0,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x02,0x00,0x22,
-0x40,0xc0,0x00,0x00,0x00,0x08,0x00,0x02,0x41,0x02,0x12,0x00,0x21,0x87,0x81,0x00,
-0x00,0x80,0x04,0x0b,0x28,0x01,0xb0,0x00,0x82,0x00,0x40,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,
-0xf7,0xff,0xfe,0x7f,0xed,0x79,0xff,0xde,0xeb,0x7f,0x74,0xf7,0xf7,0xe1,0xf9,0xff,
-0xf6,0x5f,0x7f,0xff,0xff,0xff,0xd7,0xdb,0xef,0xff,0xbb,0xff,0xff,0xff,0xcc,0xff,
-0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x3d,0xcd,0x49,0x7f,0x6f,
-0x2b,0xba,0x5c,0xd2,0xda,0xf6,0xf3,0x3e,0xf7,0xff,0xbd,0xf1,0xfa,0xdf,0xfe,0xf7,
-0xcc,0xf6,0xbb,0xa5,0xb3,0xad,0xbf,0x6f,0x7d,0x6f,0x6b,0xdb,0xdf,0xbd,0xff,0xfe,
-0xb0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xfb,0xdb,0x57,0xf6,0xfe,0x9f,0xd5,
-0xb7,0xff,0xaf,0xe5,0x3f,0xff,0xff,0x6f,0xff,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0x69,
-0x6c,0xdf,0xda,0xdf,0xcb,0xff,0xf6,0xff,0x76,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,
-0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfd,0xbd,0x08,0x03,0x89,0x4f,0x5a,
-0x0f,0xf0,0xff,0xf8,0xbf,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xf3,
-0xfa,0xa0,0xf0,0xf2,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,
-0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xfd,0x00,0x6b,0xff,0xff,0x5a,0x0f,
-0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xb3,0xf5,
-0x50,0xf0,0xf0,0xff,0xff,0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xbc,0xff,0xe4,0xe7,0x71,0xff,0xf9,0xc4,0xf4,
-0x7f,0x7f,0xcf,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xfb,0xf7,0x73,0xbf,0x14,
-0xff,0xe6,0xff,0xff,0xe1,0x7d,0xff,0xff,0xe7,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,
-0xff,0xfe,0xf5,0xff,0xff,0xfe,0xd2,0xfa,0xff,0xc4,0xf4,0x5c,0xbf,0xfa,0xff,0xff,
-0xec,0x7e,0xbf,0xff,0xff,0xff,0xf1,0xff,0xff,0xef,0xff,0xff,0x6b,0xdb,0xff,0xdf,
-0xf9,0xfb,0xbf,0xff,0xf1,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf0,0xbf,0xff,0xff,0xff,
-0xfe,0xf3,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x00,0x80,0x00,
-0x00,0x00,0x00,0x40,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x20,0x00,0x00,0x00,0x00,
-0x01,0x00,0x01,0x00,0x00,0x80,0x02,0x00,0x01,0x3c,0xf0,0x5f,0xff,0xff,0xff,0xfe,
-0xfd,0xbf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0x7f,0xff,0xdf,0xff,0xef,0xff,
-0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,
-0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xc3,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf0,
-0xff,0xdf,0xff,0xff,0xf7,0x23,0xff,0xff,0xfd,0xff,0xef,0xff,0xfe,0x7f,0x7d,0xf7,
-0xfe,0xff,0x7f,0x71,0xff,0xfb,0x7f,0xff,0xff,0xff,0x6e,0xfd,0xf7,0xfd,0xff,0xbf,
-0xff,0xbf,0xf9,0xfd,0xff,0xdf,0xef,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x30,
-0x40,0x01,0x00,0x83,0x00,0x00,0x00,0x0c,0x06,0x08,0x04,0x26,0x26,0x00,0x00,0x06,
-0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x70,0x08,0x80,0x00,0x20,0x01,0x20,
-0x00,0x02,0x00,0x30,0x00,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
-0xff,0xff,0x7b,0x3f,0xf7,0xff,0xd7,0xfe,0xfe,0xfb,0xfe,0x3b,0xfe,0xbd,0xff,0x2f,
-0xff,0x71,0xff,0xfb,0x7f,0xe7,0xff,0xf9,0xef,0xff,0xd7,0xfa,0xff,0xb7,0xbb,0xfe,
-0xff,0xff,0x74,0xff,0xf7,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xb5,
-0xbd,0x6f,0x7c,0xeb,0x7f,0xfb,0xdb,0xd3,0x4b,0xee,0xd6,0xf6,0xb7,0xfd,0xac,0xa1,
-0xfb,0xdf,0xfe,0xf7,0xf4,0x96,0xbd,0xb4,0xc5,0xa5,0xaf,0x6f,0x69,0x4f,0x7f,0xba,
-0xdb,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,
-0xf6,0xff,0xf6,0xff,0xbd,0xbf,0xa5,0xbf,0xff,0x7d,0x7f,0xef,0xff,0xfb,0xf1,0xfd,
-0xbf,0xff,0x6f,0xff,0x6b,0x7a,0xdb,0xff,0xdb,0xdf,0xf6,0xfe,0xb6,0xfd,0xfd,0xbf,
-0xfe,0xf7,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf4,0x2f,0xff,
-0xfc,0x43,0x6b,0xff,0xff,0xff,0x0d,0xff,0xfc,0x33,0x3f,0xf0,0x5f,0xf1,0xff,0xff,
-0xff,0xff,0xf9,0xde,0xf0,0x4c,0xfe,0x77,0xaf,0xff,0xff,0xef,0xff,0xf0,0xff,0xdb,
-0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xfe,0xf7,0xff,0xf0,0x2f,0xff,0xfd,
-0x43,0x7f,0xff,0xff,0xf1,0x0f,0xff,0xfc,0x33,0x3f,0xff,0xaf,0xf1,0xff,0xff,0xff,
-0xff,0xf6,0xd7,0xff,0xbc,0xfd,0xbd,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,
-0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xfb,0xf1,
-0xbf,0xff,0xf9,0xfd,0xcf,0xf2,0x70,0xff,0x1f,0x9f,0xf3,0xf1,0xff,0xff,0xff,0xff,
-0xfc,0xf7,0xff,0x13,0x9f,0xfc,0xff,0xff,0x84,0xf7,0xff,0xff,0x47,0xff,0xff,0xff,
-0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xf1,0xfc,0xff,0xfe,0xfe,0x79,
-0x3f,0xff,0x1d,0x46,0xcf,0xff,0xcf,0xfc,0x7b,0xff,0xf1,0xff,0xff,0xff,0xff,0xed,
-0xf3,0xab,0xff,0xcb,0xff,0xf8,0xff,0xfc,0xf5,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,
-0x8f,0xff,0xff,0xff,0xfe,0xf3,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
-0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x04,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x20,
-0x0c,0x00,0x00,0x04,0x01,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x01,0x3c,0xf0,0x7f,
-0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfd,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,
-0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xef,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,
-0xff,0xdf,0xff,0xff,0xfb,0xf7,0x7f,0xff,0xfe,0xff,0xff,0xbf,0xdb,0xf0,0xff,0xff,
-0xff,0xff,0xfe,0xf0,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0x7f,0xf7,0xff,
-0xbf,0xbf,0xcf,0xff,0xff,0xff,0x3e,0xf1,0x7f,0xff,0xff,0xef,0xff,0xff,0xff,0xfe,
-0xff,0xfd,0xff,0xbf,0xbd,0xfe,0xff,0xfb,0xf7,0xdf,0xfb,0xd0,0xf0,0x9f,0xff,0xff,
-0xff,0xfe,0xf8,0x30,0x20,0x00,0x40,0x01,0x80,0xc0,0x30,0x00,0x00,0x20,0x00,0x10,
-0x50,0x88,0x20,0x00,0x00,0x13,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,
-0x00,0x00,0x01,0x80,0x08,0x00,0x00,0xa0,0x00,0x10,0xc1,0xf0,0xef,0xff,0xff,0xff,
-0xfe,0xfd,0xef,0x7f,0xff,0xff,0xbf,0xff,0xf7,0xff,0xef,0xfb,0xfd,0x77,0xef,0xbf,
-0xf7,0x7f,0xff,0xff,0xbf,0xd1,0x7f,0xff,0xff,0xf7,0xff,0xff,0xff,0xff,0xaf,0xff,
-0xdf,0xf7,0xfb,0xff,0xfd,0xff,0xfc,0xff,0xfd,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,
-0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x3f,0xff,0xff,0xff,0xfe,0xdd,0xff,
-0xff,0xff,0xa5,0xfd,0x6f,0x7d,0x6d,0x7f,0x52,0xdf,0x5a,0x4b,0xee,0xb6,0xee,0xf2,
-0xbb,0xac,0xa1,0x5b,0x4d,0xd6,0xf7,0xfe,0xb2,0xbd,0x35,0xb5,0xb5,0xdd,0x6f,0x7f,
-0xe9,0x5f,0x52,0xdf,0xbd,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,
-0xff,0xdb,0xfe,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xb5,0xbf,0xf9,0x7f,0x6f,0xff,
-0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0x69,0x7f,0xdb,0xff,0xd3,0xff,0xf6,0xfe,0xf2,
-0xff,0xad,0xbf,0xff,0xff,0xff,0xd0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,
-0x30,0x0f,0xff,0xff,0xfd,0x6b,0xca,0xff,0xf0,0x0f,0xd6,0xbf,0xcf,0x3f,0xff,0xff,
-0xf1,0xff,0xff,0xff,0xca,0xfe,0xbf,0xff,0xf0,0x05,0xaf,0x0f,0xff,0xfc,0xf0,0xcf,
-0xf0,0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0x30,
-0x0f,0xff,0xff,0xfc,0x3f,0xca,0xff,0x0f,0x0f,0xd6,0xbf,0xff,0xff,0xf5,0x5f,0xf1,
-0xff,0x8b,0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xfc,0xf0,0xcf,0xf0,
-0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xcf,0xff,
-0xff,0xbf,0x9f,0x3f,0xfe,0xfc,0xff,0x4f,0xff,0xff,0xff,0xff,0xff,0xf7,0xf1,0xff,
-0xdf,0xfe,0x7e,0x3f,0x9f,0xf4,0xfc,0x7f,0xfc,0xff,0xff,0x3f,0xff,0x3f,0xfe,0x3f,
-0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfb,0xff,0xfe,0xff,
-0xff,0xff,0xff,0xbf,0xfb,0xff,0xf8,0xed,0xff,0x8f,0xff,0xbb,0xff,0xb1,0xf3,0xef,
-0x8f,0xf7,0xff,0xff,0xdb,0xff,0xff,0xff,0xef,0xbf,0xfd,0x79,0xbf,0xbf,0xff,0xff,
-0xff,0xfb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x04,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04,0x08,0x08,0x01,0x01,0x00,0x90,
-0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x00,0x01,
-0x3c,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0x9f,0xff,0xaf,0xdf,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,
-0xbf,0xef,0xff,0xff,0xff,0xed,0xff,0xff,0xff,0xef,0xff,0xbf,0xff,0xff,0xff,0xc3,
-0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xfd,0xff,0xff,0xff,0xfb,0xff,0xbb,0xff,
-0xff,0xff,0x7f,0xf6,0xff,0x7f,0xfb,0xfd,0xed,0xff,0xf1,0xff,0xfe,0x7f,0xff,0xff,
-0xff,0x5f,0xff,0xf7,0xff,0x7e,0xff,0xfd,0xff,0xef,0xff,0xff,0xff,0xef,0xf0,0xf0,
-0x8f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x80,0x00,0x04,0x00,0x00,0x40,0x02,0x00,0x03,
-0x00,0x05,0x04,0x20,0x00,0x00,0x01,0xd0,0x00,0x81,0x00,0x20,0x04,0x04,0x00,0x00,
-0x81,0x04,0x08,0x80,0x10,0x00,0xc0,0x00,0x00,0x00,0x20,0x00,0x08,0xc1,0xf0,0x6f,
-0xff,0xff,0xff,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xf3,0xfd,0xff,0xed,0xfc,
-0xff,0xff,0x9f,0xfb,0xfd,0xff,0xff,0xff,0xf1,0xff,0xff,0x7f,0xfb,0x3e,0xff,0x9f,
-0xff,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0x6f,0xff,
-0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,
-0xff,0xfe,0xff,0xff,0xff,0xfd,0xbd,0xff,0xef,0x7c,0xeb,0x7f,0xfb,0xdb,0xfa,0xdc,
-0xee,0xf7,0xf6,0xd7,0xf5,0x2d,0xa1,0xbb,0xdd,0xee,0xf7,0x54,0xf7,0xfb,0x2c,0xb5,
-0xb4,0xbd,0x6b,0x6f,0xef,0x6f,0xbb,0xdf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,
-0xfe,0xbf,0xff,0xff,0xff,0xfb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xff,0xbf,0xef,
-0x6f,0xff,0x6f,0xfa,0xdb,0xf1,0xc5,0xbd,0xf5,0x6f,0xff,0x6f,0xca,0xdb,0xff,0xdb,
-0xfb,0xf6,0x97,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x9f,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0x7f,0xff,0xff,0xe7,0x63,0xff,0xff,
-0xff,0xfc,0x77,0xdf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,
-0xc3,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xfc,0xff,0xcf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,0xc3,
-0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xbf,0xff,0xca,0xff,0x9f,0xff,0xfa,0xb9,0xe7,
-0x9f,0xf3,0x81,0xff,0xff,0xfc,0x73,0xd7,0xff,0xff,0x77,0xff,0xfd,0xff,0xfc,0xff,
-0xff,0xff,0xff,0xcf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,
-0xff,0xf7,0xde,0xff,0xfe,0x7e,0xff,0xbf,0xff,0xbf,0xf1,0xb3,0xff,0xff,0xe3,0xfb,
-0xff,0xe1,0x1f,0x7f,0xff,0xf8,0x78,0xff,0xfb,0x1e,0xff,0xf7,0xfe,0xe7,0xff,0xff,
-0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x04,0x00,
-0x01,0x80,0x40,0x40,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
-0x80,0x00,0x00,0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xff,
-0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xf7,0xf1,
-0xfd,0xff,0xff,0xff,0xdf,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
-0xff,0xff,0xff,0xdb,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xdf,0xff,0xff,0x7f,
-0xff,0xff,0xff,0xbe,0xd7,0xff,0xed,0xbd,0x7e,0xbf,0xfe,0xf6,0x7f,0xbf,0x71,0xff,
-0xff,0xda,0xff,0xf9,0xff,0xbf,0x7f,0xfe,0xff,0x6f,0x7f,0xff,0xff,0xff,0xff,0xff,
-0x7f,0xff,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x42,0x00,0x00,0x00,0x00,
-0x80,0xc1,0x00,0x00,0x90,0x00,0xc4,0x00,0x00,0x12,0x20,0x43,0x22,0x81,0x84,0x00,
-0x00,0x14,0x00,0x01,0x00,0x08,0x80,0x00,0x02,0x00,0x02,0x00,0x04,0x02,0x00,0x00,
-0x10,0xc1,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfd,0xff,0xff,0xdd,0xfe,0xff,
-0xb6,0x76,0xe5,0xbc,0xf9,0xf7,0xaf,0x5f,0xbf,0xfc,0xdf,0xcf,0xf1,0xff,0xef,0x79,
-0xff,0xbd,0xff,0xef,0xff,0xff,0xf7,0x6f,0x5f,0xff,0xff,0xfd,0xef,0xef,0xbf,0xff,
-0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xf0,0xff,0xff,0xff,0xff,0xfe,0xdb,0xff,0xff,0xfd,0x2d,0xff,0x69,0x2a,0xef,0x77,
-0xbb,0xdd,0x5a,0xdf,0xf6,0xf6,0xd6,0xf7,0x7d,0xbd,0xd1,0xb2,0x4a,0xd6,0xb2,0xbe,
-0x97,0xf5,0xbd,0xb3,0xad,0xff,0xef,0x7f,0x69,0x6b,0xfb,0xdf,0xff,0xff,0xff,0xf0,
-0x2f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0x9f,0xd4,0xbf,
-0xed,0xaf,0xff,0x6b,0x6f,0xf7,0xff,0xdd,0xdb,0x31,0xfd,0xbf,0xff,0x6f,0x7f,0xff,
-0xff,0xdb,0xff,0xcb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x8f,
-0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,
-0xa5,0xff,0xff,0xff,0xdf,0xb7,0xff,0xff,0xf1,0xff,0xff,0xff,0xf7,0xe9,0x6a,0xbf,
-0xff,0xff,0xfd,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xaf,0xf0,0x4f,0xff,
-0xff,0xff,0xfe,0xfe,0xdf,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,0xa5,
-0xff,0xff,0xff,0xc0,0x37,0xff,0xff,0xf1,0x99,0x8e,0xdc,0x7f,0xe9,0x6a,0xbf,0xff,
-0xf0,0x0f,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff,
-0xff,0xfe,0xff,0xff,0xff,0xff,0x07,0xff,0xc0,0xbe,0xff,0xff,0xcf,0xef,0x9f,0xff,
-0xff,0xfb,0xff,0xe7,0xff,0xff,0xa1,0xe3,0xce,0x3c,0x58,0x3f,0xf3,0xff,0xfd,0xef,
-0xf9,0xff,0xff,0xf7,0xf1,0x7f,0xff,0xcb,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,
-0xfe,0xf5,0x7f,0xff,0xf0,0xff,0xfe,0xff,0xc4,0x75,0xe7,0xb9,0xff,0xff,0xff,0xef,
-0xff,0xc7,0x37,0x3b,0xff,0xf0,0x13,0x9e,0x0f,0xf4,0xff,0xfe,0xfb,0xff,0xff,0xf9,
-0xfc,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xef,0xff,0xff,0xff,0xfe,
-0xf3,0xc0,0x01,0x00,0x00,0x02,0x00,0x02,0x22,0x00,0x00,0xc0,0x40,0x00,0x40,0x00,
-0x04,0x08,0x04,0x0a,0x01,0x01,0x10,0x20,0x20,0x00,0x00,0x04,0x08,0x08,0x04,0x00,
-0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x3c,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xfd,
-0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0xcf,0x9d,0xff,
-0xff,0xf7,0xfd,0xf1,0xff,0xff,0xff,0xee,0xbf,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xff,
-0xff,0xff,0xf7,0xf7,0xff,0xff,0xfe,0xbf,0xf7,0xff,0xff,0x5b,0xff,0xbf,0xf7,0xff,
-0xfd,0x7f,0x71,0xfd,0xff,0xed,0xf7,0xfe,0xef,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
-0xff,0xff,0xef,0xff,0x7f,0xff,0xd0,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf8,0x30,0x11,
-0x00,0x48,0x60,0x40,0x82,0x60,0x24,0x60,0x00,0xcc,0x00,0x80,0x04,0x01,0x00,0x00,
-0x14,0x01,0x0c,0x04,0x00,0x30,0x00,0x00,0x00,0x08,0x08,0x00,0x01,0x00,0xc2,0x00,
-0x00,0x02,0x00,0x80,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
-0xf7,0x7b,0xff,0xf3,0xeb,0xbf,0xff,0xf7,0xff,0xff,0xff,0xe7,0x5d,0x3f,0xff,0xf6,
-0xd1,0xfd,0xff,0xeb,0xf7,0x3d,0xff,0xff,0xff,0x5f,0xff,0x7f,0x7f,0xf3,0xff,0xff,
-0xef,0xfd,0xbf,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xb5,0xdf,
-0x6f,0x7d,0x69,0x7f,0xfb,0xdf,0x52,0x5f,0xf6,0xf7,0xfe,0xf6,0xf3,0xbd,0xb1,0xda,
-0xcd,0xfe,0xf6,0xee,0xd2,0xbd,0xa5,0xaf,0xbd,0xff,0x6f,0x7c,0xeb,0x2b,0xfa,0xda,
-0xff,0xfe,0xdf,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,
-0xff,0xf6,0xff,0xbd,0xbf,0xcd,0xbf,0xeb,0x6f,0xf7,0x6f,0xdf,0xdb,0x51,0xfd,0xbd,
-0xff,0x6f,0xff,0x6f,0xfb,0x5b,0xff,0xdb,0xff,0xf6,0xfe,0xf6,0xfd,0xfd,0xbf,0xfe,
-0xf7,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfa,0x50,0xff,0xff,0xff,
-0xf0,0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0xfc,0xff,0xff,
-0xf7,0xdb,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,
-0xaf,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xa0,0xff,0xff,0xff,0xf0,
-0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,
-0xf3,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,0xff,
-0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0x9f,0xf0,0x7f,
-0xff,0xf9,0xfc,0x4f,0xf3,0xff,0x27,0xeb,0xff,0xfc,0x81,0xfc,0x7f,0xfe,0x7b,0xff,
-0xf7,0xff,0x12,0x7f,0xff,0xff,0xff,0xff,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,
-0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xdf,0xfe,0xff,0xfc,0x7e,0x7f,0xbf,
-0xff,0xff,0xaf,0xef,0xff,0xdf,0xdf,0xfb,0xff,0xf1,0xc3,0xfe,0x6f,0xf1,0xcf,0x3f,
-0xfb,0xff,0xff,0xcf,0xfe,0xff,0xff,0xfe,0x7f,0xbf,0xff,0xff,0xbf,0xfa,0xf0,0xdf,
-0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
-0x20,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x02,0x00,0x00,0x80,0x00,0x02,0x80,0x00,0x02,0x3c,0xf0,0x2f,0xff,
-0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xf1,0xff,0x7f,0xff,0xff,0xff,0xff,0xef,0xff,
-0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x2f,0xff,0xff,
-0xff,0xfe,0xf0,0xff,0xff,0xff,0xfb,0xff,0xbf,0xff,0xff,0xff,0xff,0xf7,0xbf,0xfb,
-0xff,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xf7,0xbf,0xfb,0xff,0xff,0xff,0x7f,0xde,0xff,
-0xff,0xff,0xff,0xff,0xff,0xed,0xf7,0xff,0xff,0x7f,0xd0,0xf0,0x3f,0xff,0xff,0xff,
-0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x80,
-0x20,0x01,0x01,0x92,0x00,0x01,0x01,0x00,0xe0,0x1c,0x60,0x20,0x30,0x08,0x08,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xc1,0xf0,0x6f,0xff,0xff,0xff,0xfe,
-0xff,0xff,0xff,0xff,0xff,0xdb,0xfe,0xff,0xff,0xdf,0xff,0xfc,0x7f,0xfb,0xbf,0xff,
-0xff,0xff,0xff,0xff,0xf1,0xf6,0xff,0xf7,0x7e,0x3f,0xff,0x7f,0xff,0xff,0xff,0xf7,
-0xff,0xff,0xff,0xed,0xff,0xdf,0xff,0xb7,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,
-0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xbf,0xff,0xdf,
-0x57,0xef,0xf1,0xfd,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfb,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
-0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xdf,0xff,
-0xff,0xf1,0xfd,0xff,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xf7,0xfd,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,
-0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
-0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0x6f,0xff,0xfe,0xbf,0xff,0xf1,0xff,
-0xf7,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,
-0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0x57,0xff,0xfd,0xbf,0xff,0xf1,0xff,0xef,
-0xfe,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,
-0xde,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd,
-0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xe7,0x2f,0xf1,0x3c,0xbf,0xfd,
-0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff,
-0x02,0x01,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff };
index de2d48624683d03388039a15aff3bc4b22d9dbc9..f50fac25be403167f147c1867b31f4b4cac8bb31 100644 (file)
@@ -448,8 +448,11 @@ s32 igb_copper_link_setup_igp(struct e1000_hw *hw)
                goto out;
        }
 
-       /* Wait 15ms for MAC to configure PHY from NVM settings. */
-       msleep(15);
+       /*
+        * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+        * timeout issues when LFS is enabled.
+        */
+       msleep(100);
 
        /*
         * The NVM settings will configure LPLU in D3 for
index fb09c8ad9f0d2c80fc15ba28797fbea04acaa5be..27eae49e79c27c068ad31cbafc9fc441fed20f46 100644 (file)
@@ -1419,7 +1419,6 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 ctrl_reg = 0;
-       u32 stat_reg = 0;
 
        hw->mac.autoneg = false;
 
@@ -1443,18 +1442,11 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
        ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
                     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
                     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
-                    E1000_CTRL_FD);     /* Force Duplex to FULL */
+                    E1000_CTRL_FD |     /* Force Duplex to FULL */
+                    E1000_CTRL_SLU);    /* Set link up enable bit */
 
-       if (hw->phy.media_type == e1000_media_type_copper &&
-           hw->phy.type == e1000_phy_m88)
+       if (hw->phy.type == e1000_phy_m88)
                ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
-       else {
-               /* Set the ILOS bit on the fiber Nic if half duplex link is
-                * detected. */
-               stat_reg = rd32(E1000_STATUS);
-               if ((stat_reg & E1000_STATUS_FD) == 0)
-                       ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
-       }
 
        wr32(E1000_CTRL, ctrl_reg);
 
index ca842163dce4257abb61782b6d2dcdf2a5e30c39..03aa9593dd9e2d0e9efdc3660a5c25c5e88570ab 100644 (file)
@@ -135,8 +135,8 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int);
 static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
 static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
 
-static int igb_suspend(struct pci_dev *, pm_message_t);
 #ifdef CONFIG_PM
+static int igb_suspend(struct pci_dev *, pm_message_t);
 static int igb_resume(struct pci_dev *);
 #endif
 static void igb_shutdown(struct pci_dev *);
@@ -420,6 +420,9 @@ static void igb_free_queues(struct igb_adapter *adapter)
        for (i = 0; i < adapter->num_rx_queues; i++)
                netif_napi_del(&adapter->rx_ring[i].napi);
 
+       adapter->num_rx_queues = 0;
+       adapter->num_tx_queues = 0;
+
        kfree(adapter->tx_ring);
        kfree(adapter->rx_ring);
 }
@@ -1476,9 +1479,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                 netdev->name,
                 ((hw->bus.speed == e1000_bus_speed_2500)
                  ? "2.5Gb/s" : "unknown"),
-                ((hw->bus.width == e1000_bus_width_pcie_x4)
-                 ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1)
-                 ? "Width x1" : "unknown"),
+                ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
+                 (hw->bus.width == e1000_bus_width_pcie_x2) ? "Width x2" :
+                 (hw->bus.width == e1000_bus_width_pcie_x1) ? "Width x1" :
+                  "unknown"),
                 netdev->dev_addr);
 
        igb_read_part_num(hw, &part_num);
@@ -5056,7 +5060,7 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
        return 0;
 }
 
-static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct igb_adapter *adapter = netdev_priv(netdev);
@@ -5115,15 +5119,9 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
                wr32(E1000_WUFC, 0);
        }
 
-       /* make sure adapter isn't asleep if manageability/wol is enabled */
-       if (wufc || adapter->en_mng_pt) {
-               pci_enable_wake(pdev, PCI_D3hot, 1);
-               pci_enable_wake(pdev, PCI_D3cold, 1);
-       } else {
+       *enable_wake = wufc || adapter->en_mng_pt;
+       if (!*enable_wake)
                igb_shutdown_fiber_serdes_link_82575(hw);
-               pci_enable_wake(pdev, PCI_D3hot, 0);
-               pci_enable_wake(pdev, PCI_D3cold, 0);
-       }
 
        /* Release control of h/w to f/w.  If f/w is AMT enabled, this
         * would have already happened in close and is redundant. */
@@ -5131,12 +5129,29 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
 
        pci_disable_device(pdev);
 
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
        return 0;
 }
 
 #ifdef CONFIG_PM
+static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       int retval;
+       bool wake;
+
+       retval = __igb_shutdown(pdev, &wake);
+       if (retval)
+               return retval;
+
+       if (wake) {
+               pci_prepare_to_sleep(pdev);
+       } else {
+               pci_wake_from_d3(pdev, false);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
+
+       return 0;
+}
+
 static int igb_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
@@ -5189,7 +5204,14 @@ static int igb_resume(struct pci_dev *pdev)
 
 static void igb_shutdown(struct pci_dev *pdev)
 {
-       igb_suspend(pdev, PMSG_SUSPEND);
+       bool wake;
+
+       __igb_shutdown(pdev, &wake);
+
+       if (system_state == SYSTEM_POWER_OFF) {
+               pci_wake_from_d3(pdev, wake);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
index 1243bc8e0035877dd2edf703b96edfbacdaaa54b..ac0e4b6b6b66793ca8fd16b2ffff4818975c2a28 100644 (file)
@@ -1871,13 +1871,6 @@ static int __init vlsi_mod_init(void)
         * without procfs - it's not required for the driver to work.
         */
        vlsi_proc_root = proc_mkdir(PROC_DIR, NULL);
-       if (vlsi_proc_root) {
-               /* protect registered procdir against module removal.
-                * Because we are in the module init path there's no race
-                * window after create_proc_entry (and no barrier needed).
-                */
-               vlsi_proc_root->owner = THIS_MODULE;
-       }
 
        ret = pci_register_driver(&vlsi_irda_driver);
 
index ed265a7a898faea70408ae635c92328ae54003a7..de4db0dc78795c925882d11a9c830cbd416e4102 100644 (file)
@@ -411,7 +411,8 @@ static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
 
        /* Decide whether to use autoneg or not. */
        hw->mac.ops.check_link(hw, &speed, &link_up, false);
-       if (hw->phy.multispeed_fiber && (speed == IXGBE_LINK_SPEED_1GB_FULL))
+       if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber &&
+           (speed == IXGBE_LINK_SPEED_1GB_FULL))
                ret_val = ixgbe_fc_autoneg(hw);
 
        if (ret_val)
index 8cfd3fd309a03036dc1ad4ec357e8cbd7d74ce12..63ab6671d08e34b5cf0d54a0aa269a40c5d983a4 100644 (file)
@@ -1937,7 +1937,8 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
 
        /* Decide whether to use autoneg or not. */
        hw->mac.ops.check_link(hw, &speed, &link_up, false);
-       if (hw->phy.multispeed_fiber && (speed == IXGBE_LINK_SPEED_1GB_FULL))
+       if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber &&
+           (speed == IXGBE_LINK_SPEED_1GB_FULL))
                ret_val = ixgbe_fc_autoneg(hw);
 
        if (ret_val)
index 7e94d6d399abfc0b9ebe25c21cad39bcea12ff67..24f73e719c3f48d41bfdb819d73e1b8931749ac2 100644 (file)
@@ -96,14 +96,11 @@ s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val);
 #define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
 
 #ifdef DEBUG
+extern char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw);
 #define hw_dbg(hw, format, arg...) \
-printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg);
+       printk(KERN_DEBUG "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg)
 #else
-static inline int __attribute__ ((format (printf, 2, 3)))
-hw_dbg(struct ixgbe_hw *hw, const char *format, ...)
-{
-       return 0;
-}
+#define hw_dbg(hw, format, arg...) do {} while (0)
 #endif
 
 #endif /* IXGBE_COMMON */
index 0a8731f1f237061eca666b4a973587ddd984c234..bd0a0c2769520fd3b3f7186dfc7a539a00397d2d 100644 (file)
@@ -90,6 +90,8 @@ int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
                        src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc;
        }
 
+       dst_dcb_cfg->pfc_mode_enable = src_dcb_cfg->pfc_mode_enable;
+
        return 0;
 }
 
@@ -298,8 +300,10 @@ static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority,
 
        adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting;
        if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc !=
-           adapter->dcb_cfg.tc_config[priority].dcb_pfc)
+           adapter->dcb_cfg.tc_config[priority].dcb_pfc) {
                adapter->dcb_set_bitmap |= BIT_PFC;
+               adapter->temp_dcb_cfg.pfc_mode_enable = true;
+       }
 }
 
 static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
index 18ecba7f6ecb32951ebb82324da1637aaf5cb9c9..aafc120f164e66abe809eb28d781f2454969443f 100644 (file)
@@ -129,6 +129,15 @@ static int ixgbe_get_settings(struct net_device *netdev,
                        ecmd->advertising |= ADVERTISED_10000baseT_Full;
                if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
                        ecmd->advertising |= ADVERTISED_1000baseT_Full;
+               /*
+                * It's possible that phy.autoneg_advertised may not be
+                * set yet.  If so display what the default would be -
+                * both 1G and 10G supported.
+                */
+               if (!(ecmd->advertising & (ADVERTISED_1000baseT_Full |
+                                          ADVERTISED_10000baseT_Full)))
+                       ecmd->advertising |= (ADVERTISED_10000baseT_Full |
+                                             ADVERTISED_1000baseT_Full);
 
                ecmd->port = PORT_TP;
        } else if (hw->phy.media_type == ixgbe_media_type_backplane) {
@@ -225,7 +234,16 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 
-       pause->autoneg = (hw->fc.current_mode == ixgbe_fc_full ? 1 : 0);
+       /*
+        * Flow Control Autoneg isn't on if
+        *  - we didn't ask for it OR
+        *  - it failed, we know this by tx & rx being off
+        */
+       if (hw->fc.disable_fc_autoneg ||
+           (hw->fc.current_mode == ixgbe_fc_none))
+               pause->autoneg = 0;
+       else
+               pause->autoneg = 1;
 
        if (hw->fc.current_mode == ixgbe_fc_rx_pause) {
                pause->rx_pause = 1;
@@ -243,8 +261,12 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 
-       if ((pause->autoneg == AUTONEG_ENABLE) ||
-           (pause->rx_pause && pause->tx_pause))
+       if (pause->autoneg != AUTONEG_ENABLE)
+               hw->fc.disable_fc_autoneg = true;
+       else
+               hw->fc.disable_fc_autoneg = false;
+
+       if (pause->rx_pause && pause->tx_pause)
                hw->fc.requested_mode = ixgbe_fc_full;
        else if (pause->rx_pause && !pause->tx_pause)
                hw->fc.requested_mode = ixgbe_fc_rx_pause;
@@ -712,9 +734,10 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
                                struct ethtool_ringparam *ring)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       struct ixgbe_ring *temp_ring;
+       struct ixgbe_ring *temp_tx_ring, *temp_rx_ring;
        int i, err;
        u32 new_rx_count, new_tx_count;
+       bool need_update = false;
 
        if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
                return -EINVAL;
@@ -733,80 +756,94 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
                return 0;
        }
 
-       temp_ring = kcalloc(adapter->num_tx_queues,
-                           sizeof(struct ixgbe_ring), GFP_KERNEL);
-       if (!temp_ring)
-               return -ENOMEM;
-
        while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
                msleep(1);
 
-       if (new_tx_count != adapter->tx_ring->count) {
+       temp_tx_ring = kcalloc(adapter->num_tx_queues,
+                              sizeof(struct ixgbe_ring), GFP_KERNEL);
+       if (!temp_tx_ring) {
+               err = -ENOMEM;
+               goto err_setup;
+       }
+
+       if (new_tx_count != adapter->tx_ring_count) {
+               memcpy(temp_tx_ring, adapter->tx_ring,
+                      adapter->num_tx_queues * sizeof(struct ixgbe_ring));
                for (i = 0; i < adapter->num_tx_queues; i++) {
-                       temp_ring[i].count = new_tx_count;
-                       err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]);
+                       temp_tx_ring[i].count = new_tx_count;
+                       err = ixgbe_setup_tx_resources(adapter,
+                                                      &temp_tx_ring[i]);
                        if (err) {
                                while (i) {
                                        i--;
                                        ixgbe_free_tx_resources(adapter,
-                                                               &temp_ring[i]);
+                                                               &temp_tx_ring[i]);
                                }
                                goto err_setup;
                        }
-                       temp_ring[i].v_idx = adapter->tx_ring[i].v_idx;
+                       temp_tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
                }
-               if (netif_running(netdev))
-                       netdev->netdev_ops->ndo_stop(netdev);
-               ixgbe_reset_interrupt_capability(adapter);
-               ixgbe_napi_del_all(adapter);
-               INIT_LIST_HEAD(&netdev->napi_list);
-               kfree(adapter->tx_ring);
-               adapter->tx_ring = temp_ring;
-               temp_ring = NULL;
-               adapter->tx_ring_count = new_tx_count;
+               need_update = true;
        }
 
-       temp_ring = kcalloc(adapter->num_rx_queues,
-                           sizeof(struct ixgbe_ring), GFP_KERNEL);
-       if (!temp_ring) {
-               if (netif_running(netdev))
-                       netdev->netdev_ops->ndo_open(netdev);
-               return -ENOMEM;
+       temp_rx_ring = kcalloc(adapter->num_rx_queues,
+                              sizeof(struct ixgbe_ring), GFP_KERNEL);
+       if ((!temp_rx_ring) && (need_update)) {
+               for (i = 0; i < adapter->num_tx_queues; i++)
+                       ixgbe_free_tx_resources(adapter, &temp_tx_ring[i]);
+               kfree(temp_tx_ring);
+               err = -ENOMEM;
+               goto err_setup;
        }
 
-       if (new_rx_count != adapter->rx_ring->count) {
+       if (new_rx_count != adapter->rx_ring_count) {
+               memcpy(temp_rx_ring, adapter->rx_ring,
+                      adapter->num_rx_queues * sizeof(struct ixgbe_ring));
                for (i = 0; i < adapter->num_rx_queues; i++) {
-                       temp_ring[i].count = new_rx_count;
-                       err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]);
+                       temp_rx_ring[i].count = new_rx_count;
+                       err = ixgbe_setup_rx_resources(adapter,
+                                                      &temp_rx_ring[i]);
                        if (err) {
                                while (i) {
                                        i--;
                                        ixgbe_free_rx_resources(adapter,
-                                                               &temp_ring[i]);
+                                                             &temp_rx_ring[i]);
                                }
                                goto err_setup;
                        }
-                       temp_ring[i].v_idx = adapter->rx_ring[i].v_idx;
+                       temp_rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
                }
+               need_update = true;
+       }
+
+       /* if rings need to be updated, here's the place to do it in one shot */
+       if (need_update) {
                if (netif_running(netdev))
-                       netdev->netdev_ops->ndo_stop(netdev);
-               ixgbe_reset_interrupt_capability(adapter);
-               ixgbe_napi_del_all(adapter);
-               INIT_LIST_HEAD(&netdev->napi_list);
-               kfree(adapter->rx_ring);
-               adapter->rx_ring = temp_ring;
-               temp_ring = NULL;
-
-               adapter->rx_ring_count = new_rx_count;
+                       ixgbe_down(adapter);
+
+               /* tx */
+               if (new_tx_count != adapter->tx_ring_count) {
+                       kfree(adapter->tx_ring);
+                       adapter->tx_ring = temp_tx_ring;
+                       temp_tx_ring = NULL;
+                       adapter->tx_ring_count = new_tx_count;
+               }
+
+               /* rx */
+               if (new_rx_count != adapter->rx_ring_count) {
+                       kfree(adapter->rx_ring);
+                       adapter->rx_ring = temp_rx_ring;
+                       temp_rx_ring = NULL;
+                       adapter->rx_ring_count = new_rx_count;
+               }
        }
 
        /* success! */
        err = 0;
-err_setup:
-       ixgbe_init_interrupt_scheme(adapter);
        if (netif_running(netdev))
-               netdev->netdev_ops->ndo_open(netdev);
+               ixgbe_up(adapter);
 
+err_setup:
        clear_bit(__IXGBE_RESETTING, &adapter->state);
        return err;
 }
index 79aa811c403c5c2d5dcd3bfff6939ae067ccc1e5..286ecc0e6ab75148c8ff08513c1776fe68f5cf04 100644 (file)
@@ -187,15 +187,14 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
                                              struct ixgbe_tx_buffer
                                              *tx_buffer_info)
 {
-       if (tx_buffer_info->dma) {
-               pci_unmap_page(adapter->pdev, tx_buffer_info->dma,
-                              tx_buffer_info->length, PCI_DMA_TODEVICE);
-               tx_buffer_info->dma = 0;
-       }
+       tx_buffer_info->dma = 0;
        if (tx_buffer_info->skb) {
+               skb_dma_unmap(&adapter->pdev->dev, tx_buffer_info->skb,
+                             DMA_TO_DEVICE);
                dev_kfree_skb_any(tx_buffer_info->skb);
                tx_buffer_info->skb = NULL;
        }
+       tx_buffer_info->time_stamp = 0;
        /* tx_buffer_info must be completely set up in the transmit path */
 }
 
@@ -204,15 +203,11 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
                                        unsigned int eop)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 head, tail;
 
        /* Detect a transmit hang in hardware, this serializes the
         * check with the clearing of time_stamp and movement of eop */
-       head = IXGBE_READ_REG(hw, tx_ring->head);
-       tail = IXGBE_READ_REG(hw, tx_ring->tail);
        adapter->detect_tx_hung = false;
-       if ((head != tail) &&
-           tx_ring->tx_buffer_info[eop].time_stamp &&
+       if (tx_ring->tx_buffer_info[eop].time_stamp &&
            time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) &&
            !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) {
                /* detected Tx unit hang */
@@ -227,7 +222,8 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
                        "  time_stamp           <%lx>\n"
                        "  jiffies              <%lx>\n",
                        tx_ring->queue_index,
-                       head, tail,
+                       IXGBE_READ_REG(hw, tx_ring->head),
+                       IXGBE_READ_REG(hw, tx_ring->tail),
                        tx_ring->next_to_use, eop,
                        tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
                return true;
@@ -2934,6 +2930,7 @@ err_tx_ring_allocation:
  **/
 static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
 {
+       struct ixgbe_hw *hw = &adapter->hw;
        int err = 0;
        int vector, v_budget;
 
@@ -2948,12 +2945,12 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
 
        /*
         * At the same time, hardware can only support a maximum of
-        * MAX_MSIX_COUNT vectors.  With features such as RSS and VMDq,
-        * we can easily reach upwards of 64 Rx descriptor queues and
-        * 32 Tx queues.  Thus, we cap it off in those rare cases where
-        * the cpu count also exceeds our vector limit.
+        * hw.mac->max_msix_vectors vectors.  With features
+        * such as RSS and VMDq, we can easily surpass the number of Rx and Tx
+        * descriptor queues supported by our device.  Thus, we cap it off in
+        * those rare cases where the cpu count also exceeds our vector limit.
         */
-       v_budget = min(v_budget, MAX_MSIX_COUNT);
+       v_budget = min(v_budget, (int)hw->mac.max_msix_vectors);
 
        /* A failure in MSI-X entry allocation isn't fatal, but it does
         * mean we disable MSI-X capabilities of the adapter. */
@@ -3169,11 +3166,13 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
 #endif
 
        /* default flow control settings */
-       hw->fc.requested_mode = ixgbe_fc_none;
+       hw->fc.requested_mode = ixgbe_fc_full;
+       hw->fc.current_mode = ixgbe_fc_full;    /* init for ethtool output */
        hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
        hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
        hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
        hw->fc.send_xon = true;
+       hw->fc.disable_fc_autoneg = false;
 
        /* enable itr by default in dynamic mode */
        adapter->itr_setting = 1;
@@ -3489,10 +3488,10 @@ err_up:
        ixgbe_release_hw_control(adapter);
        ixgbe_free_irq(adapter);
 err_req_irq:
-       ixgbe_free_all_rx_resources(adapter);
 err_setup_rx:
-       ixgbe_free_all_tx_resources(adapter);
+       ixgbe_free_all_rx_resources(adapter);
 err_setup_tx:
+       ixgbe_free_all_tx_resources(adapter);
        ixgbe_reset(adapter);
 
        return err;
@@ -4163,32 +4162,39 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
                         struct sk_buff *skb, unsigned int first)
 {
        struct ixgbe_tx_buffer *tx_buffer_info;
-       unsigned int len = skb->len;
+       unsigned int len = skb_headlen(skb);
        unsigned int offset = 0, size, count = 0, i;
        unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
        unsigned int f;
-
-       len -= skb->data_len;
+       dma_addr_t *map;
 
        i = tx_ring->next_to_use;
 
+       if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) {
+               dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+               return 0;
+       }
+
+       map = skb_shinfo(skb)->dma_maps;
+
        while (len) {
                tx_buffer_info = &tx_ring->tx_buffer_info[i];
                size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
 
                tx_buffer_info->length = size;
-               tx_buffer_info->dma = pci_map_single(adapter->pdev,
-                                                    skb->data + offset,
-                                                    size, PCI_DMA_TODEVICE);
+               tx_buffer_info->dma = map[0] + offset;
                tx_buffer_info->time_stamp = jiffies;
                tx_buffer_info->next_to_watch = i;
 
                len -= size;
                offset += size;
                count++;
-               i++;
-               if (i == tx_ring->count)
-                       i = 0;
+
+               if (len) {
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+               }
        }
 
        for (f = 0; f < nr_frags; f++) {
@@ -4196,33 +4202,27 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
 
                frag = &skb_shinfo(skb)->frags[f];
                len = frag->size;
-               offset = frag->page_offset;
+               offset = 0;
 
                while (len) {
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+
                        tx_buffer_info = &tx_ring->tx_buffer_info[i];
                        size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
 
                        tx_buffer_info->length = size;
-                       tx_buffer_info->dma = pci_map_page(adapter->pdev,
-                                                          frag->page,
-                                                          offset,
-                                                          size,
-                                                          PCI_DMA_TODEVICE);
+                       tx_buffer_info->dma = map[f + 1] + offset;
                        tx_buffer_info->time_stamp = jiffies;
                        tx_buffer_info->next_to_watch = i;
 
                        len -= size;
                        offset += size;
                        count++;
-                       i++;
-                       if (i == tx_ring->count)
-                               i = 0;
                }
        }
-       if (i == 0)
-               i = tx_ring->count - 1;
-       else
-               i = i - 1;
+
        tx_ring->tx_buffer_info[i].skb = skb;
        tx_ring->tx_buffer_info[first].next_to_watch = i;
 
@@ -4388,13 +4388,19 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                 (skb->ip_summed == CHECKSUM_PARTIAL))
                tx_flags |= IXGBE_TX_FLAGS_CSUM;
 
-       ixgbe_tx_queue(adapter, tx_ring, tx_flags,
-                      ixgbe_tx_map(adapter, tx_ring, skb, first),
-                      skb->len, hdr_len);
+       count = ixgbe_tx_map(adapter, tx_ring, skb, first);
 
-       netdev->trans_start = jiffies;
+       if (count) {
+               ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len,
+                              hdr_len);
+               netdev->trans_start = jiffies;
+               ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
 
-       ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
+       } else {
+               dev_kfree_skb_any(skb);
+               tx_ring->tx_buffer_info[first].time_stamp = 0;
+               tx_ring->next_to_use = first;
+       }
 
        return NETDEV_TX_OK;
 }
@@ -4987,8 +4993,20 @@ static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
 
        return ret_val ? NOTIFY_BAD : NOTIFY_DONE;
 }
+
 #endif /* CONFIG_IXGBE_DCA */
+#ifdef DEBUG
+/**
+ * ixgbe_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       return adapter->netdev->name;
+}
 
+#endif
 module_exit(ixgbe_exit_module);
 
 /* ixgbe_main.c */
index 2b2ecba7b6094d909ba21dcdd56dd68b58808796..030ff0a9ea6757079e75f020679f42360d1b76d9 100644 (file)
@@ -2005,6 +2005,7 @@ struct ixgbe_fc_info {
        u16 pause_time; /* Flow Control Pause timer */
        bool send_xon; /* Flow control send XON */
        bool strict_ieee; /* Strict IEEE mode */
+       bool disable_fc_autoneg; /* Turn off autoneg FC mode */
        enum ixgbe_fc_mode current_mode; /* FC mode in effect */
        enum ixgbe_fc_mode requested_mode; /* FC mode requested by caller */
 };
index 9f6644a440304e756822119142dd0602e0c7ccc1..303c23de6cacff0c917b1e6c48f62e5f1003b5b2 100644 (file)
@@ -505,7 +505,7 @@ out:
 
 static void mlx4_en_do_get_stats(struct work_struct *work)
 {
-       struct delayed_work *delay = container_of(work, struct delayed_work, work);
+       struct delayed_work *delay = to_delayed_work(work);
        struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
                                                 stats_task);
        struct mlx4_en_dev *mdev = priv->mdev;
index a4130e764991a79e77a30395c685a2ac5088188e..7e40741fb7d87ef9d1136797cb54145db8cbe6dc 100644 (file)
@@ -298,7 +298,7 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
 
 void mlx4_en_rx_refill(struct work_struct *work)
 {
-       struct delayed_work *delay = container_of(work, struct delayed_work, work);
+       struct delayed_work *delay = to_delayed_work(work);
        struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
                                                 refill_task);
        struct mlx4_en_dev *mdev = priv->mdev;
index 6d5089ecb5af2c2d3d51202e90a1a2ed3cd645f4..f36ae691cab3c343091fb7130591c8737ab4afee 100644 (file)
@@ -103,7 +103,7 @@ void mlx4_do_sense_ports(struct mlx4_dev *dev,
 
 static void mlx4_sense_port(struct work_struct *work)
 {
-       struct delayed_work *delay = container_of(work, struct delayed_work, work);
+       struct delayed_work *delay = to_delayed_work(work);
        struct mlx4_sense *sense = container_of(delay, struct mlx4_sense,
                                                sense_poll);
        struct mlx4_dev *dev = sense->dev;
index d304d38cd5d1728c45587efa0a986ca207d21240..eceadf787a67d5762cad157b5104a033f952a063 100644 (file)
@@ -294,14 +294,12 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
 
 static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
-                       HIPQUAD(nt->np.local_ip));
+       return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 }
 
 static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
-                       HIPQUAD(nt->np.remote_ip));
+       return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 }
 
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -438,7 +436,7 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
                return -EINVAL;
        }
 
-       nt->np.local_ip = ntohl(in_aton(buf));
+       nt->np.local_ip = in_aton(buf);
 
        return strnlen(buf, count);
 }
@@ -454,7 +452,7 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
                return -EINVAL;
        }
 
-       nt->np.remote_ip = ntohl(in_aton(buf));
+       nt->np.remote_ip = in_aton(buf);
 
        return strnlen(buf, count);
 }
index 539e18ab485cd5da15f1efe17061a5600b48baad..2a8da476ab3d1d9a77b3dbcf796cf75227aa1478 100644 (file)
@@ -189,6 +189,17 @@ static void __init trigger_irq(int ioaddr)
                outb(MM_EN_XMT|MM_MUX, IE_MMODE); /* Start transmission */
 }
 
+static const struct net_device_ops ni5010_netdev_ops = {
+       .ndo_open               = ni5010_open,
+       .ndo_stop               = ni5010_close,
+       .ndo_start_xmit         = ni5010_send_packet,
+       .ndo_set_multicast_list = ni5010_set_multicast_list,
+       .ndo_tx_timeout         = ni5010_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+};
+
 /*
  *      This is the real probe routine.  Linux has a history of friendly device
  *      probes on the ISA bus.  A good device probes avoids doing writes, and
@@ -328,13 +339,8 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
                outb(0, IE_RBUF);       /* set buffer byte 0 to 0 again */
        }
         printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
-       memset(netdev_priv(dev), 0, sizeof(struct ni5010_local));
 
-       dev->open               = ni5010_open;
-       dev->stop               = ni5010_close;
-       dev->hard_start_xmit    = ni5010_send_packet;
-       dev->set_multicast_list = ni5010_set_multicast_list;
-       dev->tx_timeout         = ni5010_timeout;
+       dev->netdev_ops         = &ni5010_netdev_ops;
        dev->watchdog_timeo     = HZ/20;
 
        dev->flags &= ~IFF_MULTICAST;   /* Multicast doesn't work */
index 50c11126a3db5adaa6dbb5d48ccfad1dafe95aa6..02c37e2f08a9fadc9dfaaa222193f97b036b0ba3 100644 (file)
@@ -3441,7 +3441,8 @@ static int niu_rx_pkt_ignore(struct niu *np, struct rx_ring_info *rp)
        return num_rcr;
 }
 
-static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp)
+static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
+                             struct rx_ring_info *rp)
 {
        unsigned int index = rp->rcr_index;
        struct sk_buff *skb;
@@ -3518,7 +3519,7 @@ static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp)
 
        skb->protocol = eth_type_trans(skb, np->dev);
        skb_record_rx_queue(skb, rp->rx_channel);
-       netif_receive_skb(skb);
+       napi_gro_receive(napi, skb);
 
        return num_rcr;
 }
@@ -3706,7 +3707,8 @@ static inline void niu_sync_rx_discard_stats(struct niu *np,
        }
 }
 
-static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget)
+static int niu_rx_work(struct napi_struct *napi, struct niu *np,
+                      struct rx_ring_info *rp, int budget)
 {
        int qlen, rcr_done = 0, work_done = 0;
        struct rxdma_mailbox *mbox = rp->mbox;
@@ -3728,7 +3730,7 @@ static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget)
        rcr_done = work_done = 0;
        qlen = min(qlen, budget);
        while (work_done < qlen) {
-               rcr_done += niu_process_rx_pkt(np, rp);
+               rcr_done += niu_process_rx_pkt(napi, np, rp);
                work_done++;
        }
 
@@ -3776,7 +3778,7 @@ static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget)
                if (rx_vec & (1 << rp->rx_channel)) {
                        int this_work_done;
 
-                       this_work_done = niu_rx_work(np, rp,
+                       this_work_done = niu_rx_work(&lp->napi, np, rp,
                                                     budget);
 
                        budget -= this_work_done;
diff --git a/drivers/net/pcmcia/ositech.h b/drivers/net/pcmcia/ositech.h
deleted file mode 100644 (file)
index 4126efc..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
-    This file contains the firmware of Seven of Diamonds from OSITECH.
-    (Special thanks to Kevin MacPherson of OSITECH)
-
-    This software may be used and distributed according to the terms of
-    the GNU General Public License, incorporated herein by reference.
-*/
-
-    static const u_char __Xilinx7OD[] = {
-    0xFF, 0x04, 0xA0, 0x36, 0xF3, 0xEC, 0xFF, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF,
-    0xF3, 0xFF, 0xFF, 0xFF, 
-    0xEF, 0x3F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F, 0xFE, 0xFF,
-    0xCE, 0xFE, 0xFE, 0xFE, 
-    0xFE, 0xDE, 0xBD, 0xDD, 0xFD, 0xFF, 0xFD, 0xCF, 0xF7, 0xBF, 0x7F, 0xFF,
-    0x7F, 0x3F, 0xFE, 0xBF, 
-    0xFF, 0xFF, 0xFF, 0xBC, 0xFF, 0xFF, 0xBD, 0xB5, 0x7F, 0x7F, 0xBF, 0xBF,
-    0x7F, 0xFF, 0xEF, 0xFF, 
-    0xFF, 0xFF, 0xFB, 0xFF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDE,
-    0xFE, 0xFE, 0xFA, 0xDE, 
-    0xBD, 0xFD, 0xED, 0xFD, 0xFD, 0xCF, 0xEF, 0xEF, 0xEF, 0xEF, 0xC7, 0xDF,
-    0xDF, 0xDF, 0xDF, 0xDF, 
-    0xFF, 0x7E, 0xFE, 0xFD, 0x7D, 0x6D, 0xEE, 0xFE, 0x7C, 0xFB, 0xF4, 0xFB,
-    0xCF, 0xDB, 0xDF, 0xFF, 
-    0xFF, 0xBB, 0x7F, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0x9E, 0xBF, 0x3B, 0xBF,
-    0xBF, 0x7F, 0x7F, 0x7F, 
-    0x7E, 0x6F, 0xDF, 0xEF, 0xF5, 0xF6, 0xFD, 0xF6, 0xF5, 0xED, 0xEB, 0xFF,
-    0xEF, 0xEF, 0xEF, 0x7E, 
-    0x7F, 0x7F, 0x6F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xEF, 0xBF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0x1F, 0x1F, 0xEE, 0xFF, 0xBC,
-    0xB7, 0xFF, 0xDF, 0xFF, 
-    0xDF, 0xEF, 0x3B, 0xE3, 0xD3, 0xFF, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF,
-    0xFF, 0xBA, 0xBF, 0x2D, 
-    0xDB, 0xBD, 0xFD, 0xDB, 0xDF, 0xFA, 0xFB, 0xFF, 0xEF, 0xFB, 0xDB, 0xF3,
-    0xFF, 0xDF, 0xFD, 0x7F, 
-    0xEF, 0xFB, 0xFF, 0xFF, 0xBE, 0xBF, 0x27, 0xBA, 0xFE, 0xFB, 0xDF, 0xFF,
-    0xF6, 0xFF, 0xFF, 0xEF, 
-    0xFB, 0xDB, 0xF3, 0xD9, 0x9A, 0x3F, 0xFF, 0xAF, 0xBF, 0xFF, 0xFF, 0xBE,
-    0x3F, 0x37, 0xBD, 0x96, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE, 0xFB, 0xF3, 0xF3, 0xEB, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xF7, 0xFA, 0xBC, 0xAE, 0xFE, 0xBE, 0xFE, 0xBB, 0x7F, 0xFD, 0xFF,
-    0x7F, 0xEF, 0xF7, 0xFB, 
-    0xBB, 0xD7, 0xF7, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xBC, 0xED, 0xFD,
-    0xBD, 0x9D, 0x7D, 0x7B, 
-    0xFB, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xF7, 
-    0xAA, 0xB9, 0xBF, 0x8F, 0xBF, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xCF,
-    0xFB, 0xEB, 0xCB, 0xEB, 
-    0xEE, 0xFF, 0xFF, 0xD7, 0xFF, 0xFF, 0xFF, 0x3E, 0x33, 0x3F, 0x1C, 0x7C,
-    0xFC, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xCF, 0xD3, 0xF3, 0xE3, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xEB, 0xFE, 0x35, 
-    0x3F, 0x3D, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0x6F, 0xE3,
-    0xE3, 0xE3, 0xEF, 0xFF, 
-    0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0xFE, 0x3E, 0x5E, 0xFE, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFD, 0xFF, 0xFF, 
-    0xAF, 0xCF, 0xF2, 0xCB, 0xCF, 0x8E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD,
-    0xFC, 0x3E, 0x1F, 0x9E, 
-    0xAD, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xB3, 0xF7, 0xE7,
-    0xF7, 0xFA, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xEE, 0xEB, 0xAB, 0xAF, 0x9F, 0xE3, 0x7F, 0xFF, 0xDE,
-    0xFF, 0x7F, 0xEE, 0xFF, 
-    0xFF, 0xFB, 0x3A, 0xFA, 0xFF, 0xF2, 0x77, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF,
-    0xFE, 0xBD, 0xAE, 0xDE, 
-    0x7D, 0x7D, 0xFD, 0xFF, 0xBF, 0xEE, 0xFF, 0xFD, 0xFF, 0xDB, 0xFB, 0xFF,
-    0xF7, 0xEF, 0xFB, 0xFF, 
-    0xFF, 0xFE, 0xFF, 0x2D, 0xAF, 0xB9, 0xFD, 0x79, 0xFB, 0xFA, 0xFF, 0xBF,
-    0xEF, 0xFF, 0xFF, 0x91, 
-    0xFA, 0xFB, 0xDF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF, 0x37, 0xBF,
-    0xBF, 0xFF, 0x7F, 0x7F, 
-    0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xF3, 0xFB, 0xFB, 0xFF, 0xF5, 0xEF,
-    0xFF, 0xFF, 0xF7, 0xFA, 
-    0xFF, 0xFF, 0xEE, 0xFA, 0xFE, 0xFB, 0x55, 0xDD, 0xFF, 0x7F, 0xAF, 0xFE,
-    0xFF, 0xFB, 0xFB, 0xF5, 
-    0xFF, 0xF7, 0xEF, 0xFF, 0xFF, 0xFF, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D,
-    0x7B, 0x7B, 0x7B, 0x7B, 
-    0xFB, 0xAE, 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xF7, 0xDA, 0xB7, 0x61, 
-    0xFF, 0xB9, 0x59, 0xF3, 0x73, 0xF3, 0xDF, 0x7F, 0x6F, 0xDF, 0xEF, 0xF7,
-    0xEB, 0xEB, 0xD7, 0xFF, 
-    0xD7, 0xFF, 0xFF, 0xF7, 0xFE, 0x7F, 0xFB, 0x3E, 0x38, 0x73, 0xF6, 0x7F,
-    0xFC, 0xFF, 0xFF, 0xCF, 
-    0xFF, 0xB7, 0xFB, 0xB3, 0xB3, 0x67, 0xFF, 0xE7, 0xFD, 0xFF, 0xEF, 0xF6,
-    0x7F, 0xB7, 0xBC, 0xF5, 
-    0x7B, 0xF6, 0xF7, 0xF5, 0xFF, 0xFF, 0xEF, 0xFF, 0xF7, 0xFF, 0xF7, 0xCE,
-    0xE7, 0xFF, 0x9F, 0xFF, 
-    0xFF, 0xF5, 0xFE, 0x7D, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xEF, 0xFF, 0xF6, 
-    0xCB, 0xDB, 0xEE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xBE,
-    0x1E, 0x3E, 0xFE, 0xFF, 
-    0x7D, 0xFE, 0xFF, 0xFF, 0xEF, 0xBF, 0xE7, 0xFF, 0xE3, 0xE3, 0xFF, 0xDF,
-    0xE7, 0xFF, 0xFF, 0xFF, 
-    0xB8, 0xEF, 0xB7, 0x2F, 0xEE, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0x7F, 0xEF,
-    0xEB, 0xBF, 0xA3, 0xD3, 
-    0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xFD, 0x3F, 0xCF, 0xFD,
-    0xFB, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xAF, 0xFB, 0xBF, 0xBB, 0xBF, 0xDB, 0xFD, 0xFB, 0xFF, 0xFF,
-    0xFF, 0xFF, 0x3E, 0xFE, 
-    0x3F, 0xBA, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xEF, 0xC3, 0x7F,
-    0xB2, 0x9B, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0x3C, 0xFF, 0x3F, 0x3C, 0xFF, 0xFE, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xAF, 0xF3, 0xFE, 0xF3, 0xE3, 0xEB, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xF7,
-    0x9A, 0xFE, 0xAF, 0x9E, 
-    0xBE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0x7B, 0xEF, 0xF7, 0xBF, 0xFB, 0xFB,
-    0xFB, 0xFF, 0xFF, 0x7F, 
-    0xFF, 0xFF, 0xFF, 0xBC, 0xBD, 0xFD, 0xBD, 0xDD, 0x7D, 0x7B, 0x7B, 0x7B,
-    0x7B, 0xFB, 0xAE, 0xFF, 
-    0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0x9A, 0xFF,
-    0x9F, 0xFF, 0xAF, 0xEF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xCF, 0xF3, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF,
-    0xFF, 0xBF, 0xFF, 0xFF, 
-    0xEF, 0xFE, 0xFF, 0x37, 0xFC, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xCF, 0xEF, 0xFD, 0xF3, 
-    0xFF, 0xEE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0xFD, 0x2F, 0xFD,
-    0xFF, 0xFD, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xEF, 0xCF, 0xFF, 0xF3, 0xBF, 0x69, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFE, 
-    0xFB, 0x9F, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x87,
-    0xFE, 0xDA, 0xEF, 0xCF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xBF, 0xEF, 0xEF, 0xFD,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xEF, 0xFD, 0xFF, 0x7B, 0xFF, 0xEB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xEB, 0xF8, 0xFF, 0xEF, 
-    0xAF, 0xFF, 0xFF, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F, 0xEE, 0x7F, 0xEF, 0xFF,
-    0xBB, 0xFF, 0xBF, 0xFB, 
-    0xFF, 0xFF, 0xFF, 0xF7, 0xF6, 0xFB, 0xBD, 0xFD, 0xDD, 0xF5, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xAF, 
-    0xFF, 0x5F, 0xF5, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6,
-    0xF3, 0xFF, 0xDE, 0xFE, 
-    0xEF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xDE, 0xDF, 0x5F, 0xDF,
-    0xFD, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xAF, 0xFF, 0xFF, 
-    0xEF, 0xED, 0xFF, 0xDF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xDA, 0xBD, 0xBE,
-    0xAE, 0xFE, 0x7F, 0xFD, 
-    0xDF, 0xFF, 0xFF, 0x7F, 0xEF, 0xFF, 0xFB, 0xFB, 0xFB, 0x7F, 0xF7, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xF7, 
-    0xBC, 0xFD, 0xBD, 0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE,
-    0xFF, 0xFF, 0xFD, 0xFF, 
-    0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x9F, 0xBF, 0xBF, 0xCF,
-    0x7F, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xAF, 0xFF, 0xEB, 0xEB, 0xEB, 0xFF, 0xD7, 0xFE, 0xFF, 0xFF,
-    0xBF, 0xE7, 0xFE, 0xBF, 
-    0x7F, 0xFC, 0xFF, 0xFF, 0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFB,
-    0xFB, 0xFF, 0xFF, 0xDD, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBD, 0xDF, 0x9D, 0xFD, 0xDF, 0xB9,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xEF, 0xFF, 0xFB, 0xEF, 0xEB, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xF6, 0x9F, 0xFF, 0xFC, 
-    0xFE, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xDF, 0xFA, 0xCD, 0xCF,
-    0xBF, 0x9F, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xF7, 0xFE, 0xBF, 0xFF, 0xDF, 0xEF, 0x5F, 0xFF, 0xFF, 0xFF,
-    0xFF, 0x7F, 0x6F, 0xFF, 
-    0xBB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0xFF,
-    0x5F, 0xFF, 0xBF, 0xBF, 
-    0xF9, 0xFF, 0xFF, 0xFF, 0x7F, 0x6E, 0x7B, 0xFF, 0xEF, 0xFD, 0xEB, 0xDF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xF7, 0xB6, 0x3E, 0xFC, 0xFD, 0xBF, 0x7E, 0xFB, 0xFF, 0xFF, 0xFF, 0xF7,
-    0xEF, 0xF7, 0xF3, 0xF7, 
-    0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0x35, 0x79, 0xFF,
-    0xBF, 0xFC, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0x53, 0xDF, 0xFF, 0xEB, 0xBF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xBC, 
-    0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF5,
-    0xFF, 0xF7, 0xFF, 0xFB, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xAA, 0xEE, 0xFE, 0x3F, 0x7D,
-    0xFD, 0xFF, 0xFF, 0xFF, 
-    0x7F, 0xAF, 0x77, 0xFB, 0xFB, 0xFF, 0xFB, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xF7, 0xBE, 0xBD, 0xBD, 
-    0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE, 0xFF, 0xEF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFC, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0x9A, 0xD9, 0xB8, 0xFF, 0xFF, 0x79, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xCF, 
-    0xFB, 0xFF, 0xEB, 0xFF, 0xEB, 0xD7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xDE,
-    0xF8, 0xFB, 0xFE, 0x3F, 
-    0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xAD, 0xBF, 0xFA, 0xFF, 0x73,
-    0xDF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0x3A, 0xF5, 0xB7, 0xFC, 0x3F, 0xF9, 0xFD, 0xFF, 0xFF, 0xFF,
-    0x7F, 0xEF, 0xF3, 0xFF, 
-    0xBF, 0xFE, 0xF3, 0x9F, 0xFE, 0xFF, 0xFF, 0xFF, 0xF7, 0x3E, 0xFF, 0xFF,
-    0xFF, 0xBF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xD3, 0xFE, 0xDB, 0xFF, 0xDB, 0xDF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0x3E, 0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F,
-    0xF3, 0xFF, 0xED, 0xFF, 
-    0xF7, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF6, 0x3C, 0xFE, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0x9F, 0xEF, 0xEF, 0xD1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0x7E, 0xBF, 
-    0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBB, 0xEF, 0xDF, 0xF1,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x3E, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xBF, 
-    0xEF, 0xFD, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
-    0xFC, 0x3E, 0xFE, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2E, 0xEF, 0xF3, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xF7, 0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0x7F, 0xAF, 0xFB, 
-    0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xF2, 0xD6, 0xED,
-    0xBD, 0xBD, 0xBD, 0x7D, 
-    0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0x92, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
-    0xAF, 0xEB, 0xEB, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFE, 0x2E, 0xFE, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0x4F, 0xEF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFE, 
-    0x3C, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xCE,
-    0xC3, 0xFD, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xEF, 0xCF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xF7, 0xEE, 0x3E, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xDF, 0xE2, 0xFF,
-    0xFF, 0xFF, 0xFB, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0xBE, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0x7F, 0xEE, 
-    0x5F, 0xE6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E,
-    0x7D, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xBF, 0xF7, 0x36, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xEF, 0xD3, 0xF6, 
-    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x7F, 0xEE,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xEF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE,
-    0xFB, 0xFA, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xD6, 0xFD, 0xBD, 0xBD, 0xBD,
-    0x7D, 0x7B, 0x7B, 0x7B, 
-    0x7B, 0xFB, 0xAE, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xF7, 0xBA, 0xBF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xEB, 0x6B,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0x4F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
-    0x3E, 0x6E, 0xFC, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xC3, 0xC9, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0x3E, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xEF, 0xFB, 
-    0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE,
-    0xFE, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0xEF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFB,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xF6, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE,
-    0xEF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFE, 0xFF, 0xF7, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0x7F, 0xFA, 0xEF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xE7, 0xFF, 0xFE, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xEF, 0xBF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xA7, 0xFF, 0xFC, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0x7F, 
-    0xFE, 0xAE, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7,
-    0xF7, 0xFA, 0xFF, 0xFD, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B,
-    0x7B, 0x7B, 0xFB, 0xAF, 
-    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xE7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xCF, 0xFE, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xE7, 0xF2, 0xFC, 
-    0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAE, 0xEF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7E, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
-    0xFE, 0xFE, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0xDD, 0xFE, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xAF, 0xEF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xFE,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xF6, 0x9C, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB,
-    0xAE, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7A, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xDF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0x6F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xF7, 0xFE, 
-    0xFE, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xEB,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x9E, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xEF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFE, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xCB, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFD, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xEF, 
-    0xEF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFB, 0xAF, 0x7F, 0xFF, 
-    0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xBF, 0xFF, 
-    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0x7F, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xF7, 0xBC, 0xBD, 
-    0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0x7F, 
-    0xAF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
-    0xFE, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF,
-    0xFF, 0xFF, 0xEF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
-    0xFF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xBF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-    0xEF, 0xFF, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFE, 0xFF, 0x9F, 0x9F,
-    0x9F, 0x3F, 0x3F, 0x3F, 
-    0x3F, 0x3F, 0xFF, 0xEF, 0xDF, 0xDF, 0xDF, 0xDF, 0xCF, 0xB7, 0xBF, 0xBF,
-    0xBF, 0xBF, 0xFF, 0xBC, 
-    0xB9, 0x9D, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xEF, 0xD7,
-    0xF5, 0xF3, 0xF1, 0xD1, 
-    0x65, 0xE3, 0xE3, 0xE3, 0xA3, 0xFF, 0xFE, 0x7F, 0xFE, 0xDE, 0xDE, 0xFF,
-    0xBD, 0xBD, 0xBD, 0xBD, 
-    0xDF, 0xEF, 0xFB, 0xF7, 0xF3, 0xF3, 0xF3, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7,
-    0xFB, 0xFE, 0xFF, 0xFF, 
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-    
-    };
index 774232c13b3188db1d163ee167dd3982ea4acaf1..48dbb35747d8aefa4f04ee098e1f8dd37b022ed7 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/jiffies.h>
+#include <linux/firmware.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-/* Ositech Seven of Diamonds firmware */
-#include "ositech.h"
-
 /*====================================================================*/
 
 static const char *if_names[] = { "auto", "10baseT", "10base2"};
 
+/* Firmware name */
+#define FIRMWARE_NAME          "ositech/Xilinx7OD.bin"
+
 /* Module parameters */
 
 MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE_NAME);
 
 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
 
@@ -771,6 +773,26 @@ static int osi_config(struct pcmcia_device *link)
     return i;
 }
 
+static int osi_load_firmware(struct pcmcia_device *link)
+{
+       const struct firmware *fw;
+       int i, err;
+
+       err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
+       if (err) {
+               pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
+               return err;
+       }
+
+       /* Download the Seven of Diamonds firmware */
+       for (i = 0; i < fw->size; i++) {
+           outb(fw->data[i], link->io.BasePort1 + 2);
+           udelay(50);
+       }
+       release_firmware(fw);
+       return err;
+}
+
 static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
 {
     struct net_device *dev = link->priv;
@@ -811,11 +833,9 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
         (cardid == PRODID_OSITECH_SEVEN)) ||
        ((manfid == MANFID_PSION) &&
         (cardid == PRODID_PSION_NET100))) {
-       /* Download the Seven of Diamonds firmware */
-       for (i = 0; i < sizeof(__Xilinx7OD); i++) {
-           outb(__Xilinx7OD[i], link->io.BasePort1+2);
-           udelay(50);
-       }
+       rc = osi_load_firmware(link);
+       if (rc)
+               goto free_cfg_mem;
     } else if (manfid == MANFID_OSITECH) {
        /* Make sure both functions are powered up */
        set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
@@ -862,10 +882,10 @@ static int smc91c92_resume(struct pcmcia_device *link)
             (smc->cardid == PRODID_OSITECH_SEVEN)) ||
            ((smc->manfid == MANFID_PSION) &&
             (smc->cardid == PRODID_PSION_NET100))) {
-               /* Download the Seven of Diamonds firmware */
-               for (i = 0; i < sizeof(__Xilinx7OD); i++) {
-                       outb(__Xilinx7OD[i], link->io.BasePort1+2);
-                       udelay(50);
+               i = osi_load_firmware(link);
+               if (i) {
+                       pr_err("smc91c92_cs: Failed to load firmware\n");
+                       return i;
                }
        }
        if (link->open) {
index 58b73b08dde08503b35d6e8d3c7ef4f6620ad8c2..3ff1f425f1bb2e48c3321034bb7d9c646331229f 100644 (file)
@@ -757,8 +757,7 @@ EXPORT_SYMBOL(phy_start);
  */
 static void phy_state_machine(struct work_struct *work)
 {
-       struct delayed_work *dwork =
-                       container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct phy_device *phydev =
                        container_of(dwork, struct phy_device, state_queue);
        int needs_aneg = 0;
index a50078627fb6a40f7eeb07772f49eef5fc05131b..913b2a5fafc9fea160fb90bf0c18d1fd2f6e4447 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 
-#include <linux/version.h>
 
 #include "qlge.h"
 
index 06c535222666be7e1c5a0f933268cec7b58052a0..e1a638a05f8621d15cfb74c6f15806bc33323fe8 100644 (file)
@@ -2075,8 +2075,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!tp->pcie_cap && netif_msg_probe(tp))
                dev_info(&pdev->dev, "no PCI Express capability\n");
 
-       /* Unneeded ? Don't mess with Mrs. Murphy. */
-       rtl8169_irq_mask_and_ack(ioaddr);
+       RTL_W16(IntrMask, 0x0000);
 
        /* Soft reset the chip. */
        RTL_W8(ChipCmd, CmdReset);
@@ -2088,6 +2087,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                msleep_interruptible(1);
        }
 
+       RTL_W16(IntrStatus, 0xffff);
+
        /* Identify chip attached to board */
        rtl8169_get_mac_version(tp, ioaddr);
 
index 88dd2e09832f2875eba2ff0eebbe9f3e2abbb83b..ce7551e17ba780e4c1aa5be39b6cc49be2792a8e 100644 (file)
@@ -2299,7 +2299,7 @@ static int sbmac_init(struct platform_device *pldev, long long base)
        eaddr = sc->sbm_hwaddr;
 
        /*
-        * Read the ethernet address.  The firwmare left this programmed
+        * Read the ethernet address.  The firmware left this programmed
         * for us in the ethernet address register for each mac.
         */
 
index 00c23b1babcad720154fe7f73b346cddc1b3b3f9..dee23b159df2b26deff21e9d18c70339ace15daf 100644 (file)
@@ -448,6 +448,9 @@ static void efx_init_channels(struct efx_nic *efx)
 
                WARN_ON(channel->rx_pkt != NULL);
                efx_rx_strategy(channel);
+
+               netif_napi_add(channel->napi_dev, &channel->napi_str,
+                              efx_poll, napi_weight);
        }
 }
 
@@ -462,10 +465,6 @@ static void efx_start_channel(struct efx_channel *channel)
 
        EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
 
-       if (!(channel->efx->net_dev->flags & IFF_UP))
-               netif_napi_add(channel->napi_dev, &channel->napi_str,
-                              efx_poll, napi_weight);
-
        /* The interrupt handler for this channel may set work_pending
         * as soon as we enable it.  Make sure it's cleared before
         * then.  Similarly, make sure it sees the enabled flag set. */
index 1a606d4bfe5e98253ff3b7f241de99887804ebee..e1a7e5f683dc67a0eb91526295f9223f74f878b1 100644 (file)
@@ -145,7 +145,7 @@ struct hw_modul {
        int     leave_isr ;             /* leave fddi_isr immedeately if set */
        int     isr_flag ;              /* set, when HWM is entered from isr */
        /*
-        * varaibles for the current transmit frame
+        * variables for the current transmit frame
         */
        struct s_smt_tx_queue *tx_p ;   /* pointer to the transmit queue */
        u_long  tx_descr ;              /* tx descriptor for FORMAC+ */
index b52a1c088f37717ff19e82df83ee0bd4743bd352..d91e95b237b7822f1442c97d3533b576bcf88dbd 100644 (file)
@@ -1908,7 +1908,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget)
        do {
                tc_writel(status, &tr->Int_Src);        /* write to clear */
 
-               handled = tc35815_do_interrupt(dev, status, limit);
+               handled = tc35815_do_interrupt(dev, status, budget - received);
                if (handled >= 0) {
                        received += handled;
                        if (received >= budget)
index f7efcecc4108f44e8fcdb26a83bb653a17660a36..437683aab32c8dab18a91fe92b5ae0741bfed03a 100644 (file)
@@ -4392,7 +4392,7 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key,
 #if TG3_VLAN_TAG_USED
 static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag)
 {
-       return vlan_hwaccel_receive_skb(skb, tp->vlgrp, vlan_tag);
+       return vlan_gro_receive(&tp->napi, tp->vlgrp, vlan_tag, skb);
 }
 #endif
 
@@ -4539,7 +4539,7 @@ static int tg3_rx(struct tg3 *tp, int budget)
                                    desc->err_vlan & RXD_VLAN_MASK);
                } else
 #endif
-                       netif_receive_skb(skb);
+                       napi_gro_receive(&tp->napi, skb);
 
                received++;
                budget--;
@@ -11225,7 +11225,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
                return tg3_phy_init(tp);
 
        /* Reading the PHY ID register can conflict with ASF
-        * firwmare access to the PHY hardware.
+        * firmware access to the PHY hardware.
         */
        err = 0;
        if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
index 4a65fc2dd9282ffef9dc72a92a559c90b85dd7e3..534c0f38483c3ea97cb47097182f817deab369db 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
+#include <linux/firmware.h>
 
 #include <net/checksum.h>
 
 static char version[] __devinitdata  = 
 "3c359.c v1.2.0 2/17/01 - Mike Phillips (mikep@linuxtr.net)" ; 
 
+#define FW_NAME                "3com/3C359.bin"
 MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; 
 MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ;
+MODULE_FIRMWARE(FW_NAME);
 
 /* Module paramters */
 
@@ -114,8 +117,6 @@ MODULE_PARM_DESC(message_level, "3c359: Level of reported messages") ;
  *     will be stuck with 1555 lines of hex #'s in the code.
  */
 
-#include "3c359_microcode.h" 
-
 static struct pci_device_id xl_pci_tbl[] =
 {
        {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, },
@@ -364,10 +365,30 @@ static int __devinit xl_probe(struct pci_dev *pdev,
        return 0; 
 }
 
+static int xl_init_firmware(struct xl_private *xl_priv)
+{
+       int err;
+
+       err = request_firmware(&xl_priv->fw, FW_NAME, &xl_priv->pdev->dev);
+       if (err) {
+               printk(KERN_ERR "Failed to load firmware \"%s\"\n", FW_NAME);
+               return err;
+       }
+
+       if (xl_priv->fw->size < 16) {
+               printk(KERN_ERR "Bogus length %zu in \"%s\"\n",
+                      xl_priv->fw->size, FW_NAME);
+               release_firmware(xl_priv->fw);
+               err = -EINVAL;
+       }
+
+       return err;
+}
 
 static int __devinit xl_init(struct net_device *dev) 
 {
        struct xl_private *xl_priv = netdev_priv(dev);
+       int err;
 
        printk(KERN_INFO "%s \n", version);
        printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n",
@@ -375,8 +396,11 @@ static int __devinit xl_init(struct net_device *dev)
 
        spin_lock_init(&xl_priv->xl_lock) ; 
 
-       return xl_hw_reset(dev) ; 
+       err = xl_init_firmware(xl_priv);
+       if (err == 0)
+               err = xl_hw_reset(dev);
 
+       return err;
 }
 
 
@@ -386,7 +410,7 @@ static int __devinit xl_init(struct net_device *dev)
  */
 
 static int xl_hw_reset(struct net_device *dev) 
-{ 
+{
        struct xl_private *xl_priv = netdev_priv(dev);
        u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
        unsigned long t ; 
@@ -396,6 +420,9 @@ static int xl_hw_reset(struct net_device *dev)
        u16 start ; 
        int j ;
 
+       if (xl_priv->fw == NULL)
+               return -EINVAL;
+
        /*
         *  Reset the card.  If the card has got the microcode on board, we have 
          *  missed the initialization interrupt, so we must always do this.
@@ -458,25 +485,30 @@ static int xl_hw_reset(struct net_device *dev)
 
                /* 
                 * Now to write the microcode into the shared ram 
-                * The microcode must finish at position 0xFFFF, so we must subtract
-                * to get the start position for the code
+                * The microcode must finish at position 0xFFFF,
+                * so we must subtract to get the start position for the code
+                *
+                * Looks strange but ensures compiler only uses
+                * 16 bit unsigned int
                 */
+               start = (0xFFFF - (xl_priv->fw->size) + 1) ;
 
-               start = (0xFFFF - (mc_size) + 1 ) ; /* Looks strange but ensures compiler only uses 16 bit unsigned int for this */ 
-               
                printk(KERN_INFO "3C359: Uploading Microcode: "); 
-               
-               for (i = start, j = 0; j < mc_size; i++, j++) { 
-                       writel(MEM_BYTE_WRITE | 0XD0000 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 
-                       writeb(microcode[j],xl_mmio + MMIO_MACDATA) ; 
+
+               for (i = start, j = 0; j < xl_priv->fw->size; i++, j++) {
+                       writel(MEM_BYTE_WRITE | 0XD0000 | i,
+                              xl_mmio + MMIO_MAC_ACCESS_CMD);
+                       writeb(xl_priv->fw->data[j], xl_mmio + MMIO_MACDATA);
                        if (j % 1024 == 0)
                                printk(".");
                }
                printk("\n") ; 
 
-               for (i=0;i < 16; i++) { 
-                       writel( (MEM_BYTE_WRITE | 0xDFFF0) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 
-                       writeb(microcode[mc_size - 16 + i], xl_mmio + MMIO_MACDATA) ; 
+               for (i = 0; i < 16; i++) {
+                       writel((MEM_BYTE_WRITE | 0xDFFF0) + i,
+                              xl_mmio + MMIO_MAC_ACCESS_CMD);
+                       writeb(xl_priv->fw->data[xl_priv->fw->size - 16 + i],
+                              xl_mmio + MMIO_MACDATA);
                }
 
                /*
@@ -1782,6 +1814,7 @@ static void __devexit xl_remove_one (struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct xl_private *xl_priv=netdev_priv(dev);
        
+       release_firmware(xl_priv->fw);
        unregister_netdev(dev);
        iounmap(xl_priv->xl_mmio) ; 
        pci_release_regions(pdev) ; 
index 66b1ff603234774b1b4a1247af34dc4486afce9c..bcb1a6b4a4c774799a9db2e0d7d10dc3e743ee46 100644 (file)
@@ -284,5 +284,8 @@ struct xl_private {
        u8 xl_laa[6] ; 
        u32 rx_ring_dma_addr ; 
        u32 tx_ring_dma_addr ; 
+
+       /* firmware section */
+       const struct firmware *fw;
 };
 
diff --git a/drivers/net/tokenring/3c359_microcode.h b/drivers/net/tokenring/3c359_microcode.h
deleted file mode 100644 (file)
index 0400c02..0000000
+++ /dev/null
@@ -1,1581 +0,0 @@
-
-/*
- * The firmware this driver downloads into the tokenring card is a
- * separate program and is not GPL'd source code, even though the Linux
- * side driver and the routine that loads this data into the card are.
- *
- * This firmware is licensed to you strictly for use in conjunction
- * with the use of 3Com 3C359 TokenRing adapters. There is no
- * waranty expressed or implied about its fitness for any purpose.
- */
-
-/* 3c359_microcode.mac: 3Com 3C359 Tokenring microcode.
- *
- * Notes:
- *  - Loaded from xl_init upon adapter initialization.
- *
- * Available from 3Com as part of their standard 3C359 driver. 
- *
- * mc_size *must* must match the microcode being used, each version is a 
- * different length.
- */
-
-static int mc_size = 24880 ; 
-
-static const u8 microcode[] = { 
- 0xfe,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x33,0x2f,0x30,0x32,0x2f,0x39,0x39,0x20,0x31
-,0x37,0x3a,0x31,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46
-,0x00,0x00,0x07,0xff,0x02,0x00,0xfe,0x9f,0x06,0x00,0x00,0x7c,0x48,0x00,0x00,0x70
-,0x82,0x00,0xff,0xff,0x86,0x00,0xff,0xff,0x88,0x00,0xff,0xff,0x9a,0x00,0xff,0xff
-,0xff,0xff,0x11,0x00,0xc0,0x00,0xff,0xff,0xff,0xff,0x11,0x22,0x33,0x44,0x55,0x66
-,0x33,0x43,0x4f,0x4d,0x20,0x42,0x41,0x42,0x45,0x11,0x40,0xc0,0x00,0xff,0xff,0xff
-,0xff,0x11,0x22,0x33,0x44,0x55,0x66,0x53,0x74,0x61,0x72,0x74,0x20,0x6f,0x66,0x20
-,0x4c,0x4c,0x43,0x20,0x66,0x72,0x61,0x6d,0x65,0x2e,0x20,0x20,0x54,0x6f,0x74,0x61
-,0x6c,0x20,0x64,0x61,0x74,0x61,0x20,0x73,0x69,0x7a,0x65,0x20,0x69,0x73,0x20,0x78
-,0x78,0x78,0x20,0x20,0x20,0x42,0x41,0x42,0x45,0xe8,0xd2,0x01,0x83,0x3e,0xf7,0x34
-,0x00,0x75,0x21,0xe8,0x41,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75,0x17,0xe8,0x82,0x00
-,0x83,0x3e,0xf7,0x34,0x00,0x75,0x0d,0xe8,0xbf,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75
-,0x03,0xe8,0x41,0x02,0xc3,0x1e,0xb8,0x00,0xf0,0x8e,0xd8,0x33,0xf6,0xb9,0x00,0x80
-,0x33,0xdb,0xad,0x03,0xd8,0xe2,0xfb,0x1f,0xb8,0x00,0x00,0x83,0xfb,0x00,0x74,0x03
-,0xb8,0x22,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x56,0x00,0xb0,0xff,0xee,0x33,0xc0
-,0x8e,0xc0,0x33,0xf6,0xb9,0xff,0x7f,0x83,0x3e,0xff,0x34,0x00,0x74,0x08,0x8d,0x3e
-,0x30,0x61,0xd1,0xef,0x2b,0xcf,0x26,0x8b,0x1c,0x26,0xc7,0x04,0xff,0xff,0x26,0x83
-,0x3c,0xff,0x75,0x17,0x26,0xc7,0x04,0x00,0x00,0x26,0x83,0x3c,0x00,0x75,0x0c,0x26
-,0x89,0x1c,0x46,0x46,0xe2,0xe0,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x24,0x00,0xa3,0xf7
-,0x34,0xc3,0xfa,0xb4,0xd7,0x9e,0x73,0x3a,0x75,0x38,0x79,0x36,0x7b,0x34,0x9f,0xb1
-,0x05,0xd2,0xec,0x73,0x2d,0xb0,0x40,0xd0,0xe0,0x71,0x27,0x79,0x25,0xd0,0xe0,0x73
-,0x21,0x7b,0x1f,0x32,0xc0,0x75,0x1b,0x32,0xe4,0x9e,0x72,0x16,0x74,0x14,0x78,0x12
-,0x7a,0x10,0x9f,0xd2,0xec,0x72,0x0b,0xd0,0xe4,0x70,0x07,0x75,0x05,0xb8,0x00,0x00
-,0xeb,0x03,0xb8,0x26,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x5a,0x00,0x33,0xc0,0xef
-,0xef,0xef,0xef,0xb0,0x00,0xe6,0x56,0xb0,0x00,0xe6,0x54,0xba,0x52,0x00,0xb8,0x01
-,0x01,0xef,0xe8,0xca,0x00,0x3c,0x01,0x75,0x7f,0xe8,0x83,0x00,0xba,0x52,0x00,0xb8
-,0x02,0x02,0xef,0xe8,0xb9,0x00,0x3c,0x02,0x75,0x6e,0xe8,0x7a,0x00,0xba,0x52,0x00
-,0xb8,0x04,0x04,0xef,0xe8,0xa8,0x00,0x3c,0x04,0x75,0x5d,0xe8,0x71,0x00,0xba,0x52
-,0x00,0xb8,0x08,0x08,0xef,0xe8,0x97,0x00,0x3c,0x08,0x75,0x4c,0xe8,0x68,0x00,0xba
-,0x52,0x00,0xb8,0x10,0x10,0xef,0xe8,0x86,0x00,0x3c,0x10,0x75,0x3b,0xe8,0x5f,0x00
-,0xba,0x52,0x00,0xb8,0x20,0x20,0xef,0xe8,0x75,0x00,0x3c,0x20,0x75,0x2a,0xe8,0x56
-,0x00,0xba,0x52,0x00,0xb8,0x40,0x40,0xef,0xe8,0x64,0x00,0x3c,0x40,0x75,0x19,0xe8
-,0x4d,0x00,0xba,0x52,0x00,0xb8,0x80,0x80,0xef,0xe8,0x53,0x00,0x3c,0x80,0x75,0x08
-,0xe8,0x44,0x00,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x28,0x00,0xa3,0xf7,0x34,0xc3,0xba
-,0x5a,0x00,0xb8,0x00,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x01,0x80,0xef,0xc3,0xba
-,0x5a,0x00,0xb8,0x02,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x03,0x80,0xef,0xc3,0xba
-,0x5a,0x00,0xb8,0x04,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x05,0x80,0xef,0xc3,0xba
-,0x5a,0x00,0xb8,0x06,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x07,0x80,0xef,0xc3,0xb9
-,0xff,0xff,0xe4,0x58,0xe4,0x54,0x3c,0x00,0x75,0x03,0x49,0x75,0xf7,0xc3,0xfa,0x32
-,0xc0,0xe6,0x56,0xe4,0x56,0x3c,0x00,0x74,0x03,0xe9,0x82,0x00,0xb0,0xff,0xe6,0x56
-,0xe4,0x56,0x3c,0xff,0x75,0x78,0xba,0x52,0x00,0xb8,0xff,0xff,0xef,0xed,0x3c,0xff
-,0x75,0x6c,0xb8,0x00,0xff,0xef,0xed,0x3c,0x00,0x75,0x63,0xb0,0xff,0xe6,0x54,0xe4
-,0x54,0x3c,0xff,0x75,0x59,0x32,0xc0,0xe6,0x54,0xe4,0x54,0x3c,0x00,0x75,0x4f,0xb0
-,0x0f,0xe6,0x50,0xe4,0x50,0x24,0x0f,0x3c,0x0f,0x75,0x43,0xb0,0x00,0xe6,0x50,0xe4
-,0x50,0x24,0x0f,0x3c,0x00,0x75,0x37,0x8c,0xc8,0x8e,0xc0,0xbe,0x70,0x00,0x26,0x8b
-,0x14,0x26,0x8b,0x5c,0x02,0xb8,0x00,0x00,0xef,0xed,0x23,0xc3,0x3d,0x00,0x00,0x75
-,0x1d,0xb8,0xff,0xff,0x23,0xc3,0xef,0x8b,0xc8,0xed,0x23,0xc3,0x3b,0xc1,0x75,0x0e
-,0x83,0xc6,0x04,0x26,0x83,0x3c,0xff,0x75,0xd5,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x2a
-,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0x33,0xc0,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xab
-,0xbf,0x00,0x30,0xb9,0x17,0x00,0xf3,0xab,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xab
-,0xbf,0x00,0x32,0xb9,0x40,0x00,0xf3,0xab,0xfc,0x1e,0x8c,0xc8,0x8e,0xd8,0x33,0xc0
-,0x8e,0xc0,0xbe,0x92,0x00,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xa4,0xbe,0xa9,0x00
-,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0xfb,0x34,0x64,0x00,0xba
-,0x08,0x00,0xb8,0x0f,0x00,0xef,0xe8,0x82,0x01,0xe8,0x9b,0x01,0x72,0x0d,0xc7,0x06
-,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34,0x04,0x00,0xc3,0xba,0x0a,0x00,0x33,0xc0
-,0xef,0xe8,0x98,0x01,0xe8,0xb5,0x01,0xb8,0x17,0x00,0xba,0x9c,0x00,0xef,0xb8,0x00
-,0x10,0xba,0x9a,0x00,0xef,0xb8,0x17,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x8c
-,0x00,0xef,0xb8,0x00,0x18,0xba,0x86,0x00,0xef,0xb8,0x0c,0x00,0xba,0x82,0x00,0xef
-,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x02,0x00,0xef,0xba,0x06,0x00,0x33,0xc0
-,0xef,0xba,0x04,0x00,0xb8,0x60,0x00,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba
-,0x80,0x00,0xb9,0xff,0xff,0xed,0xa9,0x01,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x3e,0xba
-,0x0a,0x00,0xed,0xa9,0x00,0x40,0x74,0x35,0xa9,0x00,0x20,0x74,0x30,0x33,0xc0,0xef
-,0x51,0xb9,0xc8,0x00,0xe2,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x30,0x83
-,0xf9,0x17,0x75,0x18,0x49,0x49,0xbe,0x02,0x20,0xbf,0x06,0x30,0xf3,0xa6,0x1f,0x23
-,0xc9,0x75,0x0a,0xff,0x0e,0xfb,0x34,0x74,0x12,0xe9,0x4d,0xff,0x1f,0xb8,0x2c,0x00
-,0xbb,0x00,0x00,0xa3,0xf7,0x34,0x89,0x1e,0xf9,0x34,0xc3,0xc7,0x06,0xfb,0x34,0x64
-,0x00,0xe8,0xd3,0x00,0x72,0x0d,0xc7,0x06,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34
-,0x04,0x00,0xc3,0xe8,0xd6,0x00,0xe8,0xf3,0x00,0xb8,0x03,0x00,0xba,0x82,0x00,0xef
-,0xb8,0x40,0x80,0xba,0x98,0x00,0xef,0xb8,0x00,0x11,0xba,0x96,0x00,0xef,0xb8,0x40
-,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x92,0x00,0xef,0xb8,0x00,0x19,0xba,0x8e
-,0x00,0xef,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x06,0x00,0xef,0xba,0x06,0x00
-,0x33,0xc0,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba,0x80,0x00,0xb9,0xff,0xff
-,0xed,0xa9,0x20,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x43,0xba,0x0a,0x00,0xed,0xa9,0x00
-,0x40,0x74,0x3a,0xa9,0x00,0x20,0x74,0x35,0x33,0xc0,0xef,0x51,0xb9,0xc8,0x00,0xe2
-,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x32,0x83,0xf9,0x40,0x75,0x1d,0x49
-,0x49,0xbe,0x02,0x22,0xbf,0x06,0x32,0xf3,0xa6,0x1f,0x23,0xc9,0x75,0x0f,0xff,0x0e
-,0xfb,0x34,0x74,0x03,0xe9,0x5a,0xff,0xb8,0x00,0x00,0xeb,0x0b,0x1f,0xb8,0x2c,0x00
-,0xbb,0x02,0x00,0x89,0x1e,0xf9,0x34,0xa3,0xf7,0x34,0xc3,0xba,0x02,0x00,0xb8,0x00
-,0x9c,0xef,0xba,0x00,0x00,0xb8,0x00,0x84,0xef,0x33,0xc0,0xef,0xba,0x0a,0x00,0xef
-,0xba,0x0e,0x00,0x33,0xc0,0xef,0xc3,0xba,0x0a,0x00,0xb9,0xff,0xff,0xed,0x25,0x00
-,0x60,0x3d,0x00,0x60,0x74,0x04,0xe2,0xf5,0xf8,0xc3,0xf9,0xc3,0xb0,0x00,0xe6,0x56
-,0xb8,0x00,0xff,0xba,0x52,0x00,0xef,0xb9,0xff,0xff,0xba,0x58,0x00,0xed,0x25,0xef
-,0x00,0x74,0x08,0xba,0x5a,0x00,0x33,0xc0,0xef,0xe2,0xef,0xc3,0xba,0x80,0x00,0xed
-,0xba,0x84,0x00,0xef,0xba,0x80,0x00,0xed,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0xc6,0x06,0xec,0x34,0x15,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0x1e,0x8c,0xc8,0xbe,0x40
-,0x54,0xbf,0x60,0xfe,0x8e,0xd8,0xb9,0x10,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0x80,0x36
-,0x10,0x35,0xc7,0x06,0x8c,0x36,0x30,0x35,0x8d,0x06,0x38,0x35,0xa3,0x30,0x35,0xa3
-,0x32,0x35,0x05,0x33,0x01,0xa3,0x34,0x35,0xc7,0x06,0x36,0x35,0x50,0x01,0xc7,0x06
-,0x84,0x36,0x80,0xfe,0xc7,0x06,0x88,0x36,0xc0,0xfe,0xc6,0x06,0xc2,0xfe,0xff,0xc6
-,0x06,0x93,0x36,0x80,0xc6,0x06,0x92,0x36,0x00,0xc6,0x06,0x80,0xfe,0x80,0xc7,0x06
-,0x82,0xfe,0x54,0x50,0xc7,0x06,0x84,0xfe,0x2b,0x4d,0xe5,0xce,0xa9,0x02,0x00,0x75
-,0x08,0xc6,0x06,0x81,0xfe,0x23,0xe9,0x05,0x00,0xc6,0x06,0x81,0xfe,0x22,0xa1,0xf7
-,0x34,0xa3,0x86,0xfe,0xb8,0x48,0x34,0x86,0xe0,0xa3,0x88,0xfe,0x8d,0x06,0x4e,0x34
-,0x86,0xe0,0xa3,0x8a,0xfe,0xb8,0x58,0x34,0x86,0xe0,0xa3,0x8c,0xfe,0xb8,0x9c,0x34
-,0x86,0xe0,0xa3,0x8e,0xfe,0x8d,0x06,0x20,0x03,0x86,0xe0,0xa3,0x90,0xfe,0x33,0xc0
-,0xba,0x72,0x00,0xef,0x33,0xc0,0xba,0x74,0x00,0xef,0xba,0x76,0x00,0xef,0xb8,0x80
-,0xfe,0x86,0xe0,0xba,0x72,0x00,0xef,0xe8,0xbf,0x07,0xba,0x0c,0x01,0xb8,0x40,0x40
-,0xef,0xed,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0xb9
-,0x0a,0x00,0xe8,0x94,0x00,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0xef,0xa1
-,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33,0xc1
-,0xe8,0x04,0xcd,0x39,0xc7,0x06,0x90,0x36,0xff,0xff,0xe9,0xe3,0x00,0x63,0x0d,0x66
-,0x0d,0x66,0x0d,0x8a,0x0d,0xe6,0x0e,0x75,0x12,0x2e,0x0f,0x03,0x0f,0x50,0x0f,0x60
-,0x0d,0x60,0x0d,0x60,0x0d,0xed,0x0f,0xe9,0x12,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60
-,0x0d,0x60,0x0d,0x22,0x10,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xfe,0x10,0x60
-,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xaf,0x0f,0x32,0x10,0x37
-,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60
-,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60
-,0x0d,0x64,0x0e,0x00,0x0f,0x95,0x09,0x60,0x0a,0x49,0xbb,0xff,0xff,0xba,0x6a,0x00
-,0xed,0xa9,0x00,0x20,0x74,0x38,0x80,0x3e,0x80,0xfe,0x12,0x75,0x31,0xe8,0x4a,0x00
-,0xa1,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33
-,0xc1,0xe8,0x04,0xcd,0x39,0xe8,0x22,0x00,0xc7,0x06,0xf3,0x34,0x46,0x00,0xc7,0x06
-,0xf5,0x34,0xff,0xff,0xc7,0x06,0x90,0x36,0xff,0xff,0x58,0xe9,0x32,0x00,0x4b,0x83
-,0xfb,0x00,0x75,0xb9,0x83,0xf9,0x00,0x75,0xb0,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03
-,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0x5a,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03
-,0x00,0xc1,0xe0,0x08,0xef,0x5a,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x68,0x80,0x07,0xa1,0x90,0x36,0xcd,0x35,0x8b,0x36,0x24,0x02,0x2e,0xff,0xa4,0x35
-,0x0a,0xfa,0x8a,0x26,0x94,0x36,0x88,0x26,0xe8,0x34,0xc6,0x06,0x94,0x36,0x00,0xfb
-,0x22,0xe4,0x75,0x01,0xc3,0xf6,0xc4,0x20,0x74,0x7d,0xf6,0xc4,0x08,0x74,0x05,0x80
-,0x0e,0x92,0x36,0x04,0x80,0x26,0xe8,0x34,0xd7,0xc4,0x1e,0x84,0x36,0x26,0x8b,0x37
-,0x81,0xe6,0xff,0x00,0x83,0xfe,0x20,0x76,0x05,0xb0,0x01,0xe9,0x28,0x00,0x53,0x06
-,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0x07,0x5b,0x26,0x88,0x47,0x02,0x3c,0xff,0x74
-,0x07,0x3c,0xfe,0x75,0x11,0xe9,0x3b,0x00,0xf6,0x06,0x92,0x36,0x08,0x75,0x34,0xf6
-,0x06,0x92,0x36,0x04,0x74,0x2d,0x80,0x26,0x92,0x36,0xf3,0x80,0x3e,0x95,0x36,0x00
-,0x75,0x21,0x26,0x80,0x3f,0x05,0x75,0x13,0xc6,0x06,0x95,0x36,0x00,0x26,0x80,0x7f
-,0x06,0x00,0x74,0x07,0x26,0x8b,0x47,0x04,0xa2,0x95,0x36,0xba,0x0c,0x01,0xb8,0x40
-,0x40,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x10,0x75,0x03,0xe9,0x5b,0x00,0xf6
-,0xc4,0x04,0x74,0x05,0x80,0x0e,0x92,0x36,0x01,0x80,0x26,0xe8,0x34,0xeb,0xc4,0x3e
-,0x88,0x36,0x26,0x8b,0x35,0x83,0xe6,0x7f,0x83,0xfe,0x12,0x72,0x08,0x26,0xc6,0x45
-,0x02,0x01,0xe9,0x24,0x00,0x83,0xc6,0x20,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0xc4
-,0x3e,0x88,0x36,0x26,0x88,0x45,0x02,0x3c,0xff,0x75,0x0e,0xf6,0x06,0x92,0x36,0x01
-,0x74,0x14,0xf6,0x06,0x92,0x36,0x02,0x75,0x0d,0x80,0x26,0x92,0x36,0xfc,0xba,0x0c
-,0x01,0xb8,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x08,0x74,0x22,0x80
-,0x26,0xe8,0x34,0xf7,0x80,0x0e,0x92,0x36,0x04,0xf6,0x06,0x92,0x36,0x08,0x74,0x11
-,0x80,0x26,0x92,0x36,0xf3,0xba,0x0c,0x01,0xb8,0x40,0x40,0xef,0xed,0x8a,0x26,0xe8
-,0x34,0xf6,0xc4,0x04,0x74,0x22,0x80,0x26,0xe8,0x34,0xfb,0x80,0x0e,0x92,0x36,0x01
-,0xf6,0x06,0x92,0x36,0x02,0x75,0x11,0x80,0x26,0x92,0x36,0xfe,0xba,0x0c,0x01,0xb8
-,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x01,0x74,0x67,0x80,0x26,0xe8
-,0x34,0xfe,0x80,0x3e,0xe8,0xff,0x00,0x74,0x39,0x80,0x3e,0xe8,0xff,0x04,0x74,0x32
-,0x80,0x3e,0xe8,0xff,0x01,0x75,0x21,0xe5,0x80,0xa9,0x00,0x07,0x74,0x0a,0xba,0x9e
-,0x00,0xb8,0x00,0x02,0xef,0xe9,0xef,0xff,0xc6,0x06,0xe8,0xff,0x03,0xba,0x0c,0x01
-,0xb8,0x08,0x08,0xef,0xed,0xe9,0x28,0x00,0x80,0x3e,0xe8,0xff,0x03,0x74,0x06,0xe9
-,0x1e,0x00,0xe9,0x00,0x00,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0xe5,0x00,0x0d
-,0x18,0x00,0xe7,0x00,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xc6,0x06,0xe8,0xff,0x04
-,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x02,0x74,0x0d,0x80,0x26,0xe8,0x34,0xfd,0x80,0x26
-,0x92,0x36,0xbf,0xe8,0x4f,0x0b,0xfa,0xa0,0xe8,0x34,0x08,0x06,0x94,0x36,0xc6,0x06
-,0xe8,0x34,0x00,0xfb,0xc3,0xe8,0xe7,0x0f,0xc4,0x1e,0x84,0x36,0x2e,0xff,0x16,0x01
-,0x07,0x26,0x88,0x47,0x02,0xe9,0x7e,0xfe,0xe8,0x2d,0x10,0xc4,0x1e,0x84,0x36,0x2e
-,0xff,0x16,0x03,0x07,0x26,0x88,0x47,0x02,0xe9,0x6b,0xfe,0x8e,0x06,0x26,0x02,0x2e
-,0xff,0x16,0x07,0x07,0xc3,0xc3,0x83,0x3e,0xf5,0x34,0x00,0x74,0x0f,0xff,0x0e,0xf3
-,0x34,0x75,0x09,0xe8,0xc4,0xfd,0xc7,0x06,0xf5,0x34,0x00,0x00,0xf6,0x06,0x93,0x36
-,0x20,0x74,0x30,0xa1,0xc2,0x34,0x3b,0x06,0xe9,0x34,0xa3,0xe9,0x34,0x74,0x24,0x80
-,0x3e,0x95,0x36,0x00,0x75,0x1d,0xf7,0x06,0xe6,0x34,0x20,0x00,0x74,0x12,0xa9,0x20
-,0x00,0x74,0x0d,0x83,0x26,0xc2,0x34,0xdf,0x83,0x26,0xe9,0x34,0xdf,0xe9,0x03,0x00
-,0xe8,0xdd,0x09,0xba,0x06,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e
-,0x03,0x16,0x74,0x34,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06,0x74
-,0x34,0xba,0x02,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e,0x03,0x16
-,0x70,0x34,0xc1,0xe0,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0xc7
-,0x06,0xa6,0x33,0x04,0x00,0xc7,0x06,0xaa,0x33,0x00,0x00,0x8d,0x06,0xa0,0x33,0xc1
-,0xe8,0x04,0xcd,0x39,0xc3,0x95,0x09,0x95,0x09,0x65,0x09,0x78,0x09,0x95,0x09,0x95
-,0x09,0x91,0x07,0x95,0x09,0x96,0x09,0x8b,0x09,0x95,0x09,0x95,0x09,0x95,0x09,0x95
-,0x09,0x95,0x09,0x95,0x09,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x90
-,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9,0xcc,0x00,0x8c,0xc0,0x40,0x8e,0xc0,0x26
-,0x8b,0x0e,0x06,0x00,0x86,0xe9,0x26,0x89,0x0e,0x06,0x00,0x8c,0xc2,0xc1,0xe2,0x04
-,0xbe,0x0e,0x00,0x26,0xa1,0x04,0x00,0xd0,0xe0,0x24,0xc0,0x8a,0xe0,0xc0,0xec,0x04
-,0x0a,0xc4,0x26,0xa2,0x05,0x00,0x26,0xa1,0x08,0x00,0xa9,0x00,0xc0,0x74,0x03,0xe9
-,0x9e,0x00,0x26,0xf6,0x06,0x10,0x00,0x80,0x75,0x03,0xe9,0x0a,0x00,0x26,0xa0,0x16
-,0x00,0x24,0x1f,0x32,0xe4,0x03,0xf0,0x80,0x3e,0xec,0x34,0x06,0x72,0x5c,0x80,0x3e
-,0x95,0x36,0x00,0x75,0x66,0x8b,0xfa,0x33,0xdb,0x8e,0xc3,0x26,0x89,0x1d,0x26,0x88
-,0x5d,0x04,0x51,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x21,0x09
-,0x58,0x59,0x0b,0xdb,0x74,0x34,0xfe,0x0e,0xe6,0x3a,0x26,0xc6,0x07,0x81,0x26,0xc6
-,0x47,0x01,0x00,0x26,0xc6,0x47,0x02,0xff,0x26,0xc7,0x47,0x04,0x00,0x00,0x26,0x89
-,0x4f,0x0a,0x86,0xf2,0x26,0x89,0x57,0x06,0x26,0x89,0x77,0x08,0x26,0xc6,0x47,0x09
-,0x00,0x26,0xc6,0x47,0x0c,0x02,0xe8,0x8c,0x09,0xc3,0xff,0x06,0xec,0x33,0x8c,0xc0
-,0x48,0x8e,0xc0,0xfa,0xe8,0x97,0x10,0xfb,0xe9,0xeb,0xff,0x8c,0xc0,0x48,0x8e,0xc0
-,0xfa,0xe8,0x8a,0x10,0xfb,0xc3,0x8c,0xc0,0x8e,0xc0,0xfa,0xe8,0x80,0x10,0xfb,0xc3
-,0x80,0x3e,0x95,0x36,0x00,0x75,0x03,0xe9,0xc2,0x00,0xbf,0x08,0x00,0x26,0xf6,0x06
-,0x10,0x00,0x80,0x75,0x05,0x03,0xfe,0xe9,0x0c,0x00,0x26,0xa0,0x16,0x00,0x24,0x1f
-,0x32,0xe4,0x03,0xf0,0x03,0xfe,0xa0,0x95,0x36,0x3c,0x00,0x75,0x03,0xe9,0x9c,0x00
-,0x3c,0x01,0x74,0x0b,0x3c,0x02,0x74,0x14,0x3c,0x03,0x74,0x1d,0xe9,0x8d,0x00,0xc6
-,0x06,0x96,0x36,0x01,0xe8,0x3c,0x01,0x72,0x27,0xe9,0x80,0x00,0xc6,0x06,0x96,0x36
-,0x02,0xe8,0x83,0x00,0x72,0x1a,0xe9,0x73,0x00,0xc6,0x06,0x96,0x36,0x01,0xe8,0x22
-,0x01,0x72,0x0d,0xc6,0x06,0x96,0x36,0x02,0xe8,0x6c,0x00,0x72,0x03,0xe9,0x5c,0x00
-,0x53,0x06,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0b,0x00,0x33,0xc0,0xe8,0x42,0x08,0x58
-,0x26,0xc6,0x07,0x82,0x26,0xc6,0x47,0x02,0xff,0x8d,0x06,0xe0,0xfe,0x86,0xc4,0x26
-,0x89,0x47,0x06,0xa0,0x96,0x36,0x26,0x88,0x47,0x08,0xe8,0xc8,0x08,0x07,0x5b,0x83
-,0x26,0xad,0x36,0xfe,0xa1,0xad,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef
-,0xed,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0x52,0xba,0xe0,0x00,0xb8,0x41,0x10
-,0xef,0x5a,0xb8,0x9c,0x03,0xcd,0x39,0xc6,0x06,0x95,0x36,0x00,0x8c,0xc0,0x48,0x8e
-,0xc0,0xfa,0xe8,0xa9,0x0f,0xfb,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x8b
-,0xf0,0x8d,0x3e,0x20,0xf3,0x51,0xb1,0x0a,0x26,0x83,0x7d,0x0c,0x01,0x75,0x2a,0x57
-,0x26,0x83,0x7d,0x0e,0x00,0x74,0x06,0xe8,0x2f,0x00,0xe9,0x03,0x00,0xe8,0x66,0x07
-,0x5f,0x73,0x16,0x33,0xc0,0x8e,0xd8,0x26,0x8b,0x4d,0x12,0x8d,0x75,0x20,0x8d,0x3e
-,0xe0,0xfe,0xf3,0xa4,0x59,0x07,0x1f,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20
-,0x01,0xe9,0xc4,0xff,0x59,0x07,0x1f,0xf8,0xc3,0x51,0x50,0x53,0x56,0x52,0x57,0x33
-,0xdb,0x26,0x8a,0x5d,0x0e,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0x5a,0x87,0xd7,0x26
-,0x8a,0x45,0x14,0x87,0xd7,0x42,0x32,0xff,0x80,0xff,0x08,0x75,0x08,0xfe,0xcb,0x22
-,0xdb,0x75,0xea,0x33,0xdb,0x23,0xdb,0x74,0x06,0xfe,0xc7,0xd0,0xc8,0x73,0x0c,0x50
-,0x26,0x8a,0x05,0x38,0x04,0x58,0x74,0x03,0xe9,0x0a,0x00,0x49,0x46,0x47,0x23,0xc9
-,0x74,0x0a,0xe9,0xd3,0xff,0x5a,0x5e,0x5b,0x58,0x59,0xf8,0xc3,0x5a,0x5e,0x5b,0x58
-,0x59,0xf9,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x86,0xcd,0x2b,0xce,0x8b
-,0xf7,0x8b,0xc1,0x33,0xc9,0x80,0x3c,0xff,0x74,0x16,0x80,0xf9,0x06,0x73,0x09,0x32
-,0xc9,0x46,0x48,0x74,0x2e,0xe9,0xed,0xff,0x3d,0x60,0x00,0x73,0x0c,0xe9,0x23,0x00
-,0xfe,0xc1,0x46,0x48,0x74,0x1d,0xe9,0xdc,0xff,0xb8,0x10,0x00,0x8d,0x3e,0x18,0x34
-,0x32,0xed,0xb1,0x06,0xf3,0xa6,0x74,0x03,0xe9,0x08,0x00,0x48,0x23,0xc0,0x74,0x07
-,0xe9,0xe9,0xff,0x07,0x1f,0xf8,0xc3,0x8d,0x36,0x18,0x34,0x33,0xc0,0x8e,0xd8,0x8d
-,0x3e,0xe0,0xfe,0xb8,0x10,0x00,0xb9,0x06,0x00,0x56,0xf3,0xa4,0x5e,0x48,0x3d,0x00
-,0x00,0x75,0xf3,0x07,0x1f,0xf9,0xc3,0xff,0x06,0xe4,0x33,0xc6,0x06,0xeb,0x34,0x00
-,0x26,0x8b,0x45,0x06,0x86,0xe0,0xc1,0xe8,0x04,0x48,0x06,0x8e,0xc0,0xfe,0x06,0xe6
-,0x3a,0xfa,0xe8,0x69,0x0e,0xfb,0x07,0xb0,0xff,0xc3,0x00,0x00,0x00,0x00,0x00,0x00
-,0xb0,0x01,0xc3,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3
-,0x8b,0x0e,0x97,0x36,0x81,0xe1,0x80,0x30,0x26,0x8b,0x47,0x04,0x25,0x7f,0xcf,0x0b
-,0xc1,0xa3,0x97,0x36,0xa3,0xe6,0x34,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x74
-,0x03,0xb0,0x03,0xc3,0x26,0x8b,0x47,0x08,0xa3,0x97,0x36,0xa3,0xe6,0x34,0x26,0x8a
-,0x47,0x20,0xa2,0xfd,0x34,0x3c,0x01,0x75,0x06,0xc7,0x06,0xa1,0x36,0x00,0x00,0x26
-,0x8a,0x47,0x21,0xa2,0xfe,0x34,0x26,0x8b,0x47,0x0a,0xa3,0x18,0x34,0xa3,0x58,0x34
-,0x26,0x8b,0x47,0x0c,0xa3,0x1a,0x34,0xa3,0x5a,0x34,0x26,0x8b,0x47,0x0e,0xa3,0x1c
-,0x34,0xa3,0x5c,0x34,0xc6,0x06,0x2a,0x34,0xc0,0x26,0x8b,0x47,0x14,0x25,0x7f,0xff
-,0x09,0x06,0x2c,0x34,0x26,0x8b,0x47,0x16,0x25,0xff,0xfe,0x25,0xff,0xfc,0x09,0x06
-,0x2e,0x34,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47,0x10,0xa3,0x02,0x34,0x26,0x8b
-,0x47,0x12,0xa3,0x04,0x34,0x06,0x53,0xe8,0x84,0x0a,0x5b,0x07,0x3d,0x00,0x00,0x75
-,0x07,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3,0xb9,0x00,0x01,0xa1,0xac,0x33,0x33
-,0xd2,0xf7,0xf9,0xa3,0xae,0x33,0x91,0x49,0x33,0xd2,0xf7,0xe9,0x05,0x00,0x3b,0xa3
-,0x46,0x34,0xbf,0x00,0x3b,0x89,0x3e,0x44,0x34,0xba,0x68,0x00,0xb8,0xe0,0xe0,0xef
-,0xa1,0xae,0x33,0xe7,0x62,0xa1,0xae,0x33,0xba,0x08,0x01,0xef,0xa1,0x44,0x34,0xe7
-,0x64,0xa1,0x44,0x34,0xba,0x0a,0x01,0xef,0xb8,0x00,0x01,0x2d,0x04,0x00,0x0d,0x00
-,0x10,0xe7,0x92,0xc3,0x3d,0x00,0x00,0x74,0x0a,0x26,0x89,0x47,0x07,0xe8,0x83,0x3a
-,0xb0,0x07,0xc3,0xa1,0xae,0x33,0x26,0x89,0x47,0x2b,0xa1,0x44,0x34,0x26,0x89,0x47
-,0x2d,0xa1,0x46,0x34,0x26,0x89,0x47,0x2f,0x80,0x0e,0x93,0x36,0x20,0xa1,0x88,0x36
-,0x86,0xe0,0x26,0x89,0x47,0x08,0xa1,0x84,0x36,0x86,0xe0,0x26,0x89,0x47,0x0a,0xa1
-,0x80,0x36,0x86,0xe0,0x26,0x89,0x47,0x0c,0xb8,0x60,0xfe,0x86,0xe0,0x26,0x89,0x47
-,0x0e,0xa0,0xa1,0x36,0x26,0x88,0x47,0x10,0x8b,0x36,0x88,0x36,0x26,0xc6,0x44,0x02
-,0xff,0xe5,0x9e,0xa9,0x00,0x08,0x74,0x0c,0xba,0x84,0x00,0xed,0x0d,0x08,0x00,0xef
-,0xba,0x8e,0x00,0xef,0xe5,0x02,0x25,0xf9,0xff,0xe7,0x02,0xba,0x10,0x01,0xb8,0x02
-,0x02,0xef,0xed,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3
-,0x80,0x26,0x93,0x36,0x9f,0xe8,0x8d,0x0a,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3
-,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x2a
-,0x34,0xc0,0x26,0x8b,0x47,0x06,0x25,0x7f,0xff,0xa3,0x2c,0x34,0x26,0x8b,0x47,0x08
-,0x25,0xff,0xfe,0x25,0xff,0xfc,0xa3,0x2e,0x34,0xcd,0x52,0xb0,0x00,0xc3,0xf6,0x06
-,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47
-,0x06,0xa3,0x02,0x34,0x26,0x8b,0x47,0x08,0xa3,0x04,0x34,0xcd,0x52,0xb0,0x00,0xc3
-,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x57,0x8d,0x7f,0x06,0x51,0xb9
-,0x07,0x00,0x33,0xc0,0xf3,0xab,0x59,0x8d,0x7f,0x06,0xa1,0x7a,0x34,0x03,0x06,0x39
-,0x37,0x26,0x88,0x05,0xa1,0x95,0x37,0x26,0x88,0x45,0x02,0xa1,0x80,0x34,0x03,0x06
-,0x76,0x34,0x26,0x88,0x45,0x07,0xa1,0xc6,0x34,0x26,0x88,0x45,0x09,0xa1,0xd8,0x33
-,0x26,0x88,0x45,0x0a,0x33,0xc0,0xa3,0x7a,0x34,0xa3,0x39,0x37,0xa3,0x95,0x37,0xa3
-,0x80,0x34,0xa3,0x76,0x34,0xa3,0xc6,0x34,0xa3,0xd8,0x33,0x5f,0xb0,0x00,0xc3,0xf6
-,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x83,0xf9,0x06
-,0x74,0x12,0x83,0xf9,0x04,0x74,0x0d,0x83,0xf9,0x00,0x74,0x08,0x83,0xf9,0x02,0x74
-,0x03,0xb0,0x01,0xc3,0x89,0x0e,0xe8,0x3a,0x83,0x26,0xab,0x36,0xf9,0x09,0x0e,0xab
-,0x36,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc1,0xe7,0x02,0xb0,0x00,0xc3,0xf6,0x06,0x93
-,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x80,0xf9,0xff,0x74,0x08
-,0x80,0xf9,0x00,0x74,0x10,0xb0,0x01,0xc3,0x83,0x0e,0xad,0x36,0x02,0xa1,0xad,0x36
-,0xe7,0x04,0xe9,0x0a,0x00,0x83,0x26,0xad,0x36,0xfd,0xa1,0xad,0x36,0xe7,0x04,0xb0
-,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xe8,0xd5,0x04,0xb0
-,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x06
-,0x05,0x75,0x03,0xe9,0x9d,0x00,0x26,0x8b,0x57,0x04,0x26,0x8b,0x47,0x08,0x26,0x81
-,0x7f,0x06,0x00,0x80,0x75,0x08,0xed,0x26,0x89,0x47,0x0a,0xe9,0x9d,0x00,0x26,0x83
-,0x7f,0x06,0x01,0x75,0x04,0xef,0xe9,0x92,0x00,0x26,0x81,0x7f,0x06,0x01,0x80,0x75
-,0x09,0xef,0xed,0x26,0x89,0x47,0x0a,0xe9,0x81,0x00,0x26,0x83,0x7f,0x06,0x02,0x75
-,0x07,0x26,0x21,0x47,0x04,0xe9,0x73,0x00,0x26,0x81,0x7f,0x06,0x02,0x80,0x75,0x0c
-,0x26,0x21,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x5f,0x00,0x26,0x83,0x7f,0x06
-,0x03,0x75,0x07,0x26,0x09,0x47,0x04,0xe9,0x51,0x00,0x26,0x81,0x7f,0x06,0x03,0x80
-,0x75,0x0c,0x26,0x09,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x3d,0x00,0x26,0x83
-,0x7f,0x06,0x04,0x75,0x07,0x26,0x31,0x47,0x04,0xe9,0x2f,0x00,0x26,0x81,0x7f,0x06
-,0x04,0x80,0x75,0x0c,0x26,0x31,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x1b,0x00
-,0xb0,0x01,0xc3,0xfa,0x53,0x26,0x8b,0x4f,0x08,0x0b,0xc9,0x74,0x0c,0x8d,0x1e,0xe0
-,0xfe,0xe8,0x52,0xff,0x83,0xc3,0x08,0xe2,0xf8,0x5b,0xfb,0xb0,0x00,0xc3,0xf6,0x06
-,0x93,0x36,0x80,0x75,0x0a,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3,0x8d
-,0x3e,0xe0,0xfe,0xe5,0x00,0x26,0x89,0x05,0xe5,0x02,0x26,0x89,0x45,0x02,0xa1,0xad
-,0x36,0x26,0x89,0x45,0x04,0xe5,0x06,0x26,0x89,0x45,0x06,0xe5,0x08,0x26,0x89,0x45
-,0x08,0xe5,0x0a,0x26,0x89,0x45,0x0a,0xe5,0x0e,0x26,0x89,0x45,0x0c,0xe5,0x48,0x26
-,0x89,0x45,0x0e,0xe5,0x4a,0x26,0x89,0x45,0x10,0xe5,0x4c,0x26,0x89,0x45,0x12,0xa1
-,0xb7,0x36,0x26,0x89,0x45,0x14,0xe5,0x50,0x26,0x89,0x45,0x16,0xe5,0x52,0x26,0x89
-,0x45,0x18,0xe5,0x54,0x26,0x89,0x45,0x1a,0xe5,0x56,0x26,0x89,0x45,0x1c,0xe5,0x58
-,0x26,0x89,0x45,0x1e,0xe5,0x62,0x26,0x89,0x45,0x20,0xe5,0x64,0x26,0x89,0x45,0x22
-,0xe5,0x66,0x26,0x89,0x45,0x24,0xe5,0x68,0x26,0x89,0x45,0x26,0xe5,0x6a,0x26,0x89
-,0x45,0x28,0xe5,0x6c,0x26,0x89,0x45,0x2a,0xe5,0x70,0x26,0x89,0x45,0x2c,0xe5,0x72
-,0x26,0x89,0x45,0x2e,0xe5,0x74,0x26,0x89,0x45,0x30,0xe5,0x76,0x26,0x89,0x45,0x32
-,0xe5,0x7c,0x26,0x89,0x45,0x34,0xe5,0x7e,0x26,0x89,0x45,0x36,0xe5,0x80,0x26,0x89
-,0x45,0x38,0xe5,0x82,0x26,0x89,0x45,0x3a,0xe5,0x86,0x26,0x89,0x45,0x3c,0xe5,0x88
-,0x26,0x89,0x45,0x3e,0xe5,0x9a,0x26,0x89,0x45,0x40,0xe5,0x9e,0x26,0x89,0x45,0x42
-,0xe5,0xcc,0x26,0x89,0x45,0x44,0xe5,0xce,0x26,0x89,0x45,0x46,0xe5,0xd0,0x26,0x89
-,0x45,0x48,0xe5,0xd2,0x26,0x89,0x45,0x4a,0xba,0x00,0x01,0xed,0x11,0x06,0x66,0x34
-,0x73,0x04,0xff,0x06,0x68,0x34,0x26,0x89,0x45,0x4c,0xba,0x02,0x01,0xed,0xc1,0xe0
-,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0x26,0x89,0x45,0x4e,0xba
-,0x04,0x01,0xed,0x11,0x06,0x6a,0x34,0x73,0x04,0xff,0x06,0x6c,0x34,0x26,0x89,0x45
-,0x50,0xba,0x06,0x01,0xed,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06
-,0x74,0x34,0x26,0x89,0x45,0x52,0xba,0x08,0x01,0xed,0x26,0x89,0x45,0x54,0xba,0x0a
-,0x01,0xed,0x26,0x89,0x45,0x56,0xba,0x0c,0x01,0xed,0x26,0x89,0x45,0x58,0xba,0x0e
-,0x01,0xed,0x01,0x06,0x7a,0x34,0x26,0x89,0x45,0x5e,0xba,0x10,0x01,0xed,0x26,0x89
-,0x45,0x5c,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x74,0x07,0xf6,0x06,0x93,0x36
-,0x20,0x75,0x03,0xb0,0x01,0xc3,0x26,0x80,0x7f,0x06,0x00,0x75,0x30,0x80,0x3e,0x95
-,0x36,0x00,0x74,0x52,0xc6,0x06,0x95,0x36,0x00,0x83,0x26,0xad,0x36,0xfe,0xa1,0xad
-,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef,0xed,0xba,0x10,0x01,0xb8,0x02
-,0x02,0xef,0xed,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0xb0,0x00,0xc3,0x26,0x8b,0x47
-,0x04,0x3d,0x00,0x00,0x74,0x20,0x3d,0x03,0x00,0x77,0x1b,0xba,0x10,0x01,0xb8,0x02
-,0x00,0xef,0xba,0xe0,0x00,0xb8,0x01,0x10,0xef,0x83,0x0e,0xad,0x36,0x01,0xa1,0xad
-,0x36,0xe7,0x04,0xb0,0x00,0xc3,0xb0,0x06,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03
-,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x04,0x01,0x74,0x0a,0x26,0x83,0x7f,0x04,0x02,0x74
-,0x19,0xb0,0x06,0xc3,0x26,0x83,0x7f,0x06,0x0c,0x77,0xf6,0x26,0x83,0x7f,0x0a,0x60
-,0x77,0xef,0xe8,0x10,0x00,0x72,0x0b,0xb0,0x46,0xc3,0xe8,0x4e,0x00,0x72,0x03,0xb0
-,0x46,0xc3,0xb0,0x00,0xc3,0x51,0xb1,0x0a,0x8b,0x3e,0x20,0xf3,0x26,0x83,0x7d,0x0c
-,0x02,0x75,0x03,0xe9,0x0e,0x00,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01,0xe9,0xeb
-,0xff,0x59,0xf8,0xc3,0x57,0x8d,0x7d,0x0e,0x8d,0x77,0x06,0xb9,0x12,0x00,0xf3,0xa4
-,0x8d,0x7d,0x20,0x8d,0x36,0xe0,0xfe,0x26,0x8b,0x4d,0x12,0xf3,0xa4,0xff,0x06,0x01
-,0x35,0x5f,0x26,0xc7,0x45,0x0c,0x01,0x00,0x59,0xf9,0xc3,0x51,0xb1,0x0a,0x8d,0x3e
-,0x20,0xf3,0x8d,0x36,0xe0,0xfe,0x26,0x83,0x7d,0x0c,0x01,0x75,0x1b,0x57,0xe8,0x25
-,0x00,0x5f,0x73,0x14,0x33,0xc0,0xb9,0x20,0x01,0xf3,0xaa,0x26,0xc7,0x45,0x0c,0x02
-,0x00,0xff,0x0e,0x01,0x35,0x59,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01
-,0xe9,0xd3,0xff,0x59,0xf8,0xc3,0x51,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0xf3,0xa6
-,0x74,0x03,0x59,0xf8,0xc3,0x59,0xf9,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x80,0x3e,0xec,0x34,0x06,0x72,0x33,0xff,0x06,0xf0,0x33,0x50,0xc4,0x1e,0x8c,0x36
-,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x29,0x00,0x58,0x81,0x26,0xc2,0x34,0xdf,0x7f,0x81
-,0x26,0xe9,0x34,0xdf,0x7f,0x0b,0xdb,0x74,0x11,0x26,0xc6,0x07,0x84,0x26,0xc6,0x47
-,0x02,0xff,0x26,0x89,0x47,0x06,0xe8,0xac,0x00,0xc3,0xff,0x06,0xea,0x33,0xe9,0xf5
-,0xff,0x57,0x26,0x8b,0x3f,0x03,0xf9,0x26,0x3b,0x7f,0x02,0x74,0x16,0x26,0x3b,0x7f
-,0x04,0x7c,0x2a,0x3d,0x00,0x00,0x75,0x13,0x8d,0x7f,0x08,0x03,0xf9,0x26,0x3b,0x7f
-,0x02,0x7c,0x14,0xff,0x06,0xde,0x33,0x33,0xdb,0x5f,0xc3,0x26,0x8b,0x7f,0x02,0x26
-,0x89,0x3f,0x03,0xf9,0xe9,0x06,0x00,0x26,0x89,0x3f,0x26,0x29,0x0f,0x26,0xc7,0x05
-,0xff,0xff,0x26,0x87,0x3f,0x26,0x89,0x0d,0x8d,0x5d,0x02,0x50,0x8b,0xfb,0x83,0xe9
-,0x02,0x33,0xc0,0xf3,0xaa,0x58,0xfe,0x0e,0xec,0x34,0x5f,0xc3,0x8b,0x7c,0x02,0x3b
-,0x3c,0x74,0x2f,0x83,0x3d,0xff,0x75,0x0b,0x8d,0x7c,0x08,0x89,0x7c,0x02,0x83,0x3d
-,0xff,0x74,0x1e,0x8a,0x45,0x02,0x3c,0x81,0x75,0x0c,0x80,0x3e,0xeb,0x34,0x00,0x74
-,0x05,0x33,0xc0,0xe9,0x0b,0x00,0x8b,0x0d,0x01,0x4c,0x02,0x8d,0x75,0x02,0x83,0xe9
-,0x02,0xc3,0x80,0x3e,0xec,0x34,0x06,0x72,0x05,0x33,0xc0,0xe9,0xf3,0xff,0xff,0x06
-,0xee,0x33,0xe9,0xbe,0xff,0xf6,0x06,0x92,0x36,0x40,0x74,0x01,0xc3,0x57,0x56,0x51
-,0x52,0x8b,0x36,0x8c,0x36,0xe8,0xa4,0xff,0x75,0x03,0xe9,0x1a,0x00,0xe9,0x1c,0x00
-,0xfe,0x06,0xec,0x34,0xc4,0x3e,0x80,0x36,0xf3,0xa4,0x80,0x0e,0x92,0x36,0x40,0xba
-,0x0c,0x01,0xb8,0x80,0x80,0xef,0xed,0x5a,0x59,0x5e,0x5f,0xc3,0xff,0x06,0xe0,0x33
-,0x80,0x3c,0x81,0x75,0x0c,0xff,0x06,0xe2,0x33,0xc6,0x06,0xeb,0x34,0x01,0xe9,0xcf
-,0xff,0x80,0x3c,0x84,0x75,0x07,0xff,0x06,0xe6,0x33,0xe9,0xc3,0xff,0xff,0x06,0xe8
-,0x33,0xe9,0xbc,0xff,0x8d,0x3e,0xe0,0xfe,0xa1,0x72,0x34,0xc7,0x06,0x72,0x34,0x00
-,0x00,0x89,0x05,0xa1,0x74,0x34,0xc7,0x06,0x74,0x34,0x00,0x00,0x89,0x45,0x02,0xba
-,0x04,0x01,0xed,0x89,0x45,0x04,0xc7,0x45,0x06,0x00,0x00,0xa1,0x6e,0x34,0xc7,0x06
-,0x6e,0x34,0x00,0x00,0x89,0x45,0x08,0xa1,0x70,0x34,0xc7,0x06,0x70,0x34,0x00,0x00
-,0x89,0x45,0x0a,0xba,0x00,0x01,0xed,0x89,0x45,0x0c,0xc7,0x45,0x0e,0x00,0x00,0x32
-,0xe4,0xba,0x0e,0x01,0xec,0x89,0x45,0x10,0xa1,0x7e,0x34,0xc7,0x06,0x7e,0x34,0x00
-,0x00,0x89,0x45,0x12,0xa1,0x8c,0x34,0xc7,0x06,0x8c,0x34,0x00,0x00,0x89,0x45,0x14
-,0xa1,0x8a,0x34,0xc7,0x06,0x8a,0x34,0x00,0x00,0x89,0x45,0x16,0xa1,0x7c,0x34,0xc7
-,0x06,0x7c,0x34,0x00,0x00,0x89,0x45,0x18,0xa1,0x88,0x34,0xc7,0x06,0x88,0x34,0x00
-,0x00,0x89,0x45,0x1a,0xa1,0xca,0x33,0xc7,0x06,0xca,0x33,0x00,0x00,0x89,0x45,0x1c
-,0xa1,0x78,0x34,0xc7,0x06,0x78,0x34,0x00,0x00,0x89,0x45,0x1e,0xa1,0xc6,0x34,0xc7
-,0x06,0xc6,0x34,0x00,0x00,0x89,0x45,0x20,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0xfa,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0xb8,0xa0,0x01,0xc1,0xe8,0x04,0x8e,0xd0,0x8d
-,0x26,0x80,0x00,0xe8,0x00,0x01,0xe8,0x10,0xeb,0x8b,0x1e,0xf7,0x34,0x8b,0x16,0xf9
-,0x34,0x8b,0x36,0xff,0x34,0x33,0xc0,0xb9,0xef,0xff,0x8d,0x3e,0x14,0x00,0x2b,0xcf
-,0x2b,0xce,0xd1,0xe9,0xf3,0xab,0x89,0x1e,0xf7,0x34,0x89,0x16,0xf9,0x34,0x83,0xfe
-,0x00,0x74,0x0c,0xb9,0xef,0xff,0xbf,0x80,0xfe,0x2b,0xcf,0xd1,0xe9,0xf3,0xab,0xb9
-,0xff,0xff,0x81,0xe9,0x00,0x3b,0x83,0xfe,0x00,0x74,0x03,0xe9,0x1b,0x00,0x51,0x1e
-,0xb8,0x00,0xe0,0x8e,0xd8,0x33,0xf6,0x8d,0x3e,0x00,0xd8,0xb9,0x00,0x0c,0xf3,0xa5
-,0x1f,0x59,0xbe,0xff,0xff,0x81,0xee,0x00,0xd8,0x2b,0xce,0x81,0xe1,0x00,0xff,0x89
-,0x0e,0xac,0x33,0x8d,0x06,0x20,0x02,0xc1,0xe8,0x04,0xa3,0x32,0x34,0x8e,0xd0,0x36
-,0xc7,0x06,0x1e,0x00,0x80,0x18,0x36,0xc7,0x06,0x22,0x00,0xff,0x7f,0x36,0xc7,0x06
-,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0x8d,0x06,0xa0,0x02,0xc1
-,0xe8,0x04,0xa3,0x30,0x34,0x8e,0xd0,0x36,0xc7,0x06,0x1e,0x00,0x50,0x28,0x36,0xc7
-,0x06,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0xb8,0xa0,0x01,0xc1
-,0xe8,0x04,0xa3,0x34,0x34,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00,0xb8,0x00
-,0x90,0xe7,0x02,0x8d,0x3e,0x70,0x01,0x8b,0xc7,0xc1,0xe8,0x04,0xb9,0x03,0x00,0x89
-,0x45,0x0e,0x89,0x45,0x02,0xc7,0x05,0xff,0xff,0x83,0xc7,0x10,0x05,0x01,0x00,0xe2
-,0xee,0xe8,0x5b,0x01,0xe5,0xce,0xa3,0xb5,0x36,0xe8,0x21,0x00,0xe8,0x45,0x01,0xa1
-,0x32,0x34,0x8c,0xcb,0xcd,0x37,0x0e,0x58,0xa9,0x00,0xf0,0x74,0x07,0x33,0xf6,0x89
-,0x36,0xff,0x34,0xc3,0x8d,0x36,0x30,0x61,0x89,0x36,0xff,0x34,0xc3,0x33,0xc0,0x8b
-,0xd0,0x8b,0xf2,0xb9,0x68,0x00,0x2e,0x80,0xbc,0xac,0x17,0x80,0x75,0x01,0xef,0x83
-,0xc2,0x02,0x46,0xe2,0xf1,0xb8,0x02,0x00,0xe7,0x50,0xb9,0x5a,0x00,0x33,0xff,0xc7
-,0x05,0x65,0x18,0x8c,0x4d,0x02,0x83,0xc7,0x04,0xe2,0xf4,0x33,0xc0,0x8e,0xc0,0x8c
-,0xc8,0x8e,0xd8,0x8d,0x3e,0x80,0x00,0x8d,0x36,0x9c,0x17,0xb9,0x08,0x00,0xe8,0x37
-,0x00,0x8d,0x36,0x20,0x21,0x8d,0x3e,0xc0,0x00,0xb9,0x0d,0x00,0xe8,0x29,0x00,0x8d
-,0x3e,0x40,0x01,0xb9,0x0a,0x00,0xe8,0x1f,0x00,0xe8,0x4b,0x0e,0x33,0xc0,0x8e,0xd8
-,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xe7,0x48,0xe7,0x4c,0xb8,0x40,0x9c,0xe7,0x4a,0xe5
-,0x48,0x90,0xb8,0x00,0x70,0xe7,0x48,0xc3,0xa5,0x83,0xc7,0x02,0xe2,0xfa,0xc3,0xe5
-,0x4c,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe5,0x58,0xd1
-,0xe0,0x73,0x11,0x8b,0xf0,0xd1,0xe6,0x33,0xc0,0x8e,0xd8,0x8b,0xb4,0x80,0x00,0x83
-,0xc6,0x0b,0xff,0xe6,0x1f,0x07,0x5a,0x5f,0x5e,0x59,0x58,0xcf,0x58,0x1c,0xe4,0x1c
-,0x6c,0x1c,0x8e,0x1a,0xc0,0x1f,0x40,0x1a,0x44,0x1c,0x65,0x18,0x80,0x80,0x80,0xff
-,0x80,0x03,0x02,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
-,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
-,0x80,0x03,0x03,0x43,0x80,0x80,0x02,0x80,0x42,0x03,0x02,0xff,0x03,0x01,0x03,0x01
-,0x01,0x03,0x02,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x03,0x01,0x03
-,0x03,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0x01,0x03,0x03,0x03,0xff,0xff,0xff,0xff
-,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
-,0xff,0xff,0xff,0x02,0xb8,0x0f,0x00,0xe7,0x84,0xb8,0x0f,0xf8,0xe7,0x82,0xc3,0xb9
-,0x08,0x00,0x89,0x0e,0xe6,0x3a,0x8d,0x06,0x20,0x03,0x8b,0xd0,0xc1,0xe8,0x04,0xa3
-,0x90,0x01,0x8b,0xc2,0x8b,0xd8,0xc1,0xe8,0x04,0x8e,0xc0,0x05,0x61,0x00,0x26,0xa3
-,0x00,0x00,0xa1,0x30,0x34,0x26,0xa3,0x02,0x00,0x83,0xc3,0x14,0xd1,0xeb,0x26,0x89
-,0x1e,0x08,0x00,0x81,0xc2,0x10,0x06,0xe2,0xd9,0x26,0xc7,0x06,0x00,0x00,0xff,0xff
-,0x8c,0x06,0x92,0x01,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8
-,0xe7,0x5a,0xff,0x06,0xbe,0x33,0xba,0xd2,0x00,0xed,0xcf,0x00,0x00,0x00,0x00,0x00
-,0x8c,0xcb,0xa1,0x30,0x34,0xcd,0x37,0xe9,0x06,0xed,0xb8,0x32,0x00,0xc3,0xe8,0x8c
-,0x01,0xfe,0x06,0xe2,0x34,0xe8,0x21,0x01,0x75,0xf0,0xe8,0x53,0x0e,0x81,0x0e,0xaf
-,0x36,0x00,0xc0,0xc7,0x06,0xad,0x36,0x60,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75
-,0x1a,0xf7,0x06,0xe6,0x34,0x00,0x08,0x74,0x09,0xc7,0x06,0xab,0x36,0x0b,0x00,0xe9
-,0x0f,0x00,0xc7,0x06,0xab,0x36,0x03,0x00,0xe9,0x06,0x00,0xc7,0x06,0xab,0x36,0x11
-,0x9c,0xc7,0x06,0xa9,0x36,0x18,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75,0x0d,0xf7
-,0x06,0xb5,0x36,0x02,0x00,0x74,0x05,0x83,0x0e,0xa9,0x36,0x20,0xa1,0xa9,0x36,0xe7
-,0x00,0xa1,0xab,0x36,0xe7,0x02,0xf7,0x06,0xe6,0x34,0x80,0x00,0x74,0x2e,0xe8,0xf2
-,0x2f,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08
-,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xb8,0x40,0x00,0xe7,0x4e,0x33
-,0xc0,0xe7,0x0e,0xc7,0x06,0x26,0x02,0x00,0x00,0xe9,0x23,0x00,0xc7,0x06,0x4e,0x37
-,0x3f,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x80,0x74,0x07,0x26
-,0x81,0x0e,0x08,0x00,0x00,0x80,0xc6,0x06,0xe0,0x34,0x01,0xb8,0x00,0x00,0xc3,0xfe
-,0x06,0xe1,0x34,0xc6,0x06,0xe0,0x34,0x00,0xa1,0x26,0x02,0x0b,0xc0,0x74,0x01,0xc3
-,0xe8,0x04,0x00,0xb8,0x00,0x00,0xc3,0xa1,0xa9,0x36,0xe7,0x00,0x8b,0x1e,0xab,0x36
-,0x83,0xe3,0x06,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc3,0x0d,0x10,0x00,0xe7,0x02,0xa1
-,0xad,0x36,0xe7,0x04,0xc3,0xb8,0x0a,0x00,0xe7,0x84,0xfe,0x06,0xe5,0x34,0xc6,0x06
-,0xe3,0x34,0x01,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x40,0x74,0x07
-,0x26,0x81,0x0e,0x08,0x00,0x00,0x40,0xc3,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xfe,0x06
-,0xe4,0x34,0xc6,0x06,0xe3,0x34,0x00,0xc3,0xc3,0xf6,0x06,0x18,0x34,0x80,0x75,0x0d
-,0xa1,0x18,0x34,0x0b,0x06,0x1a,0x34,0x0b,0x06,0x1c,0x34,0x75,0x01,0xc3,0xa1,0x2e
-,0x34,0x25,0xff,0xfe,0x8b,0x16,0xe7,0x36,0x81,0xe2,0x00,0x01,0x0b,0xc2,0xa3,0x2e
-,0x34,0x8d,0x16,0x10,0x00,0xbf,0x00,0x00,0xb9,0x08,0x00,0x8b,0x85,0x00,0x34,0xef
-,0x83,0xc2,0x10,0x8b,0x85,0x02,0x34,0xef,0x83,0xc2,0x10,0x8b,0x85,0x04,0x34,0xef
-,0x83,0xc2,0xe2,0x83,0xc7,0x06,0x49,0x75,0xe2,0xb8,0x00,0x00,0x8e,0xc0,0xbe,0x00
-,0x34,0xbf,0xb9,0x36,0xb9,0x18,0x00,0xf3,0xa5,0xb8,0x00,0x00,0xc3,0x33,0xc0,0x8e
-,0xc0,0x8d,0x3e,0xb0,0x33,0xb9,0x08,0x00,0xf3,0xab,0x8d,0x3e,0x3e,0x34,0xb9,0x03
-,0x00,0xf3,0xab,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xba
-,0x33,0xe5,0x56,0x0d,0x20,0x00,0xe7,0x56,0xba,0x7a,0x00,0xed,0x08,0x26,0x94,0x36
-,0x33,0xc0,0xb1,0x08,0x32,0xed,0x06,0x8e,0xc0,0x8d,0x3e,0xe0,0xff,0xf3,0xaa,0x8e
-,0x06,0x32,0x34,0x26,0x81,0x0e,0x08,0x00,0x00,0x02,0x07,0xe5,0x56,0x25,0xdf,0xff
-,0xe7,0x56,0xe9,0xf8,0xfc,0x00,0xbd,0x1b,0x10,0x1b,0xd9,0x1a,0xf3,0x1a,0x50,0x51
-,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb6,0x33,0x53
-,0x06,0x51,0xe5,0x80,0xa3,0xb4,0x33,0x8b,0xd8,0x8b,0xc8,0x25,0x10,0x00,0xa3,0xed
-,0x34,0x0b,0xc0,0x74,0x14,0xff,0x06,0x80,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x03
-,0xe9,0x06,0x00,0xb8,0x80,0x00,0xe8,0x9d,0x04,0x83,0xe3,0x03,0xd1,0xe3,0x2e,0xff
-,0x97,0x86,0x1a,0x59,0x07,0x5b,0xe9,0xa4,0xfc,0xba,0x20,0x00,0x8e,0x06,0x3c,0x34
-,0x83,0x3e,0x3c,0x34,0x00,0x75,0x03,0xe9,0xf0,0x00,0xc7,0x06,0x3c,0x34,0x00,0x00
-,0xe9,0x2a,0x00,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0x83,0x3e,0x3a,0x34,0x00,0x75
-,0x03,0xe9,0xd5,0xff,0xc7,0x06,0x3a,0x34,0x00,0x00,0xe8,0x10,0x00,0xe9,0xc9,0xff
-,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0xc7,0x06,0x3a,0x34,0x00,0x00,0x26,0xa1,0x14
-,0x00,0x26,0xa3,0x0c,0x00,0x26,0xa1,0x16,0x00,0x26,0xa3,0x0e,0x00,0x26,0xc6,0x06
-,0x0a,0x00,0x00,0xc1,0xea,0x02,0x23,0xd1,0x74,0x1c,0xba,0x20,0x00,0x26,0xc7,0x06
-,0x0e,0x00,0xea,0x05,0x26,0x0b,0x16,0x0c,0x00,0x26,0x89,0x16,0x0c,0x00,0xff,0x06
-,0x86,0x34,0xff,0x06,0xdc,0x33,0x26,0xa1,0x0c,0x00,0xa9,0x00,0x37,0x74,0x16,0x26
-,0xc6,0x06,0x0a,0x00,0x02,0xa9,0x00,0x30,0x74,0x04,0xff,0x06,0x7a,0x34,0xff,0x06
-,0xda,0x33,0xe9,0x49,0x00,0xc0,0xec,0x07,0x83,0x16,0x8a,0x34,0x00,0x24,0x07,0x3c
-,0x07,0x75,0x04,0xff,0x06,0x8c,0x34,0xff,0x06,0x7e,0x34,0xa1,0x30,0x34,0x8c,0xc3
-,0x8e,0xc0,0x8e,0xdb,0x26,0x83,0x0e,0x08,0x00,0x40,0x8c,0xd8,0x26,0x87,0x06,0x16
-,0x00,0x26,0x83,0x3e,0x14,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x8c,0x1e,0x00,0x00
-,0xe9,0x05,0x00,0x26,0x8c,0x1e,0x14,0x00,0x33,0xc0,0x8e,0xd8,0xc3,0xc3,0x8c,0xc0
-,0x87,0x06,0x92,0x01,0x3d,0xff,0xff,0x74,0x0d,0x8e,0xd8,0x8c,0x06,0x00,0x00,0x33
-,0xc0,0x8e,0xd8,0xe9,0x04,0x00,0x8c,0x06,0x90,0x01,0xe8,0x01,0x00,0xc3,0x06,0x83
-,0x3e,0x90,0x01,0xff,0x74,0x29,0x83,0x3e,0x3a,0x34,0x00,0x75,0x11,0xba,0x86,0x00
-,0xe8,0x1e,0x00,0x8c,0x06,0x3a,0x34,0x83,0x3e,0x90,0x01,0xff,0x74,0x11,0x83,0x3e
-,0x3c,0x34,0x00,0x75,0x0a,0xba,0x88,0x00,0xe8,0x06,0x00,0x8c,0x06,0x3c,0x34,0x07
-,0xc3,0xa1,0x90,0x01,0x8e,0xc0,0x26,0xa1,0x08,0x00,0xef,0x26,0xa1,0x00,0x00,0x26
-,0xc7,0x06,0x00,0x00,0xff,0xff,0xa3,0x90,0x01,0x3d,0xff,0xff,0x75,0x03,0xa3,0x92
-,0x01,0x83,0x3e,0xed,0x34,0x00,0x74,0x0b,0xb8,0x10,0x00,0xe7,0x84,0xc7,0x06,0xed
-,0x34,0x00,0x00,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7
-,0x5a,0xff,0x06,0xbc,0x33,0xe9,0x25,0xfb,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33
-,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb0,0x33,0xe9,0x11,0xfb,0x50,0x51,0x56,0x57
-,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb4,0x33,0x06,0xff,0x06
-,0x76,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x04,0x07,0xe9,0xf0,0xfa,0xb8,0x80,0x00
-,0xe8,0xd3,0x02,0x07,0xe9,0xe6,0xfa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0xc6,0x1d,0x08,0x1d,0x91,0x1e,0x5d,0x1e,0x73,0x1e,0x89,0x1e,0x91,0x1e,0xa8,0x1d
-,0x91,0x1e,0x91,0x1e,0xaf,0x1e,0xaf,0x1e,0x15,0x1d,0x15,0x1d,0x91,0x1e,0x99,0x1f
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00
-,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00
-,0x07,0xe9,0x99,0xfa,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7
-,0x5a,0xff,0x06,0xb2,0x33,0x06,0x68,0xf6,0x1c,0xe5,0x06,0xa3,0xb2,0x33,0x8b,0xf0
-,0x83,0xe6,0x1e,0x2e,0xff,0xa4,0xa0,0x1c,0xe5,0x0c,0xa9,0x80,0x00,0x74,0x06,0xe8
-,0xa4,0x01,0xe5,0x06,0xc3,0x53,0xe5,0x0c,0x8b,0xd8,0xa9,0x01,0x00,0x74,0x14,0x83
-,0x3e,0xe0,0x3a,0x00,0x74,0x0d,0x8e,0x06,0x38,0x34,0xe8,0xbf,0x06,0xc7,0x06,0xe0
-,0x3a,0x00,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7
-,0x02,0x8b,0xc3,0x5b,0xa9,0x01,0x00,0x74,0x01,0xc3,0x8b,0xd0,0xb8,0x00,0x08,0xe7
-,0x84,0x8b,0xc2,0x8e,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0x8b,0xd0,0xc1,0xe0,0x03
-,0x83,0x16,0x88,0x34,0x00,0xff,0x06,0x7c,0x34,0x26,0x83,0x3e,0x06,0x00,0x0a,0x75
-,0x21,0x8b,0xc2,0x25,0x40,0x18,0x3d,0x40,0x00,0x74,0x0c,0x3d,0x00,0x10,0x75,0x12
-,0x26,0xfe,0x0e,0x0a,0x00,0x74,0x0b,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x03,0xe9
-,0x5a,0x06,0x8c,0xc0,0x26,0x8e,0x06,0x02,0x00,0x26,0x83,0x0e,0x08,0x00,0x20,0x26
-,0xa3,0x12,0x00,0x26,0xa3,0x10,0x00,0xc3,0xff,0x06,0xc4,0x33,0xe5,0x0c,0xa9,0x01
-,0x00,0x75,0x01,0xc3,0xa9,0xf0,0x07,0x74,0x01,0xc3,0xff,0x06,0xd4,0x33,0xe5,0x00
-,0x0d,0x18,0x00,0xe7,0x00,0xc3,0xff,0x06,0xca,0x33,0x80,0x3e,0xa0,0x36,0x08,0x75
-,0x14,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26,0x81
-,0x0e,0x08,0x00,0x00,0x08,0xe5,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe5,0x0c,0x50,0xe5
-,0x80,0x25,0x00,0x07,0xa3,0xe4,0x3a,0xe5,0x8c,0x25,0x00,0x80,0xa3,0xe2,0x3a,0x58
-,0xa9,0x02,0x00,0x75,0x25,0x83,0x3e,0xe2,0x3a,0x00,0x75,0x1e,0x83,0x3e,0xe4,0x3a
-,0x00,0x75,0x17,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe8,0x6a,0x01
-,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xe9,0x21,0x00,0xe8,0x1a,0x06,0x80,0x3e,0xe8
-,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x0d,0x00,0xc6,0x06
-,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0x80,0x3e,0x9f,0x36,0x06
-,0x75,0x05,0x83,0x0e,0x99,0x36,0x40,0xb8,0x00,0x01,0xe9,0x09,0x01,0xff,0x06,0xcc
-,0x33,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xff,0x06,0xc6,0x34
-,0xe9,0x1e,0x00,0xff,0x06,0xce,0x33,0xff,0x06,0x95,0x37,0x81,0x26,0xaf,0x36,0xff
-,0xef,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x08,0x00,0xff,0x06,0xd0,0x33,0xff,0x06,0x7a
-,0x34,0xff,0x06,0xd2,0x33,0xd1,0xe6,0x8e,0x06,0x30,0x34,0x2e,0x8b,0x84,0xc0,0x1c
-,0x26,0x09,0x06,0x08,0x00,0x2e,0x8b,0x84,0xc2,0x1c,0x09,0x06,0x66,0x37,0xc3,0xe5
-,0x0c,0xa9,0x80,0x00,0x74,0x56,0x50,0xe8,0xf0,0x00,0x58,0xa9,0x00,0x01,0x75,0x07
-,0xff,0x06,0xc6,0x33,0xe9,0x08,0x00,0xff,0x06,0x78,0x34,0xff,0x06,0xc8,0x33,0xe5
-,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe8,0x6e,0x05,0xba,0x10,0x01,0xed,0x80,0x3e,0xe8
-,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x1d,0x00,0xc6,0x06
-,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xe9,0x0d,0x00,0xc6,0x06
-,0xe8,0xff,0x03,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xc3,0xa9,0x01,0x00,0x74
-,0x1c,0xe8,0x2c,0x00,0x83,0x3e,0xe0,0x3a,0x00,0x74,0x0f,0x06,0x8e,0x06,0x38,0x34
-,0xe8,0xc9,0x04,0xc7,0x06,0xe0,0x3a,0x00,0x00,0x07,0xe9,0x5d,0x00,0x8b,0xd0,0x8e
-,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0xe8,0x06,0x00,0x68,0x69,0x1d,0xe9,0x4a,0x00
-,0xa9,0x00,0x04,0x74,0x0a,0xb8,0x00,0x04,0xff,0x06,0xd8,0x33,0xe9,0x17,0x00,0xa9
-,0x00,0x01,0x74,0x0a,0xff,0x06,0x39,0x37,0xb8,0x00,0x01,0xe9,0x08,0x00,0xa9,0x10
-,0x00,0xb8,0x10,0x00,0x74,0x1d,0x09,0x06,0x66,0x37,0x8c,0xc0,0x8e,0x06,0x30,0x34
-,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01
-,0x8e,0xc0,0xc3,0xff,0x06,0xc2,0x33,0xe9,0xf8,0xff,0xe5,0x00,0x0d,0x18,0x00,0xe7
-,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0xc3,0x58,0xe9,0x43,0xfd,0xe5,0x08,0x0d
-,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe9,0xe0,0xff,0xe5,0x0e,0xa9,0x00,0x08,0x75
-,0x01,0xc3,0xe9,0xf5,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb8
-,0x33,0xe5,0x48,0x06,0x53,0x57,0xff,0x16,0x4e,0x37,0x5f,0x5b,0x83,0x3e,0x80,0x01
-,0xff,0x74,0x58,0x8e,0x06,0x80,0x01,0x26,0xff,0x0e,0x08,0x00,0x75,0x4d,0x26,0xa1
-,0x00,0x00,0xa3,0x80,0x01,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8c,0xc0,0x26,0x8e
-,0x06,0x02,0x00,0x26,0x81,0x0e,0x08,0x00,0x80,0x00,0x8b,0xd0,0x26,0x87,0x06,0x1a
-,0x00,0x26,0x83,0x3e,0x18,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x89,0x16,0x00,0x00
-,0xe9,0x05,0x00,0x26,0x89,0x16,0x18,0x00,0x83,0x3e,0x80,0x01,0xff,0x74,0x0c,0x8e
-,0x06,0x80,0x01,0x26,0x83,0x3e,0x08,0x00,0x00,0x74,0xb3,0x07,0xe9,0x3e,0xf7,0xe5
-,0x4c,0x90,0xe5,0x02,0xa9,0x00,0x20,0x74,0x0d,0x25,0xff,0xdf,0x0d,0x01,0x00,0xe7
-,0x02,0x0d,0x00,0x20,0xe7,0x02,0xe5,0x0a,0x8b,0xd8,0xa3,0xf4,0x33,0x25,0xc3,0x57
-,0x0d,0x00,0x10,0xe7,0x0a,0xf7,0x06,0x9b,0x36,0x00,0x80,0x74,0x37,0xf7,0xc3,0x00
-,0x80,0x74,0x06,0xf7,0xc3,0x00,0x08,0x74,0x5d,0x81,0x26,0xc2,0x34,0x7f,0xff,0xc7
-,0x06,0x35,0x37,0x05,0x00,0xb8,0x80,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0xff,0x7f
-,0xc7,0x06,0x0f,0x37,0x04,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06
-,0x0f,0x37,0x03,0x00,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x2a,0xf7,0xc3,0x00,0x08
-,0x74,0x24,0x80,0x3e,0x9d,0x36,0x06,0x7c,0x1d,0xff,0x06,0x94,0x34,0x83,0x0e,0x66
-,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26
-,0x81,0x0e,0x08,0x00,0x00,0x01,0xf7,0xc3,0x00,0x20,0x75,0x3b,0xf7,0x06,0x9a,0x37
-,0x80,0x00,0x74,0x0b,0xff,0x06,0x89,0x37,0x33,0xc0,0xe7,0x0e,0xe9,0x04,0x00,0xff
-,0x06,0x3b,0x37,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x1c,0x80,0x26,0x9e,0x36,0xff
-,0x75,0x15,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26
-,0x81,0x0e,0x08,0x00,0x00,0x08,0xc3,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x02,0x23,0x02,0x23,0x02,0x23,0x02,0x23,0x03,0x23,0xdd,0x22,0x02,0x23,0xfd,0x21
-,0x02,0x23,0xa4,0x24,0xf3,0x24,0x02,0x23,0x8d,0x22,0x7a,0x23,0x02,0x23,0x97,0x24
-,0x1b,0x24,0x75,0x24,0x02,0x23,0x02,0x23,0x8e,0x25,0xfb,0x8e,0x06,0x7e,0x01,0xfb
-,0x26,0x83,0x3e,0x00,0x00,0xff,0x74,0xf2,0x26,0x8e,0x06,0x00,0x00,0xfa,0x26,0x8b
-,0x1e,0x08,0x00,0x26,0x23,0x1e,0x0a,0x00,0x74,0xe5,0x8c,0xc0,0x8e,0xd0,0x26,0x8b
-,0x26,0x02,0x00,0x8c,0x16,0xf2,0x33,0x22,0xff,0x75,0x6a,0x26,0xa1,0x1c,0x00,0x8a
-,0xe3,0x8a,0xdc,0x22,0xd8,0x75,0x0d,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0xf2,0xb0
-,0x80,0xe9,0xed,0xff,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0x02,0xb0,0x80,0x32,0xe4
-,0x26,0xa3,0x1c,0x00,0xf7,0xc3,0x08,0x00,0x75,0x47,0x2e,0x8a,0x9f,0xc5,0x25,0x2e
-,0x8b,0xbf,0xc5,0x26,0x80,0xc3,0x10,0x26,0x8e,0x1d,0x26,0x8c,0x1e,0x06,0x00,0x8b
-,0x16,0x00,0x00,0xc7,0x06,0x00,0x00,0xff,0xff,0x26,0x89,0x15,0x83,0xfa,0xff,0x75
-,0x0a,0x2e,0x8b,0x97,0xcd,0x26,0x26,0x21,0x16,0x08,0x00,0x33,0xc0,0x8e,0xd8,0x26
-,0x89,0x1e,0x04,0x00,0xc3,0x8a,0xdf,0xb7,0x00,0x2e,0x8a,0x9f,0xc5,0x25,0xe9,0xe0
-,0xff,0x26,0x83,0x26,0x08,0x00,0xf7,0x83,0xc3,0x10,0xe9,0xde,0xff,0x60,0x06,0x1e
-,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x8b,0x0e,0x34,0x34,0x39,0x0e
-,0xf2,0x33,0x74,0x0e,0x26,0x81,0x0e,0x0a,0x00,0x00,0x02,0x26,0x81,0x0e,0x08,0x00
-,0x00,0x02,0x26,0x89,0x26,0x02,0x00,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00
-,0x36,0x89,0x26,0x02,0x00,0x36,0x89,0x1e,0x20,0x00,0x36,0xc7,0x06,0x08,0x00,0x00
-,0x00,0xb9,0x04,0x00,0xbe,0x00,0x00,0x2e,0x8b,0xbc,0xc5,0x26,0x36,0xc7,0x05,0xff
-,0xff,0x36,0xc7,0x45,0x02,0xff,0xff,0x83,0xc6,0x02,0xe2,0xeb,0x8e,0x06,0x7e,0x01
-,0x36,0x8b,0x0e,0x22,0x00,0x8c,0xc0,0x26,0x83,0x3e,0x00,0x00,0xff,0x26,0x8e,0x06
-,0x00,0x00,0x74,0x07,0x26,0x3b,0x0e,0x22,0x00,0x7d,0xea,0x36,0x8c,0x06,0x00,0x00
-,0x8e,0xc0,0x26,0x8c,0x16,0x00,0x00,0xfb,0x36,0xff,0x2e,0x1e,0x00,0x06,0x1e,0x68
-,0x8b,0x25,0x6a,0x00,0x1f,0x26,0x09,0x36,0x08,0x00,0xf7,0xc6,0x00,0xff,0x74,0x01
-,0xc3,0x56,0x52,0x2e,0x8b,0xb4,0xc5,0x25,0x81,0xe6,0xff,0x00,0x2e,0x8b,0xb4,0xc5
-,0x26,0x8c,0xc2,0x8e,0xc0,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8e,0xc2,0x26,0x83
-,0x3c,0xff,0x74,0x0f,0x8b,0xd0,0x26,0x87,0x54,0x02,0x8e,0xc2,0x26,0xa3,0x00,0x00
-,0xe9,0x07,0x00,0x26,0x89,0x44,0x02,0x26,0x89,0x04,0x5a,0x5e,0xc3,0x06,0x1e,0x68
-,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x26,0xa3,0x0a,0x00,0x26,0x89,0x26
-,0x02,0x00,0xa1,0x34,0x34,0x8e,0xd0,0x8d,0x26,0x80,0x00,0x8c,0x16,0xf2,0x33,0xe9
-,0x4d,0xfe,0xcf,0x50,0x1e,0x52,0x53,0x33,0xc0,0x8e,0xd8,0x26,0x83,0x3e,0x04,0x00
-,0xff,0x26,0xc7,0x06,0x04,0x00,0x00,0x00,0x74,0x03,0xe9,0x1a,0x00,0x83,0x3e,0xe6
-,0x3a,0x02,0x76,0x13,0xff,0x06,0xd6,0x33,0x8c,0xc0,0x8e,0x06,0x32,0x34,0xbe,0x40
-,0x00,0x68,0x3a,0x23,0xe9,0x5e,0xff,0xe8,0x84,0xf8,0x5b,0x5a,0x1f,0x58,0xcf,0xe8
-,0xe1,0x00,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0x8a,0x1e,0x29,0x00,0x88,0x1e,0x1b
-,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c,0x26,0xa1
-,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x80,0xfb,0x08,0x74,0x09,0x0d,0x18,0xac,0xe7,0x00
-,0x07,0x1f,0x58,0xcf,0x0d,0x18,0x00,0xe9,0xf4,0xff,0x50,0x1e,0x06,0x33,0xc0,0x8e
-,0xd8,0x83,0x3e,0xa1,0x36,0x00,0x75,0xb7,0x26,0x8b,0x36,0x06,0x00,0x2e,0xff,0x94
-,0xdc,0x23,0x07,0x1f,0x58,0xcf,0xe8,0x8a,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00
-,0xe8,0x49,0x00,0xc3,0x53,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x2d,0xe5,0x8c,0x25
-,0x00,0x70,0x8b,0xd8,0xe5,0x8c,0x25,0x00,0x70,0x3b,0xc3,0x74,0x05,0x8b,0xd8,0xe9
-,0xf2,0xff,0x3d,0x00,0x30,0x75,0x10,0xe5,0x02,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06
-,0xe0,0x3a,0xff,0xff,0xe9,0x03,0x00,0xe8,0x12,0x00,0x5b,0xc3,0xa3,0x23,0x96,0x23
-,0xa4,0x23,0xa4,0x23,0x96,0x23,0xa4,0x23,0x96,0x23,0x96,0x23,0x26,0xa0,0x29,0x00
-,0xa2,0x1b,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c
-,0x26,0xa1,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x25,0xff,0x53,0x26,0x8b,0x36,0x06,0x00
-,0x83,0xe6,0x0e,0x2e,0x0b,0x84,0xad,0x25,0xe7,0x00,0xc3,0x06,0x1e,0x68,0x8b,0x25
-,0x6a,0x00,0x1f,0x83,0x0e,0xef,0x34,0x20,0x83,0x0e,0x9b,0x36,0x08,0xe5,0x00,0x25
-,0xef,0xff,0x0d,0x08,0x00,0xe7,0x00,0xe5,0x00,0xa9,0x10,0x00,0x75,0x01,0xc3,0xe5
-,0x00,0xa9,0x10,0x00,0x75,0xf9,0xc3,0x50,0x53,0x51,0x56,0x06,0x1e,0x33,0xc0,0x8e
-,0xd8,0xb8,0x05,0x00,0xe7,0x84,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08
-,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0x1f,0x07
-,0x5e,0x59,0x5b,0x58,0xc3,0x50,0x1e,0x33,0xc0,0x8e,0xd8,0xc7,0x06,0xef,0x34,0x00
-,0x00,0x83,0x26,0x9b,0x36,0xf7,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d
-,0x11,0x00,0xe7,0x02,0x1f,0x58,0xcf,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f
-,0xe8,0x16,0xf5,0xc3,0x06,0x1e,0x68,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x26,0x83
-,0x3e,0x0a,0x00,0x00,0x74,0x03,0xe8,0x43,0x00,0x26,0xc7,0x06,0x0a,0x00,0xff,0xff
-,0x26,0x8b,0x16,0x06,0x00,0x8e,0x1e,0x8e,0x01,0x8c,0xd8,0x8b,0xca,0x83,0x3e,0x00
-,0x00,0xff,0x8e,0x1e,0x00,0x00,0x74,0x0a,0x2b,0x16,0x08,0x00,0x73,0xeb,0x29,0x0e
-,0x08,0x00,0x26,0x89,0x0e,0x08,0x00,0x26,0x8c,0x1e,0x00,0x00,0x8e,0xd8,0x8c,0x06
-,0x00,0x00,0xc3,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x8b,0xc8
-,0x8e,0x1e,0x8e,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x8c,0xd8,0x83,0x3e,0x00
-,0x00,0xff,0x74,0x25,0x3b,0x0e,0x00,0x00,0x8e,0x1e,0x00,0x00,0x75,0xed,0x8e,0xd8
-,0x26,0xa1,0x00,0x00,0xa3,0x00,0x00,0x3d,0xff,0xff,0x74,0x56,0x8e,0xd8,0x26,0xa1
-,0x08,0x00,0x01,0x06,0x08,0x00,0xe9,0x49,0x00,0x26,0x8e,0x1e,0x02,0x00,0xbe,0x18
-,0x00,0x83,0x3c,0xff,0x74,0x3c,0x39,0x0c,0x74,0x19,0x8e,0x1c,0xbe,0x00,0x00,0x83
-,0x3e,0x00,0x00,0xff,0x74,0x2c,0x39,0x0e,0x00,0x00,0x74,0x07,0x8e,0x1e,0x00,0x00
-,0xe9,0xec,0xff,0x26,0xa1,0x00,0x00,0x89,0x04,0x33,0xc9,0x8e,0xd9,0x3d,0xff,0xff
-,0x75,0x10,0x83,0xfe,0x18,0x75,0x0b,0x26,0x8e,0x1e,0x02,0x00,0x81,0x26,0x08,0x00
-,0x7f,0xff,0x33,0xc0,0x8e,0xd8,0xc3,0x1f,0x07,0x61,0xcf,0x1f,0x07,0xcf,0x60,0x06
-,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75
-,0xf6,0xb9,0x08,0x00,0xe5,0x58,0xe7,0x5a,0x23,0xc0,0xe0,0xf8,0xc3,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x00,0x00,0x00,0xa8,0x00,0x8c,0x02,0x04,0x00
-,0x00,0x08,0x10,0x20,0x00,0xff,0x0e,0x0c,0x0c,0x0a,0x0a,0x0a,0x0a,0x08,0x08,0x08
-,0x08,0x08,0x08,0x08,0x08,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06
-,0x06,0x06,0x06,0x06,0x06,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04
-,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04
-,0x04,0x04,0x04,0x04,0x04,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02
-,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02
-,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02
-,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02
-,0x02,0x02,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x14,0x00,0x10,0x00,0x0c,0x00,0xff,0x7f,0xff
-,0xbf,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0x7f,0xff,0xbf
-,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0xff,0x00,0x00,0x00
-,0x80,0x3e,0xe2,0x34,0x01,0x76,0x03,0xe9,0xa5,0x00,0xb8,0x00,0x00,0xe7,0x4e,0xb9
-,0x28,0x00,0xe2,0xfe,0xc6,0x06,0x45,0x37,0x02,0xbf,0x3f,0x28,0x2e,0x8b,0x45,0x08
-,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x1d,0xc7,0x06,0xb3,0x36,0x40,0x11
-,0xc7,0x06,0xb1,0x36,0x27,0x00,0xc7,0x06,0x46,0x37,0x02,0x00,0xc7,0x06,0x48,0x37
-,0x64,0x00,0xf7,0x06,0xb5,0x36,0x02,0x00,0x75,0x1c,0x2e,0x0b,0x5d,0x02,0x81,0x26
-,0xb3,0x36,0xff,0xfe,0xc7,0x06,0xb1,0x36,0x9c,0x00,0xc7,0x06,0x46,0x37,0x08,0x00
-,0xc7,0x06,0x48,0x37,0x90,0x01,0x89,0x1e,0xb7,0x36,0x89,0x1e,0xfe,0x33,0xbe,0x20
-,0x00,0x8b,0xc3,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x45,0x04,0xe7,0x4e
-,0xb9,0x28,0x00,0xe2,0xfe,0xe5,0x4e,0x8b,0xcb,0x2e,0x23,0x45,0x06,0x2e,0x23,0x4d
-,0x06,0x3a,0xc1,0x74,0x36,0x4e,0x75,0xd9,0x80,0x3e,0x45,0x37,0x00,0x74,0x0b,0xc6
-,0x06,0x45,0x37,0x00,0xbf,0x2f,0x28,0xe9,0x72,0xff,0xc6,0x06,0x45,0x37,0x01,0xf7
-,0x06,0xb5,0x36,0x02,0x00,0x74,0x14,0xe5,0xce,0x25,0xfd,0xff,0xe7,0xce,0xe8,0x43
-,0x00,0xe5,0xce,0x0d,0x02,0x00,0xe7,0xce,0xe8,0x39,0x00,0x80,0x3e,0xe2,0x34,0x01
-,0x76,0x01,0xc3,0xb8,0xea,0x05,0xe7,0x8c,0xfa,0xe8,0x12,0xf4,0xfb,0x8d,0x06,0xd0
-,0x39,0x8b,0xd8,0xc1,0xe8,0x04,0xa3,0x38,0x34,0x8e,0xc0,0xa1,0x30,0x34,0x26,0xa3
-,0x02,0x00,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x83,0xc3,0x18,0xd1,0xeb,0x26,0x89
-,0x1e,0x08,0x00,0xc3,0xe5,0x02,0x0d,0x00,0x40,0xe7,0x02,0xe5,0x00,0x0d,0x04,0x00
-,0xe7,0x00,0xb8,0x00,0x00,0xe7,0x0a,0xe5,0x0a,0xa9,0x00,0x80,0x75,0x14,0xe5,0x08
-,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x0a,0x0d,0x00,0x08,0xb9,0x05,0x00,0xe7,0x0a,0xe2
-,0xfc,0xc3,0xe5,0x08,0x0d,0x00,0x10,0xb9,0x05,0x00,0xe7,0x08,0xe2,0xfc,0xc3,0x04
-,0x0c,0x20,0x00,0x01,0x0c,0x7e,0xff,0x00,0x0c,0x02,0x00,0x10,0x00,0x40,0x00,0x0c
-,0xc6,0x01,0x00,0x00,0xc0,0xf7,0xff,0x00,0xc0,0x02,0x00,0x10,0x00,0x40,0x00,0x00
-,0x33,0xc0,0x8e,0xd8,0x8d,0x3e,0x72,0x49,0x8d,0x36,0xb0,0x37,0xb9,0x14,0x00,0x8b
-,0x1e,0x30,0x34,0x89,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05
-,0x89,0x44,0x04,0x83,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xc6,0x06,0x9e,0x36,0x0e
-,0xe8,0xfd,0x26,0x68,0x83,0x28,0xa1,0xaa,0x02,0xcd,0x35,0x83,0x3e,0xa1,0x36,0x00
-,0x74,0x03,0xe9,0x3b,0x27,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e
-,0xff,0xa4,0x2e,0x30,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x01,0x00,0xc6
-,0x06,0xca,0x34,0x01,0xe9,0x7d,0x19,0x80,0x3e,0xa0,0x36,0x08,0x74,0xe6,0x80,0x26
-,0x9e,0x36,0xff,0x75,0x1a,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x12,0xf7,0x06,0x9b
-,0x36,0x03,0x00,0x75,0x0a,0x83,0x0e,0x66,0x37,0x10,0xc6,0x06,0xa0,0x36,0x08,0xe9
-,0xfb,0x01,0x80,0x3e,0x9e,0x36,0x02,0x75,0xce,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xec
-,0x01,0xc3,0xe9,0xe8,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x26,0xff,0x26,0x04
-,0x00,0xa1,0xd1,0x36,0x26,0x39,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39
-,0x06,0x1c,0x00,0x75,0x18,0xa1,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26
-,0xf7,0x06,0x0c,0x00,0x40,0x00,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf
-,0x36,0x00,0x10,0xa1,0xaf,0x36,0xe7,0x06,0x80,0x3e,0x9d,0x36,0x02,0x75,0x06,0xcd
-,0x34,0xe9,0xa2,0x1a,0xc3,0xf7,0x06,0x9b,0x36,0x10,0x00,0x75,0x54,0x26,0xf6,0x06
-,0x0a,0x00,0xff,0x75,0x4c,0x26,0xa0,0x19,0x00,0x24,0xc0,0x3c,0x40,0x75,0x11,0x80
-,0x3e,0x95,0x36,0x00,0x74,0x3b,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0xe9,0x31,0x00
-,0xe8,0xf1,0x04,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0x2f,0x8b,0xd8,0xb8,0x7d,0x03
-,0xcd,0x3a,0x8b,0xc3,0xc6,0x06,0xa0,0x36,0x06,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75
-,0x05,0xc6,0x06,0xa0,0x36,0x04,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83,0x26,0x9b,0x36
-,0xfc,0xe9,0x23,0x01,0xe8,0x87,0x1d,0xe9,0x33,0x01,0x50,0x26,0xa1,0x0c,0x00,0x25
-,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x84,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9
-,0x7c,0x00,0x83,0x3e,0xe8,0x3a,0x04,0x74,0x75,0x83,0x3e,0xe8,0x3a,0x02,0x74,0x6e
-,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00
-,0x80,0x74,0x35,0x26,0x80,0x3e,0x29,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36
-,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x74,0x45
-,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1
-,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b
-,0x26,0x80,0x3e,0x19,0x00,0x00,0x74,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10
-,0x00,0x74,0x12,0x26,0xa0,0x28,0x00,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7
-,0x06,0x04,0x00,0xff,0xff,0x58,0x23,0xc0,0x74,0x03,0xe9,0x57,0xff,0x81,0x26,0x9b
-,0x36,0xff,0xfe,0x83,0xfe,0x06,0x7f,0x24,0x26,0xa1,0x20,0x00,0x3b,0x06,0xd1,0x36
-,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10,0x26,0xa1,0x24,0x00
-,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01,0x26,0xa1,0x20,0x00
-,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba,0x34,0x26,0xa1,0x24
-,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1,0xe6,0x80,0xfc,0x09
-,0x74,0x03,0xe8,0xaa,0x1c,0x8b,0xc6,0x2e,0xff,0xa4,0x30,0x49,0x26,0xa1,0x0c,0x00
-,0x3d,0xff,0x7f,0x74,0x0f,0x26,0xff,0x26,0x04,0x00,0x8e,0x06,0x38,0x34,0xe8,0x36
-,0x06,0xcd,0x50,0xc3,0xe9,0x16,0x00,0xcd,0x34,0xe9,0x11,0x00,0xcd,0x34,0x89,0x36
-,0x3d,0x37,0xa1,0x9d,0x36,0xa3,0x3f,0x37,0xc6,0x06,0xa0,0x36,0x0c,0xe8,0x8e,0x00
-,0xa1,0x9f,0x36,0x22,0xe4,0x75,0x32,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x2a,0xf6
-,0x06,0x9d,0x36,0x80,0x74,0x07,0x88,0x26,0x9e,0x36,0xe9,0x31,0x00,0x3a,0x06,0x9d
-,0x36,0xa3,0x9d,0x36,0x74,0x28,0x8b,0xf0,0x2e,0xff,0xa4,0x0d,0x2b,0x44,0x29,0xee
-,0x42,0x19,0x44,0xcd,0x44,0x2f,0x45,0x5a,0x45,0x3a,0x26,0x9e,0x36,0x75,0x01,0xc3
-,0x32,0xc0,0x86,0xc4,0x8b,0xf0,0xa2,0x9e,0x36,0x2e,0xff,0xa4,0x20,0x49,0x8b,0x2e
-,0x99,0x36,0x23,0xed,0x75,0x01,0xc3,0xbf,0x01,0x00,0xbe,0x00,0x00,0x85,0xfd,0x75
-,0x1a,0x46,0xd1,0xe7,0xe9,0xf6,0xff,0x2a,0x00,0x29,0x00,0x28,0x00,0x27,0x00,0x25
-,0x00,0x05,0x00,0x07,0x00,0x26,0x00,0x06,0x00,0x20,0x00,0xf7,0xd7,0x21,0x3e,0x99
-,0x36,0xd1,0xe6,0x2e,0x8b,0xb4,0x47,0x2b,0xe9,0x4f,0xff,0xe9,0x56,0xff,0x80,0x26
-,0x9e,0x36,0xff,0x75,0x17,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x0f,0xf6,0x06,0x9d
-,0x36,0x80,0x74,0x08,0xf7,0x06,0x66,0x37,0xff,0xff,0x75,0x07,0xc7,0x06,0x66,0x37
-,0x00,0x00,0xc3,0xf7,0x06,0x41,0x37,0x01,0x00,0x75,0x0b,0xb8,0x7f,0x03,0xcd,0x39
-,0xc7,0x06,0x41,0x37,0x01,0x00,0x33,0xf6,0xb8,0x00,0x40,0x85,0x06,0x66,0x37,0x74
-,0x21,0x80,0xbc,0x54,0x37,0xff,0x74,0x04,0xfe,0x84,0x54,0x37,0x80,0xbc,0x96,0x34
-,0xff,0x74,0x04,0xfe,0x84,0x96,0x34,0x31,0x06,0x66,0x37,0x83,0x3e,0x66,0x37,0x00
-,0x74,0x05,0x46,0xd1,0xe8,0x73,0xd4,0xc3,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b
-,0xa9,0x00,0x10,0x75,0x09,0x8b,0x1e,0x43,0x37,0xff,0xe3,0xe9,0xd7,0x00,0xc7,0x06
-,0x35,0x37,0x05,0x00,0xc7,0x06,0x43,0x37,0x1e,0x2c,0xf7,0x06,0xf4,0x33,0x00,0x08
-,0x74,0x06,0xc7,0x06,0x43,0x37,0x10,0x2c,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xcd,0xfe
-,0xa9,0x00,0x08,0x74,0xd9,0xff,0x0e,0x35,0x37,0x75,0xed,0xe9,0x66,0x00,0xa9,0x00
-,0x08,0x75,0xcb,0xff,0x0e,0x35,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6
-,0x06,0x9d,0x36,0x80,0x74,0x48,0x81,0x0e,0x9b,0x36,0x00,0x80,0xf7,0x06,0x9b,0x36
-,0x01,0x00,0x74,0x1e,0xb8,0x7d,0x03,0xcd,0x3a,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83
-,0x26,0x9b,0x36,0xfe,0xc7,0x06,0x0f,0x37,0x02,0x00,0xc6,0x06,0xa0,0x36,0x04,0xe9
-,0x7b,0xfe,0x80,0x3e,0xa0,0x36,0x04,0x75,0x07,0x83,0x3e,0x0f,0x37,0x01,0x75,0x05
-,0xc6,0x06,0xa0,0x36,0x06,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x5f,0xfe,0xbe,0x02
-,0x00,0xe9,0x4a,0xfe,0x80,0x26,0x9e,0x36,0xff,0x75,0x3a,0xf6,0x06,0x9d,0x36,0x80
-,0x74,0x2d,0xf7,0x06,0x9b,0x36,0x00,0x20,0x75,0x2b,0xc6,0x06,0xa0,0x36,0x06,0xff
-,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a
-,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01,0xe9,0x06,0x00,0xbe
-,0x04,0x00,0xe9,0x09,0xfe,0x81,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06
-,0xe5,0x0a,0xa9,0x00,0x80,0x74,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36
-,0xe7,0x06,0xe9,0x09,0xff,0xe9,0xf5,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0x83,0x0e
-,0x99,0x36,0x02,0xe9,0xe7,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0x1d,0xf7,0x06,0x9b
-,0x36,0x00,0x40,0x75,0x05,0x83,0x0e,0x99,0x36,0x08,0x83,0x0e,0x99,0x36,0x20,0x81
-,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x85,0x03,0xcd,0x39,0xe9,0xc0,0xfd,0x80,0x3e,0x9e
-,0x36,0x06,0x74,0x07,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x34,0xf6,0x06,0x9d,0x36,0x80
-,0x75,0x06,0xbe,0x07,0x00,0xe9,0x96,0xfd,0xc6,0x06,0xa0,0x36,0x04,0x83,0x3e,0x0f
-,0x37,0x02,0x74,0x1b,0xc7,0x06,0x0f,0x37,0x04,0x00,0x80,0x3e,0x9e,0x36,0x06,0x75
-,0x0e,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xe9
-,0x7b,0xfd,0x80,0x3e,0x9d,0x36,0x04,0x75,0x12,0x81,0x0e,0xc2,0x34,0x00,0x40,0xff
-,0x06,0x92,0x34,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x62,0xfd,0xbe,0x05,0x00,0xe9,0x4d
-,0xfd,0xf6,0x06,0x9d,0x36,0x80,0x75,0x19,0x83,0x0e,0xc2,0x34,0x04,0xbe,0x06,0x00
-,0xe9,0x3b,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0xc5,0xff,0x06,0x31,0x37,0xe9,0x00
-,0x00,0x83,0x26,0xc2,0x34,0xbf,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x2f,0xfd,0xe5,0x0a
-,0x50,0x25,0xc3,0xbf,0xe7,0x0a,0x58,0x80,0x26,0x9e,0x36,0xff,0x75,0x0d,0xa9,0x00
-,0x40,0x75,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x12,0xfd,0xb8,0x83,0x03,0xcd,0x39
-,0xc3,0xb8,0x7c,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09,0xc7,0x06
-,0x33,0x37,0x02,0x00,0xe9,0xf6,0xfc,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9,0xed,0xfc
-,0xff,0x06,0x8e,0x34,0xe8,0xf7,0x19,0x83,0x0e,0xc2,0x34,0x08,0xbe,0x03,0x00,0xe9
-,0xcc,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x04,0x05
-,0x04,0x04,0x04,0x00,0x03,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x04,0x00,0x08,0x08,0x05,0x08,0x08,0x08,0x00,0x03,0x00,0x03,0x03,0x00,0x00
-,0x02,0x04,0x04,0x04,0x04,0x00,0x00,0x08,0x00,0x00,0x0a,0x14,0x00,0x00,0x1a,0x00
-,0x1c,0x00,0x1e,0x20,0x00,0x00,0x04,0x41,0x06,0x0b,0x08,0xc2,0xff,0xe7,0x04,0x03
-,0x06,0x04,0x04,0x05,0x04,0x06,0x04,0x87,0x04,0x03,0x06,0x04,0x04,0x85,0x4e,0xa2
-,0x04,0xcf,0x04,0xcd,0xc7,0x06,0xa2,0x37,0x00,0x00,0xc7,0x06,0xa6,0x37,0x00,0x00
-,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xf5,0x36,0x26,0xa1,0x22,0x00,0xa3,0xf7
-,0x36,0x26,0xa1,0x24,0x00,0xa3,0xf9,0x36,0xe8,0x3b,0x19,0x8b,0xf0,0x26,0x8b,0x0e
-,0x0e,0x00,0x2b,0xc8,0x83,0xe9,0x0e,0xb8,0x01,0x80,0x83,0xf9,0x04,0x7c,0x51,0x26
-,0x8a,0x54,0x28,0x88,0x16,0x1c,0x37,0x40,0x26,0x8b,0x6c,0x26,0x86,0xcd,0x3b,0xcd
-,0x86,0xcd,0x89,0x0e,0xa4,0x37,0x75,0x38,0x40,0x32,0xff,0x26,0x8a,0x5c,0x29,0x80
-,0xfb,0x15,0x77,0x25,0x80,0xfb,0x0a,0x74,0x20,0x80,0xfb,0x01,0x74,0x1b,0xb8,0x04
-,0x80,0x2e,0x3a,0x97,0x02,0x2e,0x74,0x07,0x2e,0x3a,0x97,0x18,0x2e,0x75,0x11,0x33
-,0xc0,0x80,0xfb,0x09,0x75,0x4f,0x8b,0xf3,0xc3,0x26,0xc7,0x06,0x04,0x00,0xff,0xff
-,0x50,0x52,0xa1,0xa4,0x37,0x86,0xc4,0x26,0x3b,0x06,0x26,0x00,0x7c,0x32,0x26,0x81
-,0x3e,0x26,0x00,0x00,0x04,0x7e,0x29,0x8d,0x74,0x2a,0x26,0x8b,0x14,0x22,0xd2,0x74
-,0x1f,0x80,0xe6,0xbf,0x80,0xfe,0x09,0x75,0x17,0xc7,0x06,0xa2,0x37,0x01,0x00,0x80
-,0xfa,0x04,0x75,0x0c,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34
-,0x5a,0x58,0xe9,0xb1,0xff,0xbd,0x72,0x37,0x2e,0x8a,0x87,0x2e,0x2e,0x22,0xc0,0x74
-,0x16,0x05,0x44,0x2e,0x8b,0xf8,0x2e,0x8b,0x05,0x3e,0x89,0x46,0x00,0x83,0xc5,0x02
-,0x83,0xc7,0x02,0x22,0xe4,0x7d,0xef,0x8d,0x74,0x2a,0x83,0xe9,0x04,0x75,0x03,0xe9
-,0xa1,0x00,0x26,0x8b,0x14,0x22,0xd2,0x75,0x03,0xe9,0x7c,0x00,0xc7,0x06,0xa6,0x37
-,0x01,0x00,0xbf,0x72,0x37,0x8b,0x05,0x83,0xc7,0x02,0x80,0xe6,0xbf,0x80,0xe4,0x3f
-,0x80,0xfe,0x09,0x75,0x22,0x80,0xfa,0x04,0x75,0x5e,0xc7,0x06,0xa2,0x37,0x01,0x00
-,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34,0x86,0xc4,0xc7,0x06
-,0xa6,0x37,0x00,0x00,0xe9,0x47,0x00,0x3b,0xfd,0x7e,0x15,0x26,0x8b,0x04,0xa8,0x40
-,0x74,0x06,0xb8,0x07,0x80,0xe9,0x38,0xff,0x32,0xc0,0x26,0x8b,0x04,0xe9,0x2e,0x00
-,0x3a,0xf4,0x75,0xb1,0xc7,0x45,0xfe,0x00,0x00,0x80,0xfe,0x22,0x75,0x0d,0x3a,0xd0
-,0x77,0x16,0xc7,0x06,0xa6,0x37,0x00,0x00,0xe9,0x13,0x00,0x3a,0xd0,0x75,0x09,0xc7
-,0x06,0xa6,0x37,0x00,0x00,0xe9,0x06,0x00,0xb8,0x05,0x80,0xe9,0x02,0xff,0x32,0xf6
-,0x03,0xf2,0x2b,0xca,0xb8,0x05,0x80,0x23,0xc9,0x76,0x03,0xe9,0x64,0xff,0x74,0x03
-,0xe9,0xed,0xfe,0x33,0xc0,0xbf,0x72,0x37,0x8b,0x15,0x47,0x47,0x3b,0xfd,0x7f,0x1b
-,0xf6,0xc6,0x80,0x74,0x16,0xf7,0x06,0xa6,0x37,0x01,0x00,0x74,0x06,0xb8,0x08,0x80
-,0xe9,0xc3,0xfe,0xf6,0xc6,0x40,0x74,0xe0,0xb8,0x07,0x80,0xe9,0xb8,0xfe,0x7d,0x42
-,0xa3,0x45,0x44,0x29,0x44,0x29,0xb7,0x28,0xe2,0x28,0xee,0x2b,0xf2,0x28,0xf5,0x28
-,0x01,0x29,0xac,0x2a,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x00,0x00
-,0x73,0x36,0x00,0x00,0x03,0x36,0xc5,0x35,0x83,0x35,0x45,0x35,0x07,0x35,0xd2,0x34
-,0x45,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0xa6,0x38,0x00,0x00,0xe0,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0xf2,0x33,0x00,0x00,0xa6,0x33,0x60,0x33,0xfd,0x32,0xbc,0x32,0x77,0x32,0x3c,0x32
-,0xfb,0x31,0x6a,0x31,0x0a,0x31,0xe0,0xe0,0x10,0x10,0x10,0xe0,0xe0,0xe0,0xe0,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0
-,0xe0,0x33,0xff,0x26,0xf6,0x06,0x1a,0x00,0x80,0x74,0x1b,0x26,0x80,0x26,0x1a,0x00
-,0x7f,0x26,0x8b,0x3e,0x26,0x00,0x83,0xe7,0x1f,0x74,0x0b,0x26,0x80,0x0e,0x20,0x00
-,0x80,0x26,0x01,0x3e,0x0e,0x00,0xc3,0x60,0x2e,0x8b,0x84,0xa6,0x30,0x26,0xa3,0x18
-,0x00,0xd1,0xe6,0x2e,0xff,0x94,0x50,0x30,0x61,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4
-,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x16,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26
-,0xc6,0x06,0x19,0x00,0x00,0xe8,0xbf,0x05,0xe8,0x98,0x05,0x26,0xc7,0x06,0x26,0x00
-,0x00,0x08,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x2a,0xbf,0x2a
-,0x00,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x2a,0xa1,0x93,0x37,0x33,0xdb,0xa9
-,0x40,0x00,0x75,0x02,0xb3,0x01,0xa9,0x00,0x10,0x74,0x02,0xb7,0x88,0xa9,0x00,0x08
-,0x74,0x03,0x80,0xcf,0x44,0x26,0x89,0x5d,0x02,0xc3,0x83,0x0e,0xc2,0x34,0x20,0x26
-,0xc7,0x06,0x04,0x00,0x6b,0x2b,0x26,0xc7,0x06,0x0e,0x00,0x30,0x00,0x26,0xc7,0x06
-,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00
-,0x00,0xe8,0x69,0x05,0xe8,0x2c,0x05,0x26,0xc7,0x06,0x26,0x00,0x00,0x22,0x26,0xc6
-,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x29,0xbf,0x2a,0x00,0x26,0xc6,0x05
-,0x08,0x26,0xc6,0x45,0x01,0x2d,0x8d,0x7d,0x02,0xbe,0x54,0x37,0xb9,0x03,0x00,0xf3
-,0xa5,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x2e,0x8d,0x7d,0x02,0xbe,0x5a,0x37
-,0xb9,0x03,0x00,0xf3,0xa5,0xe8,0xd4,0x05,0xe8,0x64,0x05,0xb9,0x06,0x00,0xbe,0x54
-,0x37,0x8d,0x2e,0x2c,0x00,0x26,0x8b,0x46,0x00,0x29,0x04,0x83,0xc6,0x02,0x83,0xc5
-,0x02,0x83,0xf9,0x04,0x75,0x02,0x45,0x45,0xe2,0xeb,0xc3,0x26,0xc7,0x06,0x04,0x00
-,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00
-,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xe4,0x04,0xe8,0xa7,0x04,0x26,0xc7,0x06,0x26
-,0x00,0x00,0x16,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x28,0xbf
-,0x2a,0x00,0xe8,0x5b,0x06,0xe8,0x74,0x05,0xe8,0x04,0x05,0xc3,0x26,0xc7,0x06,0x04
-,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1a,0x00,0x26,0xc7,0x06,0x06,0x00,0x06
-,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xa3,0x04,0xe8,0x66,0x04,0x26,0xc7,0x06
-,0x26,0x00,0x00,0x0c,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x27
-,0xbf,0x2a,0x00,0xe8,0x21,0x05,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7
-,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a
-,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x4b,0x04,0xe8,0x24,0x04,0x26
-,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29
-,0x00,0x26,0xbf,0x2a,0x00,0xe8,0xf4,0x04,0xe8,0x84,0x04,0xc3,0x26,0xc7,0x06,0x04
-,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06
-,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x0d,0x04,0xe8,0xe6,0x03,0x26,0xc7,0x06
-,0x26,0x00,0x00,0x26,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x25
-,0xbf,0x2a,0x00,0xe8,0xb6,0x04,0xe8,0x46,0x04,0xe8,0xfa,0x04,0xc3,0x26,0xc7,0x06
-,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x38,0x00,0xa1,0xa2,0x37,0x50,0x0b
-,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06
-,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x99,0x03,0xe8,0xa4,0xfd,0x26,0xc7,0x45
-,0x26,0x00,0x2a,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c
-,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x24,0x83,0xc7,0x2a
-,0xe8,0x29,0x04,0xe8,0xa0,0x04,0xe8,0x22,0x05,0xe8,0xf8,0x03,0xe8,0x09,0x04,0xc3
-,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x32,0x00,0x26,0xc7
-,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x45,0x03,0xe8,0x50
-,0xfd,0x26,0xc7,0x45,0x26,0x00,0x24,0xa1,0x1c,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45
-,0x28,0x26,0xc6,0x45,0x29,0x23,0x83,0xc7,0x2a,0xe8,0xe0,0x03,0xe8,0x6c,0x04,0xe8
-,0x8a,0x04,0xe8,0x9c,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06
-,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00
-,0x00,0xe8,0xff,0x02,0xe8,0x0a,0xfd,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c,0x37
-,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x22,0x83,0xc7,0x2a,0xe8
-,0x9a,0x03,0xe8,0xc7,0x03,0xe8,0x57,0x03,0xe8,0xf8,0x03,0xe8,0x78,0x04,0xe8,0x8a
-,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0x74,0x45,0x26,0xc7,0x06,0x0e,0x00,0x3e,0x00
-,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6
-,0x06,0x19,0x00,0x00,0xe8,0xfc,0x02,0xe8,0xa9,0x02,0x83,0x3e,0x8d,0x37,0x03,0x75
-,0x01,0x90,0x26,0xc7,0x06,0x26,0x00,0x00,0x30,0x26,0xc6,0x06,0x28,0x00,0x50,0x26
-,0xc6,0x06,0x29,0x00,0x20,0xbf,0x2a,0x00,0xe8,0xd0,0x03,0xe8,0x01,0x03,0xe8,0xb5
-,0x03,0xe8,0x9f,0x03,0xc3,0x26,0xc7,0x06,0x04,0x00,0x61,0x43,0xb9,0xf0,0x00,0x83
-,0xe9,0x02,0x26,0x89,0x0e,0x0e,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6
-,0x06,0x19,0x00,0x00,0x26,0xc7,0x06,0x1a,0x00,0x00,0x00,0x26,0xc7,0x06,0x1c,0x00
-,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x00,0xe8,0x47,0x02,0x83,0xe9,0x0e,0x86
-,0xcd,0x26,0x89,0x0e,0x26,0x00,0x86,0xcd,0x26,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6
-,0x06,0x29,0x00,0x08,0xbf,0x2a,0x00,0x83,0xe9,0x04,0x26,0x89,0x0d,0x26,0xc6,0x45
-,0x01,0x26,0x8d,0x7d,0x02,0x83,0xe9,0x02,0xbb,0x01,0x00,0xb8,0x30,0x30,0x4b,0x75
-,0x17,0xbb,0x0a,0x00,0x8a,0xc4,0x26,0x88,0x05,0xb0,0x31,0x80,0xc4,0x01,0x80,0xfc
-,0x3a,0x75,0x0a,0xb4,0x61,0xe9,0x05,0x00,0x26,0x88,0x05,0x04,0x01,0x47,0x49,0x75
-,0xdd,0xc3,0x26,0xc7,0x06,0x04,0x00,0x04,0x45,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00
-,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x01,0xe8,0xe5,0x01
-,0xe8,0xd0,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x04,0x26,0xc6,0x06,0x28,0x00,0x00
-,0x26,0xc6,0x06,0x29,0x00,0x07,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7
-,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19
-,0x00,0x06,0xe8,0x04,0x02,0xe8,0x9b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26
-,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x06,0xbf,0x2a,0x00,0xe8,0x6b
-,0x02,0xe8,0xfb,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e
-,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x05
-,0xe8,0xc6,0x01,0xe8,0x5d,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06
-,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x05,0xbf,0x2a,0x00,0xe8,0x2d,0x02,0xe8
-,0xbd,0x01,0xc3,0xff,0x06,0x82,0x34,0x26,0xc7,0x06,0x04,0x00,0x3d,0x41,0x26,0xc7
-,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0e,0x00,0x26,0xc6,0x06,0x19
-,0x00,0x04,0xe8,0x84,0x01,0xe8,0x1b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26
-,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x04,0xbf,0x2a,0x00,0xe8,0xeb
-,0x01,0xe8,0x7b,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7,0x06,0x0e
-,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19,0x00,0x03
-,0xe8,0x46,0x01,0xe8,0xdd,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06
-,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x03,0xbf,0x2a,0x00,0xe8,0xad,0x01,0xe8
-,0x3d,0x01,0xc3,0xff,0x06,0x84,0x34,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7
-,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19
-,0x00,0x02,0xe8,0x04,0x01,0xe8,0x9b,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x16,0x26
-,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x02,0xbf,0x2a,0x00,0x26,0xc6
-,0x05,0x04,0x26,0xc6,0x45,0x01,0x01,0xa1,0x0f,0x37,0x86,0xe0,0xf6,0x06,0x6f,0x37
-,0x01,0x75,0x0f,0x39,0x06,0xcc,0x34,0x74,0x09,0x8b,0xd8,0xb8,0x89,0x03,0xcd,0x39
-,0x8b,0xc3,0xa3,0xcc,0x34,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xe8,0x3d,0x01,0xe8
-,0xcd,0x00,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1c
-,0x00,0xa1,0xa2,0x37,0x50,0x0b,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x18,0x00
-,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x23,0x00
-,0xe8,0x2e,0xfa,0x26,0xc7,0x45,0x26,0x00,0x0e,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7
-,0x45,0x26,0x00,0x0a,0x26,0xc6,0x45,0x29,0x00,0x83,0xc7,0x2a,0xe8,0xbd,0x00,0xe8
-,0xff,0x00,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x20,0x00,0xf3
-,0xa5,0x59,0x5f,0x5e,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x1a
-,0x00,0xf3,0xa5,0x59,0x5f,0x5e,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7
-,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x10,0xc3,0x26,0xc7,0x06
-,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00
-,0x00,0x08,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00
-,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x02,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00
-,0x26,0xc7,0x06,0x1c,0x00,0xff,0xff,0x26,0xc7,0x06,0x1e,0x00,0xff,0xff,0xc3,0x26
-,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03
-,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x06,0xa1,0x0d,0x37
-,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01
-,0x07,0xa1,0x0b,0x37,0x26,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0xa1,0xa2,0x37,0x0b
-,0xc0,0x74,0x13,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x09,0xa1,0x03,0x37,0x26
-,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02
-,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06
-,0x26,0xc6,0x45,0x01,0x0b,0x8d,0x7d,0x02,0xbe,0xef,0x36,0xb9,0x02,0x00,0xf3,0xa5
-,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x20,0xa1,0x68,0x37,0x26,0x89,0x45
-,0x02,0xa1,0x6a,0x37,0x26,0x88,0x65,0x05,0xc1,0xe0,0x04,0x26,0x88,0x45,0x04,0x83
-,0xc7,0x06,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45,0x02
-,0x00,0x00,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x14,0x26,0xc6,0x45,0x01,0x22,0x8d
-,0x7d,0x02,0xbe,0x1f,0x37,0xb9,0x09,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x0c,0x26
-,0xc6,0x45,0x01,0x23,0x8d,0x7d,0x02,0x1e,0x0e,0x1f,0x8d,0x36,0x40,0x54,0xb9,0x03
-,0x00,0xf3,0xa5,0x33,0xc0,0xb9,0x02,0x00,0xf3,0xab,0x1f,0xc3,0x26,0xc6,0x05,0x08
-,0x26,0xc6,0x45,0x01,0x28,0x8d,0x7d,0x02,0xbe,0xd1,0x36,0xb9,0x03,0x00,0xf3,0xa5
-,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x29,0xa1,0xc2,0x34,0x86,0xe0,0x26
-,0x89,0x45,0x02,0xa1,0x9b,0x36,0x26,0x89,0x45,0x04,0x26,0x88,0x45,0x06,0x26,0x88
-,0x45,0x07,0x8d,0x7d,0x08,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x2b,0x8d
-,0x7d,0x02,0xbe,0xbb,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06,0x26
-,0xc6,0x45,0x01,0x2c,0x8d,0x7d,0x02,0xbe,0xe5,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3
-,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x30,0xa1,0x37,0x37,0x86,0xe0,0x26,0x89
-,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc7,0x06,0x0e,0x00,0x1e,0x00,0x26,0xc7,0x06
-,0x06,0x00,0x02,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x6c,0xfe,0xe8,0x03,0xfe
-,0x26,0xc7,0x06,0x26,0x00,0x00,0x10,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06
-,0x29,0x00,0x11,0xbf,0x2a,0x00,0xe8,0x35,0x00,0xe8,0x45,0x00,0xe8,0x55,0x00,0xc3
-,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6
-,0x06,0x19,0x00,0x00,0xe8,0x32,0xfe,0xe8,0xc9,0xfd,0x26,0xc7,0x06,0x26,0x00,0x00
-,0x04,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06,0x29,0x00,0x13,0xc3,0x26,0xc6
-,0x05,0x04,0x26,0xc6,0x45,0x01,0x0c,0x26,0xc7,0x45,0x02,0x00,0x01,0x83,0xc7,0x04
-,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x0e,0x26,0xc7,0x45,0x02,0x00,0x02
-,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45
-,0x02,0x00,0x00,0x83,0xc7,0x04,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0xb3,0x39,0xc9,0x39,0x83,0x3a,0xb3,0x39,0xb3,0x39,0xb3,0x39,0x1c,0x3a,0x1c,0x3a
-,0xa3,0xb6,0x34,0xa1,0xe9,0x36,0xa3,0x11,0x37,0xa3,0xd2,0x34,0xa1,0xeb,0x36,0xa3
-,0x13,0x37,0xa3,0xd4,0x34,0xa1,0xed,0x36,0xa3,0x15,0x37,0xa3,0xd6,0x34,0xa1,0x01
-,0x37,0xa3,0xce,0x34,0xa1,0xf7,0x36,0xa3,0x17,0x37,0xa3,0xdc,0x34,0xa1,0xf9,0x36
-,0xa3,0x19,0x37,0xa3,0xde,0x34,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75,0x0c,0x33,0xc0
-,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x50,0x39,0xe9,0x0f,0x01,0xbe,0x07,0x00
-,0xe9,0x19,0xf1,0xf6,0x06,0x9d,0x36,0x80,0x74,0xf3,0xc6,0x06,0xa0,0x36,0x02,0xc6
-,0x06,0x6e,0x37,0x08,0xc6,0x06,0x70,0x37,0x02,0xb8,0x88,0x03,0xcd,0x39,0xf6,0x06
-,0x6f,0x37,0x01,0x75,0x4a,0xa1,0xd1,0x36,0x3a,0x06,0xe9,0x36,0x75,0x41,0x3a,0x26
-,0xea,0x36,0x75,0x3b,0xa1,0xd3,0x36,0x3a,0x06,0xeb,0x36,0x75,0x32,0x3a,0x26,0xec
-,0x36,0x75,0x2c,0xa1,0xd5,0x36,0x3a,0x06,0xed,0x36,0x75,0x23,0x3a,0x26,0xee,0x36
-,0x75,0x1d,0xc6,0x06,0x70,0x37,0x02,0xfe,0x0e,0x6e,0x37,0x75,0x0f,0xb8,0x88,0x03
-,0xcd,0x3a,0x83,0x0e,0x9b,0x36,0x12,0xc6,0x06,0xa0,0x36,0x0c,0xe9,0xa8,0xf0,0xa1
-,0x05,0x37,0x26,0x3b,0x06,0x20,0x00,0x75,0x40,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22
-,0x00,0x75,0x36,0xa1,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x2c,0xa0,0x9e,0x36
-,0x3c,0x02,0x75,0x08,0x26,0xf6,0x06,0x18,0x00,0x08,0x75,0x47,0xc6,0x06,0x6e,0x37
-,0x08,0xfe,0x0e,0x70,0x37,0x75,0x1c,0xc6,0x06,0x70,0x37,0x02,0xe5,0x02,0x0d,0x01
-,0x04,0x25,0xef,0xff,0xe7,0x02,0xe9,0x5e,0xf0,0xc6,0x06,0x70,0x37,0x02,0xc6,0x06
-,0x6e,0x37,0x08,0xe5,0x02,0x25,0xff,0xfb,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02
-,0xe9,0x44,0xf0,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x25,0x26,0xf6,0x06,0x18,0x00
-,0x08,0x75,0xed,0x81,0x26,0x9b,0x36,0x7f,0xff,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x84
-,0x03,0xcd,0x3a,0xc6,0x06,0xa0,0x36,0x06,0x83,0x26,0xc2,0x34,0xaf,0xe9,0x17,0xf0
-,0xa1,0x01,0x37,0x3a,0x26,0x0f,0x37,0x7f,0xc7,0xe9,0xf7,0xfe,0x83,0x26,0x9b,0x36
-,0xec,0xe8,0x2a,0x0d,0x81,0x0e,0x9b,0x36,0x80,0x00,0xbb,0xff,0x7f,0xcd,0x53,0xc6
-,0x06,0xa0,0x36,0x02,0xe9,0xf0,0xef,0x83,0x0e,0x9b,0x36,0x11,0xc6,0x06,0xa0,0x36
-,0x0c,0xe9,0xf9,0xef,0x44,0x3b,0x2c,0x3b,0xc7,0x2a,0x6b,0x3b,0x44,0x3b,0xc7,0x2a
-,0xc7,0x2a,0xc7,0x2a,0xa3,0xb6,0x34,0x81,0x0e,0xc2,0x34,0x00,0x20,0xf7,0x06,0x41
-,0x37,0x01,0x00,0x74,0x1b,0x8c,0xc3,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f,0x03
-,0xcd,0x3a,0x33,0xc0,0x8e,0xc0,0xbf,0x54,0x37,0xb9,0x06,0x00,0xf3,0xab,0x8e,0xc3
-,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0xe4,0x3a,0xf7,0x06,0x9b,0x36
-,0x00,0x01,0x75,0x21,0x83,0x26,0xc2,0x34,0xbf,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0x9b
-,0x36,0xe9,0x09,0x00,0xa1,0x9b,0x36,0x81,0x26,0x9b,0x36,0xff,0xdf,0xa9,0x00,0x20
-,0x75,0x06,0xe9,0x6e,0x00,0xe9,0x6f,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37
-,0x37,0x01,0x00,0xc6,0x06,0xca,0x34,0x01,0xe9,0x58,0x00,0x83,0x0e,0x9b,0x36,0x40
-,0xe8,0x58,0x00,0xa1,0x05,0x37,0x3b,0x06,0xe9,0x36,0x75,0x37,0xa1,0x07,0x37,0x3b
-,0x06,0xeb,0x36,0x75,0x2e,0xa1,0x09,0x37,0x3b,0x06,0xed,0x36,0x75,0x25,0xfe,0x0e
-,0x71,0x37,0x75,0x1c,0xb8,0x87,0x03,0xcd,0x3a,0x83,0x0e,0x99,0x36,0x10,0xa1,0x50
-,0x37,0xc7,0x06,0x50,0x37,0x00,0x00,0x09,0x06,0x99,0x36,0xc6,0x06,0xa0,0x36,0x08
-,0xe9,0x14,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x03,0x00,0xc6,0x06
-,0xca,0x34,0x03,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0xfc,0xee,0xa1,0xd1,0x36,0x26,0x3b
-,0x06,0x20,0x00,0x75,0x15,0xa1,0xd3,0x36,0x26,0x3b,0x06,0x22,0x00,0x75,0x12,0xa1
-,0xd5,0x36,0x26,0x3b,0x06,0x24,0x00,0x75,0x0f,0xc3,0x8d,0x36,0x20,0x00,0xe9,0x0b
-,0x00,0x8d,0x36,0x22,0x00,0xe9,0x04,0x00,0x8d,0x36,0x24,0x00,0x83,0xc4,0x02,0xf7
-,0x06,0xe6,0x34,0x01,0x00,0x74,0x15,0x26,0x3a,0x04,0x77,0x08,0x72,0x0e,0x26,0x3a
-,0x64,0x01,0x72,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xab,0xee,0xe8,0x7c,0x0a,0x8c
-,0xc0,0x3d,0xff,0xff,0x74,0x1b,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0xc7,0x06,0x04
-,0x00,0x49,0x3c,0x26,0xc7,0x06,0x06,0x00,0x0c,0x00,0xcd,0x50,0xb9,0x4e,0x00,0xe2
-,0xfe,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0x94,0xee,0xe9,0x7b,0xee,0x8f,0x3c,0x06,0x3d
-,0x06,0x3d,0x06,0x3d,0xd2,0x3c,0xea,0x3c,0x06,0x3d,0x06,0x3d,0xa3,0xb6,0x34,0x81
-,0x26,0xc2,0x34,0xaf,0xdf,0xc7,0x06,0x4c,0x37,0x00,0x00,0xb8,0x8a,0x03,0xcd,0x3a
-,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74,0x05,0xc6,0x06
-,0x9f,0x36,0x06,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x4c,0x3c,0xf7
-,0x06,0x9b,0x36,0x00,0x20,0x75,0x0e,0x81,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x8b,0x03
-,0xcd,0x3a,0xe9,0x54,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x03,0xe9,0x17,0xee
-,0xc7,0x06,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04
-,0x83,0x0e,0x50,0x37,0x04,0xf6,0x06,0x9d,0x36,0x80,0x75,0x2a,0xe8,0x1f,0x0b,0xe9
-,0x27,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x75,0xd3,0xc7,0x06,0x37,0x37,0x02,0x00
-,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0xc6,0x06,0xa0,0x36,0x00,0xf6
-,0x06,0x9d,0x36,0x80,0x74,0x03,0xe8,0xde,0x0a,0x81,0x26,0x9b,0x36,0x7c,0xff,0xbb
-,0xff,0xff,0xcd,0x53,0xcd,0x54,0xe9,0xbe,0xed,0xa3,0xb6,0x34,0xe8,0xad,0x01,0xb8
-,0x86,0x03,0xcd,0x39,0xc7,0x06,0x4c,0x37,0x00,0x00,0x81,0x26,0xc2,0x34,0xaf,0xdf
-,0xf6,0x06,0x9d,0x36,0x80,0x74,0x34,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x56,0xf7
-,0x06,0x9b,0x36,0x00,0x01,0x74,0x27,0xe8,0x35,0x01,0x72,0x1c,0xbe,0x00,0x40,0x85
-,0x36,0xc2,0x34,0x75,0x08,0x09,0x36,0xc2,0x34,0xff,0x06,0x92,0x34,0xe8,0x8b,0x01
-,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x6c,0xed,0xe9,0xb5,0x00,0xc7,0x06
-,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0x83,0x0e
-,0x50,0x37,0x04,0x80,0x3e,0x9e,0x36,0x08,0x74,0x03,0xe8,0x5a,0x0a,0xe8,0xef,0x00
-,0x72,0xd6,0xe9,0xc8,0xff,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x12,0xc6,0x06,0xa0,0x36
-,0x00,0xf7,0x06,0x9b,0x36,0x08,0x00,0x74,0x02,0xcd,0x54,0xe8,0x39,0x0a,0x81,0x26
-,0x9b,0x36,0xff,0xbf,0xe8,0xc8,0x00,0x72,0xaf,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x9c
-,0xff,0xf6,0x06,0x9e,0x36,0xff,0x75,0x58,0xa3,0xb6,0x34,0xe8,0xfe,0x00,0x81,0x26
-,0xc2,0x34,0xff,0xbf,0xf6,0x06,0x9d,0x36,0x80,0x74,0x48,0xf7,0x06,0x9b,0x36,0x00
-,0x20,0x74,0x22,0xf7,0x06,0x9b,0x36,0x00,0x40,0x75,0x08,0xe8,0x91,0x00,0x72,0x30
-,0xe9,0x22,0x00,0x26,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x75,0x24,0x81,0x0e,0x66,0x37
-,0x00,0x08,0xe9,0xd2,0xec,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe8,0x71,0x00,0x72,0x10
-,0xb8,0x8b,0x03,0xcd,0x39,0xe8,0xd3,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00
-,0xe9,0xb4,0xec,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74
-,0x46,0xc6,0x06,0x9f,0x36,0x06,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x0c,0x80,0x3e
-,0x9d,0x36,0x08,0x75,0x05,0xc6,0x06,0x9f,0x36,0x0a,0xe8,0x32,0x00,0x72,0xd1,0xe8
-,0x99,0x00,0x80,0x3e,0x9d,0x36,0x08,0x75,0x13,0x81,0x0e,0x99,0x36,0x80,0x00,0xf7
-,0x06,0x9b,0x36,0x00,0x20,0x75,0x08,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x68,0xec,0xc6
-,0x06,0x9f,0x36,0x0a,0xe9,0x60,0xec,0xb8,0x86,0x03,0xcd,0x3a,0xe9,0x58,0xec,0x26
-,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x74,0x08,0x81,0x26,0xc2,0x34,0xff,0xbf,0xf9,0xc3
-,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x13,0x81,0x0e,0x66,0x37,0x00,0x08,0xe8,0x4a
-,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xf9,0xc3,0x81,0x0e,0x9b,0x36,0x00
-,0x40,0x80,0x26,0x6f,0x37,0xfe,0x81,0x26,0x9b,0x36,0x7f,0xff,0xc6,0x06,0xa0,0x36
-,0x00,0xf8,0xc3,0x81,0x0e,0x99,0x36,0x00,0x01,0xe9,0x21,0xec,0x26,0xa1,0x20,0x00
-,0xa3,0xfb,0x36,0xa3,0xaa,0x34,0x26,0xa1,0x22,0x00,0xa3,0xfd,0x36,0xa3,0xac,0x34
-,0x26,0xa1,0x24,0x00,0xa3,0xff,0x36,0xa3,0xae,0x34,0xc3,0xa1,0x05,0x37,0x26,0x3b
-,0x06,0x20,0x00,0x75,0x19,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22,0x00,0x75,0x0f,0xa1
-,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x05,0xe8,0x02,0x00,0xf8,0xc3,0x51,0x1e
-,0x06,0x8b,0xc7,0x8d,0x36,0x20,0x00,0xbf,0x05,0x37,0xb9,0x03,0x00,0x1e,0x06,0x1f
-,0x07,0xf3,0xa5,0x8b,0xf8,0x8d,0x36,0x20,0x00,0xbf,0xa0,0x34,0xb9,0x03,0x00,0xf3
-,0xa5,0x07,0x1f,0x59,0x8b,0xf8,0xa1,0x07,0x37,0xa3,0xa6,0x34,0xa1,0x09,0x37,0xa3
-,0xa8,0x34,0xf9,0xc3,0xc6,0x06,0xb6,0x34,0x01,0xe9,0x8b,0xeb,0xe8,0x87,0x08,0x8b
-,0xf0,0x05,0x12,0x00,0x26,0x29,0x06,0x0e,0x00,0x26,0x8b,0x44,0x2a,0x26,0x3a,0x06
-,0x0e,0x00,0x75,0x5b,0x26,0x83,0x2e,0x0e,0x00,0x02,0x80,0xfc,0x27,0x75,0x50,0x26
-,0x8b,0x44,0x2c,0xa9,0xff,0xff,0x75,0x47,0x8b,0xfe,0x33,0xc0,0x26,0xf6,0x45,0x3c
-,0x80,0x74,0x06,0x26,0x8a,0x45,0x3a,0x24,0x1f,0x03,0xf8,0x26,0x80,0x7d,0x45,0x09
-,0x75,0x2d,0x8c,0xc2,0x8e,0x06,0x38,0x34,0x8e,0xda,0x8b,0x0e,0x0e,0x00,0x26,0x89
-,0x0e,0x0e,0x00,0x8d,0x74,0x2c,0xbf,0x18,0x00,0xf3,0xa4,0x33,0xc0,0x8e,0xd8,0x26
-,0xc7,0x06,0x04,0x00,0xb5,0x3f,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0xcd,0x50,0xb8
-,0x06,0x80,0xe9,0xef,0xe9,0x26,0xa1,0x0c,0x00,0xa3,0x93,0x37,0x83,0x0e,0x99,0x36
-,0x01,0xe9,0x00,0xeb,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e
-,0x00,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36
-,0x26,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3
-,0x1e,0x00,0xb8,0x0a,0x80,0xe8,0x36,0x07,0xe9,0xe2,0xea,0xff,0x06,0x90,0x34,0xbe
-,0x0a,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e
-,0xc2,0x34,0x01,0xe9,0xb6,0xea,0x80,0x3e,0x9d,0x36,0x0a,0x75,0x0f,0x26,0xa1,0x0c
-,0x00,0x25,0x07,0x00,0x3d,0x04,0x00,0x75,0x03,0xe8,0x79,0x00,0xa1,0xf3,0x36,0x86
-,0xe0,0xe7,0x1e,0xa3,0xe3,0x36,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37
-,0x7b,0x7f,0x83,0x0e,0x0d,0x37,0x48,0xe8,0x1e,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07
-,0x00,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20,0x00,0x75,0x06,0xb8
-,0x01,0x00,0xe9,0x3f,0xe9,0xe9,0x5f,0xea,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f
-,0x03,0xcd,0x3a,0xa1,0x1d,0x37,0xa3,0xc4,0x34,0x86,0xe0,0x68,0x7f,0x03,0x1f,0xa3
-,0x06,0x00,0x33,0xc0,0x8e,0xd8,0xa1,0x0b,0x37,0xa3,0xb2,0x34,0xa1,0x0d,0x37,0xa3
-,0xb4,0x34,0xa1,0xf3,0x36,0xa3,0xc8,0x34,0xa1,0xef,0x36,0xa3,0x9c,0x34,0xa1,0xf1
-,0x36,0xa3,0x9e,0x34,0xc3,0x80,0x0e,0x9d,0x36,0x80,0xbe,0x00,0x00,0xe8,0xb4,0x07
-,0xb8,0x7b,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00
-,0xa1,0xe5,0x36,0xe7,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xb8,0x82,0x03,0xcd,0x3a,0xf7
-,0x06,0x9b,0x36,0x00,0x20,0x75,0x03,0xe8,0xfd,0x06,0xa1,0xd3,0x36,0xa3,0xef,0x36
-,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3,0xf1,0x36,0xa3,0x9e,0x34,0xc3,0xf6,0x06,0x9d
-,0x36,0x80,0x74,0x31,0xbe,0x22,0x00,0xe9,0x17,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74
-,0x24,0xbe,0x23,0x00,0xe9,0x0a,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x17,0xbe,0x24
-,0x00,0x56,0xe8,0xa8,0x05,0x8c,0xc0,0x3d,0xff,0xff,0x5e,0x74,0x05,0xe8,0xd7,0xef
-,0xcd,0x50,0xe9,0x1f,0xe8,0xe9,0x9f,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x8a,0x03,0xcd,0x39,0xe9,0xf7,0x00,0x80,0x3e,0xa0
-,0x36,0x08,0x75,0x2e,0xa9,0xd0,0x07,0x75,0x2c,0xa1,0xb1,0x36,0x0d,0x00,0x04,0xe7
-,0x08,0xe5,0x00,0x25,0xff,0x73,0xe7,0x00,0xb8,0x8a,0x03,0xcd,0x3a,0xe8,0xc3,0x06
-,0x33,0xc0,0xe7,0x0e,0xe5,0x0a,0x25,0xc3,0x17,0xe7,0x0a,0xcd,0x54,0xc6,0x06,0xa0
-,0x36,0x00,0xe9,0x68,0xe9,0xbe,0x04,0x00,0xe9,0x3f,0xe9,0x83,0x26,0x9b,0x36,0xbf
-,0xc6,0x06,0x71,0x37,0x03,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8
-,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x39,0x81,0x0e,0xc2,0x34,0x00,0x20,0xe9
-,0x92,0x00,0xe8,0x49,0x06,0xb8,0x87,0x03,0xcd,0x39,0xbb,0xff,0x7f,0xcd,0x53,0xb8
-,0x84,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x83
-,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xc3,0xe5,0x00
-,0x25,0xff,0x53,0xe7,0x00,0x83,0x0e,0xc2,0x34,0x40,0x83,0x26,0xc2,0x34,0xef,0xe8
-,0x0c,0x06,0xbb,0xff,0x7f,0xcd,0x53,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd
-,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a
-,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xc3
-,0x83,0x0e,0xc2,0x34,0x50,0xe8,0x18,0x04,0xe8,0xd3,0x05,0xf6,0x06,0x6f,0x37,0x01
-,0x75,0x12,0xb8,0x89,0x03,0xcd,0x39,0x83,0x3e,0x0f,0x37,0x00,0x75,0x06,0xc7,0x06
-,0x0f,0x37,0x04,0x00,0xa1,0x9d,0x36,0x80,0xfc,0x08,0x74,0x05,0xb8,0x84,0x03,0xcd
-,0x39,0xe5,0x02,0x0d,0x01,0x08,0x25,0xef,0xff,0xe7,0x02,0xa1,0x9d,0x36,0x86,0xe0
-,0x32,0xe4,0x8b,0xf0,0xd1,0xee,0x33,0xc0,0x0d,0x20,0x00,0x09,0x06,0xad,0x36,0xa1
-,0xad,0x36,0xe7,0x04,0xe9,0x53,0xe8,0xe9,0x5a,0xe8,0x33,0xc0,0xa0,0x1b,0x37,0xd1
-,0xe0,0x3a,0x06,0xa0,0x36,0x75,0x03,0xe9,0xba,0xff,0xe9,0x60,0xe8,0xc7,0x06,0x41
-,0x37,0x00,0x00,0xe8,0xc1,0xe1,0xe8,0x6a,0x06,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56
-,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x02,0x25,0xf9,0xff,0x0d,0x03,0x00
-,0xe7,0x02,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1,0xad,0x36,0xe7
-,0x04,0xe8,0x7c,0x03,0xe8,0x9f,0x03,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b
-,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x99,0x36,0xa3,0x9b
-,0x36,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xa3,0x4c,0x37,0xa3,0xf3,0x36,0xa3,0xef,0x36
-,0xa3,0xf1,0x36,0xe8,0x82,0xfd,0xc6,0x06,0x9f,0x36,0x02,0xe9,0xef,0xe7,0xe5,0x02
-,0x0d,0x01,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xe8,0xf2
-,0x05,0xe5,0x0a,0x0d,0x40,0x00,0xe7,0x0a,0x33,0xc0,0xa3,0x81,0x37,0xa3,0x85,0x37
-,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xe5,0x00,0x0d,0x00,0x84,0xe7,0x00
-,0xb8,0x8c,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff
-,0xe5,0x00,0x25,0xff,0x7b,0xe7,0x00,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x7e,0x03
-,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0xa7,0xed
-,0x83,0x26,0xef,0x34,0xdf,0xff,0x06,0x81,0x37,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20
-,0xc3,0xf7,0x06,0x9a,0x37,0x80,0x00,0x74,0x3d,0xa9,0xd0,0x07,0x74,0x10,0xa9,0x00
-,0x04,0x74,0x12,0x33,0xc0,0xe7,0x0e,0xff,0x06,0x87,0x37,0xe9,0xd2,0xff,0xff,0x06
-,0x85,0x37,0xe9,0xcb,0xff,0xff,0x06,0x83,0x37,0xe9,0xc4,0xff,0x83,0x26,0x9a,0x37
-,0x7f,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f,0x01,0xc3,0xbb,0xff
-,0x7f,0xcd,0x53,0xe9,0x00,0x00,0xe5,0x02,0x25,0xff,0xfb,0x25,0xef,0xff,0x0d,0x01
-,0x00,0xe7,0x02,0xa1,0x83,0x37,0x3b,0x06,0x46,0x37,0x7f,0x2a,0xa1,0x85,0x37,0x3b
-,0x06,0x48,0x37,0x7c,0x21,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f
-,0x15,0xc6,0x06,0x9f,0x36,0x04,0xe5,0x02,0x25,0xff,0xf7,0x0d,0x01,0x00,0x25,0xef
-,0xff,0xe7,0x02,0xe9,0xf7,0xe6,0xbe,0x01,0x00,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74
-,0x0a,0x83,0x26,0x9b,0x36,0xfc,0x83,0x0e,0xc2,0x34,0x04,0xe9,0xd0,0xe6,0xb8,0x7b
-,0x03,0xcd,0x39,0xe5,0x02,0x0d,0x01,0x60,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06,0xf1
-,0x34,0x20,0x03,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0x81,0x26,0xc2,0x34,0x7f,0xff,0x80
-,0x0e,0x6f,0x37,0x01,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0xd2,0xb8,0x7b,0x03,0xcd
-,0x3a,0xb8,0x7d,0x03,0xcd,0x39,0x83,0x26,0x9b,0x36,0xef,0x33,0xc0,0xb0,0x8a,0xa2
-,0x9f,0x36,0xa2,0x9d,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc7,0x06,0x0f,0x37,0x04
-,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xb8
-,0x8d,0x03,0xcd,0x39,0xe8,0x00,0xd5,0xe5,0x02,0x0d,0x01,0x40,0x25,0xef,0xff,0x8b
-,0xd8,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00,0x8b,0xc3,0x0d,0x00
-,0x20,0x25,0xf9,0xff,0x0b,0x06,0xe8,0x3a,0xe7,0x02,0xc3,0xff,0x0e,0xf1,0x34,0x75
-,0x01,0xc3,0xe5,0x4e,0xa9,0x01,0x00,0x75,0x12,0xe5,0x00,0xa9,0x00,0x04,0x75,0x05
-,0x0d,0x00,0x04,0xe7,0x00,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0xe5,0x00,0xa9,0x00,0x04
-,0x74,0xf3,0x25,0xff,0xfb,0xe7,0x00,0xe9,0xeb,0xff,0xc6,0x06,0xa0,0x36,0x04,0x83
-,0x26,0x9b,0x36,0xfc,0x81,0x0e,0x9b,0x36,0x80,0x00,0xe9,0x10,0xe6,0xb8,0x8e,0x03
-,0xcd,0x3a,0xcd,0x54,0x81,0x0e,0xaf,0x36,0x00,0x18,0xa1,0xaf,0x36,0xe7,0x06,0xb8
-,0x7b,0x03,0xcd,0x39,0xa1,0xd3,0x36,0xa3,0x8f,0x37,0xa1,0xd5,0x36,0xa3,0x91,0x37
-,0xc7,0x06,0x8b,0x37,0x02,0x00,0xc7,0x06,0x8d,0x37,0x02,0x00,0x83,0x0e,0x99,0x36
-,0x40,0xe9,0xd9,0xe5,0x80,0x3e,0x9f,0x36,0x06,0x75,0x15,0xa9,0xd0,0x07,0x75,0xec
-,0x25,0x00,0x18,0x75,0x0e,0xff,0x0e,0x8b,0x37,0x75,0xe1,0xc6,0x06,0x9f,0x36,0x08
-,0xe9,0xba,0xe5,0xff,0x0e,0x8d,0x37,0x75,0xd3,0xbe,0x08,0x00,0xe9,0x9f,0xe5,0xb8
-,0x7b,0x03,0xcd,0x39,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x08,0xc6,0x06,0x9f,0x36
-,0x0a,0xe9,0x0d,0x00,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x0b,0xb8,0x8b,0x03,0xcd
-,0x39,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x83,0xe5,0xb8,0x7b,0x03,0xcd,0x39,0xc7
-,0x06,0x8b,0x37,0x04,0x00,0xc7,0x06,0x8d,0x37,0x04,0x00,0x81,0x0e,0x99,0x36,0x00
-,0x02,0xe9,0x69,0xe5,0xf6,0x06,0x9d,0x36,0x80,0x75,0x1b,0xa9,0xd0,0x07,0x75,0xeb
-,0xa9,0x00,0x18,0x75,0x0c,0xff,0x0e,0x8d,0x37,0x75,0xe0,0xe8,0x17,0xfb,0xe9,0x4c
-,0xe5,0xb8,0x82,0x03,0xcd,0x39,0xc3,0xff,0x0e,0x8b,0x37,0x75,0xce,0xbe,0x09,0x00
-,0xe9,0x2b,0xe5,0xc7,0x06,0x3d,0x37,0x00,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8
-,0x3c,0x02,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b
-,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02
-,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x50,0x00
-,0xe8,0x73,0x00,0xb8,0x81,0x03,0xcd,0x39,0xc3,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74
-,0x0d,0xc6,0x06,0x9f,0x36,0x02,0xc6,0x06,0xa0,0x36,0x00,0xe9,0xdf,0xe4,0x83,0x0e
-,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xe7,0x02,0xe5,0x56,0x0d,0x02
-,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0x8b,0x36,0x3d,0x37,0xe8,0x44,0x02
-,0xc6,0x06,0xa0,0x36,0x0e,0xe9,0xb5,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x06,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a
-,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8
-,0x88,0x03,0xcd,0x3a,0x07,0xc3,0x06,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x7b,0x03,0xcd
-,0x3a,0xb8,0x82,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x3a
-,0xb8,0x7e,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0xb8,0x81,0x03,0xcd,0x3a,0xb8
-,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x7d,0x03,0xcd,0x3a,0xb8,0x8d
-,0x03,0xcd,0x3a,0xc7,0x06,0x41,0x37,0x00,0x00,0x07,0xc3,0x06,0x8e,0x06,0x38,0x34
-,0x1f,0x8b,0x0e,0x0e,0x00,0x26,0x89,0x0e,0x0e,0x00,0xbe,0x18,0x00,0xbf,0x18,0x00
-,0xf3,0xa4,0x06,0x1e,0x07,0xcd,0x34,0x07,0x33,0xc0,0x8e,0xd8,0xc3,0x26,0xf6,0x06
-,0x20,0x00,0x80,0x74,0x44,0x33,0xc0,0x26,0xa0,0x26,0x00,0x24,0x1f,0x8b,0xf0,0x26
-,0x8b,0x5c,0x28,0x89,0x1e,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04
-,0x26,0x88,0x5c,0x28,0x8b,0xc6,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3
-,0xa4,0x8b,0xc8,0x83,0xc7,0x06,0xf3,0xa4,0x26,0x81,0x26,0x26,0x00,0x1f,0x80,0x26
-,0x81,0x36,0x26,0x00,0x00,0x80,0xe9,0xa9,0xff,0x26,0x8b,0x1e,0x28,0x00,0x89,0x1e
-,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04,0x26,0x88,0x1e,0x28,0x00
-,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3,0xa4,0xe9,0x84,0xff,0x86,0xc4
-,0xa3,0x68,0x37,0xe8,0x87,0xff,0xf7,0x06,0x6a,0x37,0x0f,0x00,0x74,0x10,0x80,0x3e
-,0x9e,0x36,0x00,0x75,0x09,0xbe,0x00,0x00,0xe8,0xac,0xe9,0xcd,0x50,0xc3,0xc3,0x50
-,0x56,0x06,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06,0x26,0xa0,0x26,0x00
-,0x24,0x1f,0x8b,0xf0,0x26,0x8b,0x5c,0x26,0x86,0xfb,0x83,0xeb,0x04,0x74,0x4f,0x83
-,0xc6,0x2a,0x8c,0xc0,0x8e,0xd8,0xb9,0x07,0x00,0x33,0xc0,0x8e,0xc0,0xbf,0x72,0x37
-,0xf3,0xab,0x33,0xc9,0x8a,0x0c,0x80,0xf9,0x00,0x75,0x03,0xe9,0x30,0x00,0x3b,0xd9
-,0x73,0x03,0xe9,0x29,0x00,0x2b,0xd9,0x8a,0x44,0x01,0x25,0x3f,0x00,0x74,0x19,0x3d
-,0x0b,0x00,0x7d,0x14,0xd1,0xe0,0x8b,0xf8,0x2e,0x8b,0xbd,0x5c,0x49,0x8d,0x74,0x02
-,0x83,0xe9,0x02,0xf3,0xa4,0xe9,0x02,0x00,0x03,0xf1,0x23,0xdb,0x75,0xc4,0x33,0xc0
-,0x8e,0xd8,0x07,0x5e,0x58,0xc3,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06
-,0x26,0xa0,0x26,0x00,0x24,0x1f,0xc3,0xe5,0x0a,0x25,0xc3,0xbf,0xe7,0x0a,0xb8,0x86
-,0x03,0xcd,0x39,0xb8,0x83,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0x7c,0xdf,0xb8,0x85
-,0x03,0xcd,0x3a,0xe5,0x02,0x25,0xff,0xf3,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02
-,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00,0xa1,0xe7,0x36,0x25,0xff,0xfe,0xa3,0xe7,0x36
-,0xe7,0x3e,0x83,0x26,0x99,0x36,0xcf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36
-,0xe7,0x06,0xc3,0xe5,0x02,0x0d,0x01,0x0c,0x25,0xef,0xff,0xe7,0x02,0xa1,0xe7,0x36
-,0x0d,0x00,0x01,0xe7,0x3e,0xa3,0xe7,0x36,0x81,0x0e,0x9b,0x36,0x00,0x20,0x83,0x0e
-,0x99,0x36,0x20,0x81,0x26,0x9b,0x36,0x7c,0xbf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1
-,0xaf,0x36,0xe7,0x06,0xb8,0x86,0x03,0xcd,0x39,0xb8,0x85,0x03,0xcd,0x39,0xb8,0x83
-,0x03,0xcd,0x3a,0xc3,0x0b,0xf6,0x75,0x49,0x06,0x8e,0x06,0x32,0x34,0x80,0x3e,0xe0
-,0x34,0x01,0x75,0x1b,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26,0xf7,0x06
-,0x0a,0x00,0x00,0x20,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x20,0x07,0xc3,0x80
-,0x3e,0xe3,0x34,0x01,0x75,0x19,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26
-,0xf7,0x06,0x0a,0x00,0x00,0x10,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x10,0x07
-,0xc3,0xe9,0xb4,0xff,0x50,0x51,0x57,0x33,0xc0,0xb9,0x06,0x00,0x8e,0xc0,0xbf,0xd1
-,0x36,0xf3,0xae,0x5f,0x74,0x0c,0x26,0xf6,0x06,0x00,0x00,0xc0,0x75,0x04,0xf8,0x59
-,0x58,0xc3,0xf9,0xe9,0xf9,0xff,0x8b,0x05,0x0b,0x45,0x02,0x0b,0x45,0x04,0xc3,0x52
-,0x50,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75,0xf6,0xb8,0x01,0x80,0xe7,0x5a
-,0x58,0x5a,0xc3,0xe8,0xe9,0xff,0x50,0xe5,0x02,0x25,0xff,0x7f,0x0d,0x01,0x00,0x25
-,0xef,0xff,0xe7,0x02,0x0d,0x00,0x80,0xe7,0x02,0xa1,0xad,0x36,0xe7,0x04,0xa1,0xaf
-,0x36,0xe7,0x06,0x58,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x2e,0x2b,0xce,0x41,0x10,0x42,0x7b,0x41,0x30,0x41,0xa2,0x41,0xaf,0x45,0x44,0x29
-,0xc7,0x2a,0xc7,0x2a,0x60,0x39,0xf4,0x3a,0x5c,0x3c,0x09,0x3d,0xb1,0x3d,0x34,0x3f
-,0xc7,0x2a,0x3c,0x3f,0xc7,0x2a,0xc4,0x3f,0x16,0x40,0x16,0x40,0xed,0x40,0xfa,0x40
-,0x07,0x41,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xd6,0x52,0x00,0x00,0x01,0x37
-,0xe9,0x36,0xf3,0x36,0xef,0x36,0x1d,0x37,0x0d,0x37,0x0b,0x37,0x9c,0x37,0x03,0x37
-,0xfb,0x36,0x62,0x2d,0x40,0x06,0xd1,0x2d,0xf4,0x01,0xba,0x44,0x40,0x06,0x8c,0x43
-,0x64,0x00,0xe8,0x2c,0xc8,0x00,0xd8,0x2b,0x05,0x00,0xe9,0x45,0x50,0x00,0x97,0x45
-,0xfa,0x00,0xae,0x2d,0x04,0x01,0x6a,0x42,0x02,0x00,0xf6,0x2c,0xbc,0x02,0x93,0x2d
-,0xdc,0x05,0x1d,0x2d,0x64,0x00,0xa1,0x2d,0x14,0x00,0xd7,0x3a,0x08,0x07,0x81,0x2d
-,0x64,0x00,0xb3,0x3e,0x02,0x00,0x30,0x43,0x64,0x00,0xc5,0x2c,0xf4,0x01,0x8b,0x44
-,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x80,0x3e,0xfd,0x34,0x02,0x74,0x0c,0xe8,0x20,0x05,0xc7,0x06,0xa1,0x36,0x00,0x00
-,0xe9,0x9a,0xf8,0xff,0x06,0xc0,0x33,0xe8,0x10,0x05,0x8b,0x36,0x3d,0x37,0xe8,0x73
-,0xfe,0xc3,0xcd,0x34,0xe9,0xe8,0x05,0xc7,0x06,0xa3,0x36,0x00,0x00,0xc7,0x06,0x41
-,0x37,0x00,0x00,0xe8,0xed,0xfe,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36
-,0x0d,0x00,0x10,0xe7,0x08,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1
-,0xad,0x36,0xe7,0x04,0xe8,0x2b,0x09,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b
-,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x9b,0x36,0xa3,0x9d
-,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x05,0x37
-,0x00,0x00,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xa3,0xf3
-,0x36,0xa3,0xef,0x36,0xa3,0xf1,0x36,0xe8,0xfe,0xf5,0xe5,0x02,0x25,0xf9,0xff,0x0d
-,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02
-,0xb8,0x8f,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff
-,0xa1,0xa9,0x36,0xa3,0xa7,0x36,0x0d,0x00,0xa4,0x0d,0x00,0x08,0xe7,0x00,0xa3,0xa9
-,0x36,0xc7,0x06,0xa3,0x36,0x01,0x00,0xc7,0x06,0xa5,0x36,0x0c,0x00,0x83,0x3e,0xa5
-,0x36,0x00,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9,0x13,0xff,0xff,0x0e,0xa5
-,0x36,0xbe,0x11,0x00,0xe8,0x22,0x05,0xb8,0x90,0x03,0xcd,0x39,0xc3,0x83,0x3e,0xa3
-,0x36,0x01,0x74,0xd9,0xc3,0xb8,0x90,0x03,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b
-,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x01,0x74,0x03,0xe9,0xf0,0x04,0x3c
-,0x0f,0x75,0x1e,0x81,0xfb,0x00,0x02,0x75,0x18,0x26,0xa1,0x20,0x00,0xa3,0x05,0x37
-,0x26,0xa1,0x22,0x00,0xa3,0x07,0x37,0x26,0xa1,0x24,0x00,0xa3,0x09,0x37,0xe9,0x09
-,0x00,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xb6,0xfe,0xc7,0x06,0xa3,0x36,0x02,0x00
-,0xc6,0x06,0x9e,0x36,0xff,0xe8,0xcb,0xfd,0xe8,0x1c,0xd9,0x33,0xc0,0xa3,0x85,0x37
-,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xb8,0x91,0x03,0xcd,0x39,0xb8,0x80
-,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00
-,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x92,0x03,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe
-,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0x8e,0xe5,0x26,0xc7,0x06,0x04,0x00,0x7d,0x4b
-,0x83,0x26,0xef,0x34,0xdf,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20,0xc3,0xf7,0x06,0x9a
-,0x37,0x80,0x00,0x74,0x32,0xa9,0xd0,0x07,0x74,0x0c,0xa9,0x00,0x04,0x74,0x0e,0x33
-,0xc0,0xe7,0x0e,0xe9,0xda,0xff,0xff,0x06,0x85,0x37,0xe9,0xd3,0xff,0xff,0x06,0x83
-,0x37,0xe9,0xcc,0xff,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0x36,0xfe,0x83,0x26,0x9a
-,0x37,0x7f,0xbb,0xff,0x7f,0xcd,0x53,0xe5,0x00,0x0d,0x00,0xac,0xe7,0x00,0xe5,0x02
-,0x25,0xff,0xfb,0x25,0xef,0xff,0x25,0xff,0xf7,0x0d,0x01,0x00,0xe7,0x02,0xa1,0x83
-,0x37,0x3b,0x06,0x46,0x37,0x7f,0xcd,0xa1,0x85,0x37,0x3b,0x06,0x48,0x37,0x7c,0xc4
-,0xc7,0x06,0xa3,0x36,0x03,0x00,0xbe,0x13,0x00,0xe8,0xfd,0x03,0xb8,0x93,0x03,0xcd
-,0x39,0xb8,0x94,0x03,0xcd,0x39,0xb8,0x96,0x03,0xcd,0x39,0xb8,0x95,0x03,0xcd,0x39
-,0xbe,0x06,0x00,0xe8,0xe3,0x03,0xe9,0xd6,0x03,0x83,0x3e,0xa3,0x36,0x03,0x74,0x01
-,0xc3,0xbe,0x13,0x00,0xe8,0xd2,0x03,0xb8,0x94,0x03,0xcd,0x39,0xc3,0xb8,0x94,0x03
-,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3
-,0x36,0x03,0x74,0x03,0xe9,0xa8,0x03,0x3c,0x0d,0x75,0x3e,0x83,0xfb,0x00,0x75,0x39
-,0xe5,0x02,0x0d,0x00,0x20,0xe7,0x02,0xb8,0x93,0x03,0xcd,0x3a,0xc7,0x06,0xa3,0x36
-,0x04,0x00,0xbe,0x00,0x00,0xe8,0x0c,0xfc,0xc6,0x06,0x9d,0x36,0x80,0xc6,0x06,0x9e
-,0x36,0x00,0xc7,0x06,0x33,0x37,0x02,0x00,0xb8,0x9a,0x03,0xcd,0x39,0xe8,0xfc,0x00
-,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe9,0x66,0x03,0xc7,0x06,0x3d,0x37,0x08,0x00,0xe9
-,0x61,0xfd,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9
-,0x51,0xfd,0xe9,0x4a,0x03,0x83,0x3e,0xa3,0x36,0x04,0x74,0x12,0x83,0x3e,0xa3,0x36
-,0x05,0x74,0x0b,0xcd,0x34,0xc7,0x06,0x3d,0x37,0x07,0x00,0xe9,0x35,0xfd,0xc7,0x06
-,0xa3,0x36,0x06,0x00,0xc6,0x06,0x9e,0x36,0xff,0xb8,0x9a,0x03,0xcd,0x3a,0xb8,0x99
-,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03
-,0xcd,0x39,0xb8,0x9b,0x03,0xcd,0x39,0xe9,0x18,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36
-,0x04,0x77,0x18,0x83,0x3e,0xa3,0x36,0x03,0x75,0x08,0xf7,0x06,0x9b,0x36,0x00,0x01
-,0x75,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xe8,0xfc,0xe9,0xe1,0x02,0xcd,0x34
-,0x83,0x3e,0xa3,0x36,0x02,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xd3,0xfc
-,0x83,0x3e,0xa3,0x36,0x04,0x77,0x05,0xb8,0x96,0x03,0xcd,0x39,0xe9,0xc0,0x02,0x83
-,0x3e,0xa3,0x36,0x03,0x75,0x10,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x50,0x3d,0x04
-,0x00,0x75,0x03,0xe8,0x36,0x00,0xa1,0xf3,0x36,0x86,0xe0,0xe7,0x1e,0xa3,0xe3,0x36
-,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37,0x7b,0x7f,0x83,0x0e,0x0d,0x37
-,0x48,0xe8,0x14,0xf3,0x58,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20
-,0x00,0x75,0x06,0xb8,0x01,0x00,0xe9,0x7a,0x02,0xe9,0x86,0xfc,0xa1,0xe5,0x36,0xe7
-,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xa1,0xd3,0x36,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3
-,0x9e,0x34,0xc3,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e,0x00
-,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36,0x26
-,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3,0x1e
-,0x00,0xb8,0x0a,0x80,0xe9,0x2c,0x02,0xe9,0x38,0xfc,0xff,0x06,0x90,0x34,0xbe,0x0a
-,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e,0xc2
-,0x34,0x01,0xcd,0x34,0xe9,0x0c,0xfc,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06
-,0x3d,0x37,0x05,0x00,0xe9,0xfc,0xfb,0xe5,0x02,0x0d,0x03,0x00,0x0d,0x00,0x88,0x0d
-,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x05,0x00,0xc6,0x06,0x9e
-,0x36,0xff,0xbe,0x02,0x00,0xe8,0xe1,0x01,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x9a,0x03
-,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x39,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03,0xcd
-,0x39,0xe9,0xbb,0x01,0x83,0x3e,0xa3,0x36,0x03,0x74,0x0a,0x83,0x3e,0xa3,0x36,0x04
-,0x74,0x03,0xe9,0xaa,0x01,0xbe,0x06,0x00,0xe8,0xae,0x01,0xb8,0x95,0x03,0xcd,0x39
-,0xe9,0x9c,0x01,0x83,0x3e,0xa3,0x36,0x05,0x74,0x03,0xe9,0x92,0x01,0xbe,0x02,0x00
-,0xe8,0x96,0x01,0xb8,0x99,0x03,0xcd,0x39,0xe9,0x84,0x01,0xc7,0x06,0x0f,0x37,0x05
-,0x00,0xe9,0x7b,0x01,0xe5,0x02,0x25,0xff,0xdf,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x07
-,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xe9,0x65,0x01,0xe8,0xd5,0x04,0xc6,0x06,0x9d
-,0x36,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc7,0x06
-,0xa8,0x02,0x00,0x00,0xc7,0x06,0x4c,0x37,0x01,0x00,0xe5,0x02,0x25,0xf9,0xff,0x0d
-,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02
-,0xe9,0x67,0xfc,0xb8,0x9a,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09
-,0xc7,0x06,0x33,0x37,0x02,0x00,0xe9,0x16,0x01,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9
-,0x0d,0x01,0xff,0x06,0x8e,0x34,0x83,0x0e,0xc2,0x34,0x08,0xc7,0x06,0x3d,0x37,0x03
-,0x00,0xe9,0xff,0xfa,0xc3,0x52,0x50,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0x58,0x5a
-,0xc3,0xc7,0x06,0x3d,0x37,0x00,0x00,0xe9,0xe9,0xfa,0xfa,0xe8,0x54,0x04,0xb8,0x80
-,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xd8,0x2b,0xb8,0x7f,0x03,0x8e,0xc0,0x26
-,0xc7,0x06,0x04,0x00,0xe8,0x2c,0x33,0xc0,0x8e,0xc0,0xa1,0xa7,0x36,0xa3,0xa9,0x36
-,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0xab,0x36,0xe7,0x02,0xc7,0x06,0x05,0x37,0x00,0x00
-,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xc6,0x06,0x9d,0x36
-,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0xa3,0x36
-,0x00,0x00,0xc7,0x06,0x0f,0x37,0x00,0x00,0xc7,0x06,0xa8,0x02,0x00,0x00,0xc7,0x06
-,0x4c,0x37,0x01,0x00,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0xbb
-,0xff,0x7f,0xcd,0x53,0xe8,0x7c,0xf9,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xfb,0xc3
-,0x8d,0x3e,0xc0,0x53,0x8d,0x36,0xf0,0x38,0xb9,0x0e,0x00,0x8b,0x1e,0x30,0x34,0x89
-,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05,0x89,0x44,0x04,0x83
-,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xb8,0x80,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04
-,0x00,0xe2,0x51,0xb8,0x7f,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xb2,0x52,0x33
-,0xc0,0x8e,0xc0,0xc7,0x06,0xa1,0x36,0x01,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc3
-,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e,0xff,0xa4,0xa0,0x53,0xe8
-,0x8c,0xdb,0xc3,0xe8,0x48,0xf7,0xe9,0xf6,0xff,0x8e,0x06,0x38,0x34,0xe8,0x07,0xe1
-,0x26,0xc7,0x06,0x04,0x00,0xdf,0x4f,0xcd,0x50,0xc3,0x26,0xc7,0x06,0x0a,0x00,0x00
-,0x00,0x26,0xff,0x26,0x04,0x00,0xcd,0x34,0xe9,0xd4,0xff,0xa1,0xd1,0x36,0x26,0x39
-,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39,0x06,0x1c,0x00,0x75,0x18,0xa1
-,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00
-,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36
-,0xe7,0x06,0x83,0x3e,0xa3,0x36,0x02,0x75,0x05,0xcd,0x34,0xe9,0x56,0xfb,0x83,0x3e
-,0xa3,0x36,0x00,0x74,0xb1,0x83,0x3e,0xa3,0x36,0x05,0x77,0xaa,0x26,0xf6,0x06,0x0a
-,0x00,0xff,0x75,0xa2,0xe8,0xfd,0xdd,0x50,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9
-,0x8c,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x76
-,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9,0x6e,0x00,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75
-,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00,0x80,0x74,0x35,0x26,0x80,0x3e,0x29
-,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9
-,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x75,0x45,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34
-,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26
-,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b,0x26,0x80,0x3e,0x19,0x00,0x00,0x74
-,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10,0x00,0x74,0x12,0x26,0xa0,0x28,0x00
-,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0x58,0x23
-,0xc0,0x74,0x03,0xe9,0xdd,0xfe,0x81,0x26,0x9b,0x36,0xff,0xfe,0x26,0xa1,0x20,0x00
-,0x3b,0x06,0xd1,0x36,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10
-,0x26,0xa1,0x24,0x00,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01
-,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba
-,0x34,0x26,0xa1,0x24,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1
-,0xe6,0x80,0xfc,0x09,0x74,0x03,0xe8,0xf6,0xf5,0xa1,0x05,0x37,0x0b,0x06,0x07,0x37
-,0x0b,0x06,0x09,0x37,0x74,0x3e,0x26,0xa1,0x20,0x00,0x3b,0x06,0x05,0x37,0x75,0x17
-,0x26,0xa1,0x22,0x00,0x3b,0x06,0x07,0x37,0x75,0x0d,0x26,0xa1,0x24,0x00,0x3b,0x06
-,0x09,0x37,0x75,0x03,0xe9,0x1d,0x00,0x26,0xa0,0x28,0x00,0x24,0x0f,0x3c,0x03,0x74
-,0x1b,0x3c,0x00,0x75,0x0f,0x83,0x3e,0xa3,0x36,0x04,0x74,0x10,0xf7,0x06,0x9b,0x36
-,0x00,0x01,0x74,0x08,0x2e,0xff,0x94,0xf8,0x53,0xe9,0x33,0xfe,0xcd,0x34,0xc7,0x06
-,0x3d,0x37,0x01,0x00,0xe9,0x2c,0xf8,0x83,0x3e,0xa3,0x36,0x05,0x74,0x10,0x83,0x3e
-,0xa3,0x36,0x01,0x7e,0x09,0x83,0xee,0x16,0x2e,0xff,0x94,0x24,0x54,0xc3,0xcd,0x34
-,0xc3,0x26,0xa1,0x0c,0x00,0x3d,0xff,0x7f,0x74,0x05,0x26,0xff,0x26,0x04,0x00,0xe9
-,0xfd,0xfd,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b,0xa9,0x00,0x10,0x75,0x09,0x8b
-,0x1e,0x43,0x37,0xff,0xe3,0xe9,0x97,0x00,0xc7,0x06,0x35,0x37,0x05,0x00,0xc7,0x06
-,0x43,0x37,0x28,0x52,0xf7,0x06,0xf4,0x33,0x00,0x08,0x74,0x06,0xc7,0x06,0x43,0x37
-,0x1a,0x52,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xc5,0xfd,0xa9,0x00,0x08,0x74,0xd9,0xff
-,0x0e,0x35,0x37,0x75,0xed,0xe9,0x30,0x00,0xa9,0x00,0x08,0x75,0xcb,0xff,0x0e,0x35
-,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x0f
-,0x81,0x0e,0x9b,0x36,0x00,0x80,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x90,0xfd,0xc7
-,0x06,0x3d,0x37,0x02,0x00,0xe9,0x8b,0xf7,0x80,0x26,0x9e,0x36,0xff,0x75,0x30,0xf6
-,0x06,0x9d,0x36,0x80,0x74,0x20,0xff,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e
-,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08
-,0x00,0x00,0x01,0xe9,0x09,0x00,0xc7,0x06,0x3d,0x37,0x04,0x00,0xe9,0x54,0xf7,0x81
-,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06,0xe5,0x0a,0xa9,0x00,0x80,0x74
-,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x49,0xff,0xe9
-,0x2d,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0xbe,0x29,0x00,0xe8,0x2b,0xfd,0xe9,0x1e
-,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x04,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00
-,0xe9,0x10,0xf7,0xe9,0x09,0xfd,0xcd,0x34,0xc3,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8
-,0x0c,0xf5,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b
-,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02
-,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x20,0xf3
-,0xe8,0x43,0xf3,0x83,0x0e,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xd2
-,0xf5,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0xbe,0x00
-,0x00,0xe8,0x30,0xf5,0xc6,0x06,0xa0,0x36,0x0e,0xb8,0x9c,0x03,0xcd,0x39,0xb8,0x80
-,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xc7,0x06,0xa1,0x36,0x01,0x00,0xe9
-,0xa5,0xf6,0x06,0xb8,0x8f,0x03,0xcd,0x3a,0xb8,0x90,0x03,0xcd,0x3a,0xb8,0x91,0x03
-,0xcd,0x3a,0xb8,0x92,0x03,0xcd,0x3a,0xb8,0x93,0x03,0xcd,0x3a,0xb8,0x94,0x03,0xcd
-,0x3a,0xb8,0x95,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x3a
-,0xb8,0x98,0x03,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x3a,0xb8,0x9a,0x03,0xcd,0x3a,0xb8
-,0x9b,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0x07,0xc3
-,0xf7,0x49,0xf1,0x4e,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xf8,0x51,0xdf,0x4f
-,0xfa,0x4f,0x0b,0x50,0xd1,0x51,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f
-,0xe4,0x4e,0x06,0x00,0xcd,0x4a,0x04,0x00,0xe4,0x4e,0x19,0x00,0xad,0x4b,0xfa,0x00
-,0x82,0x4c,0x08,0x07,0x09,0x4c,0x14,0x00,0x24,0x4e,0x64,0x00,0xd7,0x4d,0xf4,0x01
-,0x64,0x4e,0xbc,0x02,0x7a,0x4e,0xe8,0x03,0x43,0x4e,0x02,0x00,0xb3,0x4e,0xf4,0x01
-,0x5b,0x4e,0xf4,0x01,0xe5,0x4e,0x14,0x00,0x06,0x50,0x06,0x50,0x95,0x4c,0xc1,0x52
-,0xc1,0x52,0xfe,0x4c,0xda,0x4c,0x06,0x50,0x06,0x50,0x06,0x50,0x06,0x50,0xb7,0x51
-,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0x06,0x50,0xd5,0x4a,0x06,0x50
-,0x1d,0x4c,0x06,0x50,0x83,0x4d,0x1f,0x4d,0x1f,0x4d,0xed,0x40,0xfa,0x40,0x07,0x41
-,0x37,0x37,0x2e,0x37,0x37,0x20,0x20,0x79,0x79,0x2f,0x79,0x79,0x2f,0x79,0x79,0x20
-,0x30,0x31,0x2e,0x39,0x30,0x20,0x20,0x30,0x32,0x2f,0x31,0x37,0x2f,0x39,0x39,0x20
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-,0x90,0xea,0xc0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x06
-} ;  
index 86a479f61c0c09dbceb64688f1bd2b131105031d..d3f39e86eb95a14cb8cad1b1120377fa5a3b80dc 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
-#include <linux/fsl_devices.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
 #include <linux/workqueue.h>
@@ -223,10 +222,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
                    (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT -
                                              1)));
 
-       skb->dev = ugeth->dev;
+       skb->dev = ugeth->ndev;
 
        out_be32(&((struct qe_bd __iomem *)bd)->buf,
-                     dma_map_single(&ugeth->dev->dev,
+                     dma_map_single(ugeth->dev,
                                     skb->data,
                                     ugeth->ug_info->uf_info.max_rx_buf_length +
                                     UCC_GETH_RX_DATA_BUF_ALIGNMENT,
@@ -1872,7 +1871,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
                        continue;
                for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
                        if (ugeth->tx_skbuff[i][j]) {
-                               dma_unmap_single(&ugeth->dev->dev,
+                               dma_unmap_single(ugeth->dev,
                                                 in_be32(&((struct qe_bd __iomem *)bd)->buf),
                                                 (in_be32((u32 __iomem *)bd) &
                                                  BD_LENGTH_MASK),
@@ -1900,7 +1899,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
                        bd = ugeth->p_rx_bd_ring[i];
                        for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
                                if (ugeth->rx_skbuff[i][j]) {
-                                       dma_unmap_single(&ugeth->dev->dev,
+                                       dma_unmap_single(ugeth->dev,
                                                in_be32(&((struct qe_bd __iomem *)bd)->buf),
                                                ugeth->ug_info->
                                                uf_info.max_rx_buf_length +
@@ -3071,7 +3070,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* set up the buffer descriptor */
        out_be32(&((struct qe_bd __iomem *)bd)->buf,
-                     dma_map_single(&ugeth->dev->dev, skb->data,
+                     dma_map_single(ugeth->dev, skb->data,
                              skb->len, DMA_TO_DEVICE));
 
        /* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */
@@ -3127,7 +3126,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
 
        ugeth_vdbg("%s: IN", __func__);
 
-       dev = ugeth->dev;
+       dev = ugeth->ndev;
 
        /* collect received buffers */
        bd = ugeth->rxBd[rxQ];
@@ -3161,7 +3160,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
                        skb_put(skb, length);
 
                        /* Tell the skb what kind of packet this is */
-                       skb->protocol = eth_type_trans(skb, ugeth->dev);
+                       skb->protocol = eth_type_trans(skb, ugeth->ndev);
 
                        dev->stats.rx_bytes += length;
                        /* Send the packet up the stack */
@@ -3432,7 +3431,7 @@ static int ucc_geth_close(struct net_device *dev)
 
        ucc_geth_stop(ugeth);
 
-       free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
+       free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev);
 
        netif_stop_queue(dev);
 
@@ -3446,7 +3445,7 @@ static void ucc_geth_timeout_work(struct work_struct *work)
        struct net_device *dev;
 
        ugeth = container_of(work, struct ucc_geth_private, timeout_work);
-       dev = ugeth->dev;
+       dev = ugeth->ndev;
 
        ugeth_vdbg("%s: IN", __func__);
 
@@ -3648,15 +3647,16 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                mdio = of_get_parent(phy);
 
                if (mdio == NULL)
-                       return -1;
+                       return -ENODEV;
 
                err = of_address_to_resource(mdio, 0, &res);
-               of_node_put(mdio);
-
-               if (err)
-                       return -1;
 
+               if (err) {
+                       of_node_put(mdio);
+                       return err;
+               }
                fsl_pq_mdio_bus_name(bus_name, mdio);
+               of_node_put(mdio);
                snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
                        "%s:%02x", bus_name, *prop);
        }
@@ -3755,7 +3755,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                memcpy(dev->dev_addr, mac_addr, 6);
 
        ugeth->ug_info = ug_info;
-       ugeth->dev = dev;
+       ugeth->dev = device;
+       ugeth->ndev = dev;
        ugeth->node = np;
 
        return 0;
index e3a25e64a6525f38a2329125b09e01bb116e8ae2..2f8ee7c87efe944e6e788e861ee407ce97018a59 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/fsl_devices.h>
 
 #include <asm/immap_qe.h>
 #include <asm/qe.h>
@@ -1129,7 +1128,8 @@ struct ucc_geth_info {
 struct ucc_geth_private {
        struct ucc_geth_info *ug_info;
        struct ucc_fast_private *uccf;
-       struct net_device *dev;
+       struct device *dev;
+       struct net_device *ndev;
        struct napi_struct napi;
        struct work_struct timeout_work;
        struct ucc_geth __iomem *ug_regs;
index a755bea559b98deb9d091c95eba19db84642a732..6fcb500257bc37c6b330b86c6cca19a747ad440b 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/fsl_devices.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
index cde423c6d040d1174bc88571802f52ad94d50e85..f84b78d94c400f0533a34a1a568b9e6507f0a1f0 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (C) 2008 Option International
  *                     Filip Aben <f.aben@option.com>
  *                     Denis Joseph Barrow <d.barow@option.com>
+ *                     Jan Dumon <j.dumon@option.com>
  *  Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd)
  *                     <ajb@spheresystems.co.uk>
  *  Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
@@ -462,9 +463,16 @@ static const struct usb_device_id hso_ids[] = {
        {USB_DEVICE(0x0af0, 0x7701)},
        {USB_DEVICE(0x0af0, 0x7801)},
        {USB_DEVICE(0x0af0, 0x7901)},
-       {USB_DEVICE(0x0af0, 0x7361)},
-       {USB_DEVICE(0x0af0, 0xd057)},
+       {USB_DEVICE(0x0af0, 0x8200)},
+       {USB_DEVICE(0x0af0, 0x8201)},
+       {USB_DEVICE(0x0af0, 0xd035)},
        {USB_DEVICE(0x0af0, 0xd055)},
+       {USB_DEVICE(0x0af0, 0xd155)},
+       {USB_DEVICE(0x0af0, 0xd255)},
+       {USB_DEVICE(0x0af0, 0xd057)},
+       {USB_DEVICE(0x0af0, 0xd157)},
+       {USB_DEVICE(0x0af0, 0xd257)},
+       {USB_DEVICE(0x0af0, 0xd357)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, hso_ids);
@@ -2410,20 +2418,22 @@ static void hso_free_net_device(struct hso_device *hso_dev)
        if (!hso_net)
                return;
 
+       remove_net_device(hso_net->parent);
+
+       if (hso_net->net) {
+               unregister_netdev(hso_net->net);
+               free_netdev(hso_net->net);
+       }
+
        /* start freeing */
        for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
                usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]);
                kfree(hso_net->mux_bulk_rx_buf_pool[i]);
+               hso_net->mux_bulk_rx_buf_pool[i] = NULL;
        }
        usb_free_urb(hso_net->mux_bulk_tx_urb);
        kfree(hso_net->mux_bulk_tx_buf);
-
-       remove_net_device(hso_net->parent);
-
-       if (hso_net->net) {
-               unregister_netdev(hso_net->net);
-               free_netdev(hso_net->net);
-       }
+       hso_net->mux_bulk_tx_buf = NULL;
 
        kfree(hso_dev);
 }
@@ -2526,14 +2536,15 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
 }
 
 /* Creates our network device */
-static struct hso_device *hso_create_net_device(struct usb_interface *interface)
+static struct hso_device *hso_create_net_device(struct usb_interface *interface,
+                                               int port_spec)
 {
        int result, i;
        struct net_device *net;
        struct hso_net *hso_net;
        struct hso_device *hso_dev;
 
-       hso_dev = hso_create_device(interface, HSO_INTF_MUX | HSO_PORT_NETWORK);
+       hso_dev = hso_create_device(interface, port_spec);
        if (!hso_dev)
                return NULL;
 
@@ -2613,12 +2624,12 @@ static void hso_free_tiomget(struct hso_serial *serial)
 {
        struct hso_tiocmget *tiocmget = serial->tiocmget;
        if (tiocmget) {
-               kfree(tiocmget);
                if (tiocmget->urb) {
                        usb_free_urb(tiocmget->urb);
                        tiocmget->urb = NULL;
                }
                serial->tiocmget = NULL;
+               kfree(tiocmget);
 
        }
 }
@@ -2933,7 +2944,8 @@ static int hso_probe(struct usb_interface *interface,
                if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
                        /* Create the network device */
                        if (!disable_net) {
-                               hso_dev = hso_create_net_device(interface);
+                               hso_dev = hso_create_net_device(interface,
+                                                               port_spec);
                                if (!hso_dev)
                                        goto exit;
                                tmp_dev = hso_dev;
@@ -2965,7 +2977,7 @@ static int hso_probe(struct usb_interface *interface,
                /* It's a regular bulk interface */
                if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK)
                    && !disable_net)
-                       hso_dev = hso_create_net_device(interface);
+                       hso_dev = hso_create_net_device(interface, port_spec);
                else
                        hso_dev =
                            hso_create_bulk_serial_device(interface, port_spec);
index 7cb10a0a53164dc45650a7225ae95c38e4517557..3d0d0b0b37c53d71be8396e3a2a2965bcaf01edd 100644 (file)
@@ -36,7 +36,6 @@
  * Run test procedures
  * Fix bugs from previous two steps
  * Snoop other OSs for any tricks we're not doing
- * SMP locking
  * Reduce arbitrary timeouts
  * Smart multicast support
  * Temporary MAC change support
@@ -796,7 +795,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
 
        int res;
 
-       spin_lock(&kaweth->device_lock);
+       spin_lock_irq(&kaweth->device_lock);
 
        kaweth_async_set_rx_mode(kaweth);
        netif_stop_queue(net);
@@ -814,7 +813,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
                if (!copied_skb) {
                        kaweth->stats.tx_errors++;
                        netif_start_queue(net);
-                       spin_unlock(&kaweth->device_lock);
+                       spin_unlock_irq(&kaweth->device_lock);
                        return 0;
                }
        }
@@ -848,7 +847,7 @@ skip:
                net->trans_start = jiffies;
        }
 
-       spin_unlock(&kaweth->device_lock);
+       spin_unlock_irq(&kaweth->device_lock);
 
        return 0;
 }
diff --git a/drivers/net/vxge/Makefile b/drivers/net/vxge/Makefile
new file mode 100644 (file)
index 0000000..8992ca2
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for Neterion Inc's X3100 Series 10 GbE PCIe # I/O
+# Virtualized Server Adapter linux driver
+
+obj-$(CONFIG_VXGE) += vxge.o
+
+vxge-objs := vxge-config.o vxge-traffic.o vxge-ethtool.o vxge-main.o
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
new file mode 100644 (file)
index 0000000..6b41c88
--- /dev/null
@@ -0,0 +1,5264 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-config.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#include <linux/vmalloc.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
+
+#include "vxge-traffic.h"
+#include "vxge-config.h"
+
+/*
+ * __vxge_hw_channel_allocate - Allocate memory for channel
+ * This function allocates required memory for the channel and various arrays
+ * in the channel
+ */
+struct __vxge_hw_channel*
+__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
+                          enum __vxge_hw_channel_type type,
+       u32 length, u32 per_dtr_space, void *userdata)
+{
+       struct __vxge_hw_channel *channel;
+       struct __vxge_hw_device *hldev;
+       int size = 0;
+       u32 vp_id;
+
+       hldev = vph->vpath->hldev;
+       vp_id = vph->vpath->vp_id;
+
+       switch (type) {
+       case VXGE_HW_CHANNEL_TYPE_FIFO:
+               size = sizeof(struct __vxge_hw_fifo);
+               break;
+       case VXGE_HW_CHANNEL_TYPE_RING:
+               size = sizeof(struct __vxge_hw_ring);
+               break;
+       default:
+               break;
+       }
+
+       channel = kzalloc(size, GFP_KERNEL);
+       if (channel == NULL)
+               goto exit0;
+       INIT_LIST_HEAD(&channel->item);
+
+       channel->common_reg = hldev->common_reg;
+       channel->first_vp_id = hldev->first_vp_id;
+       channel->type = type;
+       channel->devh = hldev;
+       channel->vph = vph;
+       channel->userdata = userdata;
+       channel->per_dtr_space = per_dtr_space;
+       channel->length = length;
+       channel->vp_id = vp_id;
+
+       channel->work_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+       if (channel->work_arr == NULL)
+               goto exit1;
+
+       channel->free_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+       if (channel->free_arr == NULL)
+               goto exit1;
+       channel->free_ptr = length;
+
+       channel->reserve_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+       if (channel->reserve_arr == NULL)
+               goto exit1;
+       channel->reserve_ptr = length;
+       channel->reserve_top = 0;
+
+       channel->orig_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+       if (channel->orig_arr == NULL)
+               goto exit1;
+
+       return channel;
+exit1:
+       __vxge_hw_channel_free(channel);
+
+exit0:
+       return NULL;
+}
+
+/*
+ * __vxge_hw_channel_free - Free memory allocated for channel
+ * This function deallocates memory from the channel and various arrays
+ * in the channel
+ */
+void __vxge_hw_channel_free(struct __vxge_hw_channel *channel)
+{
+       kfree(channel->work_arr);
+       kfree(channel->free_arr);
+       kfree(channel->reserve_arr);
+       kfree(channel->orig_arr);
+       kfree(channel);
+}
+
+/*
+ * __vxge_hw_channel_initialize - Initialize a channel
+ * This function initializes a channel by properly setting the
+ * various references
+ */
+enum vxge_hw_status
+__vxge_hw_channel_initialize(struct __vxge_hw_channel *channel)
+{
+       u32 i;
+       struct __vxge_hw_virtualpath *vpath;
+
+       vpath = channel->vph->vpath;
+
+       if ((channel->reserve_arr != NULL) && (channel->orig_arr != NULL)) {
+               for (i = 0; i < channel->length; i++)
+                       channel->orig_arr[i] = channel->reserve_arr[i];
+       }
+
+       switch (channel->type) {
+       case VXGE_HW_CHANNEL_TYPE_FIFO:
+               vpath->fifoh = (struct __vxge_hw_fifo *)channel;
+               channel->stats = &((struct __vxge_hw_fifo *)
+                               channel)->stats->common_stats;
+               break;
+       case VXGE_HW_CHANNEL_TYPE_RING:
+               vpath->ringh = (struct __vxge_hw_ring *)channel;
+               channel->stats = &((struct __vxge_hw_ring *)
+                               channel)->stats->common_stats;
+               break;
+       default:
+               break;
+       }
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_channel_reset - Resets a channel
+ * This function resets a channel by properly setting the various references
+ */
+enum vxge_hw_status
+__vxge_hw_channel_reset(struct __vxge_hw_channel *channel)
+{
+       u32 i;
+
+       for (i = 0; i < channel->length; i++) {
+               if (channel->reserve_arr != NULL)
+                       channel->reserve_arr[i] = channel->orig_arr[i];
+               if (channel->free_arr != NULL)
+                       channel->free_arr[i] = NULL;
+               if (channel->work_arr != NULL)
+                       channel->work_arr[i] = NULL;
+       }
+       channel->free_ptr = channel->length;
+       channel->reserve_ptr = channel->length;
+       channel->reserve_top = 0;
+       channel->post_index = 0;
+       channel->compl_index = 0;
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_pci_e_init
+ * Initialize certain PCI/PCI-X configuration registers
+ * with recommended values. Save config space for future hw resets.
+ */
+void
+__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
+{
+       u16 cmd = 0;
+
+       /* Set the PErr Repconse bit and SERR in PCI command register. */
+       pci_read_config_word(hldev->pdev, PCI_COMMAND, &cmd);
+       cmd |= 0x140;
+       pci_write_config_word(hldev->pdev, PCI_COMMAND, cmd);
+
+       pci_save_state(hldev->pdev);
+
+       return;
+}
+
+/*
+ * __vxge_hw_device_register_poll
+ * Will poll certain register for specified amount of time.
+ * Will poll until masked bit is not cleared.
+ */
+enum vxge_hw_status
+__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis)
+{
+       u64 val64;
+       u32 i = 0;
+       enum vxge_hw_status ret = VXGE_HW_FAIL;
+
+       udelay(10);
+
+       do {
+               val64 = readq(reg);
+               if (!(val64 & mask))
+                       return VXGE_HW_OK;
+               udelay(100);
+       } while (++i <= 9);
+
+       i = 0;
+       do {
+               val64 = readq(reg);
+               if (!(val64 & mask))
+                       return VXGE_HW_OK;
+               mdelay(1);
+       } while (++i <= max_millis);
+
+       return ret;
+}
+
+ /* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset
+ * in progress
+ * This routine checks the vpath reset in progress register is turned zero
+ */
+enum vxge_hw_status
+__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog)
+{
+       enum vxge_hw_status status;
+       status = __vxge_hw_device_register_poll(vpath_rst_in_prog,
+                       VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(0x1ffff),
+                       VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+       return status;
+}
+
+/*
+ * __vxge_hw_device_toc_get
+ * This routine sets the swapper and reads the toc pointer and returns the
+ * memory mapped address of the toc
+ */
+struct vxge_hw_toc_reg __iomem *
+__vxge_hw_device_toc_get(void __iomem *bar0)
+{
+       u64 val64;
+       struct vxge_hw_toc_reg __iomem *toc = NULL;
+       enum vxge_hw_status status;
+
+       struct vxge_hw_legacy_reg __iomem *legacy_reg =
+               (struct vxge_hw_legacy_reg __iomem *)bar0;
+
+       status = __vxge_hw_legacy_swapper_set(legacy_reg);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&legacy_reg->toc_first_pointer);
+       toc = (struct vxge_hw_toc_reg __iomem *)(bar0+val64);
+exit:
+       return toc;
+}
+
+/*
+ * __vxge_hw_device_reg_addr_get
+ * This routine sets the swapper and reads the toc pointer and initializes the
+ * register location pointers in the device object. It waits until the ric is
+ * completed initializing registers.
+ */
+enum vxge_hw_status
+__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
+{
+       u64 val64;
+       u32 i;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       hldev->legacy_reg = (struct vxge_hw_legacy_reg __iomem *)hldev->bar0;
+
+       hldev->toc_reg = __vxge_hw_device_toc_get(hldev->bar0);
+       if (hldev->toc_reg  == NULL) {
+               status = VXGE_HW_FAIL;
+               goto exit;
+       }
+
+       val64 = readq(&hldev->toc_reg->toc_common_pointer);
+       hldev->common_reg =
+       (struct vxge_hw_common_reg __iomem *)(hldev->bar0 + val64);
+
+       val64 = readq(&hldev->toc_reg->toc_mrpcim_pointer);
+       hldev->mrpcim_reg =
+               (struct vxge_hw_mrpcim_reg __iomem *)(hldev->bar0 + val64);
+
+       for (i = 0; i < VXGE_HW_TITAN_SRPCIM_REG_SPACES; i++) {
+               val64 = readq(&hldev->toc_reg->toc_srpcim_pointer[i]);
+               hldev->srpcim_reg[i] =
+                       (struct vxge_hw_srpcim_reg __iomem *)
+                               (hldev->bar0 + val64);
+       }
+
+       for (i = 0; i < VXGE_HW_TITAN_VPMGMT_REG_SPACES; i++) {
+               val64 = readq(&hldev->toc_reg->toc_vpmgmt_pointer[i]);
+               hldev->vpmgmt_reg[i] =
+               (struct vxge_hw_vpmgmt_reg __iomem *)(hldev->bar0 + val64);
+       }
+
+       for (i = 0; i < VXGE_HW_TITAN_VPATH_REG_SPACES; i++) {
+               val64 = readq(&hldev->toc_reg->toc_vpath_pointer[i]);
+               hldev->vpath_reg[i] =
+                       (struct vxge_hw_vpath_reg __iomem *)
+                               (hldev->bar0 + val64);
+       }
+
+       val64 = readq(&hldev->toc_reg->toc_kdfc);
+
+       switch (VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val64)) {
+       case 0:
+               hldev->kdfc = (u8 __iomem *)(hldev->bar0 +
+                       VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
+               break;
+       case 2:
+               hldev->kdfc = (u8 __iomem *)(hldev->bar1 +
+                       VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
+               break;
+       case 4:
+               hldev->kdfc = (u8 __iomem *)(hldev->bar2 +
+                       VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
+               break;
+       default:
+               break;
+       }
+
+       status = __vxge_hw_device_vpath_reset_in_prog_check(
+                       (u64 __iomem *)&hldev->common_reg->vpath_rst_in_prog);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_device_id_get
+ * This routine returns sets the device id and revision numbers into the device
+ * structure
+ */
+void __vxge_hw_device_id_get(struct __vxge_hw_device *hldev)
+{
+       u64 val64;
+
+       val64 = readq(&hldev->common_reg->titan_asic_id);
+       hldev->device_id =
+               (u16)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(val64);
+
+       hldev->major_revision =
+               (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(val64);
+
+       hldev->minor_revision =
+               (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(val64);
+
+       return;
+}
+
+/*
+ * __vxge_hw_device_access_rights_get: Get Access Rights of the driver
+ * This routine returns the Access Rights of the driver
+ */
+static u32
+__vxge_hw_device_access_rights_get(u32 host_type, u32 func_id)
+{
+       u32 access_rights = VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH;
+
+       switch (host_type) {
+       case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION:
+               if (func_id == 0) {
+                       access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+                                       VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+               }
+               break;
+       case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION:
+               access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+                               VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+               break;
+       case VXGE_HW_NO_MR_SR_VH0_FUNCTION0:
+               access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+                               VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+               break;
+       case VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION:
+       case VXGE_HW_SR_VH_VIRTUAL_FUNCTION:
+       case VXGE_HW_MR_SR_VH0_INVALID_CONFIG:
+               break;
+       case VXGE_HW_SR_VH_FUNCTION0:
+       case VXGE_HW_VH_NORMAL_FUNCTION:
+               access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+               break;
+       }
+
+       return access_rights;
+}
+/*
+ * __vxge_hw_device_host_info_get
+ * This routine returns the host type assignments
+ */
+void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
+{
+       u64 val64;
+       u32 i;
+
+       val64 = readq(&hldev->common_reg->host_type_assignments);
+
+       hldev->host_type =
+          (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
+
+       hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments);
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!(hldev->vpath_assignments & vxge_mBIT(i)))
+                       continue;
+
+               hldev->func_id =
+                       __vxge_hw_vpath_func_id_get(i, hldev->vpmgmt_reg[i]);
+
+               hldev->access_rights = __vxge_hw_device_access_rights_get(
+                       hldev->host_type, hldev->func_id);
+
+               hldev->first_vp_id = i;
+               break;
+       }
+
+       return;
+}
+
+/*
+ * __vxge_hw_verify_pci_e_info - Validate the pci-e link parameters such as
+ * link width and signalling rate.
+ */
+static enum vxge_hw_status
+__vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev)
+{
+       int exp_cap;
+       u16 lnk;
+
+       /* Get the negotiated link width and speed from PCI config space */
+       exp_cap = pci_find_capability(hldev->pdev, PCI_CAP_ID_EXP);
+       pci_read_config_word(hldev->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk);
+
+       if ((lnk & PCI_EXP_LNKSTA_CLS) != 1)
+               return VXGE_HW_ERR_INVALID_PCI_INFO;
+
+       switch ((lnk & PCI_EXP_LNKSTA_NLW) >> 4) {
+       case PCIE_LNK_WIDTH_RESRV:
+       case PCIE_LNK_X1:
+       case PCIE_LNK_X2:
+       case PCIE_LNK_X4:
+       case PCIE_LNK_X8:
+               break;
+       default:
+               return VXGE_HW_ERR_INVALID_PCI_INFO;
+       }
+
+       return VXGE_HW_OK;
+}
+
+static enum vxge_hw_status
+__vxge_hw_device_is_privilaged(struct __vxge_hw_device *hldev)
+{
+       if ((hldev->host_type == VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ||
+       hldev->host_type == VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION ||
+       hldev->host_type == VXGE_HW_NO_MR_SR_VH0_FUNCTION0) &&
+       (hldev->func_id == 0))
+               return VXGE_HW_OK;
+       else
+               return VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+}
+
+/*
+ * vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars.
+ * Rebalance the RX_WRR and KDFC_WRR calandars.
+ */
+static enum
+vxge_hw_status vxge_hw_wrr_rebalance(struct __vxge_hw_device *hldev)
+{
+       u64 val64;
+       u32 wrr_states[VXGE_HW_WEIGHTED_RR_SERVICE_STATES];
+       u32 i, j, how_often = 1;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       status = __vxge_hw_device_is_privilaged(hldev);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       /* Reset the priorities assigned to the WRR arbitration
+       phases for the receive traffic */
+       for (i = 0; i < VXGE_HW_WRR_RING_COUNT; i++)
+               writeq(0, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i));
+
+       /* Reset the transmit FIFO servicing calendar for FIFOs */
+       for (i = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) {
+               writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_0) + i));
+               writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_20) + i));
+       }
+
+       /* Assign WRR priority  0 for all FIFOs */
+       for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(0),
+                               ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl)  + i));
+
+               writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(0),
+                       ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i));
+       }
+
+       /* Reset to service non-offload doorbells */
+       writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_0);
+       writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_1);
+
+       /* Set priority 0 to all receive queues */
+       writeq(0, &hldev->mrpcim_reg->rx_queue_priority_0);
+       writeq(0, &hldev->mrpcim_reg->rx_queue_priority_1);
+       writeq(0, &hldev->mrpcim_reg->rx_queue_priority_2);
+
+       /* Initialize all the slots as unused */
+       for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++)
+               wrr_states[i] = -1;
+
+       /* Prepare the Fifo service states */
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!hldev->config.vp_config[i].min_bandwidth)
+                       continue;
+
+               how_often = VXGE_HW_VPATH_BANDWIDTH_MAX /
+                               hldev->config.vp_config[i].min_bandwidth;
+               if (how_often) {
+
+                       for (j = 0; j < VXGE_HW_WRR_FIFO_SERVICE_STATES;) {
+                               if (wrr_states[j] == -1) {
+                                       wrr_states[j] = i;
+                                       /* Make sure each fifo is serviced
+                                        * atleast once */
+                                       if (i == j)
+                                               j += VXGE_HW_MAX_VIRTUAL_PATHS;
+                                       else
+                                               j += how_often;
+                               } else
+                                       j++;
+                       }
+               }
+       }
+
+       /* Fill the unused slots with 0 */
+       for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) {
+               if (wrr_states[j] == -1)
+                       wrr_states[j] = 0;
+       }
+
+       /* Assign WRR priority number for FIFOs */
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(i),
+                               ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i));
+
+               writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(i),
+                       ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i));
+       }
+
+       /* Modify the servicing algorithm applied to the 3 types of doorbells.
+       i.e, none-offload, message and offload */
+       writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(0) |
+                               VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(0) |
+                               VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(0) |
+                               VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(0) |
+                               VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(1) |
+                               VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(0) |
+                               VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(0) |
+                               VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(0),
+                               &hldev->mrpcim_reg->kdfc_entry_type_sel_0);
+
+       writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(1),
+                               &hldev->mrpcim_reg->kdfc_entry_type_sel_1);
+
+       for (i = 0, j = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) {
+
+               val64 = VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(wrr_states[j++]);
+               val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(wrr_states[j++]);
+               val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(wrr_states[j++]);
+               val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(wrr_states[j++]);
+               val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(wrr_states[j++]);
+               val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(wrr_states[j++]);
+               val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(wrr_states[j++]);
+               val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(wrr_states[j++]);
+
+               writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_0 + i));
+               writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_20 + i));
+       }
+
+       /* Set up the priorities assigned to receive queues */
+       writeq(VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(0) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(1) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(2) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(3) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(4) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(5) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(6) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(7),
+                       &hldev->mrpcim_reg->rx_queue_priority_0);
+
+       writeq(VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(8) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(9) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(10) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(11) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(12) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(13) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(14) |
+                       VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(15),
+                       &hldev->mrpcim_reg->rx_queue_priority_1);
+
+       writeq(VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(16),
+                               &hldev->mrpcim_reg->rx_queue_priority_2);
+
+       /* Initialize all the slots as unused */
+       for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++)
+               wrr_states[i] = -1;
+
+       /* Prepare the Ring service states */
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!hldev->config.vp_config[i].min_bandwidth)
+                       continue;
+
+               how_often = VXGE_HW_VPATH_BANDWIDTH_MAX /
+                               hldev->config.vp_config[i].min_bandwidth;
+
+               if (how_often) {
+                       for (j = 0; j < VXGE_HW_WRR_RING_SERVICE_STATES;) {
+                               if (wrr_states[j] == -1) {
+                                       wrr_states[j] = i;
+                                       /* Make sure each ring is
+                                        * serviced atleast once */
+                                       if (i == j)
+                                               j += VXGE_HW_MAX_VIRTUAL_PATHS;
+                                       else
+                                               j += how_often;
+                               } else
+                                       j++;
+                       }
+               }
+       }
+
+       /* Fill the unused slots with 0 */
+       for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) {
+               if (wrr_states[j] == -1)
+                       wrr_states[j] = 0;
+       }
+
+       for (i = 0, j = 0; i < VXGE_HW_WRR_RING_COUNT; i++) {
+               val64 =  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0(
+                               wrr_states[j++]);
+               val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1(
+                               wrr_states[j++]);
+               val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2(
+                               wrr_states[j++]);
+               val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3(
+                               wrr_states[j++]);
+               val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4(
+                               wrr_states[j++]);
+               val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5(
+                               wrr_states[j++]);
+               val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6(
+                               wrr_states[j++]);
+               val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7(
+                               wrr_states[j++]);
+
+               writeq(val64, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i));
+       }
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_device_initialize
+ * Initialize Titan-V hardware.
+ */
+enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       /* Validate the pci-e link width and speed */
+       status = __vxge_hw_verify_pci_e_info(hldev);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       vxge_hw_wrr_rebalance(hldev);
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_device_hw_info_get - Get the hw information
+ * Returns the vpath mask that has the bits set for each vpath allocated
+ * for the driver, FW version information and the first mac addresse for
+ * each vpath
+ */
+enum vxge_hw_status __devinit
+vxge_hw_device_hw_info_get(void __iomem *bar0,
+                          struct vxge_hw_device_hw_info *hw_info)
+{
+       u32 i;
+       u64 val64;
+       struct vxge_hw_toc_reg __iomem *toc;
+       struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg;
+       struct vxge_hw_common_reg __iomem *common_reg;
+       struct vxge_hw_vpath_reg __iomem *vpath_reg;
+       struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg;
+       enum vxge_hw_status status;
+
+       memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info));
+
+       toc = __vxge_hw_device_toc_get(bar0);
+       if (toc == NULL) {
+               status = VXGE_HW_ERR_CRITICAL;
+               goto exit;
+       }
+
+       val64 = readq(&toc->toc_common_pointer);
+       common_reg = (struct vxge_hw_common_reg __iomem *)(bar0 + val64);
+
+       status = __vxge_hw_device_vpath_reset_in_prog_check(
+               (u64 __iomem *)&common_reg->vpath_rst_in_prog);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       hw_info->vpath_mask = readq(&common_reg->vpath_assignments);
+
+       val64 = readq(&common_reg->host_type_assignments);
+
+       hw_info->host_type =
+          (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
+                       continue;
+
+               val64 = readq(&toc->toc_vpmgmt_pointer[i]);
+
+               vpmgmt_reg = (struct vxge_hw_vpmgmt_reg __iomem *)
+                               (bar0 + val64);
+
+               hw_info->func_id = __vxge_hw_vpath_func_id_get(i, vpmgmt_reg);
+               if (__vxge_hw_device_access_rights_get(hw_info->host_type,
+                       hw_info->func_id) &
+                       VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) {
+
+                       val64 = readq(&toc->toc_mrpcim_pointer);
+
+                       mrpcim_reg = (struct vxge_hw_mrpcim_reg __iomem *)
+                                       (bar0 + val64);
+
+                       writeq(0, &mrpcim_reg->xgmac_gen_fw_memo_mask);
+                       wmb();
+               }
+
+               val64 = readq(&toc->toc_vpath_pointer[i]);
+
+               vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64);
+
+               hw_info->function_mode =
+                       __vxge_hw_vpath_pci_func_mode_get(i, vpath_reg);
+
+               status = __vxge_hw_vpath_fw_ver_get(i, vpath_reg, hw_info);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+
+               status = __vxge_hw_vpath_card_info_get(i, vpath_reg, hw_info);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+
+               break;
+       }
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
+                       continue;
+
+               val64 = readq(&toc->toc_vpath_pointer[i]);
+               vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64);
+
+               status =  __vxge_hw_vpath_addr_get(i, vpath_reg,
+                               hw_info->mac_addrs[i],
+                               hw_info->mac_addr_masks[i]);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+       }
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_device_initialize - Initialize Titan device.
+ * Initialize Titan device. Note that all the arguments of this public API
+ * are 'IN', including @hldev. Driver cooperates with
+ * OS to find new Titan device, locate its PCI and memory spaces.
+ *
+ * When done, the driver allocates sizeof(struct __vxge_hw_device) bytes for HW
+ * to enable the latter to perform Titan hardware initialization.
+ */
+enum vxge_hw_status __devinit
+vxge_hw_device_initialize(
+       struct __vxge_hw_device **devh,
+       struct vxge_hw_device_attr *attr,
+       struct vxge_hw_device_config *device_config)
+{
+       u32 i;
+       u32 nblocks = 0;
+       struct __vxge_hw_device *hldev = NULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       status = __vxge_hw_device_config_check(device_config);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       hldev = (struct __vxge_hw_device *)
+                       vmalloc(sizeof(struct __vxge_hw_device));
+       if (hldev == NULL) {
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto exit;
+       }
+
+       memset(hldev, 0, sizeof(struct __vxge_hw_device));
+       hldev->magic = VXGE_HW_DEVICE_MAGIC;
+
+       vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_ALL);
+
+       /* apply config */
+       memcpy(&hldev->config, device_config,
+               sizeof(struct vxge_hw_device_config));
+
+       hldev->bar0 = attr->bar0;
+       hldev->bar1 = attr->bar1;
+       hldev->bar2 = attr->bar2;
+       hldev->pdev = attr->pdev;
+
+       hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up;
+       hldev->uld_callbacks.link_down = attr->uld_callbacks.link_down;
+       hldev->uld_callbacks.crit_err = attr->uld_callbacks.crit_err;
+
+       __vxge_hw_device_pci_e_init(hldev);
+
+       status = __vxge_hw_device_reg_addr_get(hldev);
+       if (status != VXGE_HW_OK)
+               goto exit;
+       __vxge_hw_device_id_get(hldev);
+
+       __vxge_hw_device_host_info_get(hldev);
+
+       /* Incrementing for stats blocks */
+       nblocks++;
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!(hldev->vpath_assignments & vxge_mBIT(i)))
+                       continue;
+
+               if (device_config->vp_config[i].ring.enable ==
+                       VXGE_HW_RING_ENABLE)
+                       nblocks += device_config->vp_config[i].ring.ring_blocks;
+
+               if (device_config->vp_config[i].fifo.enable ==
+                       VXGE_HW_FIFO_ENABLE)
+                       nblocks += device_config->vp_config[i].fifo.fifo_blocks;
+               nblocks++;
+       }
+
+       if (__vxge_hw_blockpool_create(hldev,
+               &hldev->block_pool,
+               device_config->dma_blockpool_initial + nblocks,
+               device_config->dma_blockpool_max + nblocks) != VXGE_HW_OK) {
+
+               vxge_hw_device_terminate(hldev);
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto exit;
+       }
+
+       status = __vxge_hw_device_initialize(hldev);
+
+       if (status != VXGE_HW_OK) {
+               vxge_hw_device_terminate(hldev);
+               goto exit;
+       }
+
+       *devh = hldev;
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_device_terminate - Terminate Titan device.
+ * Terminate HW device.
+ */
+void
+vxge_hw_device_terminate(struct __vxge_hw_device *hldev)
+{
+       vxge_assert(hldev->magic == VXGE_HW_DEVICE_MAGIC);
+
+       hldev->magic = VXGE_HW_DEVICE_DEAD;
+       __vxge_hw_blockpool_destroy(&hldev->block_pool);
+       vfree(hldev);
+}
+
+/*
+ * vxge_hw_device_stats_get - Get the device hw statistics.
+ * Returns the vpath h/w stats for the device.
+ */
+enum vxge_hw_status
+vxge_hw_device_stats_get(struct __vxge_hw_device *hldev,
+                       struct vxge_hw_device_stats_hw_info *hw_stats)
+{
+       u32 i;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!(hldev->vpaths_deployed & vxge_mBIT(i)) ||
+                       (hldev->virtual_paths[i].vp_open ==
+                               VXGE_HW_VP_NOT_OPEN))
+                       continue;
+
+               memcpy(hldev->virtual_paths[i].hw_stats_sav,
+                               hldev->virtual_paths[i].hw_stats,
+                               sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+               status = __vxge_hw_vpath_stats_get(
+                       &hldev->virtual_paths[i],
+                       hldev->virtual_paths[i].hw_stats);
+       }
+
+       memcpy(hw_stats, &hldev->stats.hw_dev_info_stats,
+                       sizeof(struct vxge_hw_device_stats_hw_info));
+
+       return status;
+}
+
+/*
+ * vxge_hw_driver_stats_get - Get the device sw statistics.
+ * Returns the vpath s/w stats for the device.
+ */
+enum vxge_hw_status vxge_hw_driver_stats_get(
+                       struct __vxge_hw_device *hldev,
+                       struct vxge_hw_device_stats_sw_info *sw_stats)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       memcpy(sw_stats, &hldev->stats.sw_dev_info_stats,
+               sizeof(struct vxge_hw_device_stats_sw_info));
+
+       return status;
+}
+
+/*
+ * vxge_hw_mrpcim_stats_access - Access the statistics from the given location
+ *                           and offset and perform an operation
+ * Get the statistics from the given location and offset.
+ */
+enum vxge_hw_status
+vxge_hw_mrpcim_stats_access(struct __vxge_hw_device *hldev,
+                           u32 operation, u32 location, u32 offset, u64 *stat)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       status = __vxge_hw_device_is_privilaged(hldev);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = VXGE_HW_XMAC_STATS_SYS_CMD_OP(operation) |
+               VXGE_HW_XMAC_STATS_SYS_CMD_STROBE |
+               VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(location) |
+               VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(offset);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &hldev->mrpcim_reg->xmac_stats_sys_cmd,
+                               VXGE_HW_XMAC_STATS_SYS_CMD_STROBE,
+                               hldev->config.device_poll_millis);
+
+       if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ))
+               *stat = readq(&hldev->mrpcim_reg->xmac_stats_sys_data);
+       else
+               *stat = 0;
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_device_xmac_aggr_stats_get - Get the Statistics on aggregate port
+ * Get the Statistics on aggregate port
+ */
+enum vxge_hw_status
+vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *hldev, u32 port,
+                                  struct vxge_hw_xmac_aggr_stats *aggr_stats)
+{
+       u64 *val64;
+       int i;
+       u32 offset = VXGE_HW_STATS_AGGRn_OFFSET;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       val64 = (u64 *)aggr_stats;
+
+       status = __vxge_hw_device_is_privilaged(hldev);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       for (i = 0; i < sizeof(struct vxge_hw_xmac_aggr_stats) / 8; i++) {
+               status = vxge_hw_mrpcim_stats_access(hldev,
+                                       VXGE_HW_STATS_OP_READ,
+                                       VXGE_HW_STATS_LOC_AGGR,
+                                       ((offset + (104 * port)) >> 3), val64);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+
+               offset += 8;
+               val64++;
+       }
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_device_xmac_port_stats_get - Get the Statistics on a port
+ * Get the Statistics on port
+ */
+enum vxge_hw_status
+vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *hldev, u32 port,
+                                  struct vxge_hw_xmac_port_stats *port_stats)
+{
+       u64 *val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       int i;
+       u32 offset = 0x0;
+       val64 = (u64 *) port_stats;
+
+       status = __vxge_hw_device_is_privilaged(hldev);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       for (i = 0; i < sizeof(struct vxge_hw_xmac_port_stats) / 8; i++) {
+               status = vxge_hw_mrpcim_stats_access(hldev,
+                                       VXGE_HW_STATS_OP_READ,
+                                       VXGE_HW_STATS_LOC_AGGR,
+                                       ((offset + (608 * port)) >> 3), val64);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+
+               offset += 8;
+               val64++;
+       }
+
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_device_xmac_stats_get - Get the XMAC Statistics
+ * Get the XMAC Statistics
+ */
+enum vxge_hw_status
+vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *hldev,
+                             struct vxge_hw_xmac_stats *xmac_stats)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       u32 i;
+
+       status = vxge_hw_device_xmac_aggr_stats_get(hldev,
+                                       0, &xmac_stats->aggr_stats[0]);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       status = vxge_hw_device_xmac_aggr_stats_get(hldev,
+                               1, &xmac_stats->aggr_stats[1]);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       for (i = 0; i <= VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) {
+
+               status = vxge_hw_device_xmac_port_stats_get(hldev,
+                                       i, &xmac_stats->port_stats[i]);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+       }
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
+                       continue;
+
+               status = __vxge_hw_vpath_xmac_tx_stats_get(
+                                       &hldev->virtual_paths[i],
+                                       &xmac_stats->vpath_tx_stats[i]);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+
+               status = __vxge_hw_vpath_xmac_rx_stats_get(
+                                       &hldev->virtual_paths[i],
+                                       &xmac_stats->vpath_rx_stats[i]);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+       }
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_device_debug_set - Set the debug module, level and timestamp
+ * This routine is used to dynamically change the debug output
+ */
+void vxge_hw_device_debug_set(struct __vxge_hw_device *hldev,
+                             enum vxge_debug_level level, u32 mask)
+{
+       if (hldev == NULL)
+               return;
+
+#if defined(VXGE_DEBUG_TRACE_MASK) || \
+       defined(VXGE_DEBUG_ERR_MASK)
+       hldev->debug_module_mask = mask;
+       hldev->debug_level = level;
+#endif
+
+#if defined(VXGE_DEBUG_ERR_MASK)
+       hldev->level_err = level & VXGE_ERR;
+#endif
+
+#if defined(VXGE_DEBUG_TRACE_MASK)
+       hldev->level_trace = level & VXGE_TRACE;
+#endif
+}
+
+/*
+ * vxge_hw_device_error_level_get - Get the error level
+ * This routine returns the current error level set
+ */
+u32 vxge_hw_device_error_level_get(struct __vxge_hw_device *hldev)
+{
+#if defined(VXGE_DEBUG_ERR_MASK)
+       if (hldev == NULL)
+               return VXGE_ERR;
+       else
+               return hldev->level_err;
+#else
+       return 0;
+#endif
+}
+
+/*
+ * vxge_hw_device_trace_level_get - Get the trace level
+ * This routine returns the current trace level set
+ */
+u32 vxge_hw_device_trace_level_get(struct __vxge_hw_device *hldev)
+{
+#if defined(VXGE_DEBUG_TRACE_MASK)
+       if (hldev == NULL)
+               return VXGE_TRACE;
+       else
+               return hldev->level_trace;
+#else
+       return 0;
+#endif
+}
+/*
+ * vxge_hw_device_debug_mask_get - Get the debug mask
+ * This routine returns the current debug mask set
+ */
+u32 vxge_hw_device_debug_mask_get(struct __vxge_hw_device *hldev)
+{
+#if defined(VXGE_DEBUG_TRACE_MASK) || defined(VXGE_DEBUG_ERR_MASK)
+       if (hldev == NULL)
+               return 0;
+       return hldev->debug_module_mask;
+#else
+       return 0;
+#endif
+}
+
+/*
+ * vxge_hw_getpause_data -Pause frame frame generation and reception.
+ * Returns the Pause frame generation and reception capability of the NIC.
+ */
+enum vxge_hw_status vxge_hw_device_getpause_data(struct __vxge_hw_device *hldev,
+                                                u32 port, u32 *tx, u32 *rx)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
+               status = VXGE_HW_ERR_INVALID_DEVICE;
+               goto exit;
+       }
+
+       if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) {
+               status = VXGE_HW_ERR_INVALID_PORT;
+               goto exit;
+       }
+
+       if (!(hldev->access_rights & VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) {
+               status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+               goto exit;
+       }
+
+       val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
+       if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN)
+               *tx = 1;
+       if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN)
+               *rx = 1;
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_device_setpause_data -  set/reset pause frame generation.
+ * It can be used to set or reset Pause frame generation or reception
+ * support of the NIC.
+ */
+
+enum vxge_hw_status vxge_hw_device_setpause_data(struct __vxge_hw_device *hldev,
+                                                u32 port, u32 tx, u32 rx)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
+               status = VXGE_HW_ERR_INVALID_DEVICE;
+               goto exit;
+       }
+
+       if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) {
+               status = VXGE_HW_ERR_INVALID_PORT;
+               goto exit;
+       }
+
+       status = __vxge_hw_device_is_privilaged(hldev);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
+       if (tx)
+               val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN;
+       else
+               val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN;
+       if (rx)
+               val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN;
+       else
+               val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN;
+
+       writeq(val64, &hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
+exit:
+       return status;
+}
+
+u16 vxge_hw_device_link_width_get(struct __vxge_hw_device *hldev)
+{
+       int link_width, exp_cap;
+       u16 lnk;
+
+       exp_cap = pci_find_capability(hldev->pdev, PCI_CAP_ID_EXP);
+       pci_read_config_word(hldev->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk);
+       link_width = (lnk & VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH) >> 4;
+       return link_width;
+}
+
+/*
+ * __vxge_hw_ring_block_memblock_idx - Return the memblock index
+ * This function returns the index of memory block
+ */
+static inline u32
+__vxge_hw_ring_block_memblock_idx(u8 *block)
+{
+       return (u32)*((u64 *)(block + VXGE_HW_RING_MEMBLOCK_IDX_OFFSET));
+}
+
+/*
+ * __vxge_hw_ring_block_memblock_idx_set - Sets the memblock index
+ * This function sets index to a memory block
+ */
+static inline void
+__vxge_hw_ring_block_memblock_idx_set(u8 *block, u32 memblock_idx)
+{
+       *((u64 *)(block + VXGE_HW_RING_MEMBLOCK_IDX_OFFSET)) = memblock_idx;
+}
+
+/*
+ * __vxge_hw_ring_block_next_pointer_set - Sets the next block pointer
+ * in RxD block
+ * Sets the next block pointer in RxD block
+ */
+static inline void
+__vxge_hw_ring_block_next_pointer_set(u8 *block, dma_addr_t dma_next)
+{
+       *((u64 *)(block + VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET)) = dma_next;
+}
+
+/*
+ * __vxge_hw_ring_first_block_address_get - Returns the dma address of the
+ *             first block
+ * Returns the dma address of the first RxD block
+ */
+u64 __vxge_hw_ring_first_block_address_get(struct __vxge_hw_ring *ring)
+{
+       struct vxge_hw_mempool_dma *dma_object;
+
+       dma_object = ring->mempool->memblocks_dma_arr;
+       vxge_assert(dma_object != NULL);
+
+       return dma_object->addr;
+}
+
+/*
+ * __vxge_hw_ring_item_dma_addr - Return the dma address of an item
+ * This function returns the dma address of a given item
+ */
+static dma_addr_t __vxge_hw_ring_item_dma_addr(struct vxge_hw_mempool *mempoolh,
+                                              void *item)
+{
+       u32 memblock_idx;
+       void *memblock;
+       struct vxge_hw_mempool_dma *memblock_dma_object;
+       ptrdiff_t dma_item_offset;
+
+       /* get owner memblock index */
+       memblock_idx = __vxge_hw_ring_block_memblock_idx(item);
+
+       /* get owner memblock by memblock index */
+       memblock = mempoolh->memblocks_arr[memblock_idx];
+
+       /* get memblock DMA object by memblock index */
+       memblock_dma_object = mempoolh->memblocks_dma_arr + memblock_idx;
+
+       /* calculate offset in the memblock of this item */
+       dma_item_offset = (u8 *)item - (u8 *)memblock;
+
+       return memblock_dma_object->addr + dma_item_offset;
+}
+
+/*
+ * __vxge_hw_ring_rxdblock_link - Link the RxD blocks
+ * This function returns the dma address of a given item
+ */
+static void __vxge_hw_ring_rxdblock_link(struct vxge_hw_mempool *mempoolh,
+                                        struct __vxge_hw_ring *ring, u32 from,
+                                        u32 to)
+{
+       u8 *to_item , *from_item;
+       dma_addr_t to_dma;
+
+       /* get "from" RxD block */
+       from_item = mempoolh->items_arr[from];
+       vxge_assert(from_item);
+
+       /* get "to" RxD block */
+       to_item = mempoolh->items_arr[to];
+       vxge_assert(to_item);
+
+       /* return address of the beginning of previous RxD block */
+       to_dma = __vxge_hw_ring_item_dma_addr(mempoolh, to_item);
+
+       /* set next pointer for this RxD block to point on
+        * previous item's DMA start address */
+       __vxge_hw_ring_block_next_pointer_set(from_item, to_dma);
+}
+
+/*
+ * __vxge_hw_ring_mempool_item_alloc - Allocate List blocks for RxD
+ * block callback
+ * This function is callback passed to __vxge_hw_mempool_create to create memory
+ * pool for RxD block
+ */
+static void
+__vxge_hw_ring_mempool_item_alloc(struct vxge_hw_mempool *mempoolh,
+                                 u32 memblock_index,
+                                 struct vxge_hw_mempool_dma *dma_object,
+                                 u32 index, u32 is_last)
+{
+       u32 i;
+       void *item = mempoolh->items_arr[index];
+       struct __vxge_hw_ring *ring =
+               (struct __vxge_hw_ring *)mempoolh->userdata;
+
+       /* format rxds array */
+       for (i = 0; i < ring->rxds_per_block; i++) {
+               void *rxdblock_priv;
+               void *uld_priv;
+               struct vxge_hw_ring_rxd_1 *rxdp;
+
+               u32 reserve_index = ring->channel.reserve_ptr -
+                               (index * ring->rxds_per_block + i + 1);
+               u32 memblock_item_idx;
+
+               ring->channel.reserve_arr[reserve_index] = ((u8 *)item) +
+                                               i * ring->rxd_size;
+
+               /* Note: memblock_item_idx is index of the item within
+                *       the memblock. For instance, in case of three RxD-blocks
+                *       per memblock this value can be 0, 1 or 2. */
+               rxdblock_priv = __vxge_hw_mempool_item_priv(mempoolh,
+                                       memblock_index, item,
+                                       &memblock_item_idx);
+
+               rxdp = (struct vxge_hw_ring_rxd_1 *)
+                               ring->channel.reserve_arr[reserve_index];
+
+               uld_priv = ((u8 *)rxdblock_priv + ring->rxd_priv_size * i);
+
+               /* pre-format Host_Control */
+               rxdp->host_control = (u64)(size_t)uld_priv;
+       }
+
+       __vxge_hw_ring_block_memblock_idx_set(item, memblock_index);
+
+       if (is_last) {
+               /* link last one with first one */
+               __vxge_hw_ring_rxdblock_link(mempoolh, ring, index, 0);
+       }
+
+       if (index > 0) {
+               /* link this RxD block with previous one */
+               __vxge_hw_ring_rxdblock_link(mempoolh, ring, index - 1, index);
+       }
+
+       return;
+}
+
+/*
+ * __vxge_hw_ring_initial_replenish - Initial replenish of RxDs
+ * This function replenishes the RxDs from reserve array to work array
+ */
+enum vxge_hw_status
+vxge_hw_ring_replenish(struct __vxge_hw_ring *ring, u16 min_flag)
+{
+       void *rxd;
+       int i = 0;
+       struct __vxge_hw_channel *channel;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       channel = &ring->channel;
+
+       while (vxge_hw_channel_dtr_count(channel) > 0) {
+
+               status = vxge_hw_ring_rxd_reserve(ring, &rxd);
+
+               vxge_assert(status == VXGE_HW_OK);
+
+               if (ring->rxd_init) {
+                       status = ring->rxd_init(rxd, channel->userdata);
+                       if (status != VXGE_HW_OK) {
+                               vxge_hw_ring_rxd_free(ring, rxd);
+                               goto exit;
+                       }
+               }
+
+               vxge_hw_ring_rxd_post(ring, rxd);
+               if (min_flag) {
+                       i++;
+                       if (i == VXGE_HW_RING_MIN_BUFF_ALLOCATION)
+                               break;
+               }
+       }
+       status = VXGE_HW_OK;
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_ring_create - Create a Ring
+ * This function creates Ring and initializes it.
+ *
+ */
+enum vxge_hw_status
+__vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
+                     struct vxge_hw_ring_attr *attr)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_ring *ring;
+       u32 ring_length;
+       struct vxge_hw_ring_config *config;
+       struct __vxge_hw_device *hldev;
+       u32 vp_id;
+       struct vxge_hw_mempool_cbs ring_mp_callback;
+
+       if ((vp == NULL) || (attr == NULL)) {
+               status = VXGE_HW_FAIL;
+               goto exit;
+       }
+
+       hldev = vp->vpath->hldev;
+       vp_id = vp->vpath->vp_id;
+
+       config = &hldev->config.vp_config[vp_id].ring;
+
+       ring_length = config->ring_blocks *
+                       vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
+
+       ring = (struct __vxge_hw_ring *)__vxge_hw_channel_allocate(vp,
+                                               VXGE_HW_CHANNEL_TYPE_RING,
+                                               ring_length,
+                                               attr->per_rxd_space,
+                                               attr->userdata);
+
+       if (ring == NULL) {
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto exit;
+       }
+
+       vp->vpath->ringh = ring;
+       ring->vp_id = vp_id;
+       ring->vp_reg = vp->vpath->vp_reg;
+       ring->common_reg = hldev->common_reg;
+       ring->stats = &vp->vpath->sw_stats->ring_stats;
+       ring->config = config;
+       ring->callback = attr->callback;
+       ring->rxd_init = attr->rxd_init;
+       ring->rxd_term = attr->rxd_term;
+       ring->buffer_mode = config->buffer_mode;
+       ring->rxds_limit = config->rxds_limit;
+
+       ring->rxd_size = vxge_hw_ring_rxd_size_get(config->buffer_mode);
+       ring->rxd_priv_size =
+               sizeof(struct __vxge_hw_ring_rxd_priv) + attr->per_rxd_space;
+       ring->per_rxd_space = attr->per_rxd_space;
+
+       ring->rxd_priv_size =
+               ((ring->rxd_priv_size + VXGE_CACHE_LINE_SIZE - 1) /
+               VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE;
+
+       /* how many RxDs can fit into one block. Depends on configured
+        * buffer_mode. */
+       ring->rxds_per_block =
+               vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
+
+       /* calculate actual RxD block private size */
+       ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block;
+       ring_mp_callback.item_func_alloc = __vxge_hw_ring_mempool_item_alloc;
+       ring->mempool = __vxge_hw_mempool_create(hldev,
+                               VXGE_HW_BLOCK_SIZE,
+                               VXGE_HW_BLOCK_SIZE,
+                               ring->rxdblock_priv_size,
+                               ring->config->ring_blocks,
+                               ring->config->ring_blocks,
+                               &ring_mp_callback,
+                               ring);
+
+       if (ring->mempool == NULL) {
+               __vxge_hw_ring_delete(vp);
+               return VXGE_HW_ERR_OUT_OF_MEMORY;
+       }
+
+       status = __vxge_hw_channel_initialize(&ring->channel);
+       if (status != VXGE_HW_OK) {
+               __vxge_hw_ring_delete(vp);
+               goto exit;
+       }
+
+       /* Note:
+        * Specifying rxd_init callback means two things:
+        * 1) rxds need to be initialized by driver at channel-open time;
+        * 2) rxds need to be posted at channel-open time
+        *    (that's what the initial_replenish() below does)
+        * Currently we don't have a case when the 1) is done without the 2).
+        */
+       if (ring->rxd_init) {
+               status = vxge_hw_ring_replenish(ring, 1);
+               if (status != VXGE_HW_OK) {
+                       __vxge_hw_ring_delete(vp);
+                       goto exit;
+               }
+       }
+
+       /* initial replenish will increment the counter in its post() routine,
+        * we have to reset it */
+       ring->stats->common_stats.usage_cnt = 0;
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_ring_abort - Returns the RxD
+ * This function terminates the RxDs of ring
+ */
+enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring)
+{
+       void *rxdh;
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       for (;;) {
+               vxge_hw_channel_dtr_try_complete(channel, &rxdh);
+
+               if (rxdh == NULL)
+                       break;
+
+               vxge_hw_channel_dtr_complete(channel);
+
+               if (ring->rxd_term)
+                       ring->rxd_term(rxdh, VXGE_HW_RXD_STATE_POSTED,
+                               channel->userdata);
+
+               vxge_hw_channel_dtr_free(channel, rxdh);
+       }
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_ring_reset - Resets the ring
+ * This function resets the ring during vpath reset operation
+ */
+enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       __vxge_hw_ring_abort(ring);
+
+       status = __vxge_hw_channel_reset(channel);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       if (ring->rxd_init) {
+               status = vxge_hw_ring_replenish(ring, 1);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+       }
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_ring_delete - Removes the ring
+ * This function freeup the memory pool and removes the ring
+ */
+enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp)
+{
+       struct __vxge_hw_ring *ring = vp->vpath->ringh;
+
+       __vxge_hw_ring_abort(ring);
+
+       if (ring->mempool)
+               __vxge_hw_mempool_destroy(ring->mempool);
+
+       vp->vpath->ringh = NULL;
+       __vxge_hw_channel_free(&ring->channel);
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_mempool_grow
+ * Will resize mempool up to %num_allocate value.
+ */
+enum vxge_hw_status
+__vxge_hw_mempool_grow(struct vxge_hw_mempool *mempool, u32 num_allocate,
+                      u32 *num_allocated)
+{
+       u32 i, first_time = mempool->memblocks_allocated == 0 ? 1 : 0;
+       u32 n_items = mempool->items_per_memblock;
+       u32 start_block_idx = mempool->memblocks_allocated;
+       u32 end_block_idx = mempool->memblocks_allocated + num_allocate;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       *num_allocated = 0;
+
+       if (end_block_idx > mempool->memblocks_max) {
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto exit;
+       }
+
+       for (i = start_block_idx; i < end_block_idx; i++) {
+               u32 j;
+               u32 is_last = ((end_block_idx - 1) == i);
+               struct vxge_hw_mempool_dma *dma_object =
+                       mempool->memblocks_dma_arr + i;
+               void *the_memblock;
+
+               /* allocate memblock's private part. Each DMA memblock
+                * has a space allocated for item's private usage upon
+                * mempool's user request. Each time mempool grows, it will
+                * allocate new memblock and its private part at once.
+                * This helps to minimize memory usage a lot. */
+               mempool->memblocks_priv_arr[i] =
+                               vmalloc(mempool->items_priv_size * n_items);
+               if (mempool->memblocks_priv_arr[i] == NULL) {
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto exit;
+               }
+
+               memset(mempool->memblocks_priv_arr[i], 0,
+                            mempool->items_priv_size * n_items);
+
+               /* allocate DMA-capable memblock */
+               mempool->memblocks_arr[i] =
+                       __vxge_hw_blockpool_malloc(mempool->devh,
+                               mempool->memblock_size, dma_object);
+               if (mempool->memblocks_arr[i] == NULL) {
+                       vfree(mempool->memblocks_priv_arr[i]);
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto exit;
+               }
+
+               (*num_allocated)++;
+               mempool->memblocks_allocated++;
+
+               memset(mempool->memblocks_arr[i], 0, mempool->memblock_size);
+
+               the_memblock = mempool->memblocks_arr[i];
+
+               /* fill the items hash array */
+               for (j = 0; j < n_items; j++) {
+                       u32 index = i * n_items + j;
+
+                       if (first_time && index >= mempool->items_initial)
+                               break;
+
+                       mempool->items_arr[index] =
+                               ((char *)the_memblock + j*mempool->item_size);
+
+                       /* let caller to do more job on each item */
+                       if (mempool->item_func_alloc != NULL)
+                               mempool->item_func_alloc(mempool, i,
+                                       dma_object, index, is_last);
+
+                       mempool->items_current = index + 1;
+               }
+
+               if (first_time && mempool->items_current ==
+                                       mempool->items_initial)
+                       break;
+       }
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_mempool_create
+ * This function will create memory pool object. Pool may grow but will
+ * never shrink. Pool consists of number of dynamically allocated blocks
+ * with size enough to hold %items_initial number of items. Memory is
+ * DMA-able but client must map/unmap before interoperating with the device.
+ */
+struct vxge_hw_mempool*
+__vxge_hw_mempool_create(
+       struct __vxge_hw_device *devh,
+       u32 memblock_size,
+       u32 item_size,
+       u32 items_priv_size,
+       u32 items_initial,
+       u32 items_max,
+       struct vxge_hw_mempool_cbs *mp_callback,
+       void *userdata)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       u32 memblocks_to_allocate;
+       struct vxge_hw_mempool *mempool = NULL;
+       u32 allocated;
+
+       if (memblock_size < item_size) {
+               status = VXGE_HW_FAIL;
+               goto exit;
+       }
+
+       mempool = (struct vxge_hw_mempool *)
+                       vmalloc(sizeof(struct vxge_hw_mempool));
+       if (mempool == NULL) {
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto exit;
+       }
+       memset(mempool, 0, sizeof(struct vxge_hw_mempool));
+
+       mempool->devh                   = devh;
+       mempool->memblock_size          = memblock_size;
+       mempool->items_max              = items_max;
+       mempool->items_initial          = items_initial;
+       mempool->item_size              = item_size;
+       mempool->items_priv_size        = items_priv_size;
+       mempool->item_func_alloc        = mp_callback->item_func_alloc;
+       mempool->userdata               = userdata;
+
+       mempool->memblocks_allocated = 0;
+
+       mempool->items_per_memblock = memblock_size / item_size;
+
+       mempool->memblocks_max = (items_max + mempool->items_per_memblock - 1) /
+                                       mempool->items_per_memblock;
+
+       /* allocate array of memblocks */
+       mempool->memblocks_arr =
+               (void **) vmalloc(sizeof(void *) * mempool->memblocks_max);
+       if (mempool->memblocks_arr == NULL) {
+               __vxge_hw_mempool_destroy(mempool);
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               mempool = NULL;
+               goto exit;
+       }
+       memset(mempool->memblocks_arr, 0,
+               sizeof(void *) * mempool->memblocks_max);
+
+       /* allocate array of private parts of items per memblocks */
+       mempool->memblocks_priv_arr =
+               (void **) vmalloc(sizeof(void *) * mempool->memblocks_max);
+       if (mempool->memblocks_priv_arr == NULL) {
+               __vxge_hw_mempool_destroy(mempool);
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               mempool = NULL;
+               goto exit;
+       }
+       memset(mempool->memblocks_priv_arr, 0,
+                   sizeof(void *) * mempool->memblocks_max);
+
+       /* allocate array of memblocks DMA objects */
+       mempool->memblocks_dma_arr = (struct vxge_hw_mempool_dma *)
+               vmalloc(sizeof(struct vxge_hw_mempool_dma) *
+                       mempool->memblocks_max);
+
+       if (mempool->memblocks_dma_arr == NULL) {
+               __vxge_hw_mempool_destroy(mempool);
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               mempool = NULL;
+               goto exit;
+       }
+       memset(mempool->memblocks_dma_arr, 0,
+                       sizeof(struct vxge_hw_mempool_dma) *
+                       mempool->memblocks_max);
+
+       /* allocate hash array of items */
+       mempool->items_arr =
+               (void **) vmalloc(sizeof(void *) * mempool->items_max);
+       if (mempool->items_arr == NULL) {
+               __vxge_hw_mempool_destroy(mempool);
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               mempool = NULL;
+               goto exit;
+       }
+       memset(mempool->items_arr, 0, sizeof(void *) * mempool->items_max);
+
+       /* calculate initial number of memblocks */
+       memblocks_to_allocate = (mempool->items_initial +
+                                mempool->items_per_memblock - 1) /
+                                               mempool->items_per_memblock;
+
+       /* pre-allocate the mempool */
+       status = __vxge_hw_mempool_grow(mempool, memblocks_to_allocate,
+                                       &allocated);
+       if (status != VXGE_HW_OK) {
+               __vxge_hw_mempool_destroy(mempool);
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               mempool = NULL;
+               goto exit;
+       }
+
+exit:
+       return mempool;
+}
+
+/*
+ * vxge_hw_mempool_destroy
+ */
+void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool)
+{
+       u32 i, j;
+       struct __vxge_hw_device *devh = mempool->devh;
+
+       for (i = 0; i < mempool->memblocks_allocated; i++) {
+               struct vxge_hw_mempool_dma *dma_object;
+
+               vxge_assert(mempool->memblocks_arr[i]);
+               vxge_assert(mempool->memblocks_dma_arr + i);
+
+               dma_object = mempool->memblocks_dma_arr + i;
+
+               for (j = 0; j < mempool->items_per_memblock; j++) {
+                       u32 index = i * mempool->items_per_memblock + j;
+
+                       /* to skip last partially filled(if any) memblock */
+                       if (index >= mempool->items_current)
+                               break;
+               }
+
+               vfree(mempool->memblocks_priv_arr[i]);
+
+               __vxge_hw_blockpool_free(devh, mempool->memblocks_arr[i],
+                               mempool->memblock_size, dma_object);
+       }
+
+       if (mempool->items_arr)
+               vfree(mempool->items_arr);
+
+       if (mempool->memblocks_dma_arr)
+               vfree(mempool->memblocks_dma_arr);
+
+       if (mempool->memblocks_priv_arr)
+               vfree(mempool->memblocks_priv_arr);
+
+       if (mempool->memblocks_arr)
+               vfree(mempool->memblocks_arr);
+
+       vfree(mempool);
+}
+
+/*
+ * __vxge_hw_device_fifo_config_check - Check fifo configuration.
+ * Check the fifo configuration
+ */
+enum vxge_hw_status
+__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config)
+{
+       if ((fifo_config->fifo_blocks < VXGE_HW_MIN_FIFO_BLOCKS) ||
+            (fifo_config->fifo_blocks > VXGE_HW_MAX_FIFO_BLOCKS))
+               return VXGE_HW_BADCFG_FIFO_BLOCKS;
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_vpath_config_check - Check vpath configuration.
+ * Check the vpath configuration
+ */
+enum vxge_hw_status
+__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config)
+{
+       enum vxge_hw_status status;
+
+       if ((vp_config->min_bandwidth < VXGE_HW_VPATH_BANDWIDTH_MIN) ||
+               (vp_config->min_bandwidth >
+                                       VXGE_HW_VPATH_BANDWIDTH_MAX))
+               return VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH;
+
+       status = __vxge_hw_device_fifo_config_check(&vp_config->fifo);
+       if (status != VXGE_HW_OK)
+               return status;
+
+       if ((vp_config->mtu != VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) &&
+               ((vp_config->mtu < VXGE_HW_VPATH_MIN_INITIAL_MTU) ||
+               (vp_config->mtu > VXGE_HW_VPATH_MAX_INITIAL_MTU)))
+               return VXGE_HW_BADCFG_VPATH_MTU;
+
+       if ((vp_config->rpa_strip_vlan_tag !=
+               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) &&
+               (vp_config->rpa_strip_vlan_tag !=
+               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE) &&
+               (vp_config->rpa_strip_vlan_tag !=
+               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE))
+               return VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG;
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_config_check - Check device configuration.
+ * Check the device configuration
+ */
+enum vxge_hw_status
+__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config)
+{
+       u32 i;
+       enum vxge_hw_status status;
+
+       if ((new_config->intr_mode != VXGE_HW_INTR_MODE_IRQLINE) &&
+          (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX) &&
+          (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) &&
+          (new_config->intr_mode != VXGE_HW_INTR_MODE_DEF))
+               return VXGE_HW_BADCFG_INTR_MODE;
+
+       if ((new_config->rts_mac_en != VXGE_HW_RTS_MAC_DISABLE) &&
+          (new_config->rts_mac_en != VXGE_HW_RTS_MAC_ENABLE))
+               return VXGE_HW_BADCFG_RTS_MAC_EN;
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               status = __vxge_hw_device_vpath_config_check(
+                               &new_config->vp_config[i]);
+               if (status != VXGE_HW_OK)
+                       return status;
+       }
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * vxge_hw_device_config_default_get - Initialize device config with defaults.
+ * Initialize Titan device config with default values.
+ */
+enum vxge_hw_status __devinit
+vxge_hw_device_config_default_get(struct vxge_hw_device_config *device_config)
+{
+       u32 i;
+
+       device_config->dma_blockpool_initial =
+                                       VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE;
+       device_config->dma_blockpool_max = VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE;
+       device_config->intr_mode = VXGE_HW_INTR_MODE_DEF;
+       device_config->rth_en = VXGE_HW_RTH_DEFAULT;
+       device_config->rth_it_type = VXGE_HW_RTH_IT_TYPE_DEFAULT;
+       device_config->device_poll_millis =  VXGE_HW_DEF_DEVICE_POLL_MILLIS;
+       device_config->rts_mac_en =  VXGE_HW_RTS_MAC_DEFAULT;
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               device_config->vp_config[i].vp_id = i;
+
+               device_config->vp_config[i].min_bandwidth =
+                               VXGE_HW_VPATH_BANDWIDTH_DEFAULT;
+
+               device_config->vp_config[i].ring.enable = VXGE_HW_RING_DEFAULT;
+
+               device_config->vp_config[i].ring.ring_blocks =
+                               VXGE_HW_DEF_RING_BLOCKS;
+
+               device_config->vp_config[i].ring.buffer_mode =
+                               VXGE_HW_RING_RXD_BUFFER_MODE_DEFAULT;
+
+               device_config->vp_config[i].ring.scatter_mode =
+                               VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].ring.rxds_limit =
+                               VXGE_HW_DEF_RING_RXDS_LIMIT;
+
+               device_config->vp_config[i].fifo.enable = VXGE_HW_FIFO_ENABLE;
+
+               device_config->vp_config[i].fifo.fifo_blocks =
+                               VXGE_HW_MIN_FIFO_BLOCKS;
+
+               device_config->vp_config[i].fifo.max_frags =
+                               VXGE_HW_MAX_FIFO_FRAGS;
+
+               device_config->vp_config[i].fifo.memblock_size =
+                               VXGE_HW_DEF_FIFO_MEMBLOCK_SIZE;
+
+               device_config->vp_config[i].fifo.alignment_size =
+                               VXGE_HW_DEF_FIFO_ALIGNMENT_SIZE;
+
+               device_config->vp_config[i].fifo.intr =
+                               VXGE_HW_FIFO_QUEUE_INTR_DEFAULT;
+
+               device_config->vp_config[i].fifo.no_snoop_bits =
+                               VXGE_HW_FIFO_NO_SNOOP_DEFAULT;
+               device_config->vp_config[i].tti.intr_enable =
+                               VXGE_HW_TIM_INTR_DEFAULT;
+
+               device_config->vp_config[i].tti.btimer_val =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.timer_ac_en =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.timer_ci_en =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.timer_ri_en =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.rtimer_val =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.util_sel =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.ltimer_val =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.urange_a =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.uec_a =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.urange_b =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.uec_b =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.urange_c =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.uec_c =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].tti.uec_d =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.intr_enable =
+                               VXGE_HW_TIM_INTR_DEFAULT;
+
+               device_config->vp_config[i].rti.btimer_val =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.timer_ac_en =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.timer_ci_en =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.timer_ri_en =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.rtimer_val =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.util_sel =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.ltimer_val =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.urange_a =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.uec_a =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.urange_b =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.uec_b =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.urange_c =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.uec_c =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].rti.uec_d =
+                               VXGE_HW_USE_FLASH_DEFAULT;
+
+               device_config->vp_config[i].mtu =
+                               VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU;
+
+               device_config->vp_config[i].rpa_strip_vlan_tag =
+                       VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT;
+       }
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * _hw_legacy_swapper_set - Set the swapper bits for the legacy secion.
+ * Set the swapper bits appropriately for the lagacy section.
+ */
+enum vxge_hw_status
+__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       val64 = readq(&legacy_reg->toc_swapper_fb);
+
+       wmb();
+
+       switch (val64) {
+
+       case VXGE_HW_SWAPPER_INITIAL_VALUE:
+               return status;
+
+       case VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED:
+               writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
+                       &legacy_reg->pifm_rd_swap_en);
+               writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
+                       &legacy_reg->pifm_rd_flip_en);
+               writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
+                       &legacy_reg->pifm_wr_swap_en);
+               writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
+                       &legacy_reg->pifm_wr_flip_en);
+               break;
+
+       case VXGE_HW_SWAPPER_BYTE_SWAPPED:
+               writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
+                       &legacy_reg->pifm_rd_swap_en);
+               writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
+                       &legacy_reg->pifm_wr_swap_en);
+               break;
+
+       case VXGE_HW_SWAPPER_BIT_FLIPPED:
+               writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
+                       &legacy_reg->pifm_rd_flip_en);
+               writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
+                       &legacy_reg->pifm_wr_flip_en);
+               break;
+       }
+
+       wmb();
+
+       val64 = readq(&legacy_reg->toc_swapper_fb);
+
+       if (val64 != VXGE_HW_SWAPPER_INITIAL_VALUE)
+               status = VXGE_HW_ERR_SWAPPER_CTRL;
+
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_swapper_set - Set the swapper bits for the vpath.
+ * Set the swapper bits appropriately for the vpath.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg)
+{
+#ifndef __BIG_ENDIAN
+       u64 val64;
+
+       val64 = readq(&vpath_reg->vpath_general_cfg1);
+       wmb();
+       val64 |= VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN;
+       writeq(val64, &vpath_reg->vpath_general_cfg1);
+       wmb();
+#endif
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_kdfc_swapper_set - Set the swapper bits for the kdfc.
+ * Set the swapper bits appropriately for the vpath.
+ */
+enum vxge_hw_status
+__vxge_hw_kdfc_swapper_set(
+       struct vxge_hw_legacy_reg __iomem *legacy_reg,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg)
+{
+       u64 val64;
+
+       val64 = readq(&legacy_reg->pifm_wr_swap_en);
+
+       if (val64 == VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE) {
+               val64 = readq(&vpath_reg->kdfcctl_cfg0);
+               wmb();
+
+               val64 |= VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0 |
+                       VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1  |
+                       VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2;
+
+               writeq(val64, &vpath_reg->kdfcctl_cfg0);
+               wmb();
+       }
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * vxge_hw_mgmt_device_config - Retrieve device configuration.
+ * Get device configuration. Permits to retrieve at run-time configuration
+ * values that were used to initialize and configure the device.
+ */
+enum vxge_hw_status
+vxge_hw_mgmt_device_config(struct __vxge_hw_device *hldev,
+                          struct vxge_hw_device_config *dev_config, int size)
+{
+
+       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC))
+               return VXGE_HW_ERR_INVALID_DEVICE;
+
+       if (size != sizeof(struct vxge_hw_device_config))
+               return VXGE_HW_ERR_VERSION_CONFLICT;
+
+       memcpy(dev_config, &hldev->config,
+               sizeof(struct vxge_hw_device_config));
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * vxge_hw_mgmt_reg_read - Read Titan register.
+ */
+enum vxge_hw_status
+vxge_hw_mgmt_reg_read(struct __vxge_hw_device *hldev,
+                     enum vxge_hw_mgmt_reg_type type,
+                     u32 index, u32 offset, u64 *value)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
+               status = VXGE_HW_ERR_INVALID_DEVICE;
+               goto exit;
+       }
+
+       switch (type) {
+       case vxge_hw_mgmt_reg_type_legacy:
+               if (offset > sizeof(struct vxge_hw_legacy_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               *value = readq((void __iomem *)hldev->legacy_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_toc:
+               if (offset > sizeof(struct vxge_hw_toc_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               *value = readq((void __iomem *)hldev->toc_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_common:
+               if (offset > sizeof(struct vxge_hw_common_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               *value = readq((void __iomem *)hldev->common_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_mrpcim:
+               if (!(hldev->access_rights &
+                       VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) {
+                       status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_mrpcim_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               *value = readq((void __iomem *)hldev->mrpcim_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_srpcim:
+               if (!(hldev->access_rights &
+                       VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM)) {
+                       status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+                       break;
+               }
+               if (index > VXGE_HW_TITAN_SRPCIM_REG_SPACES - 1) {
+                       status = VXGE_HW_ERR_INVALID_INDEX;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_srpcim_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               *value = readq((void __iomem *)hldev->srpcim_reg[index] +
+                               offset);
+               break;
+       case vxge_hw_mgmt_reg_type_vpmgmt:
+               if ((index > VXGE_HW_TITAN_VPMGMT_REG_SPACES - 1) ||
+                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
+                       status = VXGE_HW_ERR_INVALID_INDEX;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_vpmgmt_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               *value = readq((void __iomem *)hldev->vpmgmt_reg[index] +
+                               offset);
+               break;
+       case vxge_hw_mgmt_reg_type_vpath:
+               if ((index > VXGE_HW_TITAN_VPATH_REG_SPACES - 1) ||
+                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
+                       status = VXGE_HW_ERR_INVALID_INDEX;
+                       break;
+               }
+               if (index > VXGE_HW_TITAN_VPATH_REG_SPACES - 1) {
+                       status = VXGE_HW_ERR_INVALID_INDEX;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_vpath_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               *value = readq((void __iomem *)hldev->vpath_reg[index] +
+                               offset);
+               break;
+       default:
+               status = VXGE_HW_ERR_INVALID_TYPE;
+               break;
+       }
+
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_mgmt_reg_Write - Write Titan register.
+ */
+enum vxge_hw_status
+vxge_hw_mgmt_reg_write(struct __vxge_hw_device *hldev,
+                     enum vxge_hw_mgmt_reg_type type,
+                     u32 index, u32 offset, u64 value)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
+               status = VXGE_HW_ERR_INVALID_DEVICE;
+               goto exit;
+       }
+
+       switch (type) {
+       case vxge_hw_mgmt_reg_type_legacy:
+               if (offset > sizeof(struct vxge_hw_legacy_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               writeq(value, (void __iomem *)hldev->legacy_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_toc:
+               if (offset > sizeof(struct vxge_hw_toc_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               writeq(value, (void __iomem *)hldev->toc_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_common:
+               if (offset > sizeof(struct vxge_hw_common_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               writeq(value, (void __iomem *)hldev->common_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_mrpcim:
+               if (!(hldev->access_rights &
+                       VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) {
+                       status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_mrpcim_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               writeq(value, (void __iomem *)hldev->mrpcim_reg + offset);
+               break;
+       case vxge_hw_mgmt_reg_type_srpcim:
+               if (!(hldev->access_rights &
+                       VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM)) {
+                       status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+                       break;
+               }
+               if (index > VXGE_HW_TITAN_SRPCIM_REG_SPACES - 1) {
+                       status = VXGE_HW_ERR_INVALID_INDEX;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_srpcim_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               writeq(value, (void __iomem *)hldev->srpcim_reg[index] +
+                       offset);
+
+               break;
+       case vxge_hw_mgmt_reg_type_vpmgmt:
+               if ((index > VXGE_HW_TITAN_VPMGMT_REG_SPACES - 1) ||
+                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
+                       status = VXGE_HW_ERR_INVALID_INDEX;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_vpmgmt_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               writeq(value, (void __iomem *)hldev->vpmgmt_reg[index] +
+                       offset);
+               break;
+       case vxge_hw_mgmt_reg_type_vpath:
+               if ((index > VXGE_HW_TITAN_VPATH_REG_SPACES-1) ||
+                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
+                       status = VXGE_HW_ERR_INVALID_INDEX;
+                       break;
+               }
+               if (offset > sizeof(struct vxge_hw_vpath_reg) - 8) {
+                       status = VXGE_HW_ERR_INVALID_OFFSET;
+                       break;
+               }
+               writeq(value, (void __iomem *)hldev->vpath_reg[index] +
+                       offset);
+               break;
+       default:
+               status = VXGE_HW_ERR_INVALID_TYPE;
+               break;
+       }
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_fifo_mempool_item_alloc - Allocate List blocks for TxD
+ * list callback
+ * This function is callback passed to __vxge_hw_mempool_create to create memory
+ * pool for TxD list
+ */
+static void
+__vxge_hw_fifo_mempool_item_alloc(
+       struct vxge_hw_mempool *mempoolh,
+       u32 memblock_index, struct vxge_hw_mempool_dma *dma_object,
+       u32 index, u32 is_last)
+{
+       u32 memblock_item_idx;
+       struct __vxge_hw_fifo_txdl_priv *txdl_priv;
+       struct vxge_hw_fifo_txd *txdp =
+               (struct vxge_hw_fifo_txd *)mempoolh->items_arr[index];
+       struct __vxge_hw_fifo *fifo =
+                       (struct __vxge_hw_fifo *)mempoolh->userdata;
+       void *memblock = mempoolh->memblocks_arr[memblock_index];
+
+       vxge_assert(txdp);
+
+       txdp->host_control = (u64) (size_t)
+       __vxge_hw_mempool_item_priv(mempoolh, memblock_index, txdp,
+                                       &memblock_item_idx);
+
+       txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdp);
+
+       vxge_assert(txdl_priv);
+
+       fifo->channel.reserve_arr[fifo->channel.reserve_ptr - 1 - index] = txdp;
+
+       /* pre-format HW's TxDL's private */
+       txdl_priv->dma_offset = (char *)txdp - (char *)memblock;
+       txdl_priv->dma_addr = dma_object->addr + txdl_priv->dma_offset;
+       txdl_priv->dma_handle = dma_object->handle;
+       txdl_priv->memblock   = memblock;
+       txdl_priv->first_txdp = txdp;
+       txdl_priv->next_txdl_priv = NULL;
+       txdl_priv->alloc_frags = 0;
+
+       return;
+}
+
+/*
+ * __vxge_hw_fifo_create - Create a FIFO
+ * This function creates FIFO and initializes it.
+ */
+enum vxge_hw_status
+__vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp,
+                     struct vxge_hw_fifo_attr *attr)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_fifo *fifo;
+       struct vxge_hw_fifo_config *config;
+       u32 txdl_size, txdl_per_memblock;
+       struct vxge_hw_mempool_cbs fifo_mp_callback;
+       struct __vxge_hw_virtualpath *vpath;
+
+       if ((vp == NULL) || (attr == NULL)) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+       vpath = vp->vpath;
+       config = &vpath->hldev->config.vp_config[vpath->vp_id].fifo;
+
+       txdl_size = config->max_frags * sizeof(struct vxge_hw_fifo_txd);
+
+       txdl_per_memblock = config->memblock_size / txdl_size;
+
+       fifo = (struct __vxge_hw_fifo *)__vxge_hw_channel_allocate(vp,
+                                       VXGE_HW_CHANNEL_TYPE_FIFO,
+                                       config->fifo_blocks * txdl_per_memblock,
+                                       attr->per_txdl_space, attr->userdata);
+
+       if (fifo == NULL) {
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto exit;
+       }
+
+       vpath->fifoh = fifo;
+       fifo->nofl_db = vpath->nofl_db;
+
+       fifo->vp_id = vpath->vp_id;
+       fifo->vp_reg = vpath->vp_reg;
+       fifo->stats = &vpath->sw_stats->fifo_stats;
+
+       fifo->config = config;
+
+       /* apply "interrupts per txdl" attribute */
+       fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ;
+
+       if (fifo->config->intr)
+               fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST;
+
+       fifo->no_snoop_bits = config->no_snoop_bits;
+
+       /*
+        * FIFO memory management strategy:
+        *
+        * TxDL split into three independent parts:
+        *      - set of TxD's
+        *      - TxD HW private part
+        *      - driver private part
+        *
+        * Adaptative memory allocation used. i.e. Memory allocated on
+        * demand with the size which will fit into one memory block.
+        * One memory block may contain more than one TxDL.
+        *
+        * During "reserve" operations more memory can be allocated on demand
+        * for example due to FIFO full condition.
+        *
+        * Pool of memory memblocks never shrinks except in __vxge_hw_fifo_close
+        * routine which will essentially stop the channel and free resources.
+        */
+
+       /* TxDL common private size == TxDL private  +  driver private */
+       fifo->priv_size =
+               sizeof(struct __vxge_hw_fifo_txdl_priv) + attr->per_txdl_space;
+       fifo->priv_size = ((fifo->priv_size  +  VXGE_CACHE_LINE_SIZE - 1) /
+                       VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE;
+
+       fifo->per_txdl_space = attr->per_txdl_space;
+
+       /* recompute txdl size to be cacheline aligned */
+       fifo->txdl_size = txdl_size;
+       fifo->txdl_per_memblock = txdl_per_memblock;
+
+       fifo->txdl_term = attr->txdl_term;
+       fifo->callback = attr->callback;
+
+       if (fifo->txdl_per_memblock == 0) {
+               __vxge_hw_fifo_delete(vp);
+               status = VXGE_HW_ERR_INVALID_BLOCK_SIZE;
+               goto exit;
+       }
+
+       fifo_mp_callback.item_func_alloc = __vxge_hw_fifo_mempool_item_alloc;
+
+       fifo->mempool =
+               __vxge_hw_mempool_create(vpath->hldev,
+                       fifo->config->memblock_size,
+                       fifo->txdl_size,
+                       fifo->priv_size,
+                       (fifo->config->fifo_blocks * fifo->txdl_per_memblock),
+                       (fifo->config->fifo_blocks * fifo->txdl_per_memblock),
+                       &fifo_mp_callback,
+                       fifo);
+
+       if (fifo->mempool == NULL) {
+               __vxge_hw_fifo_delete(vp);
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto exit;
+       }
+
+       status = __vxge_hw_channel_initialize(&fifo->channel);
+       if (status != VXGE_HW_OK) {
+               __vxge_hw_fifo_delete(vp);
+               goto exit;
+       }
+
+       vxge_assert(fifo->channel.reserve_ptr);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_fifo_abort - Returns the TxD
+ * This function terminates the TxDs of fifo
+ */
+enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo)
+{
+       void *txdlh;
+
+       for (;;) {
+               vxge_hw_channel_dtr_try_complete(&fifo->channel, &txdlh);
+
+               if (txdlh == NULL)
+                       break;
+
+               vxge_hw_channel_dtr_complete(&fifo->channel);
+
+               if (fifo->txdl_term) {
+                       fifo->txdl_term(txdlh,
+                       VXGE_HW_TXDL_STATE_POSTED,
+                       fifo->channel.userdata);
+               }
+
+               vxge_hw_channel_dtr_free(&fifo->channel, txdlh);
+       }
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_fifo_reset - Resets the fifo
+ * This function resets the fifo during vpath reset operation
+ */
+enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       __vxge_hw_fifo_abort(fifo);
+       status = __vxge_hw_channel_reset(&fifo->channel);
+
+       return status;
+}
+
+/*
+ * __vxge_hw_fifo_delete - Removes the FIFO
+ * This function freeup the memory pool and removes the FIFO
+ */
+enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp)
+{
+       struct __vxge_hw_fifo *fifo = vp->vpath->fifoh;
+
+       __vxge_hw_fifo_abort(fifo);
+
+       if (fifo->mempool)
+               __vxge_hw_mempool_destroy(fifo->mempool);
+
+       vp->vpath->fifoh = NULL;
+
+       __vxge_hw_channel_free(&fifo->channel);
+
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_vpath_pci_read - Read the content of given address
+ *                          in pci config space.
+ * Read from the vpath pci config space.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_pci_read(struct __vxge_hw_virtualpath *vpath,
+                        u32 phy_func_0, u32 offset, u32 *val)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
+
+       val64 = VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(offset);
+
+       if (phy_func_0)
+               val64 |= VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0;
+
+       writeq(val64, &vp_reg->pci_config_access_cfg1);
+       wmb();
+       writeq(VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ,
+                       &vp_reg->pci_config_access_cfg2);
+       wmb();
+
+       status = __vxge_hw_device_register_poll(
+                       &vp_reg->pci_config_access_cfg2,
+                       VXGE_HW_INTR_MASK_ALL, VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&vp_reg->pci_config_access_status);
+
+       if (val64 & VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR) {
+               status = VXGE_HW_FAIL;
+               *val = 0;
+       } else
+               *val = (u32)vxge_bVALn(val64, 32, 32);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_func_id_get - Get the function id of the vpath.
+ * Returns the function number of the vpath.
+ */
+u32
+__vxge_hw_vpath_func_id_get(u32 vp_id,
+       struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg)
+{
+       u64 val64;
+
+       val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1);
+
+       return
+        (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64);
+}
+
+/*
+ * __vxge_hw_read_rts_ds - Program RTS steering critieria
+ */
+static inline void
+__vxge_hw_read_rts_ds(struct vxge_hw_vpath_reg __iomem *vpath_reg,
+                     u64 dta_struct_sel)
+{
+       writeq(0, &vpath_reg->rts_access_steer_ctrl);
+       wmb();
+       writeq(dta_struct_sel, &vpath_reg->rts_access_steer_data0);
+       writeq(0, &vpath_reg->rts_access_steer_data1);
+       wmb();
+       return;
+}
+
+
+/*
+ * __vxge_hw_vpath_card_info_get - Get the serial numbers,
+ * part number and product description.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_card_info_get(
+       u32 vp_id,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg,
+       struct vxge_hw_device_hw_info *hw_info)
+{
+       u32 i, j;
+       u64 val64;
+       u64 data1 = 0ULL;
+       u64 data2 = 0ULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       u8 *serial_number = hw_info->serial_number;
+       u8 *part_number = hw_info->part_number;
+       u8 *product_desc = hw_info->product_desc;
+
+       __vxge_hw_read_rts_ds(vpath_reg,
+               VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER);
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vpath_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+       if (status != VXGE_HW_OK)
+               return status;
+
+       val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+               data1 = readq(&vpath_reg->rts_access_steer_data0);
+               ((u64 *)serial_number)[0] = be64_to_cpu(data1);
+
+               data2 = readq(&vpath_reg->rts_access_steer_data1);
+               ((u64 *)serial_number)[1] = be64_to_cpu(data2);
+               status = VXGE_HW_OK;
+       } else
+               *serial_number = 0;
+
+       __vxge_hw_read_rts_ds(vpath_reg,
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER);
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vpath_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+       if (status != VXGE_HW_OK)
+               return status;
+
+       val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+               data1 = readq(&vpath_reg->rts_access_steer_data0);
+               ((u64 *)part_number)[0] = be64_to_cpu(data1);
+
+               data2 = readq(&vpath_reg->rts_access_steer_data1);
+               ((u64 *)part_number)[1] = be64_to_cpu(data2);
+
+               status = VXGE_HW_OK;
+
+       } else
+               *part_number = 0;
+
+       j = 0;
+
+       for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0;
+            i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) {
+
+               __vxge_hw_read_rts_ds(vpath_reg, i);
+
+               val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+               status = __vxge_hw_pio_mem_write64(val64,
+                               &vpath_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+               if (status != VXGE_HW_OK)
+                       return status;
+
+               val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+               if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+                       data1 = readq(&vpath_reg->rts_access_steer_data0);
+                       ((u64 *)product_desc)[j++] = be64_to_cpu(data1);
+
+                       data2 = readq(&vpath_reg->rts_access_steer_data1);
+                       ((u64 *)product_desc)[j++] = be64_to_cpu(data2);
+
+                       status = VXGE_HW_OK;
+               } else
+                       *product_desc = 0;
+       }
+
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_fw_ver_get - Get the fw version
+ * Returns FW Version
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_fw_ver_get(
+       u32 vp_id,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg,
+       struct vxge_hw_device_hw_info *hw_info)
+{
+       u64 val64;
+       u64 data1 = 0ULL;
+       u64 data2 = 0ULL;
+       struct vxge_hw_device_version *fw_version = &hw_info->fw_version;
+       struct vxge_hw_device_date *fw_date = &hw_info->fw_date;
+       struct vxge_hw_device_version *flash_version = &hw_info->flash_version;
+       struct vxge_hw_device_date *flash_date = &hw_info->flash_date;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vpath_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+               data1 = readq(&vpath_reg->rts_access_steer_data0);
+               data2 = readq(&vpath_reg->rts_access_steer_data1);
+
+               fw_date->day =
+                       (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(
+                                               data1);
+               fw_date->month =
+                       (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(
+                                               data1);
+               fw_date->year =
+                       (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(
+                                               data1);
+
+               snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d",
+                       fw_date->month, fw_date->day, fw_date->year);
+
+               fw_version->major =
+                   (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data1);
+               fw_version->minor =
+                   (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data1);
+               fw_version->build =
+                   (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data1);
+
+               snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
+                   fw_version->major, fw_version->minor, fw_version->build);
+
+               flash_date->day =
+                 (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data2);
+               flash_date->month =
+                (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data2);
+               flash_date->year =
+                (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data2);
+
+               snprintf(flash_date->date, VXGE_HW_FW_STRLEN,
+                       "%2.2d/%2.2d/%4.4d",
+                       flash_date->month, flash_date->day, flash_date->year);
+
+               flash_version->major =
+                (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data2);
+               flash_version->minor =
+                (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data2);
+               flash_version->build =
+                (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data2);
+
+               snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
+                       flash_version->major, flash_version->minor,
+                       flash_version->build);
+
+               status = VXGE_HW_OK;
+
+       } else
+               status = VXGE_HW_FAIL;
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode
+ * Returns pci function mode
+ */
+u64
+__vxge_hw_vpath_pci_func_mode_get(
+       u32  vp_id,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg)
+{
+       u64 val64;
+       u64 data1 = 0ULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       __vxge_hw_read_rts_ds(vpath_reg,
+               VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE);
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vpath_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+               data1 = readq(&vpath_reg->rts_access_steer_data0);
+               status = VXGE_HW_OK;
+       } else {
+               data1 = 0;
+               status = VXGE_HW_FAIL;
+       }
+exit:
+       return data1;
+}
+
+/**
+ * vxge_hw_device_flick_link_led - Flick (blink) link LED.
+ * @hldev: HW device.
+ * @on_off: TRUE if flickering to be on, FALSE to be off
+ *
+ * Flicker the link LED.
+ */
+enum vxge_hw_status
+vxge_hw_device_flick_link_led(struct __vxge_hw_device *hldev,
+                              u64 on_off)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       if (hldev == NULL) {
+               status = VXGE_HW_ERR_INVALID_DEVICE;
+               goto exit;
+       }
+
+       vp_reg = hldev->vpath_reg[hldev->first_vp_id];
+
+       writeq(0, &vp_reg->rts_access_steer_ctrl);
+       wmb();
+       writeq(on_off, &vp_reg->rts_access_steer_data0);
+       writeq(0, &vp_reg->rts_access_steer_data1);
+       wmb();
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vp_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_rts_table_get - Get the entries from RTS access tables
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_rts_table_get(
+       struct __vxge_hw_vpath_handle *vp,
+       u32 action, u32 rts_table, u32 offset, u64 *data1, u64 *data2)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+       vp_reg = vpath->vp_reg;
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset);
+
+       if ((rts_table ==
+               VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT) ||
+           (rts_table ==
+               VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT) ||
+           (rts_table ==
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK) ||
+           (rts_table ==
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY)) {
+               val64 = val64 | VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL;
+       }
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vp_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               vpath->hldev->config.device_poll_millis);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&vp_reg->rts_access_steer_ctrl);
+
+       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+               *data1 = readq(&vp_reg->rts_access_steer_data0);
+
+               if ((rts_table ==
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
+               (rts_table ==
+               VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) {
+                       *data2 = readq(&vp_reg->rts_access_steer_data1);
+               }
+               status = VXGE_HW_OK;
+       } else
+               status = VXGE_HW_FAIL;
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_rts_table_set - Set the entries of RTS access tables
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_rts_table_set(
+       struct __vxge_hw_vpath_handle *vp, u32 action, u32 rts_table,
+       u32 offset, u64 data1, u64 data2)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+       vp_reg = vpath->vp_reg;
+
+       writeq(data1, &vp_reg->rts_access_steer_data0);
+       wmb();
+
+       if ((rts_table == VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
+           (rts_table ==
+               VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) {
+               writeq(data2, &vp_reg->rts_access_steer_data1);
+               wmb();
+       }
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vp_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               vpath->hldev->config.device_poll_millis);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&vp_reg->rts_access_steer_ctrl);
+
+       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS)
+               status = VXGE_HW_OK;
+       else
+               status = VXGE_HW_FAIL;
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath
+ *               from MAC address table.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_addr_get(
+       u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg,
+       u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN])
+{
+       u32 i;
+       u64 val64;
+       u64 data1 = 0ULL;
+       u64 data2 = 0ULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vpath_reg->rts_access_steer_ctrl,
+                               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+                               VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+               data1 = readq(&vpath_reg->rts_access_steer_data0);
+               data2 = readq(&vpath_reg->rts_access_steer_data1);
+
+               data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1);
+               data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(
+                                                       data2);
+
+               for (i = ETH_ALEN; i > 0; i--) {
+                       macaddr[i-1] = (u8)(data1 & 0xFF);
+                       data1 >>= 8;
+
+                       macaddr_mask[i-1] = (u8)(data2 & 0xFF);
+                       data2 >>= 8;
+               }
+               status = VXGE_HW_OK;
+       } else
+               status = VXGE_HW_FAIL;
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_vpath_rts_rth_set - Set/configure RTS hashing.
+ */
+enum vxge_hw_status vxge_hw_vpath_rts_rth_set(
+                       struct __vxge_hw_vpath_handle *vp,
+                       enum vxge_hw_rth_algoritms algorithm,
+                       struct vxge_hw_rth_hash_types *hash_type,
+                       u16 bucket_size)
+{
+       u64 data0, data1;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_rts_table_get(vp,
+                    VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY,
+                    VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG,
+                       0, &data0, &data1);
+
+       data0 &= ~(VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(0xf) |
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(0x3));
+
+       data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_EN |
+       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(bucket_size) |
+       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(algorithm);
+
+       if (hash_type->hash_type_tcpipv4_en)
+               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV4_EN;
+
+       if (hash_type->hash_type_ipv4_en)
+               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV4_EN;
+
+       if (hash_type->hash_type_tcpipv6_en)
+               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EN;
+
+       if (hash_type->hash_type_ipv6_en)
+               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EN;
+
+       if (hash_type->hash_type_tcpipv6ex_en)
+               data0 |=
+               VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EX_EN;
+
+       if (hash_type->hash_type_ipv6ex_en)
+               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EX_EN;
+
+       if (VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ACTIVE_TABLE(data0))
+               data0 &= ~VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE;
+       else
+               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE;
+
+       status = __vxge_hw_vpath_rts_table_set(vp,
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY,
+               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG,
+               0, data0, 0);
+exit:
+       return status;
+}
+
+static void
+vxge_hw_rts_rth_data0_data1_get(u32 j, u64 *data0, u64 *data1,
+                               u16 flag, u8 *itable)
+{
+       switch (flag) {
+       case 1:
+               *data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_NUM(j)|
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN |
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA(
+                       itable[j]);
+       case 2:
+               *data0 |=
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(j)|
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN |
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA(
+                       itable[j]);
+       case 3:
+               *data1 = VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(j)|
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN |
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA(
+                       itable[j]);
+       case 4:
+               *data1 |=
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(j)|
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN |
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(
+                       itable[j]);
+       default:
+               return;
+       }
+}
+/*
+ * vxge_hw_vpath_rts_rth_itable_set - Set/configure indirection table (IT).
+ */
+enum vxge_hw_status vxge_hw_vpath_rts_rth_itable_set(
+                       struct __vxge_hw_vpath_handle **vpath_handles,
+                       u32 vpath_count,
+                       u8 *mtable,
+                       u8 *itable,
+                       u32 itable_size)
+{
+       u32 i, j, action, rts_table;
+       u64 data0;
+       u64 data1;
+       u32 max_entries;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_vpath_handle *vp = vpath_handles[0];
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       max_entries = (((u32)1) << itable_size);
+
+       if (vp->vpath->hldev->config.rth_it_type
+                               == VXGE_HW_RTH_IT_TYPE_SOLO_IT) {
+               action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY;
+               rts_table =
+                       VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT;
+
+               for (j = 0; j < max_entries; j++) {
+
+                       data1 = 0;
+
+                       data0 =
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(
+                               itable[j]);
+
+                       status = __vxge_hw_vpath_rts_table_set(vpath_handles[0],
+                               action, rts_table, j, data0, data1);
+
+                       if (status != VXGE_HW_OK)
+                               goto exit;
+               }
+
+               for (j = 0; j < max_entries; j++) {
+
+                       data1 = 0;
+
+                       data0 =
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_ENTRY_EN |
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(
+                               itable[j]);
+
+                       status = __vxge_hw_vpath_rts_table_set(
+                               vpath_handles[mtable[itable[j]]], action,
+                               rts_table, j, data0, data1);
+
+                       if (status != VXGE_HW_OK)
+                               goto exit;
+               }
+       } else {
+               action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY;
+               rts_table =
+                       VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT;
+               for (i = 0; i < vpath_count; i++) {
+
+                       for (j = 0; j < max_entries;) {
+
+                               data0 = 0;
+                               data1 = 0;
+
+                               while (j < max_entries) {
+                                       if (mtable[itable[j]] != i) {
+                                               j++;
+                                               continue;
+                                       }
+                                       vxge_hw_rts_rth_data0_data1_get(j,
+                                               &data0, &data1, 1, itable);
+                                       j++;
+                                       break;
+                               }
+
+                               while (j < max_entries) {
+                                       if (mtable[itable[j]] != i) {
+                                               j++;
+                                               continue;
+                                       }
+                                       vxge_hw_rts_rth_data0_data1_get(j,
+                                               &data0, &data1, 2, itable);
+                                       j++;
+                                       break;
+                               }
+
+                               while (j < max_entries) {
+                                       if (mtable[itable[j]] != i) {
+                                               j++;
+                                               continue;
+                                       }
+                                       vxge_hw_rts_rth_data0_data1_get(j,
+                                               &data0, &data1, 3, itable);
+                                       j++;
+                                       break;
+                               }
+
+                               while (j < max_entries) {
+                                       if (mtable[itable[j]] != i) {
+                                               j++;
+                                               continue;
+                                       }
+                                       vxge_hw_rts_rth_data0_data1_get(j,
+                                               &data0, &data1, 4, itable);
+                                       j++;
+                                       break;
+                               }
+
+                               if (data0 != 0) {
+                                       status = __vxge_hw_vpath_rts_table_set(
+                                                       vpath_handles[i],
+                                                       action, rts_table,
+                                                       0, data0, data1);
+
+                                       if (status != VXGE_HW_OK)
+                                               goto exit;
+                               }
+                       }
+               }
+       }
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_check_leak - Check for memory leak
+ * @ringh: Handle to the ring object used for receive
+ *
+ * If PRC_RXD_DOORBELL_VPn.NEW_QW_CNT is larger or equal to
+ * PRC_CFG6_VPn.RXD_SPAT then a leak has occurred.
+ * Returns: VXGE_HW_FAIL, if leak has occurred.
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_check_leak(struct __vxge_hw_ring *ring)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       u64 rxd_new_count, rxd_spat;
+
+       if (ring == NULL)
+               return status;
+
+       rxd_new_count = readl(&ring->vp_reg->prc_rxd_doorbell);
+       rxd_spat = readq(&ring->vp_reg->prc_cfg6);
+       rxd_spat = VXGE_HW_PRC_CFG6_RXD_SPAT(rxd_spat);
+
+       if (rxd_new_count >= rxd_spat)
+               status = VXGE_HW_FAIL;
+
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_mgmt_read
+ * This routine reads the vpath_mgmt registers
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_mgmt_read(
+       struct __vxge_hw_device *hldev,
+       struct __vxge_hw_virtualpath *vpath)
+{
+       u32 i, mtu = 0, max_pyld = 0;
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       for (i = 0; i < VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) {
+
+               val64 = readq(&vpath->vpmgmt_reg->
+                               rxmac_cfg0_port_vpmgmt_clone[i]);
+               max_pyld =
+                       (u32)
+                       VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN
+                       (val64);
+               if (mtu < max_pyld)
+                       mtu = max_pyld;
+       }
+
+       vpath->max_mtu = mtu + VXGE_HW_MAC_HEADER_MAX_SIZE;
+
+       val64 = readq(&vpath->vpmgmt_reg->xmac_vsport_choices_vp);
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               if (val64 & vxge_mBIT(i))
+                       vpath->vsport_number = i;
+       }
+
+       val64 = readq(&vpath->vpmgmt_reg->xgmac_gen_status_vpmgmt_clone);
+
+       if (val64 & VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK)
+               VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_UP);
+       else
+               VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_DOWN);
+
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_reset_check - Check if resetting the vpath completed
+ * This routine checks the vpath_rst_in_prog register to see if
+ * adapter completed the reset process for the vpath
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath)
+{
+       enum vxge_hw_status status;
+
+       status = __vxge_hw_device_register_poll(
+                       &vpath->hldev->common_reg->vpath_rst_in_prog,
+                       VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(
+                               1 << (16 - vpath->vp_id)),
+                       vpath->hldev->config.device_poll_millis);
+
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_reset
+ * This routine resets the vpath on the device
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_reset(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       val64 = VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(1 << (16 - vp_id));
+
+       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+                               &hldev->common_reg->cmn_rsthdlr_cfg0);
+
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_sw_reset
+ * This routine resets the vpath structures
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_sw_reset(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_virtualpath *vpath;
+
+       vpath = (struct __vxge_hw_virtualpath *)&hldev->virtual_paths[vp_id];
+
+       if (vpath->ringh) {
+               status = __vxge_hw_ring_reset(vpath->ringh);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+       }
+
+       if (vpath->fifoh)
+               status = __vxge_hw_fifo_reset(vpath->fifoh);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_prc_configure
+ * This routine configures the prc registers of virtual path using the config
+ * passed
+ */
+void
+__vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       struct vxge_hw_vp_config *vp_config;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       vpath = &hldev->virtual_paths[vp_id];
+       vp_reg = vpath->vp_reg;
+       vp_config = vpath->vp_config;
+
+       if (vp_config->ring.enable == VXGE_HW_RING_DISABLE)
+               return;
+
+       val64 = readq(&vp_reg->prc_cfg1);
+       val64 |= VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE;
+       writeq(val64, &vp_reg->prc_cfg1);
+
+       val64 = readq(&vpath->vp_reg->prc_cfg6);
+       val64 |= VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN;
+       writeq(val64, &vpath->vp_reg->prc_cfg6);
+
+       val64 = readq(&vp_reg->prc_cfg7);
+
+       if (vpath->vp_config->ring.scatter_mode !=
+               VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT) {
+
+               val64 &= ~VXGE_HW_PRC_CFG7_SCATTER_MODE(0x3);
+
+               switch (vpath->vp_config->ring.scatter_mode) {
+               case VXGE_HW_RING_SCATTER_MODE_A:
+                       val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE(
+                                       VXGE_HW_PRC_CFG7_SCATTER_MODE_A);
+                       break;
+               case VXGE_HW_RING_SCATTER_MODE_B:
+                       val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE(
+                                       VXGE_HW_PRC_CFG7_SCATTER_MODE_B);
+                       break;
+               case VXGE_HW_RING_SCATTER_MODE_C:
+                       val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE(
+                                       VXGE_HW_PRC_CFG7_SCATTER_MODE_C);
+                       break;
+               }
+       }
+
+       writeq(val64, &vp_reg->prc_cfg7);
+
+       writeq(VXGE_HW_PRC_CFG5_RXD0_ADD(
+                               __vxge_hw_ring_first_block_address_get(
+                                       vpath->ringh) >> 3), &vp_reg->prc_cfg5);
+
+       val64 = readq(&vp_reg->prc_cfg4);
+       val64 |= VXGE_HW_PRC_CFG4_IN_SVC;
+       val64 &= ~VXGE_HW_PRC_CFG4_RING_MODE(0x3);
+
+       val64 |= VXGE_HW_PRC_CFG4_RING_MODE(
+                       VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER);
+
+       if (hldev->config.rth_en == VXGE_HW_RTH_DISABLE)
+               val64 |= VXGE_HW_PRC_CFG4_RTH_DISABLE;
+       else
+               val64 &= ~VXGE_HW_PRC_CFG4_RTH_DISABLE;
+
+       writeq(val64, &vp_reg->prc_cfg4);
+       return;
+}
+
+/*
+ * __vxge_hw_vpath_kdfc_configure
+ * This routine configures the kdfc registers of virtual path using the
+ * config passed
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_kdfc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       u64 val64;
+       u64 vpath_stride;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_virtualpath *vpath;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       vpath = &hldev->virtual_paths[vp_id];
+       vp_reg = vpath->vp_reg;
+       status = __vxge_hw_kdfc_swapper_set(hldev->legacy_reg, vp_reg);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       val64 = readq(&vp_reg->kdfc_drbl_triplet_total);
+
+       vpath->max_kdfc_db =
+               (u32)VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE(
+                       val64+1)/2;
+
+       if (vpath->vp_config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
+
+               vpath->max_nofl_db = vpath->max_kdfc_db;
+
+               if (vpath->max_nofl_db <
+                       ((vpath->vp_config->fifo.memblock_size /
+                       (vpath->vp_config->fifo.max_frags *
+                       sizeof(struct vxge_hw_fifo_txd))) *
+                       vpath->vp_config->fifo.fifo_blocks)) {
+
+                       return VXGE_HW_BADCFG_FIFO_BLOCKS;
+               }
+               val64 = VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0(
+                               (vpath->max_nofl_db*2)-1);
+       }
+
+       writeq(val64, &vp_reg->kdfc_fifo_trpl_partition);
+
+       writeq(VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE,
+               &vp_reg->kdfc_fifo_trpl_ctrl);
+
+       val64 = readq(&vp_reg->kdfc_trpl_fifo_0_ctrl);
+
+       val64 &= ~(VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(0x3) |
+                  VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0xFF));
+
+       val64 |= VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(
+                VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY) |
+#ifndef __BIG_ENDIAN
+                VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN |
+#endif
+                VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0);
+
+       writeq(val64, &vp_reg->kdfc_trpl_fifo_0_ctrl);
+       writeq((u64)0, &vp_reg->kdfc_trpl_fifo_0_wb_address);
+       wmb();
+       vpath_stride = readq(&hldev->toc_reg->toc_kdfc_vpath_stride);
+
+       vpath->nofl_db =
+               (struct __vxge_hw_non_offload_db_wrapper __iomem *)
+               (hldev->kdfc + (vp_id *
+               VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE(
+                                       vpath_stride)));
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_mac_configure
+ * This routine configures the mac of virtual path using the config passed
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_virtualpath *vpath;
+       struct vxge_hw_vp_config *vp_config;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       vpath = &hldev->virtual_paths[vp_id];
+       vp_reg = vpath->vp_reg;
+       vp_config = vpath->vp_config;
+
+       writeq(VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER(
+                       vpath->vsport_number), &vp_reg->xmac_vsport_choice);
+
+       if (vp_config->ring.enable == VXGE_HW_RING_ENABLE) {
+
+               val64 = readq(&vp_reg->xmac_rpa_vcfg);
+
+               if (vp_config->rpa_strip_vlan_tag !=
+                       VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) {
+                       if (vp_config->rpa_strip_vlan_tag)
+                               val64 |= VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG;
+                       else
+                               val64 &= ~VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG;
+               }
+
+               writeq(val64, &vp_reg->xmac_rpa_vcfg);
+               val64 = readq(&vp_reg->rxmac_vcfg0);
+
+               if (vp_config->mtu !=
+                               VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) {
+                       val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
+                       if ((vp_config->mtu  +
+                               VXGE_HW_MAC_HEADER_MAX_SIZE) < vpath->max_mtu)
+                               val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(
+                                       vp_config->mtu  +
+                                       VXGE_HW_MAC_HEADER_MAX_SIZE);
+                       else
+                               val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(
+                                       vpath->max_mtu);
+               }
+
+               writeq(val64, &vp_reg->rxmac_vcfg0);
+
+               val64 = readq(&vp_reg->rxmac_vcfg1);
+
+               val64 &= ~(VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(0x3) |
+                       VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE);
+
+               if (hldev->config.rth_it_type ==
+                               VXGE_HW_RTH_IT_TYPE_MULTI_IT) {
+                       val64 |= VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(
+                               0x2) |
+                               VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE;
+               }
+
+               writeq(val64, &vp_reg->rxmac_vcfg1);
+       }
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_tim_configure
+ * This routine configures the tim registers of virtual path using the config
+ * passed
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_virtualpath *vpath;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+       struct vxge_hw_vp_config *config;
+
+       vpath = &hldev->virtual_paths[vp_id];
+       vp_reg = vpath->vp_reg;
+       config = vpath->vp_config;
+
+       writeq((u64)0, &vp_reg->tim_dest_addr);
+       writeq((u64)0, &vp_reg->tim_vpath_map);
+       writeq((u64)0, &vp_reg->tim_bitmap);
+       writeq((u64)0, &vp_reg->tim_remap);
+
+       if (config->ring.enable == VXGE_HW_RING_ENABLE)
+               writeq(VXGE_HW_TIM_RING_ASSN_INT_NUM(
+                       (vp_id * VXGE_HW_MAX_INTR_PER_VP) +
+                       VXGE_HW_VPATH_INTR_RX), &vp_reg->tim_ring_assn);
+
+       val64 = readq(&vp_reg->tim_pci_cfg);
+       val64 |= VXGE_HW_TIM_PCI_CFG_ADD_PAD;
+       writeq(val64, &vp_reg->tim_pci_cfg);
+
+       if (config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
+
+               val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
+
+               if (config->tti.btimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
+                               0x3ffffff);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
+                                       config->tti.btimer_val);
+               }
+
+               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN;
+
+               if (config->tti.timer_ac_en != VXGE_HW_USE_FLASH_DEFAULT) {
+                       if (config->tti.timer_ac_en)
+                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
+                       else
+                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
+               }
+
+               if (config->tti.timer_ci_en != VXGE_HW_USE_FLASH_DEFAULT) {
+                       if (config->tti.timer_ci_en)
+                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
+                       else
+                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
+               }
+
+               if (config->tti.urange_a != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(
+                                       config->tti.urange_a);
+               }
+
+               if (config->tti.urange_b != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(
+                                       config->tti.urange_b);
+               }
+
+               if (config->tti.urange_c != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(
+                                       config->tti.urange_c);
+               }
+
+               writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
+               val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]);
+
+               if (config->tti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(
+                                               config->tti.uec_a);
+               }
+
+               if (config->tti.uec_b != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(
+                                               config->tti.uec_b);
+               }
+
+               if (config->tti.uec_c != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(
+                                               config->tti.uec_c);
+               }
+
+               if (config->tti.uec_d != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(
+                                               config->tti.uec_d);
+               }
+
+               writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]);
+               val64 = readq(&vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]);
+
+               if (config->tti.timer_ri_en != VXGE_HW_USE_FLASH_DEFAULT) {
+                       if (config->tti.timer_ri_en)
+                               val64 |= VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
+                       else
+                               val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
+               }
+
+               if (config->tti.rtimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
+                                       0x3ffffff);
+                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
+                                       config->tti.rtimer_val);
+               }
+
+               if (config->tti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(
+                                       config->tti.util_sel);
+               }
+
+               if (config->tti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
+                                       0x3ffffff);
+                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
+                                       config->tti.ltimer_val);
+               }
+
+               writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]);
+       }
+
+       if (config->ring.enable == VXGE_HW_RING_ENABLE) {
+
+               val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]);
+
+               if (config->rti.btimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
+                                       0x3ffffff);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
+                                       config->rti.btimer_val);
+               }
+
+               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN;
+
+               if (config->rti.timer_ac_en != VXGE_HW_USE_FLASH_DEFAULT) {
+                       if (config->rti.timer_ac_en)
+                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
+                       else
+                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
+               }
+
+               if (config->rti.timer_ci_en != VXGE_HW_USE_FLASH_DEFAULT) {
+                       if (config->rti.timer_ci_en)
+                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
+                       else
+                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
+               }
+
+               if (config->rti.urange_a != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(
+                                       config->rti.urange_a);
+               }
+
+               if (config->rti.urange_b != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(
+                                       config->rti.urange_b);
+               }
+
+               if (config->rti.urange_c != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(
+                                       config->rti.urange_c);
+               }
+
+               writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]);
+               val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]);
+
+               if (config->rti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(
+                                               config->rti.uec_a);
+               }
+
+               if (config->rti.uec_b != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(
+                                               config->rti.uec_b);
+               }
+
+               if (config->rti.uec_c != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(
+                                               config->rti.uec_c);
+               }
+
+               if (config->rti.uec_d != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(0xffff);
+                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(
+                                               config->rti.uec_d);
+               }
+
+               writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]);
+               val64 = readq(&vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]);
+
+               if (config->rti.timer_ri_en != VXGE_HW_USE_FLASH_DEFAULT) {
+                       if (config->rti.timer_ri_en)
+                               val64 |= VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
+                       else
+                               val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
+               }
+
+               if (config->rti.rtimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
+                                       0x3ffffff);
+                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
+                                       config->rti.rtimer_val);
+               }
+
+               if (config->rti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f);
+                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(
+                                       config->rti.util_sel);
+               }
+
+               if (config->rti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
+                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
+                                       0x3ffffff);
+                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
+                                       config->rti.ltimer_val);
+               }
+
+               writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]);
+       }
+
+       val64 = 0;
+       writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_EINTA]);
+       writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_EINTA]);
+       writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_EINTA]);
+       writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_BMAP]);
+       writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_BMAP]);
+       writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_BMAP]);
+
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_initialize
+ * This routine is the final phase of init which initializes the
+ * registers of the vpath using the configuration passed.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       u64 val64;
+       u32 val32;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_virtualpath *vpath;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       vpath = &hldev->virtual_paths[vp_id];
+
+       if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) {
+               status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE;
+               goto exit;
+       }
+       vp_reg = vpath->vp_reg;
+
+       status =  __vxge_hw_vpath_swapper_set(vpath->vp_reg);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       status =  __vxge_hw_vpath_mac_configure(hldev, vp_id);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       status =  __vxge_hw_vpath_kdfc_configure(hldev, vp_id);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       status = __vxge_hw_vpath_tim_configure(hldev, vp_id);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       writeq(0, &vp_reg->gendma_int);
+
+       val64 = readq(&vp_reg->rtdma_rd_optimization_ctrl);
+
+       /* Get MRRS value from device control */
+       status  = __vxge_hw_vpath_pci_read(vpath, 1, 0x78, &val32);
+
+       if (status == VXGE_HW_OK) {
+               val32 = (val32 & VXGE_HW_PCI_EXP_DEVCTL_READRQ) >> 12;
+               val64 &=
+                   ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(7));
+               val64 |=
+                   VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val32);
+
+               val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE;
+       }
+
+       val64 &= ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(7));
+       val64 |=
+           VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(
+                   VXGE_HW_MAX_PAYLOAD_SIZE_512);
+
+       val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN;
+       writeq(val64, &vp_reg->rtdma_rd_optimization_ctrl);
+
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vp_initialize - Initialize Virtual Path structure
+ * This routine is the initial phase of init which resets the vpath and
+ * initializes the software support structures.
+ */
+enum vxge_hw_status
+__vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
+                       struct vxge_hw_vp_config *config)
+{
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) {
+               status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE;
+               goto exit;
+       }
+
+       vpath = &hldev->virtual_paths[vp_id];
+
+       vpath->vp_id = vp_id;
+       vpath->vp_open = VXGE_HW_VP_OPEN;
+       vpath->hldev = hldev;
+       vpath->vp_config = config;
+       vpath->vp_reg = hldev->vpath_reg[vp_id];
+       vpath->vpmgmt_reg = hldev->vpmgmt_reg[vp_id];
+
+       __vxge_hw_vpath_reset(hldev, vp_id);
+
+       status = __vxge_hw_vpath_reset_check(vpath);
+
+       if (status != VXGE_HW_OK) {
+               memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_mgmt_read(hldev, vpath);
+
+       if (status != VXGE_HW_OK) {
+               memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
+               goto exit;
+       }
+
+       INIT_LIST_HEAD(&vpath->vpath_handles);
+
+       vpath->sw_stats = &hldev->stats.sw_dev_info_stats.vpath_info[vp_id];
+
+       VXGE_HW_DEVICE_TIM_INT_MASK_SET(hldev->tim_int_mask0,
+               hldev->tim_int_mask1, vp_id);
+
+       status = __vxge_hw_vpath_initialize(hldev, vp_id);
+
+       if (status != VXGE_HW_OK)
+               __vxge_hw_vp_terminate(hldev, vp_id);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vp_terminate - Terminate Virtual Path structure
+ * This routine closes all channels it opened and freeup memory
+ */
+void
+__vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+       struct __vxge_hw_virtualpath *vpath;
+
+       vpath = &hldev->virtual_paths[vp_id];
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN)
+               goto exit;
+
+       VXGE_HW_DEVICE_TIM_INT_MASK_RESET(vpath->hldev->tim_int_mask0,
+               vpath->hldev->tim_int_mask1, vpath->vp_id);
+       hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL;
+
+       memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
+exit:
+       return;
+}
+
+/*
+ * vxge_hw_vpath_mtu_set - Set MTU.
+ * Set new MTU value. Example, to use jumbo frames:
+ * vxge_hw_vpath_mtu_set(my_device, 9600);
+ */
+enum vxge_hw_status
+vxge_hw_vpath_mtu_set(struct __vxge_hw_vpath_handle *vp, u32 new_mtu)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_virtualpath *vpath;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+       vpath = vp->vpath;
+
+       new_mtu += VXGE_HW_MAC_HEADER_MAX_SIZE;
+
+       if ((new_mtu < VXGE_HW_MIN_MTU) || (new_mtu > vpath->max_mtu))
+               status = VXGE_HW_ERR_INVALID_MTU_SIZE;
+
+       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
+
+       val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
+       val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(new_mtu);
+
+       writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
+
+       vpath->vp_config->mtu = new_mtu - VXGE_HW_MAC_HEADER_MAX_SIZE;
+
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_vpath_open - Open a virtual path on a given adapter
+ * This function is used to open access to virtual path of an
+ * adapter for offload, GRO operations. This function returns
+ * synchronously.
+ */
+enum vxge_hw_status
+vxge_hw_vpath_open(struct __vxge_hw_device *hldev,
+                  struct vxge_hw_vpath_attr *attr,
+                  struct __vxge_hw_vpath_handle **vpath_handle)
+{
+       struct __vxge_hw_virtualpath *vpath;
+       struct __vxge_hw_vpath_handle *vp;
+       enum vxge_hw_status status;
+
+       vpath = &hldev->virtual_paths[attr->vp_id];
+
+       if (vpath->vp_open == VXGE_HW_VP_OPEN) {
+               status = VXGE_HW_ERR_INVALID_STATE;
+               goto vpath_open_exit1;
+       }
+
+       status = __vxge_hw_vp_initialize(hldev, attr->vp_id,
+                       &hldev->config.vp_config[attr->vp_id]);
+
+       if (status != VXGE_HW_OK)
+               goto vpath_open_exit1;
+
+       vp = (struct __vxge_hw_vpath_handle *)
+               vmalloc(sizeof(struct __vxge_hw_vpath_handle));
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto vpath_open_exit2;
+       }
+
+       memset(vp, 0, sizeof(struct __vxge_hw_vpath_handle));
+
+       vp->vpath = vpath;
+
+       if (vpath->vp_config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
+               status = __vxge_hw_fifo_create(vp, &attr->fifo_attr);
+               if (status != VXGE_HW_OK)
+                       goto vpath_open_exit6;
+       }
+
+       if (vpath->vp_config->ring.enable == VXGE_HW_RING_ENABLE) {
+               status = __vxge_hw_ring_create(vp, &attr->ring_attr);
+               if (status != VXGE_HW_OK)
+                       goto vpath_open_exit7;
+
+               __vxge_hw_vpath_prc_configure(hldev, attr->vp_id);
+       }
+
+       vpath->fifoh->tx_intr_num =
+               (attr->vp_id * VXGE_HW_MAX_INTR_PER_VP)  +
+                       VXGE_HW_VPATH_INTR_TX;
+
+       vpath->stats_block = __vxge_hw_blockpool_block_allocate(hldev,
+                               VXGE_HW_BLOCK_SIZE);
+
+       if (vpath->stats_block == NULL) {
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+               goto vpath_open_exit8;
+       }
+
+       vpath->hw_stats = (struct vxge_hw_vpath_stats_hw_info *)vpath->
+                       stats_block->memblock;
+       memset(vpath->hw_stats, 0,
+               sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+       hldev->stats.hw_dev_info_stats.vpath_info[attr->vp_id] =
+                                               vpath->hw_stats;
+
+       vpath->hw_stats_sav =
+               &hldev->stats.hw_dev_info_stats.vpath_info_sav[attr->vp_id];
+       memset(vpath->hw_stats_sav, 0,
+                       sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+       writeq(vpath->stats_block->dma_addr, &vpath->vp_reg->stats_cfg);
+
+       status = vxge_hw_vpath_stats_enable(vp);
+       if (status != VXGE_HW_OK)
+               goto vpath_open_exit8;
+
+       list_add(&vp->item, &vpath->vpath_handles);
+
+       hldev->vpaths_deployed |= vxge_mBIT(vpath->vp_id);
+
+       *vpath_handle = vp;
+
+       attr->fifo_attr.userdata = vpath->fifoh;
+       attr->ring_attr.userdata = vpath->ringh;
+
+       return VXGE_HW_OK;
+
+vpath_open_exit8:
+       if (vpath->ringh != NULL)
+               __vxge_hw_ring_delete(vp);
+vpath_open_exit7:
+       if (vpath->fifoh != NULL)
+               __vxge_hw_fifo_delete(vp);
+vpath_open_exit6:
+       vfree(vp);
+vpath_open_exit2:
+       __vxge_hw_vp_terminate(hldev, attr->vp_id);
+vpath_open_exit1:
+
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_rx_doorbell_post - Close the handle got from previous vpath
+ * (vpath) open
+ * @vp: Handle got from previous vpath open
+ *
+ * This function is used to close access to virtual path opened
+ * earlier.
+ */
+void
+vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp)
+{
+       struct __vxge_hw_virtualpath *vpath = NULL;
+       u64 new_count, val64, val164;
+       struct __vxge_hw_ring *ring;
+
+       vpath = vp->vpath;
+       ring = vpath->ringh;
+
+       new_count = readq(&vpath->vp_reg->rxdmem_size);
+       new_count &= 0x1fff;
+       val164 = (VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count));
+
+       writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val164),
+               &vpath->vp_reg->prc_rxd_doorbell);
+       readl(&vpath->vp_reg->prc_rxd_doorbell);
+
+       val164 /= 2;
+       val64 = readq(&vpath->vp_reg->prc_cfg6);
+       val64 = VXGE_HW_PRC_CFG6_RXD_SPAT(val64);
+       val64 &= 0x1ff;
+
+       /*
+        * Each RxD is of 4 qwords
+        */
+       new_count -= (val64 + 1);
+       val64 = min(val164, new_count) / 4;
+
+       ring->rxds_limit = min(ring->rxds_limit, val64);
+       if (ring->rxds_limit < 4)
+               ring->rxds_limit = 4;
+}
+
+/*
+ * vxge_hw_vpath_close - Close the handle got from previous vpath (vpath) open
+ * This function is used to close access to virtual path opened
+ * earlier.
+ */
+enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp)
+{
+       struct __vxge_hw_virtualpath *vpath = NULL;
+       struct __vxge_hw_device *devh = NULL;
+       u32 vp_id = vp->vpath->vp_id;
+       u32 is_empty = TRUE;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       vpath = vp->vpath;
+       devh = vpath->hldev;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto vpath_close_exit;
+       }
+
+       list_del(&vp->item);
+
+       if (!list_empty(&vpath->vpath_handles)) {
+               list_add(&vp->item, &vpath->vpath_handles);
+               is_empty = FALSE;
+       }
+
+       if (!is_empty) {
+               status = VXGE_HW_FAIL;
+               goto vpath_close_exit;
+       }
+
+       devh->vpaths_deployed &= ~vxge_mBIT(vp_id);
+
+       if (vpath->ringh != NULL)
+               __vxge_hw_ring_delete(vp);
+
+       if (vpath->fifoh != NULL)
+               __vxge_hw_fifo_delete(vp);
+
+       if (vpath->stats_block != NULL)
+               __vxge_hw_blockpool_block_free(devh, vpath->stats_block);
+
+       vfree(vp);
+
+       __vxge_hw_vp_terminate(devh, vp_id);
+
+       vpath->vp_open = VXGE_HW_VP_NOT_OPEN;
+
+vpath_close_exit:
+       return status;
+}
+
+/*
+ * vxge_hw_vpath_reset - Resets vpath
+ * This function is used to request a reset of vpath
+ */
+enum vxge_hw_status vxge_hw_vpath_reset(struct __vxge_hw_vpath_handle *vp)
+{
+       enum vxge_hw_status status;
+       u32 vp_id;
+       struct __vxge_hw_virtualpath *vpath = vp->vpath;
+
+       vp_id = vpath->vp_id;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_reset(vpath->hldev, vp_id);
+       if (status == VXGE_HW_OK)
+               vpath->sw_stats->soft_reset_cnt++;
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_vpath_recover_from_reset - Poll for reset complete and re-initialize.
+ * This function poll's for the vpath reset completion and re initializes
+ * the vpath.
+ */
+enum vxge_hw_status
+vxge_hw_vpath_recover_from_reset(struct __vxge_hw_vpath_handle *vp)
+{
+       struct __vxge_hw_virtualpath *vpath = NULL;
+       enum vxge_hw_status status;
+       struct __vxge_hw_device *hldev;
+       u32 vp_id;
+
+       vp_id = vp->vpath->vp_id;
+       vpath = vp->vpath;
+       hldev = vpath->hldev;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_reset_check(vpath);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       status = __vxge_hw_vpath_sw_reset(hldev, vp_id);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       status = __vxge_hw_vpath_initialize(hldev, vp_id);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       if (vpath->ringh != NULL)
+               __vxge_hw_vpath_prc_configure(hldev, vp_id);
+
+       memset(vpath->hw_stats, 0,
+               sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+       memset(vpath->hw_stats_sav, 0,
+               sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+       writeq(vpath->stats_block->dma_addr,
+               &vpath->vp_reg->stats_cfg);
+
+       status = vxge_hw_vpath_stats_enable(vp);
+
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_vpath_enable - Enable vpath.
+ * This routine clears the vpath reset thereby enabling a vpath
+ * to start forwarding frames and generating interrupts.
+ */
+void
+vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp)
+{
+       struct __vxge_hw_device *hldev;
+       u64 val64;
+
+       hldev = vp->vpath->hldev;
+
+       val64 = VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET(
+               1 << (16 - vp->vpath->vp_id));
+
+       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+               &hldev->common_reg->cmn_rsthdlr_cfg1);
+}
+
+/*
+ * vxge_hw_vpath_stats_enable - Enable vpath h/wstatistics.
+ * Enable the DMA vpath statistics. The function is to be called to re-enable
+ * the adapter to update stats into the host memory
+ */
+enum vxge_hw_status
+vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vp)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_virtualpath *vpath;
+
+       vpath = vp->vpath;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+
+       memcpy(vpath->hw_stats_sav, vpath->hw_stats,
+                       sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+       status = __vxge_hw_vpath_stats_get(vpath, vpath->hw_stats);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_stats_access - Get the statistics from the given location
+ *                           and offset and perform an operation
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath,
+                            u32 operation, u32 offset, u64 *stat)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto vpath_stats_access_exit;
+       }
+
+       vp_reg = vpath->vp_reg;
+
+       val64 =  VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(operation) |
+                VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE |
+                VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(offset);
+
+       status = __vxge_hw_pio_mem_write64(val64,
+                               &vp_reg->xmac_stats_access_cmd,
+                               VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE,
+                               vpath->hldev->config.device_poll_millis);
+
+       if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ))
+               *stat = readq(&vp_reg->xmac_stats_access_data);
+       else
+               *stat = 0;
+
+vpath_stats_access_exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_xmac_tx_stats_get - Get the TX Statistics of a vpath
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_xmac_tx_stats_get(
+       struct __vxge_hw_virtualpath *vpath,
+       struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats)
+{
+       u64 *val64;
+       int i;
+       u32 offset = VXGE_HW_STATS_VPATH_TX_OFFSET;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       val64 = (u64 *) vpath_tx_stats;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+
+       for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_tx_stats) / 8; i++) {
+               status = __vxge_hw_vpath_stats_access(vpath,
+                                       VXGE_HW_STATS_OP_READ,
+                                       offset, val64);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+               offset++;
+               val64++;
+       }
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_xmac_rx_stats_get - Get the RX Statistics of a vpath
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath,
+                       struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats)
+{
+       u64 *val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       int i;
+       u32 offset = VXGE_HW_STATS_VPATH_RX_OFFSET;
+       val64 = (u64 *) vpath_rx_stats;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+       for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_rx_stats) / 8; i++) {
+               status = __vxge_hw_vpath_stats_access(vpath,
+                                       VXGE_HW_STATS_OP_READ,
+                                       offset >> 3, val64);
+               if (status != VXGE_HW_OK)
+                       goto exit;
+
+               offset += 8;
+               val64++;
+       }
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_stats_get - Get the vpath hw statistics.
+ */
+enum vxge_hw_status __vxge_hw_vpath_stats_get(
+                       struct __vxge_hw_virtualpath *vpath,
+                       struct vxge_hw_vpath_stats_hw_info *hw_stats)
+{
+       u64 val64;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+       vp_reg = vpath->vp_reg;
+
+       val64 = readq(&vp_reg->vpath_debug_stats0);
+       hw_stats->ini_num_mwr_sent =
+               (u32)VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(val64);
+
+       val64 = readq(&vp_reg->vpath_debug_stats1);
+       hw_stats->ini_num_mrd_sent =
+               (u32)VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(val64);
+
+       val64 = readq(&vp_reg->vpath_debug_stats2);
+       hw_stats->ini_num_cpl_rcvd =
+               (u32)VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(val64);
+
+       val64 = readq(&vp_reg->vpath_debug_stats3);
+       hw_stats->ini_num_mwr_byte_sent =
+               VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(val64);
+
+       val64 = readq(&vp_reg->vpath_debug_stats4);
+       hw_stats->ini_num_cpl_byte_rcvd =
+               VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(val64);
+
+       val64 = readq(&vp_reg->vpath_debug_stats5);
+       hw_stats->wrcrdtarb_xoff =
+               (u32)VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(val64);
+
+       val64 = readq(&vp_reg->vpath_debug_stats6);
+       hw_stats->rdcrdtarb_xoff =
+               (u32)VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(val64);
+
+       val64 = readq(&vp_reg->vpath_genstats_count01);
+       hw_stats->vpath_genstats_count0 =
+       (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(
+               val64);
+
+       val64 = readq(&vp_reg->vpath_genstats_count01);
+       hw_stats->vpath_genstats_count1 =
+       (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(
+               val64);
+
+       val64 = readq(&vp_reg->vpath_genstats_count23);
+       hw_stats->vpath_genstats_count2 =
+       (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(
+               val64);
+
+       val64 = readq(&vp_reg->vpath_genstats_count01);
+       hw_stats->vpath_genstats_count3 =
+       (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(
+               val64);
+
+       val64 = readq(&vp_reg->vpath_genstats_count4);
+       hw_stats->vpath_genstats_count4 =
+       (u32)VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(
+               val64);
+
+       val64 = readq(&vp_reg->vpath_genstats_count5);
+       hw_stats->vpath_genstats_count5 =
+       (u32)VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(
+               val64);
+
+       status = __vxge_hw_vpath_xmac_tx_stats_get(vpath, &hw_stats->tx_stats);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       status = __vxge_hw_vpath_xmac_rx_stats_get(vpath, &hw_stats->rx_stats);
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       VXGE_HW_VPATH_STATS_PIO_READ(
+               VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET);
+
+       hw_stats->prog_event_vnum0 =
+                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(val64);
+
+       hw_stats->prog_event_vnum1 =
+                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(val64);
+
+       VXGE_HW_VPATH_STATS_PIO_READ(
+               VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET);
+
+       hw_stats->prog_event_vnum2 =
+                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(val64);
+
+       hw_stats->prog_event_vnum3 =
+                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(val64);
+
+       val64 = readq(&vp_reg->rx_multi_cast_stats);
+       hw_stats->rx_multi_cast_frame_discard =
+               (u16)VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(val64);
+
+       val64 = readq(&vp_reg->rx_frm_transferred);
+       hw_stats->rx_frm_transferred =
+               (u32)VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(val64);
+
+       val64 = readq(&vp_reg->rxd_returned);
+       hw_stats->rxd_returned =
+               (u16)VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(val64);
+
+       val64 = readq(&vp_reg->dbg_stats_rx_mpa);
+       hw_stats->rx_mpa_len_fail_frms =
+               (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(val64);
+       hw_stats->rx_mpa_mrk_fail_frms =
+               (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(val64);
+       hw_stats->rx_mpa_crc_fail_frms =
+               (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(val64);
+
+       val64 = readq(&vp_reg->dbg_stats_rx_fau);
+       hw_stats->rx_permitted_frms =
+               (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(val64);
+       hw_stats->rx_vp_reset_discarded_frms =
+       (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val64);
+       hw_stats->rx_wol_frms =
+               (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(val64);
+
+       val64 = readq(&vp_reg->tx_vp_reset_discarded_frms);
+       hw_stats->tx_vp_reset_discarded_frms =
+       (u16)VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(
+               val64);
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_blockpool_create - Create block pool
+ */
+
+enum vxge_hw_status
+__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
+                          struct __vxge_hw_blockpool *blockpool,
+                          u32 pool_size,
+                          u32 pool_max)
+{
+       u32 i;
+       struct __vxge_hw_blockpool_entry *entry = NULL;
+       void *memblock;
+       dma_addr_t dma_addr;
+       struct pci_dev *dma_handle;
+       struct pci_dev *acc_handle;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (blockpool == NULL) {
+               status = VXGE_HW_FAIL;
+               goto blockpool_create_exit;
+       }
+
+       blockpool->hldev = hldev;
+       blockpool->block_size = VXGE_HW_BLOCK_SIZE;
+       blockpool->pool_size = 0;
+       blockpool->pool_max = pool_max;
+       blockpool->req_out = 0;
+
+       INIT_LIST_HEAD(&blockpool->free_block_list);
+       INIT_LIST_HEAD(&blockpool->free_entry_list);
+
+       for (i = 0; i < pool_size + pool_max; i++) {
+               entry = kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
+                               GFP_KERNEL);
+               if (entry == NULL) {
+                       __vxge_hw_blockpool_destroy(blockpool);
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto blockpool_create_exit;
+               }
+               list_add(&entry->item, &blockpool->free_entry_list);
+       }
+
+       for (i = 0; i < pool_size; i++) {
+
+               memblock = vxge_os_dma_malloc(
+                               hldev->pdev,
+                               VXGE_HW_BLOCK_SIZE,
+                               &dma_handle,
+                               &acc_handle);
+
+               if (memblock == NULL) {
+                       __vxge_hw_blockpool_destroy(blockpool);
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto blockpool_create_exit;
+               }
+
+               dma_addr = pci_map_single(hldev->pdev, memblock,
+                               VXGE_HW_BLOCK_SIZE, PCI_DMA_BIDIRECTIONAL);
+
+               if (unlikely(pci_dma_mapping_error(hldev->pdev,
+                               dma_addr))) {
+
+                       vxge_os_dma_free(hldev->pdev, memblock, &acc_handle);
+                       __vxge_hw_blockpool_destroy(blockpool);
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto blockpool_create_exit;
+               }
+
+               if (!list_empty(&blockpool->free_entry_list))
+                       entry = (struct __vxge_hw_blockpool_entry *)
+                               list_first_entry(&blockpool->free_entry_list,
+                                       struct __vxge_hw_blockpool_entry,
+                                       item);
+
+               if (entry == NULL)
+                       entry =
+                           kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
+                                       GFP_KERNEL);
+               if (entry != NULL) {
+                       list_del(&entry->item);
+                       entry->length = VXGE_HW_BLOCK_SIZE;
+                       entry->memblock = memblock;
+                       entry->dma_addr = dma_addr;
+                       entry->acc_handle = acc_handle;
+                       entry->dma_handle = dma_handle;
+                       list_add(&entry->item,
+                                         &blockpool->free_block_list);
+                       blockpool->pool_size++;
+               } else {
+                       __vxge_hw_blockpool_destroy(blockpool);
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto blockpool_create_exit;
+               }
+       }
+
+blockpool_create_exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_blockpool_destroy - Deallocates the block pool
+ */
+
+void __vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool)
+{
+
+       struct __vxge_hw_device *hldev;
+       struct list_head *p, *n;
+       u16 ret;
+
+       if (blockpool == NULL) {
+               ret = 1;
+               goto exit;
+       }
+
+       hldev = blockpool->hldev;
+
+       list_for_each_safe(p, n, &blockpool->free_block_list) {
+
+               pci_unmap_single(hldev->pdev,
+                       ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
+                       ((struct __vxge_hw_blockpool_entry *)p)->length,
+                       PCI_DMA_BIDIRECTIONAL);
+
+               vxge_os_dma_free(hldev->pdev,
+                       ((struct __vxge_hw_blockpool_entry *)p)->memblock,
+                       &((struct __vxge_hw_blockpool_entry *) p)->acc_handle);
+
+               list_del(
+                       &((struct __vxge_hw_blockpool_entry *)p)->item);
+               kfree(p);
+               blockpool->pool_size--;
+       }
+
+       list_for_each_safe(p, n, &blockpool->free_entry_list) {
+               list_del(
+                       &((struct __vxge_hw_blockpool_entry *)p)->item);
+               kfree((void *)p);
+       }
+       ret = 0;
+exit:
+       return;
+}
+
+/*
+ * __vxge_hw_blockpool_blocks_add - Request additional blocks
+ */
+static
+void __vxge_hw_blockpool_blocks_add(struct __vxge_hw_blockpool *blockpool)
+{
+       u32 nreq = 0, i;
+
+       if ((blockpool->pool_size  +  blockpool->req_out) <
+               VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE) {
+               nreq = VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE;
+               blockpool->req_out += nreq;
+       }
+
+       for (i = 0; i < nreq; i++)
+               vxge_os_dma_malloc_async(
+                       ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+                       blockpool->hldev, VXGE_HW_BLOCK_SIZE);
+}
+
+/*
+ * __vxge_hw_blockpool_blocks_remove - Free additional blocks
+ */
+static
+void __vxge_hw_blockpool_blocks_remove(struct __vxge_hw_blockpool *blockpool)
+{
+       struct list_head *p, *n;
+
+       list_for_each_safe(p, n, &blockpool->free_block_list) {
+
+               if (blockpool->pool_size < blockpool->pool_max)
+                       break;
+
+               pci_unmap_single(
+                       ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+                       ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
+                       ((struct __vxge_hw_blockpool_entry *)p)->length,
+                       PCI_DMA_BIDIRECTIONAL);
+
+               vxge_os_dma_free(
+                       ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+                       ((struct __vxge_hw_blockpool_entry *)p)->memblock,
+                       &((struct __vxge_hw_blockpool_entry *)p)->acc_handle);
+
+               list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
+
+               list_add(p, &blockpool->free_entry_list);
+
+               blockpool->pool_size--;
+
+       }
+}
+
+/*
+ * vxge_hw_blockpool_block_add - callback for vxge_os_dma_malloc_async
+ * Adds a block to block pool
+ */
+void vxge_hw_blockpool_block_add(
+                       struct __vxge_hw_device *devh,
+                       void *block_addr,
+                       u32 length,
+                       struct pci_dev *dma_h,
+                       struct pci_dev *acc_handle)
+{
+       struct __vxge_hw_blockpool  *blockpool;
+       struct __vxge_hw_blockpool_entry  *entry = NULL;
+       dma_addr_t dma_addr;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       u32 req_out;
+
+       blockpool = &devh->block_pool;
+
+       if (block_addr == NULL) {
+               blockpool->req_out--;
+               status = VXGE_HW_FAIL;
+               goto exit;
+       }
+
+       dma_addr = pci_map_single(devh->pdev, block_addr, length,
+                               PCI_DMA_BIDIRECTIONAL);
+
+       if (unlikely(pci_dma_mapping_error(devh->pdev, dma_addr))) {
+
+               vxge_os_dma_free(devh->pdev, block_addr, &acc_handle);
+               blockpool->req_out--;
+               status = VXGE_HW_FAIL;
+               goto exit;
+       }
+
+
+       if (!list_empty(&blockpool->free_entry_list))
+               entry = (struct __vxge_hw_blockpool_entry *)
+                       list_first_entry(&blockpool->free_entry_list,
+                               struct __vxge_hw_blockpool_entry,
+                               item);
+
+       if (entry == NULL)
+               entry = (struct __vxge_hw_blockpool_entry *)
+                       vmalloc(sizeof(struct __vxge_hw_blockpool_entry));
+       else
+               list_del(&entry->item);
+
+       if (entry != NULL) {
+               entry->length = length;
+               entry->memblock = block_addr;
+               entry->dma_addr = dma_addr;
+               entry->acc_handle = acc_handle;
+               entry->dma_handle = dma_h;
+               list_add(&entry->item, &blockpool->free_block_list);
+               blockpool->pool_size++;
+               status = VXGE_HW_OK;
+       } else
+               status = VXGE_HW_ERR_OUT_OF_MEMORY;
+
+       blockpool->req_out--;
+
+       req_out = blockpool->req_out;
+exit:
+       return;
+}
+
+/*
+ * __vxge_hw_blockpool_malloc - Allocate a memory block from pool
+ * Allocates a block of memory of given size, either from block pool
+ * or by calling vxge_os_dma_malloc()
+ */
+void *
+__vxge_hw_blockpool_malloc(struct __vxge_hw_device *devh, u32 size,
+                               struct vxge_hw_mempool_dma *dma_object)
+{
+       struct __vxge_hw_blockpool_entry *entry = NULL;
+       struct __vxge_hw_blockpool  *blockpool;
+       void *memblock = NULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       blockpool = &devh->block_pool;
+
+       if (size != blockpool->block_size) {
+
+               memblock = vxge_os_dma_malloc(devh->pdev, size,
+                                               &dma_object->handle,
+                                               &dma_object->acc_handle);
+
+               if (memblock == NULL) {
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto exit;
+               }
+
+               dma_object->addr = pci_map_single(devh->pdev, memblock, size,
+                                       PCI_DMA_BIDIRECTIONAL);
+
+               if (unlikely(pci_dma_mapping_error(devh->pdev,
+                               dma_object->addr))) {
+                       vxge_os_dma_free(devh->pdev, memblock,
+                               &dma_object->acc_handle);
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+                       goto exit;
+               }
+
+       } else {
+
+               if (!list_empty(&blockpool->free_block_list))
+                       entry = (struct __vxge_hw_blockpool_entry *)
+                               list_first_entry(&blockpool->free_block_list,
+                                       struct __vxge_hw_blockpool_entry,
+                                       item);
+
+               if (entry != NULL) {
+                       list_del(&entry->item);
+                       dma_object->addr = entry->dma_addr;
+                       dma_object->handle = entry->dma_handle;
+                       dma_object->acc_handle = entry->acc_handle;
+                       memblock = entry->memblock;
+
+                       list_add(&entry->item,
+                               &blockpool->free_entry_list);
+                       blockpool->pool_size--;
+               }
+
+               if (memblock != NULL)
+                       __vxge_hw_blockpool_blocks_add(blockpool);
+       }
+exit:
+       return memblock;
+}
+
+/*
+ * __vxge_hw_blockpool_free - Frees the memory allcoated with
+                               __vxge_hw_blockpool_malloc
+ */
+void
+__vxge_hw_blockpool_free(struct __vxge_hw_device *devh,
+                       void *memblock, u32 size,
+                       struct vxge_hw_mempool_dma *dma_object)
+{
+       struct __vxge_hw_blockpool_entry *entry = NULL;
+       struct __vxge_hw_blockpool  *blockpool;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       blockpool = &devh->block_pool;
+
+       if (size != blockpool->block_size) {
+               pci_unmap_single(devh->pdev, dma_object->addr, size,
+                       PCI_DMA_BIDIRECTIONAL);
+               vxge_os_dma_free(devh->pdev, memblock, &dma_object->acc_handle);
+       } else {
+
+               if (!list_empty(&blockpool->free_entry_list))
+                       entry = (struct __vxge_hw_blockpool_entry *)
+                               list_first_entry(&blockpool->free_entry_list,
+                                       struct __vxge_hw_blockpool_entry,
+                                       item);
+
+               if (entry == NULL)
+                       entry = (struct __vxge_hw_blockpool_entry *)
+                               vmalloc(sizeof(
+                                       struct __vxge_hw_blockpool_entry));
+               else
+                       list_del(&entry->item);
+
+               if (entry != NULL) {
+                       entry->length = size;
+                       entry->memblock = memblock;
+                       entry->dma_addr = dma_object->addr;
+                       entry->acc_handle = dma_object->acc_handle;
+                       entry->dma_handle = dma_object->handle;
+                       list_add(&entry->item,
+                                       &blockpool->free_block_list);
+                       blockpool->pool_size++;
+                       status = VXGE_HW_OK;
+               } else
+                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
+
+               if (status == VXGE_HW_OK)
+                       __vxge_hw_blockpool_blocks_remove(blockpool);
+       }
+
+       return;
+}
+
+/*
+ * __vxge_hw_blockpool_block_allocate - Allocates a block from block pool
+ * This function allocates a block from block pool or from the system
+ */
+struct __vxge_hw_blockpool_entry *
+__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *devh, u32 size)
+{
+       struct __vxge_hw_blockpool_entry *entry = NULL;
+       struct __vxge_hw_blockpool  *blockpool;
+
+       blockpool = &devh->block_pool;
+
+       if (size == blockpool->block_size) {
+
+               if (!list_empty(&blockpool->free_block_list))
+                       entry = (struct __vxge_hw_blockpool_entry *)
+                               list_first_entry(&blockpool->free_block_list,
+                                       struct __vxge_hw_blockpool_entry,
+                                       item);
+
+               if (entry != NULL) {
+                       list_del(&entry->item);
+                       blockpool->pool_size--;
+               }
+       }
+
+       if (entry != NULL)
+               __vxge_hw_blockpool_blocks_add(blockpool);
+
+       return entry;
+}
+
+/*
+ * __vxge_hw_blockpool_block_free - Frees a block from block pool
+ * @devh: Hal device
+ * @entry: Entry of block to be freed
+ *
+ * This function frees a block from block pool
+ */
+void
+__vxge_hw_blockpool_block_free(struct __vxge_hw_device *devh,
+                       struct __vxge_hw_blockpool_entry *entry)
+{
+       struct __vxge_hw_blockpool  *blockpool;
+
+       blockpool = &devh->block_pool;
+
+       if (entry->length == blockpool->block_size) {
+               list_add(&entry->item, &blockpool->free_block_list);
+               blockpool->pool_size++;
+       }
+
+       __vxge_hw_blockpool_blocks_remove(blockpool);
+
+       return;
+}
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
new file mode 100644 (file)
index 0000000..afbdf6f
--- /dev/null
@@ -0,0 +1,2259 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-config.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#ifndef VXGE_CONFIG_H
+#define VXGE_CONFIG_H
+#include <linux/list.h>
+
+#ifndef VXGE_CACHE_LINE_SIZE
+#define VXGE_CACHE_LINE_SIZE 128
+#endif
+
+#define vxge_os_vaprintf(level, mask, fmt, ...) { \
+       char buff[255]; \
+               snprintf(buff, 255, fmt, __VA_ARGS__); \
+               printk(buff); \
+               printk("\n"); \
+}
+
+#ifndef VXGE_ALIGN
+#define VXGE_ALIGN(adrs, size) \
+       (((size) - (((u64)adrs) & ((size)-1))) & ((size)-1))
+#endif
+
+#define VXGE_HW_MIN_MTU                                68
+#define VXGE_HW_MAX_MTU                                9600
+#define VXGE_HW_DEFAULT_MTU                    1500
+
+#ifdef VXGE_DEBUG_ASSERT
+
+/**
+ * vxge_assert
+ * @test: C-condition to check
+ * @fmt: printf like format string
+ *
+ * This function implements traditional assert. By default assertions
+ * are enabled. It can be disabled by undefining VXGE_DEBUG_ASSERT macro in
+ * compilation
+ * time.
+ */
+#define vxge_assert(test) { \
+       if (!(test)) \
+               vxge_os_bug("bad cond: "#test" at %s:%d\n", \
+                               __FILE__, __LINE__); }
+#else
+#define vxge_assert(test)
+#endif /* end of VXGE_DEBUG_ASSERT */
+
+/**
+ * enum enum vxge_debug_level
+ * @VXGE_NONE: debug disabled
+ * @VXGE_ERR: all errors going to be logged out
+ * @VXGE_TRACE: all errors plus all kind of verbose tracing print outs
+ *                 going to be logged out. Very noisy.
+ *
+ * This enumeration going to be used to switch between different
+ * debug levels during runtime if DEBUG macro defined during
+ * compilation. If DEBUG macro not defined than code will be
+ * compiled out.
+ */
+enum vxge_debug_level {
+       VXGE_NONE   = 0,
+       VXGE_TRACE  = 1,
+       VXGE_ERR    = 2
+};
+
+#define NULL_VPID                                      0xFFFFFFFF
+#ifdef CONFIG_VXGE_DEBUG_TRACE_ALL
+#define VXGE_DEBUG_MODULE_MASK  0xffffffff
+#define VXGE_DEBUG_TRACE_MASK   0xffffffff
+#define VXGE_DEBUG_ERR_MASK     0xffffffff
+#define VXGE_DEBUG_MASK         0x000001ff
+#else
+#define VXGE_DEBUG_MODULE_MASK  0x20000000
+#define VXGE_DEBUG_TRACE_MASK   0x20000000
+#define VXGE_DEBUG_ERR_MASK     0x20000000
+#define VXGE_DEBUG_MASK         0x00000001
+#endif
+
+/*
+ * @VXGE_COMPONENT_LL: do debug for vxge link layer module
+ * @VXGE_COMPONENT_ALL: activate debug for all modules with no exceptions
+ *
+ * This enumeration going to be used to distinguish modules
+ * or libraries during compilation and runtime.  Makefile must declare
+ * VXGE_DEBUG_MODULE_MASK macro and set it to proper value.
+ */
+#define        VXGE_COMPONENT_LL                               0x20000000
+#define        VXGE_COMPONENT_ALL                              0xffffffff
+
+#define VXGE_HW_BASE_INF       100
+#define VXGE_HW_BASE_ERR       200
+#define VXGE_HW_BASE_BADCFG    300
+
+enum vxge_hw_status {
+       VXGE_HW_OK                                = 0,
+       VXGE_HW_FAIL                              = 1,
+       VXGE_HW_PENDING                           = 2,
+       VXGE_HW_COMPLETIONS_REMAIN                = 3,
+
+       VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS = VXGE_HW_BASE_INF + 1,
+       VXGE_HW_INF_OUT_OF_DESCRIPTORS            = VXGE_HW_BASE_INF + 2,
+
+       VXGE_HW_ERR_INVALID_HANDLE                = VXGE_HW_BASE_ERR + 1,
+       VXGE_HW_ERR_OUT_OF_MEMORY                 = VXGE_HW_BASE_ERR + 2,
+       VXGE_HW_ERR_VPATH_NOT_AVAILABLE           = VXGE_HW_BASE_ERR + 3,
+       VXGE_HW_ERR_VPATH_NOT_OPEN                = VXGE_HW_BASE_ERR + 4,
+       VXGE_HW_ERR_WRONG_IRQ                     = VXGE_HW_BASE_ERR + 5,
+       VXGE_HW_ERR_SWAPPER_CTRL                  = VXGE_HW_BASE_ERR + 6,
+       VXGE_HW_ERR_INVALID_MTU_SIZE              = VXGE_HW_BASE_ERR + 7,
+       VXGE_HW_ERR_INVALID_INDEX                 = VXGE_HW_BASE_ERR + 8,
+       VXGE_HW_ERR_INVALID_TYPE                  = VXGE_HW_BASE_ERR + 9,
+       VXGE_HW_ERR_INVALID_OFFSET                = VXGE_HW_BASE_ERR + 10,
+       VXGE_HW_ERR_INVALID_DEVICE                = VXGE_HW_BASE_ERR + 11,
+       VXGE_HW_ERR_VERSION_CONFLICT              = VXGE_HW_BASE_ERR + 12,
+       VXGE_HW_ERR_INVALID_PCI_INFO              = VXGE_HW_BASE_ERR + 13,
+       VXGE_HW_ERR_INVALID_TCODE                 = VXGE_HW_BASE_ERR + 14,
+       VXGE_HW_ERR_INVALID_BLOCK_SIZE            = VXGE_HW_BASE_ERR + 15,
+       VXGE_HW_ERR_INVALID_STATE                 = VXGE_HW_BASE_ERR + 16,
+       VXGE_HW_ERR_PRIVILAGED_OPEARATION         = VXGE_HW_BASE_ERR + 17,
+       VXGE_HW_ERR_INVALID_PORT                  = VXGE_HW_BASE_ERR + 18,
+       VXGE_HW_ERR_FIFO                          = VXGE_HW_BASE_ERR + 19,
+       VXGE_HW_ERR_VPATH                         = VXGE_HW_BASE_ERR + 20,
+       VXGE_HW_ERR_CRITICAL                      = VXGE_HW_BASE_ERR + 21,
+       VXGE_HW_ERR_SLOT_FREEZE                   = VXGE_HW_BASE_ERR + 22,
+
+       VXGE_HW_BADCFG_RING_INDICATE_MAX_PKTS     = VXGE_HW_BASE_BADCFG + 1,
+       VXGE_HW_BADCFG_FIFO_BLOCKS                = VXGE_HW_BASE_BADCFG + 2,
+       VXGE_HW_BADCFG_VPATH_MTU                  = VXGE_HW_BASE_BADCFG + 3,
+       VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG   = VXGE_HW_BASE_BADCFG + 4,
+       VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH        = VXGE_HW_BASE_BADCFG + 5,
+       VXGE_HW_BADCFG_INTR_MODE                  = VXGE_HW_BASE_BADCFG + 6,
+       VXGE_HW_BADCFG_RTS_MAC_EN                 = VXGE_HW_BASE_BADCFG + 7,
+
+       VXGE_HW_EOF_TRACE_BUF                     = -1
+};
+
+/**
+ * enum enum vxge_hw_device_link_state - Link state enumeration.
+ * @VXGE_HW_LINK_NONE: Invalid link state.
+ * @VXGE_HW_LINK_DOWN: Link is down.
+ * @VXGE_HW_LINK_UP: Link is up.
+ *
+ */
+enum vxge_hw_device_link_state {
+       VXGE_HW_LINK_NONE,
+       VXGE_HW_LINK_DOWN,
+       VXGE_HW_LINK_UP
+};
+
+/**
+ * struct vxge_hw_device_date - Date Format
+ * @day: Day
+ * @month: Month
+ * @year: Year
+ * @date: Date in string format
+ *
+ * Structure for returning date
+ */
+
+#define VXGE_HW_FW_STRLEN      32
+struct vxge_hw_device_date {
+       u32     day;
+       u32     month;
+       u32     year;
+       char    date[VXGE_HW_FW_STRLEN];
+};
+
+struct vxge_hw_device_version {
+       u32     major;
+       u32     minor;
+       u32     build;
+       char    version[VXGE_HW_FW_STRLEN];
+};
+
+u64
+__vxge_hw_vpath_pci_func_mode_get(
+       u32 vp_id,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg);
+
+/**
+ * struct vxge_hw_fifo_config - Configuration of fifo.
+ * @enable: Is this fifo to be commissioned
+ * @fifo_blocks: Numbers of TxDL (that is, lists of Tx descriptors)
+ *             blocks per queue.
+ * @max_frags: Max number of Tx buffers per TxDL (that is, per single
+ *             transmit operation).
+ *             No more than 256 transmit buffers can be specified.
+ * @memblock_size: Fifo descriptors are allocated in blocks of @mem_block_size
+ *             bytes. Setting @memblock_size to page size ensures
+ *             by-page allocation of descriptors. 128K bytes is the
+ *             maximum supported block size.
+ * @alignment_size: per Tx fragment DMA-able memory used to align transmit data
+ *             (e.g., to align on a cache line).
+ * @intr: Boolean. Use 1 to generate interrupt for each completed TxDL.
+ *             Use 0 otherwise.
+ * @no_snoop_bits: If non-zero, specifies no-snoop PCI operation,
+ *             which generally improves latency of the host bridge operation
+ *             (see PCI specification). For valid values please refer
+ *             to struct vxge_hw_fifo_config{} in the driver sources.
+ * Configuration of all Titan fifos.
+ * Note: Valid (min, max) range for each attribute is specified in the body of
+ * the struct vxge_hw_fifo_config{} structure.
+ */
+struct vxge_hw_fifo_config {
+       u32                             enable;
+#define VXGE_HW_FIFO_ENABLE                            1
+#define VXGE_HW_FIFO_DISABLE                           0
+
+       u32                             fifo_blocks;
+#define VXGE_HW_MIN_FIFO_BLOCKS                                2
+#define VXGE_HW_MAX_FIFO_BLOCKS                                128
+
+       u32                             max_frags;
+#define VXGE_HW_MIN_FIFO_FRAGS                         1
+#define VXGE_HW_MAX_FIFO_FRAGS                         256
+
+       u32                             memblock_size;
+#define VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE                 VXGE_HW_BLOCK_SIZE
+#define VXGE_HW_MAX_FIFO_MEMBLOCK_SIZE                 131072
+#define VXGE_HW_DEF_FIFO_MEMBLOCK_SIZE                 8096
+
+       u32                             alignment_size;
+#define VXGE_HW_MIN_FIFO_ALIGNMENT_SIZE                0
+#define VXGE_HW_MAX_FIFO_ALIGNMENT_SIZE                65536
+#define VXGE_HW_DEF_FIFO_ALIGNMENT_SIZE                VXGE_CACHE_LINE_SIZE
+
+       u32                             intr;
+#define VXGE_HW_FIFO_QUEUE_INTR_ENABLE                 1
+#define VXGE_HW_FIFO_QUEUE_INTR_DISABLE                        0
+#define VXGE_HW_FIFO_QUEUE_INTR_DEFAULT                        0
+
+       u32                             no_snoop_bits;
+#define VXGE_HW_FIFO_NO_SNOOP_DISABLED                 0
+#define VXGE_HW_FIFO_NO_SNOOP_TXD                      1
+#define VXGE_HW_FIFO_NO_SNOOP_FRM                      2
+#define VXGE_HW_FIFO_NO_SNOOP_ALL                      3
+#define VXGE_HW_FIFO_NO_SNOOP_DEFAULT                  0
+
+};
+/**
+ * struct vxge_hw_ring_config - Ring configurations.
+ * @enable: Is this ring to be commissioned
+ * @ring_blocks: Numbers of RxD blocks in the ring
+ * @buffer_mode: Receive buffer mode (1, 2, 3, or 5); for details please refer
+ *             to Titan User Guide.
+ * @scatter_mode: Titan supports two receive scatter modes: A and B.
+ *             For details please refer to Titan User Guide.
+ * @rx_timer_val: The number of 32ns periods that would be counted between two
+ *             timer interrupts.
+ * @greedy_return: If Set it forces the device to return absolutely all RxD
+ *             that are consumed and still on board when a timer interrupt
+ *             triggers. If Clear, then if the device has already returned
+ *             RxD before current timer interrupt trigerred and after the
+ *             previous timer interrupt triggered, then the device is not
+ *             forced to returned the rest of the consumed RxD that it has
+ *             on board which account for a byte count less than the one
+ *             programmed into PRC_CFG6.RXD_CRXDT field
+ * @rx_timer_ci: TBD
+ * @backoff_interval_us: Time (in microseconds), after which Titan
+ *             tries to download RxDs posted by the host.
+ *             Note that the "backoff" does not happen if host posts receive
+ *             descriptors in the timely fashion.
+ * Ring configuration.
+ */
+struct vxge_hw_ring_config {
+       u32                             enable;
+#define VXGE_HW_RING_ENABLE                                    1
+#define VXGE_HW_RING_DISABLE                                   0
+#define VXGE_HW_RING_DEFAULT                                   1
+
+       u32                             ring_blocks;
+#define VXGE_HW_MIN_RING_BLOCKS                                1
+#define VXGE_HW_MAX_RING_BLOCKS                                128
+#define VXGE_HW_DEF_RING_BLOCKS                                2
+
+       u32                             buffer_mode;
+#define VXGE_HW_RING_RXD_BUFFER_MODE_1                         1
+#define VXGE_HW_RING_RXD_BUFFER_MODE_3                         3
+#define VXGE_HW_RING_RXD_BUFFER_MODE_5                         5
+#define VXGE_HW_RING_RXD_BUFFER_MODE_DEFAULT                   1
+
+       u32                             scatter_mode;
+#define VXGE_HW_RING_SCATTER_MODE_A                            0
+#define VXGE_HW_RING_SCATTER_MODE_B                            1
+#define VXGE_HW_RING_SCATTER_MODE_C                            2
+#define VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT            0xffffffff
+
+       u64                             rxds_limit;
+#define VXGE_HW_DEF_RING_RXDS_LIMIT                            44
+};
+
+/**
+ * struct vxge_hw_vp_config - Configuration of virtual path
+ * @vp_id: Virtual Path Id
+ * @min_bandwidth: Minimum Guaranteed bandwidth
+ * @ring: See struct vxge_hw_ring_config{}.
+ * @fifo: See struct vxge_hw_fifo_config{}.
+ * @tti: Configuration of interrupt associated with Transmit.
+ *             see struct vxge_hw_tim_intr_config();
+ * @rti: Configuration of interrupt associated with Receive.
+ *              see struct vxge_hw_tim_intr_config();
+ * @mtu: mtu size used on this port.
+ * @rpa_strip_vlan_tag: Strip VLAN Tag enable/disable. Instructs the device to
+ *             remove the VLAN tag from all received tagged frames that are not
+ *             replicated at the internal L2 switch.
+ *             0 - Do not strip the VLAN tag.
+ *             1 - Strip the VLAN tag. Regardless of this setting, VLAN tags are
+ *                 always placed into the RxDMA descriptor.
+ *
+ * This structure is used by the driver to pass the configuration parameters to
+ * configure Virtual Path.
+ */
+struct vxge_hw_vp_config {
+       u32                             vp_id;
+
+#define        VXGE_HW_VPATH_PRIORITY_MIN                      0
+#define        VXGE_HW_VPATH_PRIORITY_MAX                      16
+#define        VXGE_HW_VPATH_PRIORITY_DEFAULT                  0
+
+       u32                             min_bandwidth;
+#define        VXGE_HW_VPATH_BANDWIDTH_MIN                     0
+#define        VXGE_HW_VPATH_BANDWIDTH_MAX                     100
+#define        VXGE_HW_VPATH_BANDWIDTH_DEFAULT                 0
+
+       struct vxge_hw_ring_config              ring;
+       struct vxge_hw_fifo_config              fifo;
+       struct vxge_hw_tim_intr_config  tti;
+       struct vxge_hw_tim_intr_config  rti;
+
+       u32                             mtu;
+#define VXGE_HW_VPATH_MIN_INITIAL_MTU                  VXGE_HW_MIN_MTU
+#define VXGE_HW_VPATH_MAX_INITIAL_MTU                  VXGE_HW_MAX_MTU
+#define VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU    0xffffffff
+
+       u32                             rpa_strip_vlan_tag;
+#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE                        1
+#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE               0
+#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT     0xffffffff
+
+};
+/**
+ * struct vxge_hw_device_config - Device configuration.
+ * @dma_blockpool_initial: Initial size of DMA Pool
+ * @dma_blockpool_max: Maximum blocks in DMA pool
+ * @intr_mode: Line, or MSI-X interrupt.
+ *
+ * @rth_en: Enable Receive Traffic Hashing(RTH) using IT(Indirection Table).
+ * @rth_it_type: RTH IT table programming type
+ * @rts_mac_en: Enable Receive Traffic Steering using MAC destination address
+ * @vp_config: Configuration for virtual paths
+ * @device_poll_millis: Specify the interval (in mulliseconds)
+ *                     to wait for register reads
+ *
+ * Titan configuration.
+ * Contains per-device configuration parameters, including:
+ * - stats sampling interval, etc.
+ *
+ * In addition, struct vxge_hw_device_config{} includes "subordinate"
+ * configurations, including:
+ * - fifos and rings;
+ * - MAC (done at firmware level).
+ *
+ * See Titan User Guide for more details.
+ * Note: Valid (min, max) range for each attribute is specified in the body of
+ * the struct vxge_hw_device_config{} structure. Please refer to the
+ * corresponding include file.
+ * See also: struct vxge_hw_tim_intr_config{}.
+ */
+struct vxge_hw_device_config {
+       u32                             dma_blockpool_initial;
+       u32                             dma_blockpool_max;
+#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE                        0
+#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE            0
+#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE               4
+#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE                        4096
+
+#define        VXGE_HW_MAX_PAYLOAD_SIZE_512            2
+
+       u32                             intr_mode;
+#define VXGE_HW_INTR_MODE_IRQLINE                      0
+#define VXGE_HW_INTR_MODE_MSIX                         1
+#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT                        2
+
+#define VXGE_HW_INTR_MODE_DEF                          0
+
+       u32                             rth_en;
+#define VXGE_HW_RTH_DISABLE                            0
+#define VXGE_HW_RTH_ENABLE                             1
+#define VXGE_HW_RTH_DEFAULT                            0
+
+       u32                             rth_it_type;
+#define VXGE_HW_RTH_IT_TYPE_SOLO_IT                    0
+#define VXGE_HW_RTH_IT_TYPE_MULTI_IT                   1
+#define VXGE_HW_RTH_IT_TYPE_DEFAULT                    0
+
+       u32                             rts_mac_en;
+#define VXGE_HW_RTS_MAC_DISABLE                        0
+#define VXGE_HW_RTS_MAC_ENABLE                 1
+#define VXGE_HW_RTS_MAC_DEFAULT                        0
+
+       struct vxge_hw_vp_config        vp_config[VXGE_HW_MAX_VIRTUAL_PATHS];
+
+       u32                             device_poll_millis;
+#define VXGE_HW_MIN_DEVICE_POLL_MILLIS                 1
+#define VXGE_HW_MAX_DEVICE_POLL_MILLIS                 100000
+#define VXGE_HW_DEF_DEVICE_POLL_MILLIS                 1000
+
+};
+
+/**
+ * function vxge_uld_link_up_f - Link-Up callback provided by driver.
+ * @devh: HW device handle.
+ * Link-up notification callback provided by the driver.
+ * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}.
+ *
+ * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_down_f{},
+ * vxge_hw_driver_initialize().
+ */
+
+/**
+ * function vxge_uld_link_down_f - Link-Down callback provided by
+ * driver.
+ * @devh: HW device handle.
+ *
+ * Link-Down notification callback provided by the driver.
+ * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}.
+ *
+ * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_up_f{},
+ * vxge_hw_driver_initialize().
+ */
+
+/**
+ * function vxge_uld_crit_err_f - Critical Error notification callback.
+ * @devh: HW device handle.
+ * (typically - at HW device iinitialization time).
+ * @type: Enumerated hw error, e.g.: double ECC.
+ * @serr_data: Titan status.
+ * @ext_data: Extended data. The contents depends on the @type.
+ *
+ * Link-Down notification callback provided by the driver.
+ * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}.
+ *
+ * See also: struct vxge_hw_uld_cbs{}, enum vxge_hw_event{},
+ * vxge_hw_driver_initialize().
+ */
+
+/**
+ * struct vxge_hw_uld_cbs - driver "slow-path" callbacks.
+ * @link_up: See vxge_uld_link_up_f{}.
+ * @link_down: See vxge_uld_link_down_f{}.
+ * @crit_err: See vxge_uld_crit_err_f{}.
+ *
+ * Driver slow-path (per-driver) callbacks.
+ * Implemented by driver and provided to HW via
+ * vxge_hw_driver_initialize().
+ * Note that these callbacks are not mandatory: HW will not invoke
+ * a callback if NULL is specified.
+ *
+ * See also: vxge_hw_driver_initialize().
+ */
+struct vxge_hw_uld_cbs {
+
+       void (*link_up)(struct __vxge_hw_device *devh);
+       void (*link_down)(struct __vxge_hw_device *devh);
+       void (*crit_err)(struct __vxge_hw_device *devh,
+                       enum vxge_hw_event type, u64 ext_data);
+};
+
+/*
+ * struct __vxge_hw_blockpool_entry - Block private data structure
+ * @item: List header used to link.
+ * @length: Length of the block
+ * @memblock: Virtual address block
+ * @dma_addr: DMA Address of the block.
+ * @dma_handle: DMA handle of the block.
+ * @acc_handle: DMA acc handle
+ *
+ * Block is allocated with a header to put the blocks into list.
+ *
+ */
+struct __vxge_hw_blockpool_entry {
+       struct list_head        item;
+       u32                     length;
+       void                    *memblock;
+       dma_addr_t              dma_addr;
+       struct pci_dev          *dma_handle;
+       struct pci_dev          *acc_handle;
+};
+
+/*
+ * struct __vxge_hw_blockpool - Block Pool
+ * @hldev: HW device
+ * @block_size: size of each block.
+ * @Pool_size: Number of blocks in the pool
+ * @pool_max: Maximum number of blocks above which to free additional blocks
+ * @req_out: Number of block requests with OS out standing
+ * @free_block_list: List of free blocks
+ *
+ * Block pool contains the DMA blocks preallocated.
+ *
+ */
+struct __vxge_hw_blockpool {
+       struct __vxge_hw_device *hldev;
+       u32                             block_size;
+       u32                             pool_size;
+       u32                             pool_max;
+       u32                             req_out;
+       struct list_head                free_block_list;
+       struct list_head                free_entry_list;
+};
+
+/*
+ * enum enum __vxge_hw_channel_type - Enumerated channel types.
+ * @VXGE_HW_CHANNEL_TYPE_UNKNOWN: Unknown channel.
+ * @VXGE_HW_CHANNEL_TYPE_FIFO: fifo.
+ * @VXGE_HW_CHANNEL_TYPE_RING: ring.
+ * @VXGE_HW_CHANNEL_TYPE_MAX: Maximum number of HW-supported
+ * (and recognized) channel types. Currently: 2.
+ *
+ * Enumerated channel types. Currently there are only two link-layer
+ * channels - Titan fifo and Titan ring. In the future the list will grow.
+ */
+enum __vxge_hw_channel_type {
+       VXGE_HW_CHANNEL_TYPE_UNKNOWN                    = 0,
+       VXGE_HW_CHANNEL_TYPE_FIFO                       = 1,
+       VXGE_HW_CHANNEL_TYPE_RING                       = 2,
+       VXGE_HW_CHANNEL_TYPE_MAX                        = 3
+};
+
+/*
+ * struct __vxge_hw_channel
+ * @item: List item; used to maintain a list of open channels.
+ * @type: Channel type. See enum vxge_hw_channel_type{}.
+ * @devh: Device handle. HW device object that contains _this_ channel.
+ * @vph: Virtual path handle. Virtual Path Object that contains _this_ channel.
+ * @length: Channel length. Currently allocated number of descriptors.
+ *          The channel length "grows" when more descriptors get allocated.
+ *          See _hw_mempool_grow.
+ * @reserve_arr: Reserve array. Contains descriptors that can be reserved
+ *               by driver for the subsequent send or receive operation.
+ *               See vxge_hw_fifo_txdl_reserve(),
+ *               vxge_hw_ring_rxd_reserve().
+ * @reserve_ptr: Current pointer in the resrve array
+ * @reserve_top: Reserve top gives the maximum number of dtrs available in
+ *          reserve array.
+ * @work_arr: Work array. Contains descriptors posted to the channel.
+ *            Note that at any point in time @work_arr contains 3 types of
+ *            descriptors:
+ *            1) posted but not yet consumed by Titan device;
+ *            2) consumed but not yet completed;
+ *            3) completed but not yet freed
+ *            (via vxge_hw_fifo_txdl_free() or vxge_hw_ring_rxd_free())
+ * @post_index: Post index. At any point in time points on the
+ *              position in the channel, which'll contain next to-be-posted
+ *              descriptor.
+ * @compl_index: Completion index. At any point in time points on the
+ *               position in the channel, which will contain next
+ *               to-be-completed descriptor.
+ * @free_arr: Free array. Contains completed descriptors that were freed
+ *            (i.e., handed over back to HW) by driver.
+ *            See vxge_hw_fifo_txdl_free(), vxge_hw_ring_rxd_free().
+ * @free_ptr: current pointer in free array
+ * @per_dtr_space: Per-descriptor space (in bytes) that channel user can utilize
+ *                 to store per-operation control information.
+ * @stats: Pointer to common statistics
+ * @userdata: Per-channel opaque (void*) user-defined context, which may be
+ *            driver object, ULP connection, etc.
+ *            Once channel is open, @userdata is passed back to user via
+ *            vxge_hw_channel_callback_f.
+ *
+ * HW channel object.
+ *
+ * See also: enum vxge_hw_channel_type{}, enum vxge_hw_channel_flag
+ */
+struct __vxge_hw_channel {
+       struct list_head                item;
+       enum __vxge_hw_channel_type     type;
+       struct __vxge_hw_device         *devh;
+       struct __vxge_hw_vpath_handle   *vph;
+       u32                     length;
+       u32                     vp_id;
+       void            **reserve_arr;
+       u32                     reserve_ptr;
+       u32                     reserve_top;
+       void            **work_arr;
+       u32                     post_index ____cacheline_aligned;
+       u32                     compl_index ____cacheline_aligned;
+       void            **free_arr;
+       u32                     free_ptr;
+       void            **orig_arr;
+       u32                     per_dtr_space;
+       void            *userdata;
+       struct vxge_hw_common_reg       __iomem *common_reg;
+       u32                     first_vp_id;
+       struct vxge_hw_vpath_stats_sw_common_info *stats;
+
+} ____cacheline_aligned;
+
+/*
+ * struct __vxge_hw_virtualpath - Virtual Path
+ *
+ * @vp_id: Virtual path id
+ * @vp_open: This flag specifies if vxge_hw_vp_open is called from LL Driver
+ * @hldev: Hal device
+ * @vp_config: Virtual Path Config
+ * @vp_reg: VPATH Register map address in BAR0
+ * @vpmgmt_reg: VPATH_MGMT register map address
+ * @max_mtu: Max mtu that can be supported
+ * @vsport_number: vsport attached to this vpath
+ * @max_kdfc_db: Maximum kernel mode doorbells
+ * @max_nofl_db: Maximum non offload doorbells
+ * @tx_intr_num: Interrupt Number associated with the TX
+
+ * @ringh: Ring Queue
+ * @fifoh: FIFO Queue
+ * @vpath_handles: Virtual Path handles list
+ * @stats_block: Memory for DMAing stats
+ * @stats: Vpath statistics
+ *
+ * Virtual path structure to encapsulate the data related to a virtual path.
+ * Virtual paths are allocated by the HW upon getting configuration from the
+ * driver and inserted into the list of virtual paths.
+ */
+struct __vxge_hw_virtualpath {
+       u32                             vp_id;
+
+       u32                             vp_open;
+#define VXGE_HW_VP_NOT_OPEN    0
+#define        VXGE_HW_VP_OPEN         1
+
+       struct __vxge_hw_device         *hldev;
+       struct vxge_hw_vp_config        *vp_config;
+       struct vxge_hw_vpath_reg        __iomem *vp_reg;
+       struct vxge_hw_vpmgmt_reg       __iomem *vpmgmt_reg;
+       struct __vxge_hw_non_offload_db_wrapper __iomem *nofl_db;
+
+       u32                             max_mtu;
+       u32                             vsport_number;
+       u32                             max_kdfc_db;
+       u32                             max_nofl_db;
+
+       struct __vxge_hw_ring *____cacheline_aligned ringh;
+       struct __vxge_hw_fifo *____cacheline_aligned fifoh;
+       struct list_head                vpath_handles;
+       struct __vxge_hw_blockpool_entry                *stats_block;
+       struct vxge_hw_vpath_stats_hw_info      *hw_stats;
+       struct vxge_hw_vpath_stats_hw_info      *hw_stats_sav;
+       struct vxge_hw_vpath_stats_sw_info      *sw_stats;
+};
+
+/*
+ * struct __vxge_hw_vpath_handle - List item to store callback information
+ * @item: List head to keep the item in linked list
+ * @vpath: Virtual path to which this item belongs
+ *
+ * This structure is used to store the callback information.
+ */
+struct __vxge_hw_vpath_handle{
+       struct list_head        item;
+       struct __vxge_hw_virtualpath    *vpath;
+};
+
+/*
+ * struct __vxge_hw_device
+ *
+ * HW device object.
+ */
+/**
+ * struct __vxge_hw_device  - Hal device object
+ * @magic: Magic Number
+ * @device_id: PCI Device Id of the adapter
+ * @major_revision: PCI Device major revision
+ * @minor_revision: PCI Device minor revision
+ * @bar0: BAR0 virtual address.
+ * @bar1: BAR1 virtual address.
+ * @bar2: BAR2 virtual address.
+ * @pdev: Physical device handle
+ * @config: Confguration passed by the LL driver at initialization
+ * @link_state: Link state
+ *
+ * HW device object. Represents Titan adapter
+ */
+struct __vxge_hw_device {
+       u32                             magic;
+#define VXGE_HW_DEVICE_MAGIC           0x12345678
+#define VXGE_HW_DEVICE_DEAD            0xDEADDEAD
+       u16                             device_id;
+       u8                              major_revision;
+       u8                              minor_revision;
+       void __iomem                    *bar0;
+       void __iomem                    *bar1;
+       void __iomem                    *bar2;
+       struct pci_dev                  *pdev;
+       struct net_device               *ndev;
+       struct vxge_hw_device_config    config;
+       enum vxge_hw_device_link_state  link_state;
+
+       struct vxge_hw_uld_cbs          uld_callbacks;
+
+       u32                             host_type;
+       u32                             func_id;
+       u32                             access_rights;
+#define VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH      0x1
+#define VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM     0x2
+#define VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM     0x4
+       struct vxge_hw_legacy_reg       __iomem *legacy_reg;
+       struct vxge_hw_toc_reg          __iomem *toc_reg;
+       struct vxge_hw_common_reg       __iomem *common_reg;
+       struct vxge_hw_mrpcim_reg       __iomem *mrpcim_reg;
+       struct vxge_hw_srpcim_reg       __iomem *srpcim_reg \
+                                       [VXGE_HW_TITAN_SRPCIM_REG_SPACES];
+       struct vxge_hw_vpmgmt_reg       __iomem *vpmgmt_reg \
+                                       [VXGE_HW_TITAN_VPMGMT_REG_SPACES];
+       struct vxge_hw_vpath_reg        __iomem *vpath_reg \
+                                       [VXGE_HW_TITAN_VPATH_REG_SPACES];
+       u8                              __iomem *kdfc;
+       u8                              __iomem *usdc;
+       struct __vxge_hw_virtualpath    virtual_paths \
+                                       [VXGE_HW_MAX_VIRTUAL_PATHS];
+       u64                             vpath_assignments;
+       u64                             vpaths_deployed;
+       u32                             first_vp_id;
+       u64                             tim_int_mask0[4];
+       u32                             tim_int_mask1[4];
+
+       struct __vxge_hw_blockpool      block_pool;
+       struct vxge_hw_device_stats     stats;
+       u32                             debug_module_mask;
+       u32                             debug_level;
+       u32                             level_err;
+       u32                             level_trace;
+};
+
+#define VXGE_HW_INFO_LEN       64
+/**
+ * struct vxge_hw_device_hw_info - Device information
+ * @host_type: Host Type
+ * @func_id: Function Id
+ * @vpath_mask: vpath bit mask
+ * @fw_version: Firmware version
+ * @fw_date: Firmware Date
+ * @flash_version: Firmware version
+ * @flash_date: Firmware Date
+ * @mac_addrs: Mac addresses for each vpath
+ * @mac_addr_masks: Mac address masks for each vpath
+ *
+ * Returns the vpath mask that has the bits set for each vpath allocated
+ * for the driver and the first mac address for each vpath
+ */
+struct vxge_hw_device_hw_info {
+       u32             host_type;
+#define VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION                    0
+#define VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION                     1
+#define VXGE_HW_NO_MR_SR_VH0_FUNCTION0                         2
+#define VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION                  3
+#define VXGE_HW_MR_SR_VH0_INVALID_CONFIG                       4
+#define VXGE_HW_SR_VH_FUNCTION0                                        5
+#define VXGE_HW_SR_VH_VIRTUAL_FUNCTION                         6
+#define VXGE_HW_VH_NORMAL_FUNCTION                             7
+       u64             function_mode;
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION                   0
+#define VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION                  1
+#define VXGE_HW_FUNCTION_MODE_SRIOV                            2
+#define VXGE_HW_FUNCTION_MODE_MRIOV                            3
+       u32             func_id;
+       u64             vpath_mask;
+       struct vxge_hw_device_version fw_version;
+       struct vxge_hw_device_date    fw_date;
+       struct vxge_hw_device_version flash_version;
+       struct vxge_hw_device_date    flash_date;
+       u8              serial_number[VXGE_HW_INFO_LEN];
+       u8              part_number[VXGE_HW_INFO_LEN];
+       u8              product_desc[VXGE_HW_INFO_LEN];
+       u8 (mac_addrs)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
+       u8 (mac_addr_masks)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
+};
+
+/**
+ * struct vxge_hw_device_attr - Device memory spaces.
+ * @bar0: BAR0 virtual address.
+ * @bar1: BAR1 virtual address.
+ * @bar2: BAR2 virtual address.
+ * @pdev: PCI device object.
+ *
+ * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device
+ * mapped memories. Also, includes a pointer to OS-specific PCI device object.
+ */
+struct vxge_hw_device_attr {
+       void __iomem            *bar0;
+       void __iomem            *bar1;
+       void __iomem            *bar2;
+       struct pci_dev          *pdev;
+       struct vxge_hw_uld_cbs  uld_callbacks;
+};
+
+#define VXGE_HW_DEVICE_LINK_STATE_SET(hldev, ls)       (hldev->link_state = ls)
+
+#define VXGE_HW_DEVICE_TIM_INT_MASK_SET(m0, m1, i) {   \
+       if (i < 16) {                           \
+               m0[0] |= vxge_vBIT(0x8, (i*4), 4);      \
+               m0[1] |= vxge_vBIT(0x4, (i*4), 4);      \
+       }                                       \
+       else {                                  \
+               m1[0] = 0x80000000;             \
+               m1[1] = 0x40000000;             \
+       }                                       \
+}
+
+#define VXGE_HW_DEVICE_TIM_INT_MASK_RESET(m0, m1, i) { \
+       if (i < 16) {                                   \
+               m0[0] &= ~vxge_vBIT(0x8, (i*4), 4);             \
+               m0[1] &= ~vxge_vBIT(0x4, (i*4), 4);             \
+       }                                               \
+       else {                                          \
+               m1[0] = 0;                              \
+               m1[1] = 0;                              \
+       }                                               \
+}
+
+#define VXGE_HW_DEVICE_STATS_PIO_READ(loc, offset) {           \
+       status = vxge_hw_mrpcim_stats_access(hldev, \
+                               VXGE_HW_STATS_OP_READ, \
+                               loc, \
+                               offset, \
+                               &val64);                        \
+                                                               \
+       if (status != VXGE_HW_OK)                               \
+               return status;                                          \
+}
+
+#define VXGE_HW_VPATH_STATS_PIO_READ(offset) {                         \
+       status = __vxge_hw_vpath_stats_access(vpath, \
+                       VXGE_HW_STATS_OP_READ, \
+                       offset, \
+                       &val64);                                        \
+       if (status != VXGE_HW_OK)                                       \
+               return status;                                          \
+}
+
+/*
+ * struct __vxge_hw_ring - Ring channel.
+ * @channel: Channel "base" of this ring, the common part of all HW
+ *           channels.
+ * @mempool: Memory pool, the pool from which descriptors get allocated.
+ *           (See vxge_hw_mm.h).
+ * @config: Ring configuration, part of device configuration
+ *          (see struct vxge_hw_device_config{}).
+ * @ring_length: Length of the ring
+ * @buffer_mode: 1, 3, or 5. The value specifies a receive buffer mode,
+ *          as per Titan User Guide.
+ * @rxd_size: RxD sizes for 1-, 3- or 5- buffer modes. As per Titan spec,
+ *            1-buffer mode descriptor is 32 byte long, etc.
+ * @rxd_priv_size: Per RxD size reserved (by HW) for driver to keep
+ *                 per-descriptor data (e.g., DMA handle for Solaris)
+ * @per_rxd_space: Per rxd space requested by driver
+ * @rxds_per_block: Number of descriptors per hardware-defined RxD
+ *                  block. Depends on the (1-, 3-, 5-) buffer mode.
+ * @rxdblock_priv_size: Reserved at the end of each RxD block. HW internal
+ *                      usage. Not to confuse with @rxd_priv_size.
+ * @cmpl_cnt: Completion counter. Is reset to zero upon entering the ISR.
+ * @callback: Channel completion callback. HW invokes the callback when there
+ *            are new completions on that channel. In many implementations
+ *            the @callback executes in the hw interrupt context.
+ * @rxd_init: Channel's descriptor-initialize callback.
+ *            See vxge_hw_ring_rxd_init_f{}.
+ *            If not NULL, HW invokes the callback when opening
+ *            the ring.
+ * @rxd_term: Channel's descriptor-terminate callback. If not NULL,
+ *          HW invokes the callback when closing the corresponding channel.
+ *          See also vxge_hw_channel_rxd_term_f{}.
+ * @stats: Statistics for ring
+ * Ring channel.
+ *
+ * Note: The structure is cache line aligned to better utilize
+ *       CPU cache performance.
+ */
+struct __vxge_hw_ring {
+       struct __vxge_hw_channel                channel;
+       struct vxge_hw_mempool                  *mempool;
+       struct vxge_hw_vpath_reg                __iomem *vp_reg;
+       struct vxge_hw_common_reg               __iomem *common_reg;
+       u32                                     ring_length;
+       u32                                     buffer_mode;
+       u32                                     rxd_size;
+       u32                                     rxd_priv_size;
+       u32                                     per_rxd_space;
+       u32                                     rxds_per_block;
+       u32                                     rxdblock_priv_size;
+       u32                                     cmpl_cnt;
+       u32                                     vp_id;
+       u32                                     doorbell_cnt;
+       u32                                     total_db_cnt;
+       u64                                     rxds_limit;
+
+       enum vxge_hw_status (*callback)(
+                       struct __vxge_hw_ring *ringh,
+                       void *rxdh,
+                       u8 t_code,
+                       void *userdata);
+
+       enum vxge_hw_status (*rxd_init)(
+                       void *rxdh,
+                       void *userdata);
+
+       void (*rxd_term)(
+                       void *rxdh,
+                       enum vxge_hw_rxd_state state,
+                       void *userdata);
+
+       struct vxge_hw_vpath_stats_sw_ring_info *stats  ____cacheline_aligned;
+       struct vxge_hw_ring_config              *config;
+} ____cacheline_aligned;
+
+/**
+ * enum enum vxge_hw_txdl_state - Descriptor (TXDL) state.
+ * @VXGE_HW_TXDL_STATE_NONE: Invalid state.
+ * @VXGE_HW_TXDL_STATE_AVAIL: Descriptor is available for reservation.
+ * @VXGE_HW_TXDL_STATE_POSTED: Descriptor is posted for processing by the
+ * device.
+ * @VXGE_HW_TXDL_STATE_FREED: Descriptor is free and can be reused for
+ * filling-in and posting later.
+ *
+ * Titan/HW descriptor states.
+ *
+ */
+enum vxge_hw_txdl_state {
+       VXGE_HW_TXDL_STATE_NONE = 0,
+       VXGE_HW_TXDL_STATE_AVAIL        = 1,
+       VXGE_HW_TXDL_STATE_POSTED       = 2,
+       VXGE_HW_TXDL_STATE_FREED        = 3
+};
+/*
+ * struct __vxge_hw_fifo - Fifo.
+ * @channel: Channel "base" of this fifo, the common part of all HW
+ *             channels.
+ * @mempool: Memory pool, from which descriptors get allocated.
+ * @config: Fifo configuration, part of device configuration
+ *             (see struct vxge_hw_device_config{}).
+ * @interrupt_type: Interrupt type to be used
+ * @no_snoop_bits: See struct vxge_hw_fifo_config{}.
+ * @txdl_per_memblock: Number of TxDLs (TxD lists) per memblock.
+ *             on TxDL please refer to Titan UG.
+ * @txdl_size: Configured TxDL size (i.e., number of TxDs in a list), plus
+ *             per-TxDL HW private space (struct __vxge_hw_fifo_txdl_priv).
+ * @priv_size: Per-Tx descriptor space reserved for driver
+ *             usage.
+ * @per_txdl_space: Per txdl private space for the driver
+ * @callback: Fifo completion callback. HW invokes the callback when there
+ *             are new completions on that fifo. In many implementations
+ *             the @callback executes in the hw interrupt context.
+ * @txdl_term: Fifo's descriptor-terminate callback. If not NULL,
+ *             HW invokes the callback when closing the corresponding fifo.
+ *             See also vxge_hw_fifo_txdl_term_f{}.
+ * @stats: Statistics of this fifo
+ *
+ * Fifo channel.
+ * Note: The structure is cache line aligned.
+ */
+struct __vxge_hw_fifo {
+       struct __vxge_hw_channel                channel;
+       struct vxge_hw_mempool                  *mempool;
+       struct vxge_hw_fifo_config              *config;
+       struct vxge_hw_vpath_reg                __iomem *vp_reg;
+       struct __vxge_hw_non_offload_db_wrapper __iomem *nofl_db;
+       u64                                     interrupt_type;
+       u32                                     no_snoop_bits;
+       u32                                     txdl_per_memblock;
+       u32                                     txdl_size;
+       u32                                     priv_size;
+       u32                                     per_txdl_space;
+       u32                                     vp_id;
+       u32                                     tx_intr_num;
+
+       enum vxge_hw_status (*callback)(
+                       struct __vxge_hw_fifo *fifo_handle,
+                       void *txdlh,
+                       enum vxge_hw_fifo_tcode t_code,
+                       void *userdata,
+                       void **skb_ptr);
+
+       void (*txdl_term)(
+                       void *txdlh,
+                       enum vxge_hw_txdl_state state,
+                       void *userdata);
+
+       struct vxge_hw_vpath_stats_sw_fifo_info *stats ____cacheline_aligned;
+} ____cacheline_aligned;
+
+/*
+ * struct __vxge_hw_fifo_txdl_priv - Transmit descriptor HW-private data.
+ * @dma_addr: DMA (mapped) address of _this_ descriptor.
+ * @dma_handle: DMA handle used to map the descriptor onto device.
+ * @dma_offset: Descriptor's offset in the memory block. HW allocates
+ *      descriptors in memory blocks (see struct vxge_hw_fifo_config{})
+ *             Each memblock is a contiguous block of DMA-able memory.
+ * @frags: Total number of fragments (that is, contiguous data buffers)
+ * carried by this TxDL.
+ * @align_vaddr_start: Aligned virtual address start
+ * @align_vaddr: Virtual address of the per-TxDL area in memory used for
+ *             alignement. Used to place one or more mis-aligned fragments
+ * @align_dma_addr: DMA address translated from the @align_vaddr.
+ * @align_dma_handle: DMA handle that corresponds to @align_dma_addr.
+ * @align_dma_acch: DMA access handle corresponds to @align_dma_addr.
+ * @align_dma_offset: The current offset into the @align_vaddr area.
+ * Grows while filling the descriptor, gets reset.
+ * @align_used_frags: Number of fragments used.
+ * @alloc_frags: Total number of fragments allocated.
+ * @unused: TODO
+ * @next_txdl_priv: (TODO).
+ * @first_txdp: (TODO).
+ * @linked_txdl_priv: Pointer to any linked TxDL for creating contiguous
+ *             TxDL list.
+ * @txdlh: Corresponding txdlh to this TxDL.
+ * @memblock: Pointer to the TxDL memory block or memory page.
+ *             on the next send operation.
+ * @dma_object: DMA address and handle of the memory block that contains
+ *             the descriptor. This member is used only in the "checked"
+ *             version of the HW (to enforce certain assertions);
+ *             otherwise it gets compiled out.
+ * @allocated: True if the descriptor is reserved, 0 otherwise. Internal usage.
+ *
+ * Per-transmit decsriptor HW-private data. HW uses the space to keep DMA
+ * information associated with the descriptor. Note that driver can ask HW
+ * to allocate additional per-descriptor space for its own (driver-specific)
+ * purposes.
+ *
+ * See also: struct vxge_hw_ring_rxd_priv{}.
+ */
+struct __vxge_hw_fifo_txdl_priv {
+       dma_addr_t              dma_addr;
+       struct pci_dev  *dma_handle;
+       ptrdiff_t               dma_offset;
+       u32                             frags;
+       u8                              *align_vaddr_start;
+       u8                              *align_vaddr;
+       dma_addr_t              align_dma_addr;
+       struct pci_dev  *align_dma_handle;
+       struct pci_dev  *align_dma_acch;
+       ptrdiff_t               align_dma_offset;
+       u32                             align_used_frags;
+       u32                             alloc_frags;
+       u32                             unused;
+       struct __vxge_hw_fifo_txdl_priv *next_txdl_priv;
+       struct vxge_hw_fifo_txd         *first_txdp;
+       void                    *memblock;
+};
+
+/*
+ * struct __vxge_hw_non_offload_db_wrapper - Non-offload Doorbell Wrapper
+ * @control_0: Bits 0 to 7 - Doorbell type.
+ *             Bits 8 to 31 - Reserved.
+ *             Bits 32 to 39 - The highest TxD in this TxDL.
+ *             Bits 40 to 47 - Reserved.
+       *              Bits 48 to 55 - Reserved.
+ *             Bits 56 to 63 - No snoop flags.
+ * @txdl_ptr:  The starting location of the TxDL in host memory.
+ *
+ * Created by the host and written to the adapter via PIO to a Kernel Doorbell
+ * FIFO. All non-offload doorbell wrapper fields must be written by the host as
+ * part of a doorbell write. Consumed by the adapter but is not written by the
+ * adapter.
+ */
+struct __vxge_hw_non_offload_db_wrapper {
+       u64             control_0;
+#define        VXGE_HW_NODBW_GET_TYPE(ctrl0)                   vxge_bVALn(ctrl0, 0, 8)
+#define VXGE_HW_NODBW_TYPE(val) vxge_vBIT(val, 0, 8)
+#define        VXGE_HW_NODBW_TYPE_NODBW                                0
+
+#define        VXGE_HW_NODBW_GET_LAST_TXD_NUMBER(ctrl0)        vxge_bVALn(ctrl0, 32, 8)
+#define VXGE_HW_NODBW_LAST_TXD_NUMBER(val) vxge_vBIT(val, 32, 8)
+
+#define        VXGE_HW_NODBW_GET_NO_SNOOP(ctrl0)               vxge_bVALn(ctrl0, 56, 8)
+#define VXGE_HW_NODBW_LIST_NO_SNOOP(val) vxge_vBIT(val, 56, 8)
+#define        VXGE_HW_NODBW_LIST_NO_SNOOP_TXD_READ_TXD0_WRITE         0x2
+#define        VXGE_HW_NODBW_LIST_NO_SNOOP_TX_FRAME_DATA_READ          0x1
+
+       u64             txdl_ptr;
+};
+
+/*
+ * TX Descriptor
+ */
+
+/**
+ * struct vxge_hw_fifo_txd - Transmit Descriptor
+ * @control_0: Bits 0 to 6 - Reserved.
+ *             Bit 7 - List Ownership. This field should be initialized
+ *             to '1' by the driver before the transmit list pointer is
+ *             written to the adapter. This field will be set to '0' by the
+ *             adapter once it has completed transmitting the frame or frames in
+ *             the list. Note - This field is only valid in TxD0. Additionally,
+ *             for multi-list sequences, the driver should not release any
+ *             buffers until the ownership of the last list in the multi-list
+ *             sequence has been returned to the host.
+ *             Bits 8 to 11 - Reserved
+ *             Bits 12 to 15 - Transfer_Code. This field is only valid in
+ *             TxD0. It is used to describe the status of the transmit data
+ *             buffer transfer. This field is always overwritten by the
+ *             adapter, so this field may be initialized to any value.
+ *             Bits 16 to 17 - Host steering. This field allows the host to
+ *             override the selection of the physical transmit port.
+ *             Attention:
+ *             Normal sounds as if learned from the switch rather than from
+ *             the aggregation algorythms.
+ *             00: Normal. Use Destination/MAC Address
+ *             lookup to determine the transmit port.
+ *             01: Send on physical Port1.
+ *             10: Send on physical Port0.
+       *              11: Send on both ports.
+ *             Bits 18 to 21 - Reserved
+ *             Bits 22 to 23 - Gather_Code. This field is set by the host and
+ *             is used to describe how individual buffers comprise a frame.
+ *             10: First descriptor of a frame.
+ *             00: Middle of a multi-descriptor frame.
+ *             01: Last descriptor of a frame.
+ *             11: First and last descriptor of a frame (the entire frame
+ *             resides in a single buffer).
+ *             For multi-descriptor frames, the only valid gather code sequence
+ *             is {10, [00], 01}. In other words, the descriptors must be placed
+ *             in the list in the correct order.
+ *             Bits 24 to 27 - Reserved
+ *             Bits 28 to 29 - LSO_Frm_Encap. LSO Frame Encapsulation
+ *             definition. Only valid in TxD0. This field allows the host to
+ *             indicate the Ethernet encapsulation of an outbound LSO packet.
+ *             00 - classic mode (best guess)
+ *             01 - LLC
+ *             10 - SNAP
+ *             11 - DIX
+ *             If "classic mode" is selected, the adapter will attempt to
+ *             decode the frame's Ethernet encapsulation by examining the L/T
+ *             field as follows:
+ *             <= 0x05DC LLC/SNAP encoding; must examine DSAP/SSAP to determine
+ *             if packet is IPv4 or IPv6.
+ *             0x8870 Jumbo-SNAP encoding.
+ *             0x0800 IPv4 DIX encoding
+ *             0x86DD IPv6 DIX encoding
+ *             others illegal encapsulation
+ *             Bits 30 - LSO_ Flag. Large Send Offload (LSO) flag.
+ *             Set to 1 to perform segmentation offload for TCP/UDP.
+ *             This field is valid only in TxD0.
+ *             Bits 31 to 33 - Reserved.
+ *             Bits 34 to 47 - LSO_MSS. TCP/UDP LSO Maximum Segment Size
+ *             This field is meaningful only when LSO_Control is non-zero.
+ *             When LSO_Control is set to TCP_LSO, the single (possibly large)
+ *             TCP segment described by this TxDL will be sent as a series of
+ *             TCP segments each of which contains no more than LSO_MSS
+ *             payload bytes.
+ *             When LSO_Control is set to UDP_LSO, the single (possibly large)
+ *             UDP datagram described by this TxDL will be sent as a series of
+ *             UDP datagrams each of which contains no more than LSO_MSS
+ *             payload bytes.
+ *             All outgoing frames from this TxDL will have LSO_MSS bytes of UDP
+ *             or TCP payload, with the exception of the last, which will have
+ *             <= LSO_MSS bytes of payload.
+ *             Bits 48 to 63 - Buffer_Size. Number of valid bytes in the
+ *             buffer to be read by the adapter. This field is written by the
+ *             host. A value of 0 is illegal.
+ *            Bits 32 to 63 - This value is written by the adapter upon
+ *            completion of a UDP or TCP LSO operation and indicates the number
+ *             of UDP or TCP payload bytes that were transmitted. 0x0000 will be
+ *             returned for any non-LSO operation.
+ * @control_1: Bits 0 to 4 - Reserved.
+ *             Bit 5 - Tx_CKO_IPv4 Set to a '1' to enable IPv4 header checksum
+ *             offload. This field is only valid in the first TxD of a frame.
+ *             Bit 6 - Tx_CKO_TCP Set to a '1' to enable TCP checksum offload.
+ *             This field is only valid in the first TxD of a frame (the TxD's
+ *             gather code must be 10 or 11). The driver should only set this
+ *             bit if it can guarantee that TCP is present.
+ *             Bit 7 - Tx_CKO_UDP Set to a '1' to enable UDP checksum offload.
+ *             This field is only valid in the first TxD of a frame (the TxD's
+ *             gather code must be 10 or 11). The driver should only set this
+ *             bit if it can guarantee that UDP is present.
+ *             Bits 8 to 14 - Reserved.
+ *             Bit 15 - Tx_VLAN_Enable VLAN tag insertion flag. Set to a '1' to
+ *             instruct the adapter to insert the VLAN tag specified by the
+ *             Tx_VLAN_Tag field. This field is only valid in the first TxD of
+ *             a frame.
+ *             Bits 16 to 31 - Tx_VLAN_Tag. Variable portion of the VLAN tag
+ *             to be inserted into the frame by the adapter (the first two bytes
+ *             of a VLAN tag are always 0x8100). This field is only valid if the
+ *             Tx_VLAN_Enable field is set to '1'.
+ *             Bits 32 to 33 - Reserved.
+ *             Bits 34 to 39 - Tx_Int_Number. Indicates which Tx interrupt
+ *             number the frame associated with. This field is written by the
+ *             host. It is only valid in the first TxD of a frame.
+ *             Bits 40 to 42 - Reserved.
+ *             Bit 43 - Set to 1 to exclude the frame from bandwidth metering
+ *             functions. This field is valid only in the first TxD
+ *             of a frame.
+ *             Bits 44 to 45 - Reserved.
+ *             Bit 46 - Tx_Int_Per_List Set to a '1' to instruct the adapter to
+ *             generate an interrupt as soon as all of the frames in the list
+ *             have been transmitted. In order to have per-frame interrupts,
+ *             the driver should place a maximum of one frame per list. This
+ *             field is only valid in the first TxD of a frame.
+ *             Bit 47 - Tx_Int_Utilization Set to a '1' to instruct the adapter
+ *             to count the frame toward the utilization interrupt specified in
+ *             the Tx_Int_Number field. This field is only valid in the first
+ *             TxD of a frame.
+ *             Bits 48 to 63 - Reserved.
+ * @buffer_pointer: Buffer start address.
+ * @host_control: Host_Control.Opaque 64bit data stored by driver inside the
+ *            Titan descriptor prior to posting the latter on the fifo
+ *            via vxge_hw_fifo_txdl_post().The %host_control is returned as is
+ *            to the driver with each completed descriptor.
+ *
+ * Transmit descriptor (TxD).Fifo descriptor contains configured number
+ * (list) of TxDs. * For more details please refer to Titan User Guide,
+ * Section 5.4.2 "Transmit Descriptor (TxD) Format".
+ */
+struct vxge_hw_fifo_txd {
+       u64 control_0;
+#define VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER              vxge_mBIT(7)
+
+#define VXGE_HW_FIFO_TXD_T_CODE_GET(ctrl0)             vxge_bVALn(ctrl0, 12, 4)
+#define VXGE_HW_FIFO_TXD_T_CODE(val)                   vxge_vBIT(val, 12, 4)
+#define VXGE_HW_FIFO_TXD_T_CODE_UNUSED         VXGE_HW_FIFO_T_CODE_UNUSED
+
+
+#define VXGE_HW_FIFO_TXD_GATHER_CODE(val)              vxge_vBIT(val, 22, 2)
+#define VXGE_HW_FIFO_TXD_GATHER_CODE_FIRST     VXGE_HW_FIFO_GATHER_CODE_FIRST
+#define VXGE_HW_FIFO_TXD_GATHER_CODE_LAST      VXGE_HW_FIFO_GATHER_CODE_LAST
+
+
+#define VXGE_HW_FIFO_TXD_LSO_EN                                vxge_mBIT(30)
+
+#define VXGE_HW_FIFO_TXD_LSO_MSS(val)                  vxge_vBIT(val, 34, 14)
+
+#define VXGE_HW_FIFO_TXD_BUFFER_SIZE(val)              vxge_vBIT(val, 48, 16)
+
+       u64 control_1;
+#define VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN                        vxge_mBIT(5)
+#define VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN                 vxge_mBIT(6)
+#define VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN                 vxge_mBIT(7)
+#define VXGE_HW_FIFO_TXD_VLAN_ENABLE                   vxge_mBIT(15)
+
+#define VXGE_HW_FIFO_TXD_VLAN_TAG(val)                         vxge_vBIT(val, 16, 16)
+
+#define VXGE_HW_FIFO_TXD_INT_NUMBER(val)               vxge_vBIT(val, 34, 6)
+
+#define VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST             vxge_mBIT(46)
+#define VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ                        vxge_mBIT(47)
+
+       u64 buffer_pointer;
+
+       u64 host_control;
+};
+
+/**
+ * struct vxge_hw_ring_rxd_1 - One buffer mode RxD for ring
+ * @host_control: This field is exclusively for host use and is "readonly"
+ *             from the adapter's perspective.
+ * @control_0:Bits 0 to 6 - RTH_Bucket get
+ *           Bit 7 - Own Descriptor ownership bit. This bit is set to 1
+ *            by the host, and is set to 0 by the adapter.
+ *           0 - Host owns RxD and buffer.
+ *           1 - The adapter owns RxD and buffer.
+ *           Bit 8 - Fast_Path_Eligible When set, indicates that the
+ *            received frame meets all of the criteria for fast path processing.
+ *            The required criteria are as follows:
+ *            !SYN &
+ *            (Transfer_Code == "Transfer OK") &
+ *            (!Is_IP_Fragment) &
+ *            ((Is_IPv4 & computed_L3_checksum == 0xFFFF) |
+ *            (Is_IPv6)) &
+ *            ((Is_TCP & computed_L4_checksum == 0xFFFF) |
+ *            (Is_UDP & (computed_L4_checksum == 0xFFFF |
+ *            computed _L4_checksum == 0x0000)))
+ *            (same meaning for all RxD buffer modes)
+ *           Bit 9 - L3 Checksum Correct
+ *           Bit 10 - L4 Checksum Correct
+ *           Bit 11 - Reserved
+ *           Bit 12 to 15 - This field is written by the adapter. It is
+ *            used to report the status of the frame transfer to the host.
+ *           0x0 - Transfer OK
+ *           0x4 - RDA Failure During Transfer
+ *           0x5 - Unparseable Packet, such as unknown IPv6 header.
+ *           0x6 - Frame integrity error (FCS or ECC).
+ *           0x7 - Buffer Size Error. The provided buffer(s) were not
+ *                  appropriately sized and data loss occurred.
+ *           0x8 - Internal ECC Error. RxD corrupted.
+ *           0x9 - IPv4 Checksum error
+ *           0xA - TCP/UDP Checksum error
+ *           0xF - Unknown Error or Multiple Error. Indicates an
+ *               unknown problem or that more than one of transfer codes is set.
+ *           Bit 16 - SYN The adapter sets this field to indicate that
+ *                the incoming frame contained a TCP segment with its SYN bit
+ *               set and its ACK bit NOT set. (same meaning for all RxD buffer
+ *                modes)
+ *           Bit 17 - Is ICMP
+ *           Bit 18 - RTH_SPDM_HIT Set to 1 if there was a match in the
+ *                Socket Pair Direct Match Table and the frame was steered based
+ *                on SPDM.
+ *           Bit 19 - RTH_IT_HIT Set to 1 if there was a match in the
+ *            Indirection Table and the frame was steered based on hash
+ *            indirection.
+ *           Bit 20 to 23 - RTH_HASH_TYPE Indicates the function (hash
+ *               type) that was used to calculate the hash.
+ *           Bit 19 - IS_VLAN Set to '1' if the frame was/is VLAN
+ *               tagged.
+ *           Bit 25 to 26 - ETHER_ENCAP Reflects the Ethernet encapsulation
+ *                of the received frame.
+ *           0x0 - Ethernet DIX
+ *           0x1 - LLC
+ *           0x2 - SNAP (includes Jumbo-SNAP)
+ *           0x3 - IPX
+ *           Bit 27 - IS_IPV4 Set to '1' if the frame contains an IPv4 packet.
+ *           Bit 28 - IS_IPV6 Set to '1' if the frame contains an IPv6 packet.
+ *           Bit 29 - IS_IP_FRAG Set to '1' if the frame contains a fragmented
+ *            IP packet.
+ *           Bit 30 - IS_TCP Set to '1' if the frame contains a TCP segment.
+ *           Bit 31 - IS_UDP Set to '1' if the frame contains a UDP message.
+ *           Bit 32 to 47 - L3_Checksum[0:15] The IPv4 checksum value  that
+ *            arrived with the frame. If the resulting computed IPv4 header
+ *            checksum for the frame did not produce the expected 0xFFFF value,
+ *            then the transfer code would be set to 0x9.
+ *           Bit 48 to 63 - L4_Checksum[0:15] The TCP/UDP checksum value that
+ *            arrived with the frame. If the resulting computed TCP/UDP checksum
+ *            for the frame did not produce the expected 0xFFFF value, then the
+ *            transfer code would be set to 0xA.
+ * @control_1:Bits 0 to 1 - Reserved
+ *            Bits 2 to 15 - Buffer0_Size.This field is set by the host and
+ *            eventually overwritten by the adapter. The host writes the
+ *            available buffer size in bytes when it passes the descriptor to
+ *            the adapter. When a frame is delivered the host, the adapter
+ *            populates this field with the number of bytes written into the
+ *            buffer. The largest supported buffer is 16, 383 bytes.
+ *           Bit 16 to 47 - RTH Hash Value 32-bit RTH hash value. Only valid if
+ *           RTH_HASH_TYPE (Control_0, bits 20:23) is nonzero.
+ *           Bit 48 to 63 - VLAN_Tag[0:15] The contents of the variable portion
+ *            of the VLAN tag, if one was detected by the adapter. This field is
+ *            populated even if VLAN-tag stripping is enabled.
+ * @buffer0_ptr: Pointer to buffer. This field is populated by the driver.
+ *
+ * One buffer mode RxD for ring structure
+ */
+struct vxge_hw_ring_rxd_1 {
+       u64 host_control;
+       u64 control_0;
+#define VXGE_HW_RING_RXD_RTH_BUCKET_GET(ctrl0)         vxge_bVALn(ctrl0, 0, 7)
+
+#define VXGE_HW_RING_RXD_LIST_OWN_ADAPTER              vxge_mBIT(7)
+
+#define VXGE_HW_RING_RXD_FAST_PATH_ELIGIBLE_GET(ctrl0) vxge_bVALn(ctrl0, 8, 1)
+
+#define VXGE_HW_RING_RXD_L3_CKSUM_CORRECT_GET(ctrl0)   vxge_bVALn(ctrl0, 9, 1)
+
+#define VXGE_HW_RING_RXD_L4_CKSUM_CORRECT_GET(ctrl0)   vxge_bVALn(ctrl0, 10, 1)
+
+#define VXGE_HW_RING_RXD_T_CODE_GET(ctrl0)             vxge_bVALn(ctrl0, 12, 4)
+#define VXGE_HW_RING_RXD_T_CODE(val)                   vxge_vBIT(val, 12, 4)
+
+#define VXGE_HW_RING_RXD_T_CODE_UNUSED         VXGE_HW_RING_T_CODE_UNUSED
+
+#define VXGE_HW_RING_RXD_SYN_GET(ctrl0)                vxge_bVALn(ctrl0, 16, 1)
+
+#define VXGE_HW_RING_RXD_IS_ICMP_GET(ctrl0)            vxge_bVALn(ctrl0, 17, 1)
+
+#define VXGE_HW_RING_RXD_RTH_SPDM_HIT_GET(ctrl0)       vxge_bVALn(ctrl0, 18, 1)
+
+#define VXGE_HW_RING_RXD_RTH_IT_HIT_GET(ctrl0)         vxge_bVALn(ctrl0, 19, 1)
+
+#define VXGE_HW_RING_RXD_RTH_HASH_TYPE_GET(ctrl0)      vxge_bVALn(ctrl0, 20, 4)
+
+#define VXGE_HW_RING_RXD_IS_VLAN_GET(ctrl0)            vxge_bVALn(ctrl0, 24, 1)
+
+#define VXGE_HW_RING_RXD_ETHER_ENCAP_GET(ctrl0)                vxge_bVALn(ctrl0, 25, 2)
+
+#define VXGE_HW_RING_RXD_FRAME_PROTO_GET(ctrl0)                vxge_bVALn(ctrl0, 27, 5)
+
+#define VXGE_HW_RING_RXD_L3_CKSUM_GET(ctrl0)   vxge_bVALn(ctrl0, 32, 16)
+
+#define VXGE_HW_RING_RXD_L4_CKSUM_GET(ctrl0)   vxge_bVALn(ctrl0, 48, 16)
+
+       u64 control_1;
+
+#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(ctrl1)     vxge_bVALn(ctrl1, 2, 14)
+#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE(val) vxge_vBIT(val, 2, 14)
+#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK           vxge_vBIT(0x3FFF, 2, 14)
+
+#define VXGE_HW_RING_RXD_1_RTH_HASH_VAL_GET(ctrl1)    vxge_bVALn(ctrl1, 16, 32)
+
+#define VXGE_HW_RING_RXD_VLAN_TAG_GET(ctrl1)   vxge_bVALn(ctrl1, 48, 16)
+
+       u64 buffer0_ptr;
+};
+
+enum vxge_hw_rth_algoritms {
+       RTH_ALG_JENKINS = 0,
+       RTH_ALG_MS_RSS  = 1,
+       RTH_ALG_CRC32C  = 2
+};
+
+/**
+ * struct vxge_hw_rth_hash_types - RTH hash types.
+ * @hash_type_tcpipv4_en: Enables RTH field type HashTypeTcpIPv4
+ * @hash_type_ipv4_en: Enables RTH field type HashTypeIPv4
+ * @hash_type_tcpipv6_en: Enables RTH field type HashTypeTcpIPv6
+ * @hash_type_ipv6_en: Enables RTH field type HashTypeIPv6
+ * @hash_type_tcpipv6ex_en: Enables RTH field type HashTypeTcpIPv6Ex
+ * @hash_type_ipv6ex_en: Enables RTH field type HashTypeIPv6Ex
+ *
+ * Used to pass RTH hash types to rts_rts_set.
+ *
+ * See also: vxge_hw_vpath_rts_rth_set(), vxge_hw_vpath_rts_rth_get().
+ */
+struct vxge_hw_rth_hash_types {
+       u8 hash_type_tcpipv4_en;
+       u8 hash_type_ipv4_en;
+       u8 hash_type_tcpipv6_en;
+       u8 hash_type_ipv6_en;
+       u8 hash_type_tcpipv6ex_en;
+       u8 hash_type_ipv6ex_en;
+};
+
+u32
+vxge_hw_device_debug_mask_get(struct __vxge_hw_device *devh);
+
+void vxge_hw_device_debug_set(
+       struct __vxge_hw_device *devh,
+       enum vxge_debug_level level,
+       u32 mask);
+
+u32
+vxge_hw_device_error_level_get(struct __vxge_hw_device *devh);
+
+u32
+vxge_hw_device_trace_level_get(struct __vxge_hw_device *devh);
+
+u32
+vxge_hw_device_debug_mask_get(struct __vxge_hw_device *devh);
+
+/**
+ * vxge_hw_ring_rxd_size_get   - Get the size of ring descriptor.
+ * @buf_mode: Buffer mode (1, 3 or 5)
+ *
+ * This function returns the size of RxD for given buffer mode
+ */
+static inline u32 vxge_hw_ring_rxd_size_get(u32 buf_mode)
+{
+       return sizeof(struct vxge_hw_ring_rxd_1);
+}
+
+/**
+ * vxge_hw_ring_rxds_per_block_get - Get the number of rxds per block.
+ * @buf_mode: Buffer mode (1 buffer mode only)
+ *
+ * This function returns the number of RxD for RxD block for given buffer mode
+ */
+static inline u32 vxge_hw_ring_rxds_per_block_get(u32 buf_mode)
+{
+       return (u32)((VXGE_HW_BLOCK_SIZE-16) /
+               sizeof(struct vxge_hw_ring_rxd_1));
+}
+
+/**
+ * vxge_hw_ring_rxd_1b_set - Prepare 1-buffer-mode descriptor.
+ * @rxdh: Descriptor handle.
+ * @dma_pointer: DMA address of        a single receive buffer this descriptor
+ * should carry. Note that by the time vxge_hw_ring_rxd_1b_set is called,
+ * the receive buffer should be already mapped to the device
+ * @size: Size of the receive @dma_pointer buffer.
+ *
+ * Prepare 1-buffer-mode Rx    descriptor for posting
+ * (via        vxge_hw_ring_rxd_post()).
+ *
+ * This        inline helper-function does not return any parameters and always
+ * succeeds.
+ *
+ */
+static inline
+void vxge_hw_ring_rxd_1b_set(
+       void *rxdh,
+       dma_addr_t dma_pointer,
+       u32 size)
+{
+       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
+       rxdp->buffer0_ptr = dma_pointer;
+       rxdp->control_1 &= ~VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK;
+       rxdp->control_1 |= VXGE_HW_RING_RXD_1_BUFFER0_SIZE(size);
+}
+
+/**
+ * vxge_hw_ring_rxd_1b_get - Get data from the completed 1-buf
+ * descriptor.
+ * @vpath_handle: Virtual Path handle.
+ * @rxdh: Descriptor handle.
+ * @dma_pointer: DMA address of        a single receive buffer this descriptor
+ * carries. Returned by HW.
+ * @pkt_length:        Length (in bytes) of the data in the buffer pointed by
+ *
+ * Retrieve protocol data from the completed 1-buffer-mode Rx descriptor.
+ * This        inline helper-function uses completed descriptor to populate receive
+ * buffer pointer and other "out" parameters. The function always succeeds.
+ *
+ */
+static inline
+void vxge_hw_ring_rxd_1b_get(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh,
+       u32 *pkt_length)
+{
+       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
+
+       *pkt_length =
+               (u32)VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(rxdp->control_1);
+}
+
+/**
+ * vxge_hw_ring_rxd_1b_info_get - Get extended information associated with
+ * a completed receive descriptor for 1b mode.
+ * @vpath_handle: Virtual Path handle.
+ * @rxdh: Descriptor handle.
+ * @rxd_info: Descriptor information
+ *
+ * Retrieve extended information associated with a completed receive descriptor.
+ *
+ */
+static inline
+void vxge_hw_ring_rxd_1b_info_get(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh,
+       struct vxge_hw_ring_rxd_info *rxd_info)
+{
+
+       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
+       rxd_info->syn_flag =
+               (u32)VXGE_HW_RING_RXD_SYN_GET(rxdp->control_0);
+       rxd_info->is_icmp =
+               (u32)VXGE_HW_RING_RXD_IS_ICMP_GET(rxdp->control_0);
+       rxd_info->fast_path_eligible =
+               (u32)VXGE_HW_RING_RXD_FAST_PATH_ELIGIBLE_GET(rxdp->control_0);
+       rxd_info->l3_cksum_valid =
+               (u32)VXGE_HW_RING_RXD_L3_CKSUM_CORRECT_GET(rxdp->control_0);
+       rxd_info->l3_cksum =
+               (u32)VXGE_HW_RING_RXD_L3_CKSUM_GET(rxdp->control_0);
+       rxd_info->l4_cksum_valid =
+               (u32)VXGE_HW_RING_RXD_L4_CKSUM_CORRECT_GET(rxdp->control_0);
+       rxd_info->l4_cksum =
+               (u32)VXGE_HW_RING_RXD_L4_CKSUM_GET(rxdp->control_0);;
+       rxd_info->frame =
+               (u32)VXGE_HW_RING_RXD_ETHER_ENCAP_GET(rxdp->control_0);
+       rxd_info->proto =
+               (u32)VXGE_HW_RING_RXD_FRAME_PROTO_GET(rxdp->control_0);
+       rxd_info->is_vlan =
+               (u32)VXGE_HW_RING_RXD_IS_VLAN_GET(rxdp->control_0);
+       rxd_info->vlan =
+               (u32)VXGE_HW_RING_RXD_VLAN_TAG_GET(rxdp->control_1);
+       rxd_info->rth_bucket =
+               (u32)VXGE_HW_RING_RXD_RTH_BUCKET_GET(rxdp->control_0);
+       rxd_info->rth_it_hit =
+               (u32)VXGE_HW_RING_RXD_RTH_IT_HIT_GET(rxdp->control_0);
+       rxd_info->rth_spdm_hit =
+               (u32)VXGE_HW_RING_RXD_RTH_SPDM_HIT_GET(rxdp->control_0);
+       rxd_info->rth_hash_type =
+               (u32)VXGE_HW_RING_RXD_RTH_HASH_TYPE_GET(rxdp->control_0);
+       rxd_info->rth_value =
+               (u32)VXGE_HW_RING_RXD_1_RTH_HASH_VAL_GET(rxdp->control_1);
+}
+
+/**
+ * vxge_hw_ring_rxd_private_get - Get driver private per-descriptor data
+ *                      of 1b mode 3b mode ring.
+ * @rxdh: Descriptor handle.
+ *
+ * Returns: private driver     info associated with the descriptor.
+ * driver requests     per-descriptor space via vxge_hw_ring_attr.
+ *
+ */
+static inline void *vxge_hw_ring_rxd_private_get(void *rxdh)
+{
+       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
+       return (void *)(size_t)rxdp->host_control;
+}
+
+/**
+ * vxge_hw_fifo_txdl_cksum_set_bits - Offload checksum.
+ * @txdlh: Descriptor handle.
+ * @cksum_bits: Specifies which checksums are to be offloaded: IPv4,
+ *              and/or TCP and/or UDP.
+ *
+ * Ask Titan to calculate IPv4 & transport checksums for _this_ transmit
+ * descriptor.
+ * This API is part of the preparation of the transmit descriptor for posting
+ * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include
+ * vxge_hw_fifo_txdl_mss_set(), vxge_hw_fifo_txdl_buffer_set_aligned(),
+ * and vxge_hw_fifo_txdl_buffer_set().
+ * All these APIs fill in the fields of the fifo descriptor,
+ * in accordance with the Titan specification.
+ *
+ */
+static inline void vxge_hw_fifo_txdl_cksum_set_bits(void *txdlh, u64 cksum_bits)
+{
+       struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh;
+       txdp->control_1 |= cksum_bits;
+}
+
+/**
+ * vxge_hw_fifo_txdl_mss_set - Set MSS.
+ * @txdlh: Descriptor handle.
+ * @mss: MSS size for _this_ TCP connection. Passed by TCP stack down to the
+ *       driver, which in turn inserts the MSS into the @txdlh.
+ *
+ * This API is part of the preparation of the transmit descriptor for posting
+ * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include
+ * vxge_hw_fifo_txdl_buffer_set(), vxge_hw_fifo_txdl_buffer_set_aligned(),
+ * and vxge_hw_fifo_txdl_cksum_set_bits().
+ * All these APIs fill in the fields of the fifo descriptor,
+ * in accordance with the Titan specification.
+ *
+ */
+static inline void vxge_hw_fifo_txdl_mss_set(void *txdlh, int mss)
+{
+       struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh;
+
+       txdp->control_0 |= VXGE_HW_FIFO_TXD_LSO_EN;
+       txdp->control_0 |= VXGE_HW_FIFO_TXD_LSO_MSS(mss);
+}
+
+/**
+ * vxge_hw_fifo_txdl_vlan_set - Set VLAN tag.
+ * @txdlh: Descriptor handle.
+ * @vlan_tag: 16bit VLAN tag.
+ *
+ * Insert VLAN tag into specified transmit descriptor.
+ * The actual insertion of the tag into outgoing frame is done by the hardware.
+ */
+static inline void vxge_hw_fifo_txdl_vlan_set(void *txdlh, u16 vlan_tag)
+{
+       struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh;
+
+       txdp->control_1 |= VXGE_HW_FIFO_TXD_VLAN_ENABLE;
+       txdp->control_1 |= VXGE_HW_FIFO_TXD_VLAN_TAG(vlan_tag);
+}
+
+/**
+ * vxge_hw_fifo_txdl_private_get - Retrieve per-descriptor private data.
+ * @txdlh: Descriptor handle.
+ *
+ * Retrieve per-descriptor private data.
+ * Note that driver requests per-descriptor space via
+ * struct vxge_hw_fifo_attr passed to
+ * vxge_hw_vpath_open().
+ *
+ * Returns: private driver data associated with the descriptor.
+ */
+static inline void *vxge_hw_fifo_txdl_private_get(void *txdlh)
+{
+       struct vxge_hw_fifo_txd *txdp  = (struct vxge_hw_fifo_txd *)txdlh;
+
+       return (void *)(size_t)txdp->host_control;
+}
+
+/**
+ * struct vxge_hw_ring_attr - Ring open "template".
+ * @callback: Ring completion callback. HW invokes the callback when there
+ *            are new completions on that ring. In many implementations
+ *            the @callback executes in the hw interrupt context.
+ * @rxd_init: Ring's descriptor-initialize callback.
+ *            See vxge_hw_ring_rxd_init_f{}.
+ *            If not NULL, HW invokes the callback when opening
+ *            the ring.
+ * @rxd_term: Ring's descriptor-terminate callback. If not NULL,
+ *          HW invokes the callback when closing the corresponding ring.
+ *          See also vxge_hw_ring_rxd_term_f{}.
+ * @userdata: User-defined "context" of _that_ ring. Passed back to the
+ *            user as one of the @callback, @rxd_init, and @rxd_term arguments.
+ * @per_rxd_space: If specified (i.e., greater than zero): extra space
+ *              reserved by HW per each receive descriptor.
+ *              Can be used to store
+ *              and retrieve on completion, information specific
+ *              to the driver.
+ *
+ * Ring open "template". User fills the structure with ring
+ * attributes and passes it to vxge_hw_vpath_open().
+ */
+struct vxge_hw_ring_attr {
+       enum vxge_hw_status (*callback)(
+                       struct __vxge_hw_ring *ringh,
+                       void *rxdh,
+                       u8 t_code,
+                       void *userdata);
+
+       enum vxge_hw_status (*rxd_init)(
+                       void *rxdh,
+                       void *userdata);
+
+       void (*rxd_term)(
+                       void *rxdh,
+                       enum vxge_hw_rxd_state state,
+                       void *userdata);
+
+       void            *userdata;
+       u32             per_rxd_space;
+};
+
+/**
+ * function vxge_hw_fifo_callback_f - FIFO callback.
+ * @vpath_handle: Virtual path whose Fifo "containing" 1 or more completed
+ *             descriptors.
+ * @txdlh: First completed descriptor.
+ * @txdl_priv: Pointer to per txdl space allocated
+ * @t_code: Transfer code, as per Titan User Guide.
+ *          Returned by HW.
+ * @host_control: Opaque 64bit data stored by driver inside the Titan
+ *            descriptor prior to posting the latter on the fifo
+ *            via vxge_hw_fifo_txdl_post(). The @host_control is returned
+ *            as is to the driver with each completed descriptor.
+ * @userdata: Opaque per-fifo data specified at fifo open
+ *            time, via vxge_hw_vpath_open().
+ *
+ * Fifo completion callback (type declaration). A single per-fifo
+ * callback is specified at fifo open time, via
+ * vxge_hw_vpath_open(). Typically gets called as part of the processing
+ * of the Interrupt Service Routine.
+ *
+ * Fifo callback gets called by HW if, and only if, there is at least
+ * one new completion on a given fifo. Upon processing the first @txdlh driver
+ * is _supposed_ to continue consuming completions using:
+ *    - vxge_hw_fifo_txdl_next_completed()
+ *
+ * Note that failure to process new completions in a timely fashion
+ * leads to VXGE_HW_INF_OUT_OF_DESCRIPTORS condition.
+ *
+ * Non-zero @t_code means failure to process transmit descriptor.
+ *
+ * In the "transmit" case the failure could happen, for instance, when the
+ * link is down, in which case Titan completes the descriptor because it
+ * is not able to send the data out.
+ *
+ * For details please refer to Titan User Guide.
+ *
+ * See also: vxge_hw_fifo_txdl_next_completed(), vxge_hw_fifo_txdl_term_f{}.
+ */
+/**
+ * function vxge_hw_fifo_txdl_term_f - Terminate descriptor callback.
+ * @txdlh: First completed descriptor.
+ * @txdl_priv: Pointer to per txdl space allocated
+ * @state: One of the enum vxge_hw_txdl_state{} enumerated states.
+ * @userdata: Per-fifo user data (a.k.a. context) specified at
+ * fifo open time, via vxge_hw_vpath_open().
+ *
+ * Terminate descriptor callback. Unless NULL is specified in the
+ * struct vxge_hw_fifo_attr{} structure passed to vxge_hw_vpath_open()),
+ * HW invokes the callback as part of closing fifo, prior to
+ * de-allocating the ring and associated data structures
+ * (including descriptors).
+ * driver should utilize the callback to (for instance) unmap
+ * and free DMA data buffers associated with the posted (state =
+ * VXGE_HW_TXDL_STATE_POSTED) descriptors,
+ * as well as other relevant cleanup functions.
+ *
+ * See also: struct vxge_hw_fifo_attr{}
+ */
+/**
+ * struct vxge_hw_fifo_attr - Fifo open "template".
+ * @callback: Fifo completion callback. HW invokes the callback when there
+ *            are new completions on that fifo. In many implementations
+ *            the @callback executes in the hw interrupt context.
+ * @txdl_term: Fifo's descriptor-terminate callback. If not NULL,
+ *          HW invokes the callback when closing the corresponding fifo.
+ *          See also vxge_hw_fifo_txdl_term_f{}.
+ * @userdata: User-defined "context" of _that_ fifo. Passed back to the
+ *            user as one of the @callback, and @txdl_term arguments.
+ * @per_txdl_space: If specified (i.e., greater than zero): extra space
+ *              reserved by HW per each transmit descriptor. Can be used to
+ *              store, and retrieve on completion, information specific
+ *              to the driver.
+ *
+ * Fifo open "template". User fills the structure with fifo
+ * attributes and passes it to vxge_hw_vpath_open().
+ */
+struct vxge_hw_fifo_attr {
+
+       enum vxge_hw_status (*callback)(
+                       struct __vxge_hw_fifo *fifo_handle,
+                       void *txdlh,
+                       enum vxge_hw_fifo_tcode t_code,
+                       void *userdata,
+                       void **skb_ptr);
+
+       void (*txdl_term)(
+                       void *txdlh,
+                       enum vxge_hw_txdl_state state,
+                       void *userdata);
+
+       void            *userdata;
+       u32             per_txdl_space;
+};
+
+/**
+ * struct vxge_hw_vpath_attr - Attributes of virtual path
+ * @vp_id: Identifier of Virtual Path
+ * @ring_attr: Attributes of ring for non-offload receive
+ * @fifo_attr: Attributes of fifo for non-offload transmit
+ *
+ * Attributes of virtual path.  This structure is passed as parameter
+ * to the vxge_hw_vpath_open() routine to set the attributes of ring and fifo.
+ */
+struct vxge_hw_vpath_attr {
+       u32                             vp_id;
+       struct vxge_hw_ring_attr        ring_attr;
+       struct vxge_hw_fifo_attr        fifo_attr;
+};
+
+enum vxge_hw_status
+__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
+                       struct __vxge_hw_blockpool  *blockpool,
+                       u32 pool_size,
+                       u32 pool_max);
+
+void
+__vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool  *blockpool);
+
+struct __vxge_hw_blockpool_entry *
+__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *hldev,
+                       u32 size);
+
+void
+__vxge_hw_blockpool_block_free(struct __vxge_hw_device *hldev,
+                       struct __vxge_hw_blockpool_entry *entry);
+
+void *
+__vxge_hw_blockpool_malloc(struct __vxge_hw_device *hldev,
+                       u32 size,
+                       struct vxge_hw_mempool_dma *dma_object);
+
+void
+__vxge_hw_blockpool_free(struct __vxge_hw_device *hldev,
+                       void *memblock,
+                       u32 size,
+                       struct vxge_hw_mempool_dma *dma_object);
+
+enum vxge_hw_status
+__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config);
+
+enum vxge_hw_status
+__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config);
+
+enum vxge_hw_status
+vxge_hw_mgmt_device_config(struct __vxge_hw_device *devh,
+               struct vxge_hw_device_config    *dev_config, int size);
+
+enum vxge_hw_status __devinit vxge_hw_device_hw_info_get(
+       void __iomem *bar0,
+       struct vxge_hw_device_hw_info *hw_info);
+
+enum vxge_hw_status
+__vxge_hw_vpath_fw_ver_get(
+       u32     vp_id,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg,
+       struct vxge_hw_device_hw_info *hw_info);
+
+enum vxge_hw_status
+__vxge_hw_vpath_card_info_get(
+       u32 vp_id,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg,
+       struct vxge_hw_device_hw_info *hw_info);
+
+enum vxge_hw_status __devinit vxge_hw_device_config_default_get(
+       struct vxge_hw_device_config *device_config);
+
+/**
+ * vxge_hw_device_link_state_get - Get link state.
+ * @devh: HW device handle.
+ *
+ * Get link state.
+ * Returns: link state.
+ */
+static inline
+enum vxge_hw_device_link_state vxge_hw_device_link_state_get(
+       struct __vxge_hw_device *devh)
+{
+       return devh->link_state;
+}
+
+void vxge_hw_device_terminate(struct __vxge_hw_device *devh);
+
+const u8 *
+vxge_hw_device_serial_number_get(struct __vxge_hw_device *devh);
+
+u16 vxge_hw_device_link_width_get(struct __vxge_hw_device *devh);
+
+const u8 *
+vxge_hw_device_product_name_get(struct __vxge_hw_device *devh);
+
+enum vxge_hw_status __devinit vxge_hw_device_initialize(
+       struct __vxge_hw_device **devh,
+       struct vxge_hw_device_attr *attr,
+       struct vxge_hw_device_config *device_config);
+
+enum vxge_hw_status vxge_hw_device_getpause_data(
+        struct __vxge_hw_device *devh,
+        u32 port,
+        u32 *tx,
+        u32 *rx);
+
+enum vxge_hw_status vxge_hw_device_setpause_data(
+       struct __vxge_hw_device *devh,
+       u32 port,
+       u32 tx,
+       u32 rx);
+
+static inline void *vxge_os_dma_malloc(struct pci_dev *pdev,
+                       unsigned long size,
+                       struct pci_dev **p_dmah,
+                       struct pci_dev **p_dma_acch)
+{
+       gfp_t flags;
+       void *vaddr;
+       unsigned long misaligned = 0;
+       *p_dma_acch = *p_dmah = NULL;
+
+       if (in_interrupt())
+               flags = GFP_ATOMIC | GFP_DMA;
+       else
+               flags = GFP_KERNEL | GFP_DMA;
+
+       size += VXGE_CACHE_LINE_SIZE;
+
+       vaddr = kmalloc((size), flags);
+       if (vaddr == NULL)
+               return vaddr;
+       misaligned = (unsigned long)VXGE_ALIGN(*((u64 *)&vaddr),
+                               VXGE_CACHE_LINE_SIZE);
+       *(unsigned long *)p_dma_acch = misaligned;
+       vaddr = (void *)((u8 *)vaddr + misaligned);
+       return vaddr;
+}
+
+extern void vxge_hw_blockpool_block_add(
+                       struct __vxge_hw_device *devh,
+                       void *block_addr,
+                       u32 length,
+                       struct pci_dev *dma_h,
+                       struct pci_dev *acc_handle);
+
+static inline void vxge_os_dma_malloc_async(struct pci_dev *pdev, void *devh,
+                                       unsigned long size)
+{
+       gfp_t flags;
+       void *vaddr;
+
+       if (in_interrupt())
+               flags = GFP_ATOMIC | GFP_DMA;
+       else
+               flags = GFP_KERNEL | GFP_DMA;
+
+       vaddr = kmalloc((size), flags);
+
+       vxge_hw_blockpool_block_add(devh, vaddr, size, pdev, pdev);
+}
+
+static inline void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr,
+                       struct pci_dev **p_dma_acch)
+{
+       unsigned long misaligned = *(unsigned long *)p_dma_acch;
+       u8 *tmp = (u8 *)vaddr;
+       tmp -= misaligned;
+       kfree((void *)tmp);
+}
+
+/*
+ * __vxge_hw_mempool_item_priv - will return pointer on per item private space
+ */
+static inline void*
+__vxge_hw_mempool_item_priv(
+       struct vxge_hw_mempool *mempool,
+       u32 memblock_idx,
+       void *item,
+       u32 *memblock_item_idx)
+{
+       ptrdiff_t offset;
+       void *memblock = mempool->memblocks_arr[memblock_idx];
+
+
+       offset = (u32)((u8 *)item - (u8 *)memblock);
+       vxge_assert(offset >= 0 && (u32)offset < mempool->memblock_size);
+
+       (*memblock_item_idx) = (u32) offset / mempool->item_size;
+       vxge_assert((*memblock_item_idx) < mempool->items_per_memblock);
+
+       return (u8 *)mempool->memblocks_priv_arr[memblock_idx] +
+                           (*memblock_item_idx) * mempool->items_priv_size;
+}
+
+enum vxge_hw_status
+__vxge_hw_mempool_grow(
+       struct vxge_hw_mempool *mempool,
+       u32 num_allocate,
+       u32 *num_allocated);
+
+struct vxge_hw_mempool*
+__vxge_hw_mempool_create(
+       struct __vxge_hw_device *devh,
+       u32 memblock_size,
+       u32 item_size,
+       u32 private_size,
+       u32 items_initial,
+       u32 items_max,
+       struct vxge_hw_mempool_cbs *mp_callback,
+       void *userdata);
+
+struct __vxge_hw_channel*
+__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
+                       enum __vxge_hw_channel_type type, u32 length,
+                       u32 per_dtr_space, void *userdata);
+
+void
+__vxge_hw_channel_free(
+       struct __vxge_hw_channel *channel);
+
+enum vxge_hw_status
+__vxge_hw_channel_initialize(
+       struct __vxge_hw_channel *channel);
+
+enum vxge_hw_status
+__vxge_hw_channel_reset(
+       struct __vxge_hw_channel *channel);
+
+/*
+ * __vxge_hw_fifo_txdl_priv - Return the max fragments allocated
+ * for the fifo.
+ * @fifo: Fifo
+ * @txdp: Poniter to a TxD
+ */
+static inline struct __vxge_hw_fifo_txdl_priv *
+__vxge_hw_fifo_txdl_priv(
+       struct __vxge_hw_fifo *fifo,
+       struct vxge_hw_fifo_txd *txdp)
+{
+       return (struct __vxge_hw_fifo_txdl_priv *)
+                       (((char *)((ulong)txdp->host_control)) +
+                               fifo->per_txdl_space);
+}
+
+enum vxge_hw_status vxge_hw_vpath_open(
+       struct __vxge_hw_device *devh,
+       struct vxge_hw_vpath_attr *attr,
+       struct __vxge_hw_vpath_handle **vpath_handle);
+
+enum vxge_hw_status
+__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog);
+
+enum vxge_hw_status vxge_hw_vpath_close(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status
+vxge_hw_vpath_reset(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status
+vxge_hw_vpath_recover_from_reset(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+void
+vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp);
+
+enum vxge_hw_status
+vxge_hw_vpath_check_leak(struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status vxge_hw_vpath_mtu_set(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u32 new_mtu);
+
+enum vxge_hw_status vxge_hw_vpath_stats_enable(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status
+__vxge_hw_vpath_stats_access(
+       struct __vxge_hw_virtualpath    *vpath,
+       u32                     operation,
+       u32                     offset,
+       u64                     *stat);
+
+enum vxge_hw_status
+__vxge_hw_vpath_xmac_tx_stats_get(
+       struct __vxge_hw_virtualpath    *vpath,
+       struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats);
+
+enum vxge_hw_status
+__vxge_hw_vpath_xmac_rx_stats_get(
+       struct __vxge_hw_virtualpath    *vpath,
+       struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats);
+
+enum vxge_hw_status
+__vxge_hw_vpath_stats_get(
+       struct __vxge_hw_virtualpath *vpath,
+       struct vxge_hw_vpath_stats_hw_info *hw_stats);
+
+void
+vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp);
+
+enum vxge_hw_status
+__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config);
+
+void
+__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg);
+
+enum vxge_hw_status
+__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg);
+
+enum vxge_hw_status
+__vxge_hw_kdfc_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg);
+
+enum vxge_hw_status
+__vxge_hw_device_register_poll(
+       void __iomem    *reg,
+       u64 mask, u32 max_millis);
+
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+       u64 ret = 0;
+       ret = readl(addr + 4);
+       ret <<= 32;
+       ret |= readl(addr);
+
+       return ret;
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+       writel((u32) (val), addr);
+       writel((u32) (val >> 32), (addr + 4));
+}
+#endif
+
+static inline void __vxge_hw_pio_mem_write32_upper(u32 val, void __iomem *addr)
+{
+       writel(val, addr + 4);
+}
+
+static inline void __vxge_hw_pio_mem_write32_lower(u32 val, void __iomem *addr)
+{
+       writel(val, addr);
+}
+
+static inline enum vxge_hw_status
+__vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
+                         u64 mask, u32 max_millis)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       __vxge_hw_pio_mem_write32_lower((u32)vxge_bVALn(val64, 32, 32), addr);
+       wmb();
+       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), addr);
+       wmb();
+
+       status = __vxge_hw_device_register_poll(addr, mask, max_millis);
+       return status;
+}
+
+struct vxge_hw_toc_reg __iomem *
+__vxge_hw_device_toc_get(void __iomem *bar0);
+
+enum vxge_hw_status
+__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev);
+
+void
+__vxge_hw_device_id_get(struct __vxge_hw_device *hldev);
+
+void
+__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+vxge_hw_device_flick_link_led(struct __vxge_hw_device *devh, u64 on_off);
+
+enum vxge_hw_status
+__vxge_hw_device_initialize(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_vpath_pci_read(
+       struct __vxge_hw_virtualpath    *vpath,
+       u32                     phy_func_0,
+       u32                     offset,
+       u32                     *val);
+
+enum vxge_hw_status
+__vxge_hw_vpath_addr_get(
+       u32 vp_id,
+       struct vxge_hw_vpath_reg __iomem *vpath_reg,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN]);
+
+u32
+__vxge_hw_vpath_func_id_get(
+       u32 vp_id, struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg);
+
+enum vxge_hw_status
+__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath);
+
+/**
+ * vxge_debug
+ * @level: level of debug verbosity.
+ * @mask: mask for the debug
+ * @buf: Circular buffer for tracing
+ * @fmt: printf like format string
+ *
+ * Provides logging facilities. Can be customized on per-module
+ * basis or/and with debug levels. Input parameters, except
+ * module and level, are the same as posix printf. This function
+ * may be compiled out if DEBUG macro was never defined.
+ * See also: enum vxge_debug_level{}.
+ */
+
+#define vxge_trace_aux(level, mask, fmt, ...) \
+{\
+               vxge_os_vaprintf(level, mask, fmt, __VA_ARGS__);\
+}
+
+#define vxge_debug(module, level, mask, fmt, ...) { \
+if ((level >= VXGE_TRACE && ((module & VXGE_DEBUG_TRACE_MASK) == module)) || \
+       (level >= VXGE_ERR && ((module & VXGE_DEBUG_ERR_MASK) == module))) {\
+       if ((mask & VXGE_DEBUG_MASK) == mask)\
+               vxge_trace_aux(level, mask, fmt, __VA_ARGS__); \
+} \
+}
+
+#if (VXGE_COMPONENT_LL & VXGE_DEBUG_MODULE_MASK)
+#define vxge_debug_ll(level, mask, fmt, ...) \
+{\
+       vxge_debug(VXGE_COMPONENT_LL, level, mask, fmt, __VA_ARGS__);\
+}
+
+#else
+#define vxge_debug_ll(level, mask, fmt, ...)
+#endif
+
+enum vxge_hw_status vxge_hw_vpath_rts_rth_itable_set(
+                       struct __vxge_hw_vpath_handle **vpath_handles,
+                       u32 vpath_count,
+                       u8 *mtable,
+                       u8 *itable,
+                       u32 itable_size);
+
+enum vxge_hw_status vxge_hw_vpath_rts_rth_set(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       enum vxge_hw_rth_algoritms algorithm,
+       struct vxge_hw_rth_hash_types *hash_type,
+       u16 bucket_size);
+
+#endif
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
new file mode 100644 (file)
index 0000000..c6736b9
--- /dev/null
@@ -0,0 +1,1148 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-ethtool.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                 Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#include<linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+
+#include "vxge-ethtool.h"
+
+/**
+ * vxge_ethtool_sset - Sets different link parameters.
+ * @dev: device pointer.
+ * @info: pointer to the structure with parameters given by ethtool to set
+ * link information.
+ *
+ * The function sets different link parameters provided by the user onto
+ * the NIC.
+ * Return value:
+ * 0 on success.
+ */
+
+static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info)
+{
+       /* We currently only support 10Gb/FULL */
+       if ((info->autoneg == AUTONEG_ENABLE) ||
+           (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * vxge_ethtool_gset - Return link specific information.
+ * @dev: device pointer.
+ * @info: pointer to the structure with parameters given by ethtool
+ * to return link information.
+ *
+ * Returns link specific information like speed, duplex etc.. to ethtool.
+ * Return value :
+ * return 0 on success.
+ */
+static int vxge_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
+{
+       info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+       info->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+       info->port = PORT_FIBRE;
+
+       info->transceiver = XCVR_EXTERNAL;
+
+       if (netif_carrier_ok(dev)) {
+               info->speed = SPEED_10000;
+               info->duplex = DUPLEX_FULL;
+       } else {
+               info->speed = -1;
+               info->duplex = -1;
+       }
+
+       info->autoneg = AUTONEG_DISABLE;
+       return 0;
+}
+
+/**
+ * vxge_ethtool_gdrvinfo - Returns driver specific information.
+ * @dev: device pointer.
+ * @info: pointer to the structure with parameters given by ethtool to
+ * return driver information.
+ *
+ * Returns driver specefic information like name, version etc.. to ethtool.
+ */
+static void vxge_ethtool_gdrvinfo(struct net_device *dev,
+                       struct ethtool_drvinfo *info)
+{
+       struct vxgedev *vdev;
+       vdev = (struct vxgedev *)netdev_priv(dev);
+       strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(VXGE_DRIVER_NAME));
+       strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
+       strlcpy(info->fw_version, vdev->fw_version, VXGE_HW_FW_STRLEN);
+       strlcpy(info->bus_info, pci_name(vdev->pdev), sizeof(info->bus_info));
+       info->regdump_len = sizeof(struct vxge_hw_vpath_reg)
+                               * vdev->no_of_vpath;
+
+       info->n_stats = STAT_LEN;
+}
+
+/**
+ * vxge_ethtool_gregs - dumps the entire space of Titan into the buffer.
+ * @dev: device pointer.
+ * @regs: pointer to the structure with parameters given by ethtool for
+ * dumping the registers.
+ * @reg_space: The input argumnet into which all the registers are dumped.
+ *
+ * Dumps the vpath register space of Titan NIC into the user given
+ * buffer area.
+ */
+static void vxge_ethtool_gregs(struct net_device *dev,
+                       struct ethtool_regs *regs, void *space)
+{
+       int index, offset;
+       enum vxge_hw_status status;
+       u64 reg;
+       u8 *reg_space = (u8 *) space;
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+       struct __vxge_hw_device  *hldev = (struct __vxge_hw_device *)
+                                       pci_get_drvdata(vdev->pdev);
+
+       regs->len = sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath;
+       regs->version = vdev->pdev->subsystem_device;
+       for (index = 0; index < vdev->no_of_vpath; index++) {
+               for (offset = 0; offset < sizeof(struct vxge_hw_vpath_reg);
+                               offset += 8) {
+                       status = vxge_hw_mgmt_reg_read(hldev,
+                                       vxge_hw_mgmt_reg_type_vpath,
+                                       vdev->vpaths[index].device_id,
+                                       offset, &reg);
+                       if (status != VXGE_HW_OK) {
+                               vxge_debug_init(VXGE_ERR,
+                                       "%s:%d Getting reg dump Failed",
+                                               __func__, __LINE__);
+                               return;
+                       }
+
+                       memcpy((reg_space + offset), &reg, 8);
+               }
+       }
+}
+
+/**
+ * vxge_ethtool_idnic - To physically identify the nic on the system.
+ * @dev : device pointer.
+ * @id : pointer to the structure with identification parameters given by
+ * ethtool.
+ *
+ * Used to physically identify the NIC on the system.
+ * The Link LED will blink for a time specified by the user.
+ * Return value:
+ * 0 on success
+ */
+static int vxge_ethtool_idnic(struct net_device *dev, u32 data)
+{
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+       struct __vxge_hw_device  *hldev = (struct __vxge_hw_device  *)
+                       pci_get_drvdata(vdev->pdev);
+
+       vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON);
+       msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME);
+       vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF);
+
+       return 0;
+}
+
+/**
+ * vxge_ethtool_getpause_data - Pause frame frame generation and reception.
+ * @dev : device pointer.
+ * @ep : pointer to the structure with pause parameters given by ethtool.
+ * Description:
+ * Returns the Pause frame generation and reception capability of the NIC.
+ * Return value:
+ *  void
+ */
+static void vxge_ethtool_getpause_data(struct net_device *dev,
+                                       struct ethtool_pauseparam *ep)
+{
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+       struct __vxge_hw_device  *hldev = (struct __vxge_hw_device  *)
+                       pci_get_drvdata(vdev->pdev);
+
+       vxge_hw_device_getpause_data(hldev, 0, &ep->tx_pause, &ep->rx_pause);
+}
+
+/**
+ * vxge_ethtool_setpause_data -  set/reset pause frame generation.
+ * @dev : device pointer.
+ * @ep : pointer to the structure with pause parameters given by ethtool.
+ * Description:
+ * It can be used to set or reset Pause frame generation or reception
+ * support of the NIC.
+ * Return value:
+ * int, returns 0 on Success
+ */
+static int vxge_ethtool_setpause_data(struct net_device *dev,
+                                       struct ethtool_pauseparam *ep)
+{
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+       struct __vxge_hw_device  *hldev = (struct __vxge_hw_device  *)
+                       pci_get_drvdata(vdev->pdev);
+
+       vxge_hw_device_setpause_data(hldev, 0, ep->tx_pause, ep->rx_pause);
+
+       vdev->config.tx_pause_enable = ep->tx_pause;
+       vdev->config.rx_pause_enable = ep->rx_pause;
+
+       return 0;
+}
+
+static void vxge_get_ethtool_stats(struct net_device *dev,
+                                  struct ethtool_stats *estats, u64 *tmp_stats)
+{
+       int j, k;
+       enum vxge_hw_status status;
+       enum vxge_hw_status swstatus;
+       struct vxge_vpath *vpath = NULL;
+
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+       struct __vxge_hw_device  *hldev = vdev->devh;
+       struct vxge_hw_xmac_stats *xmac_stats;
+       struct vxge_hw_device_stats_sw_info *sw_stats;
+       struct vxge_hw_device_stats_hw_info *hw_stats;
+
+       u64 *ptr = tmp_stats;
+
+       memset(tmp_stats, 0,
+               vxge_ethtool_get_sset_count(dev, ETH_SS_STATS) * sizeof(u64));
+
+       xmac_stats = kzalloc(sizeof(struct vxge_hw_xmac_stats), GFP_KERNEL);
+       if (xmac_stats == NULL) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s : %d Memory Allocation failed for xmac_stats",
+                                __func__, __LINE__);
+               return;
+       }
+
+       sw_stats = kzalloc(sizeof(struct vxge_hw_device_stats_sw_info),
+                               GFP_KERNEL);
+       if (sw_stats == NULL) {
+               kfree(xmac_stats);
+               vxge_debug_init(VXGE_ERR,
+                       "%s : %d Memory Allocation failed for sw_stats",
+                       __func__, __LINE__);
+               return;
+       }
+
+       hw_stats = kzalloc(sizeof(struct vxge_hw_device_stats_hw_info),
+                               GFP_KERNEL);
+       if (hw_stats == NULL) {
+               kfree(xmac_stats);
+               kfree(sw_stats);
+               vxge_debug_init(VXGE_ERR,
+                       "%s : %d Memory Allocation failed for hw_stats",
+                       __func__, __LINE__);
+               return;
+       }
+
+       *ptr++ = 0;
+       status = vxge_hw_device_xmac_stats_get(hldev, xmac_stats);
+       if (status != VXGE_HW_OK) {
+               if (status != VXGE_HW_ERR_PRIVILAGED_OPEARATION) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s : %d Failure in getting xmac stats",
+                               __func__, __LINE__);
+               }
+       }
+       swstatus = vxge_hw_driver_stats_get(hldev, sw_stats);
+       if (swstatus != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s : %d Failure in getting sw stats",
+                       __func__, __LINE__);
+       }
+
+       status = vxge_hw_device_stats_get(hldev, hw_stats);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s : %d hw_stats_get error", __func__, __LINE__);
+       }
+
+       for (k = 0; k < vdev->no_of_vpath; k++) {
+               struct vxge_hw_vpath_stats_hw_info *vpath_info;
+
+               vpath = &vdev->vpaths[k];
+               j = vpath->device_id;
+               vpath_info = hw_stats->vpath_info[j];
+               if (!vpath_info) {
+                       memset(ptr, 0, (VXGE_HW_VPATH_TX_STATS_LEN +
+                               VXGE_HW_VPATH_RX_STATS_LEN) * sizeof(u64));
+                       ptr += (VXGE_HW_VPATH_TX_STATS_LEN +
+                               VXGE_HW_VPATH_RX_STATS_LEN);
+                       continue;
+               }
+
+               *ptr++ = vpath_info->tx_stats.tx_ttl_eth_frms;
+               *ptr++ = vpath_info->tx_stats.tx_ttl_eth_octets;
+               *ptr++ = vpath_info->tx_stats.tx_data_octets;
+               *ptr++ = vpath_info->tx_stats.tx_mcast_frms;
+               *ptr++ = vpath_info->tx_stats.tx_bcast_frms;
+               *ptr++ = vpath_info->tx_stats.tx_ucast_frms;
+               *ptr++ = vpath_info->tx_stats.tx_tagged_frms;
+               *ptr++ = vpath_info->tx_stats.tx_vld_ip;
+               *ptr++ = vpath_info->tx_stats.tx_vld_ip_octets;
+               *ptr++ = vpath_info->tx_stats.tx_icmp;
+               *ptr++ = vpath_info->tx_stats.tx_tcp;
+               *ptr++ = vpath_info->tx_stats.tx_rst_tcp;
+               *ptr++ = vpath_info->tx_stats.tx_udp;
+               *ptr++ = vpath_info->tx_stats.tx_unknown_protocol;
+               *ptr++ = vpath_info->tx_stats.tx_lost_ip;
+               *ptr++ = vpath_info->tx_stats.tx_parse_error;
+               *ptr++ = vpath_info->tx_stats.tx_tcp_offload;
+               *ptr++ = vpath_info->tx_stats.tx_retx_tcp_offload;
+               *ptr++ = vpath_info->tx_stats.tx_lost_ip_offload;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_eth_frms;
+               *ptr++ = vpath_info->rx_stats.rx_vld_frms;
+               *ptr++ = vpath_info->rx_stats.rx_offload_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_eth_octets;
+               *ptr++ = vpath_info->rx_stats.rx_data_octets;
+               *ptr++ = vpath_info->rx_stats.rx_offload_octets;
+               *ptr++ = vpath_info->rx_stats.rx_vld_mcast_frms;
+               *ptr++ = vpath_info->rx_stats.rx_vld_bcast_frms;
+               *ptr++ = vpath_info->rx_stats.rx_accepted_ucast_frms;
+               *ptr++ = vpath_info->rx_stats.rx_accepted_nucast_frms;
+               *ptr++ = vpath_info->rx_stats.rx_tagged_frms;
+               *ptr++ = vpath_info->rx_stats.rx_long_frms;
+               *ptr++ = vpath_info->rx_stats.rx_usized_frms;
+               *ptr++ = vpath_info->rx_stats.rx_osized_frms;
+               *ptr++ = vpath_info->rx_stats.rx_frag_frms;
+               *ptr++ = vpath_info->rx_stats.rx_jabber_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_64_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_65_127_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_128_255_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_256_511_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_512_1023_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_1024_1518_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_1519_4095_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_4096_8191_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_8192_max_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ttl_gt_max_frms;
+               *ptr++ = vpath_info->rx_stats.rx_ip;
+               *ptr++ = vpath_info->rx_stats.rx_accepted_ip;
+               *ptr++ = vpath_info->rx_stats.rx_ip_octets;
+               *ptr++ = vpath_info->rx_stats.rx_err_ip;
+               *ptr++ = vpath_info->rx_stats.rx_icmp;
+               *ptr++ = vpath_info->rx_stats.rx_tcp;
+               *ptr++ = vpath_info->rx_stats.rx_udp;
+               *ptr++ = vpath_info->rx_stats.rx_err_tcp;
+               *ptr++ = vpath_info->rx_stats.rx_lost_frms;
+               *ptr++ = vpath_info->rx_stats.rx_lost_ip;
+               *ptr++ = vpath_info->rx_stats.rx_lost_ip_offload;
+               *ptr++ = vpath_info->rx_stats.rx_various_discard;
+               *ptr++ = vpath_info->rx_stats.rx_sleep_discard;
+               *ptr++ = vpath_info->rx_stats.rx_red_discard;
+               *ptr++ = vpath_info->rx_stats.rx_queue_full_discard;
+               *ptr++ = vpath_info->rx_stats.rx_mpa_ok_frms;
+       }
+       *ptr++ = 0;
+       for (k = 0; k < vdev->max_config_port; k++) {
+               *ptr++ = xmac_stats->aggr_stats[k].tx_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].tx_data_octets;
+               *ptr++ = xmac_stats->aggr_stats[k].tx_mcast_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].tx_bcast_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].tx_discarded_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].tx_errored_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].rx_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].rx_data_octets;
+               *ptr++ = xmac_stats->aggr_stats[k].rx_mcast_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].rx_bcast_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].rx_discarded_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].rx_errored_frms;
+               *ptr++ = xmac_stats->aggr_stats[k].rx_unknown_slow_proto_frms;
+       }
+       *ptr++ = 0;
+       for (k = 0; k < vdev->max_config_port; k++) {
+               *ptr++ = xmac_stats->port_stats[k].tx_ttl_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_ttl_octets;
+               *ptr++ = xmac_stats->port_stats[k].tx_data_octets;
+               *ptr++ = xmac_stats->port_stats[k].tx_mcast_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_bcast_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_ucast_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_tagged_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_vld_ip;
+               *ptr++ = xmac_stats->port_stats[k].tx_vld_ip_octets;
+               *ptr++ = xmac_stats->port_stats[k].tx_icmp;
+               *ptr++ = xmac_stats->port_stats[k].tx_tcp;
+               *ptr++ = xmac_stats->port_stats[k].tx_rst_tcp;
+               *ptr++ = xmac_stats->port_stats[k].tx_udp;
+               *ptr++ = xmac_stats->port_stats[k].tx_parse_error;
+               *ptr++ = xmac_stats->port_stats[k].tx_unknown_protocol;
+               *ptr++ = xmac_stats->port_stats[k].tx_pause_ctrl_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_marker_pdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_lacpdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_drop_ip;
+               *ptr++ = xmac_stats->port_stats[k].tx_marker_resp_pdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_char2_match;
+               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_char1_match;
+               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_column2_match;
+               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_column1_match;
+               *ptr++ = xmac_stats->port_stats[k].tx_any_err_frms;
+               *ptr++ = xmac_stats->port_stats[k].tx_drop_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_vld_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_offload_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_octets;
+               *ptr++ = xmac_stats->port_stats[k].rx_data_octets;
+               *ptr++ = xmac_stats->port_stats[k].rx_offload_octets;
+               *ptr++ = xmac_stats->port_stats[k].rx_vld_mcast_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_vld_bcast_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_accepted_ucast_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_accepted_nucast_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_tagged_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_long_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_usized_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_osized_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_frag_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_jabber_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_64_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_65_127_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_128_255_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_256_511_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_512_1023_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_1024_1518_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_1519_4095_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_4096_8191_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_8192_max_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ttl_gt_max_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_ip;
+               *ptr++ = xmac_stats->port_stats[k].rx_accepted_ip;
+               *ptr++ = xmac_stats->port_stats[k].rx_ip_octets;
+               *ptr++ = xmac_stats->port_stats[k].rx_err_ip;
+               *ptr++ = xmac_stats->port_stats[k].rx_icmp;
+               *ptr++ = xmac_stats->port_stats[k].rx_tcp;
+               *ptr++ = xmac_stats->port_stats[k].rx_udp;
+               *ptr++ = xmac_stats->port_stats[k].rx_err_tcp;
+               *ptr++ = xmac_stats->port_stats[k].rx_pause_count;
+               *ptr++ = xmac_stats->port_stats[k].rx_pause_ctrl_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_unsup_ctrl_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_fcs_err_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_in_rng_len_err_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_out_rng_len_err_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_drop_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_discarded_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_drop_ip;
+               *ptr++ = xmac_stats->port_stats[k].rx_drop_udp;
+               *ptr++ = xmac_stats->port_stats[k].rx_marker_pdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_lacpdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_unknown_pdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_marker_resp_pdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_fcs_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_illegal_pdu_frms;
+               *ptr++ = xmac_stats->port_stats[k].rx_switch_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_len_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_rpa_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_l2_mgmt_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_rts_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_trash_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_buff_full_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_red_discard;
+               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_ctrl_err_cnt;
+               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_data_err_cnt;
+               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_char1_match;
+               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_err_sym;
+               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_column1_match;
+               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_char2_match;
+               *ptr++ = xmac_stats->port_stats[k].rx_local_fault;
+               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_column2_match;
+               *ptr++ = xmac_stats->port_stats[k].rx_jettison;
+               *ptr++ = xmac_stats->port_stats[k].rx_remote_fault;
+       }
+
+       *ptr++ = 0;
+       for (k = 0; k < vdev->no_of_vpath; k++) {
+               struct vxge_hw_vpath_stats_sw_info *vpath_info;
+
+               vpath = &vdev->vpaths[k];
+               j = vpath->device_id;
+               vpath_info = (struct vxge_hw_vpath_stats_sw_info *)
+                               &sw_stats->vpath_info[j];
+               *ptr++ = vpath_info->soft_reset_cnt;
+               *ptr++ = vpath_info->error_stats.unknown_alarms;
+               *ptr++ = vpath_info->error_stats.network_sustained_fault;
+               *ptr++ = vpath_info->error_stats.network_sustained_ok;
+               *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_overwrite;
+               *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_poison;
+               *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_dma_error;
+               *ptr++ = vpath_info->error_stats.dblgen_fifo0_overflow;
+               *ptr++ = vpath_info->error_stats.statsb_pif_chain_error;
+               *ptr++ = vpath_info->error_stats.statsb_drop_timeout;
+               *ptr++ = vpath_info->error_stats.target_illegal_access;
+               *ptr++ = vpath_info->error_stats.ini_serr_det;
+               *ptr++ = vpath_info->error_stats.prc_ring_bumps;
+               *ptr++ = vpath_info->error_stats.prc_rxdcm_sc_err;
+               *ptr++ = vpath_info->error_stats.prc_rxdcm_sc_abort;
+               *ptr++ = vpath_info->error_stats.prc_quanta_size_err;
+               *ptr++ = vpath_info->ring_stats.common_stats.full_cnt;
+               *ptr++ = vpath_info->ring_stats.common_stats.usage_cnt;
+               *ptr++ = vpath_info->ring_stats.common_stats.usage_max;
+               *ptr++ = vpath_info->ring_stats.common_stats.
+                                       reserve_free_swaps_cnt;
+               *ptr++ = vpath_info->ring_stats.common_stats.total_compl_cnt;
+               for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
+                       *ptr++ = vpath_info->ring_stats.rxd_t_code_err_cnt[j];
+               *ptr++ = vpath_info->fifo_stats.common_stats.full_cnt;
+               *ptr++ = vpath_info->fifo_stats.common_stats.usage_cnt;
+               *ptr++ = vpath_info->fifo_stats.common_stats.usage_max;
+               *ptr++ = vpath_info->fifo_stats.common_stats.
+                                               reserve_free_swaps_cnt;
+               *ptr++ = vpath_info->fifo_stats.common_stats.total_compl_cnt;
+               *ptr++ = vpath_info->fifo_stats.total_posts;
+               *ptr++ = vpath_info->fifo_stats.total_buffers;
+               for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
+                       *ptr++ = vpath_info->fifo_stats.txd_t_code_err_cnt[j];
+       }
+
+       *ptr++ = 0;
+       for (k = 0; k < vdev->no_of_vpath; k++) {
+               struct vxge_hw_vpath_stats_hw_info *vpath_info;
+               vpath = &vdev->vpaths[k];
+               j = vpath->device_id;
+               vpath_info = hw_stats->vpath_info[j];
+               if (!vpath_info) {
+                       memset(ptr, 0, VXGE_HW_VPATH_STATS_LEN * sizeof(u64));
+                       ptr += VXGE_HW_VPATH_STATS_LEN;
+                       continue;
+               }
+               *ptr++ = vpath_info->ini_num_mwr_sent;
+               *ptr++ = vpath_info->ini_num_mrd_sent;
+               *ptr++ = vpath_info->ini_num_cpl_rcvd;
+               *ptr++ = vpath_info->ini_num_mwr_byte_sent;
+               *ptr++ = vpath_info->ini_num_cpl_byte_rcvd;
+               *ptr++ = vpath_info->wrcrdtarb_xoff;
+               *ptr++ = vpath_info->rdcrdtarb_xoff;
+               *ptr++ = vpath_info->vpath_genstats_count0;
+               *ptr++ = vpath_info->vpath_genstats_count1;
+               *ptr++ = vpath_info->vpath_genstats_count2;
+               *ptr++ = vpath_info->vpath_genstats_count3;
+               *ptr++ = vpath_info->vpath_genstats_count4;
+               *ptr++ = vpath_info->vpath_genstats_count5;
+               *ptr++ = vpath_info->prog_event_vnum0;
+               *ptr++ = vpath_info->prog_event_vnum1;
+               *ptr++ = vpath_info->prog_event_vnum2;
+               *ptr++ = vpath_info->prog_event_vnum3;
+               *ptr++ = vpath_info->rx_multi_cast_frame_discard;
+               *ptr++ = vpath_info->rx_frm_transferred;
+               *ptr++ = vpath_info->rxd_returned;
+               *ptr++ = vpath_info->rx_mpa_len_fail_frms;
+               *ptr++ = vpath_info->rx_mpa_mrk_fail_frms;
+               *ptr++ = vpath_info->rx_mpa_crc_fail_frms;
+               *ptr++ = vpath_info->rx_permitted_frms;
+               *ptr++ = vpath_info->rx_vp_reset_discarded_frms;
+               *ptr++ = vpath_info->rx_wol_frms;
+               *ptr++ = vpath_info->tx_vp_reset_discarded_frms;
+       }
+
+       *ptr++ = 0;
+       *ptr++ = vdev->stats.vpaths_open;
+       *ptr++ = vdev->stats.vpath_open_fail;
+       *ptr++ = vdev->stats.link_up;
+       *ptr++ = vdev->stats.link_down;
+
+       for (k = 0; k < vdev->no_of_vpath; k++) {
+               *ptr += vdev->vpaths[k].fifo.stats.tx_frms;
+               *(ptr + 1) += vdev->vpaths[k].fifo.stats.tx_errors;
+               *(ptr + 2) += vdev->vpaths[k].fifo.stats.tx_bytes;
+               *(ptr + 3) += vdev->vpaths[k].fifo.stats.txd_not_free;
+               *(ptr + 4) += vdev->vpaths[k].fifo.stats.txd_out_of_desc;
+               *(ptr + 5) += vdev->vpaths[k].ring.stats.rx_frms;
+               *(ptr + 6) += vdev->vpaths[k].ring.stats.rx_errors;
+               *(ptr + 7) += vdev->vpaths[k].ring.stats.rx_bytes;
+               *(ptr + 8) += vdev->vpaths[k].ring.stats.rx_mcast;
+               *(ptr + 9) += vdev->vpaths[k].fifo.stats.pci_map_fail +
+                               vdev->vpaths[k].ring.stats.pci_map_fail;
+               *(ptr + 10) += vdev->vpaths[k].ring.stats.skb_alloc_fail;
+       }
+
+       ptr += 12;
+
+       kfree(xmac_stats);
+       kfree(sw_stats);
+       kfree(hw_stats);
+}
+
+static void vxge_ethtool_get_strings(struct net_device *dev,
+                             u32 stringset, u8 *data)
+{
+       int stat_size = 0;
+       int i, j;
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+       switch (stringset) {
+       case ETH_SS_STATS:
+               vxge_add_string("VPATH STATISTICS%s\t\t\t",
+                       &stat_size, data, "");
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       vxge_add_string("tx_ttl_eth_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_ttl_eth_octects_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_data_octects_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_mcast_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_bcast_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_ucast_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_tagged_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_vld_ip_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_vld_ip_octects_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_icmp_%d\t\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_tcp_%d\t\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_rst_tcp_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_udp_%d\t\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_unknown_proto_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_lost_ip_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_parse_error_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_tcp_offload_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_retx_tcp_offload_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_lost_ip_offload_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_eth_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_vld_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_offload_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_eth_octects_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_data_octects_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_offload_octects_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_vld_mcast_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_vld_bcast_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_accepted_ucast_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_accepted_nucast_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_tagged_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_long_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_usized_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_osized_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_frag_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_jabber_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_64_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_65_127_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_128_255_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_256_511_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_512_1023_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_1024_1518_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_1519_4095_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_4096_8191_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_8192_max_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ttl_gt_max_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ip%d\t\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_accepted_ip_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_ip_octects_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_err_ip_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_icmp_%d\t\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_tcp_%d\t\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_udp_%d\t\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_err_tcp_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_lost_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_lost_ip_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_lost_ip_offload_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_various_discard_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_sleep_discard_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_red_discard_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_queue_full_discard_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_mpa_ok_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+               }
+
+               vxge_add_string("\nAGGR STATISTICS%s\t\t\t\t",
+                       &stat_size, data, "");
+               for (i = 0; i < vdev->max_config_port; i++) {
+                       vxge_add_string("tx_frms_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_data_octects_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_mcast_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_bcast_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_discarded_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_errored_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_frms_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_data_octects_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_mcast_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_bcast_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_discarded_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_errored_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_unknown_slow_proto_frms_%d\t",
+                               &stat_size, data, i);
+               }
+
+               vxge_add_string("\nPORT STATISTICS%s\t\t\t\t",
+                       &stat_size, data, "");
+               for (i = 0; i < vdev->max_config_port; i++) {
+                       vxge_add_string("tx_ttl_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_ttl_octects_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_data_octects_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_mcast_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_bcast_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_ucast_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_tagged_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_vld_ip_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_vld_ip_octects_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_icmp_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_tcp_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_rst_tcp_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_udp_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_parse_error_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_unknown_protocol_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_pause_ctrl_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_marker_pdu_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_lacpdu_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_drop_ip_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_marker_resp_pdu_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_xgmii_char2_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_xgmii_char1_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_xgmii_column2_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_xgmii_column1_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_any_err_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("tx_drop_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_vld_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_offload_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_octects_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_data_octects_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_offload_octects_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_vld_mcast_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_vld_bcast_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_accepted_ucast_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_accepted_nucast_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_tagged_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_long_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_usized_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_osized_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_frag_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_jabber_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_64_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_65_127_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_128_255_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_256_511_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_512_1023_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_1024_1518_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_1519_4095_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_4096_8191_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_8192_max_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ttl_gt_max_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ip_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_accepted_ip_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_ip_octets_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_err_ip_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_icmp_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_tcp_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_udp_%d\t\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_err_tcp_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_pause_count_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_pause_ctrl_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_unsup_ctrl_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_fcs_err_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_in_rng_len_err_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_out_rng_len_err_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_drop_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_discard_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_drop_ip_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_drop_udp_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_marker_pdu_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_lacpdu_frms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_unknown_pdu_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_marker_resp_pdu_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_fcs_discard_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_illegal_pdu_frms_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_switch_discard_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_len_discard_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_rpa_discard_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_l2_mgmt_discard_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_rts_discard_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_trash_discard_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_buff_full_discard_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_red_discard_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_xgmii_ctrl_err_cnt_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_xgmii_data_err_cnt_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_xgmii_char1_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_xgmii_err_sym_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_xgmii_column1_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_xgmii_char2_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_local_fault_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_xgmii_column2_match_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_jettison_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("rx_remote_fault_%d\t\t\t",
+                               &stat_size, data, i);
+               }
+
+               vxge_add_string("\n SOFTWARE STATISTICS%s\t\t\t",
+                       &stat_size, data, "");
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       vxge_add_string("soft_reset_cnt_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("unknown_alarms_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("network_sustained_fault_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("network_sustained_ok_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("kdfcctl_fifo0_overwrite_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("kdfcctl_fifo0_poison_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("kdfcctl_fifo0_dma_error_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("dblgen_fifo0_overflow_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("statsb_pif_chain_error_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("statsb_drop_timeout_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("target_illegal_access_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("ini_serr_det_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("prc_ring_bumps_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("prc_rxdcm_sc_err_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("prc_rxdcm_sc_abort_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("prc_quanta_size_err_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("ring_full_cnt_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("ring_usage_cnt_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("ring_usage_max_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("ring_reserve_free_swaps_cnt_%d\t",
+                               &stat_size, data, i);
+                       vxge_add_string("ring_total_compl_cnt_%d\t\t",
+                               &stat_size, data, i);
+                       for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
+                               vxge_add_string("rxd_t_code_err_cnt%d_%d\t\t",
+                                       &stat_size, data, j, i);
+                       vxge_add_string("fifo_full_cnt_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("fifo_usage_cnt_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("fifo_usage_max_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("fifo_reserve_free_swaps_cnt_%d\t",
+                               &stat_size, data, i);
+                       vxge_add_string("fifo_total_compl_cnt_%d\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("fifo_total_posts_%d\t\t\t",
+                               &stat_size, data, i);
+                       vxge_add_string("fifo_total_buffers_%d\t\t",
+                               &stat_size, data, i);
+                       for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
+                               vxge_add_string("txd_t_code_err_cnt%d_%d\t\t",
+                                       &stat_size, data, j, i);
+               }
+
+               vxge_add_string("\n HARDWARE STATISTICS%s\t\t\t",
+                               &stat_size, data, "");
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       vxge_add_string("ini_num_mwr_sent_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("ini_num_mrd_sent_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("ini_num_cpl_rcvd_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("ini_num_mwr_byte_sent_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("ini_num_cpl_byte_rcvd_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("wrcrdtarb_xoff_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rdcrdtarb_xoff_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("vpath_genstats_count0_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("vpath_genstats_count1_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("vpath_genstats_count2_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("vpath_genstats_count3_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("vpath_genstats_count4_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("vpath_genstats_count5_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("prog_event_vnum0_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("prog_event_vnum1_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("prog_event_vnum2_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("prog_event_vnum3_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_multi_cast_frame_discard_%d\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_frm_transferred_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rxd_returned_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_mpa_len_fail_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_mpa_mrk_fail_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_mpa_crc_fail_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_permitted_frms_%d\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_vp_reset_discarded_frms_%d\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("rx_wol_frms_%d\t\t\t",
+                                       &stat_size, data, i);
+                       vxge_add_string("tx_vp_reset_discarded_frms_%d\t",
+                                       &stat_size, data, i);
+               }
+
+               memcpy(data + stat_size, &ethtool_driver_stats_keys,
+                       sizeof(ethtool_driver_stats_keys));
+       }
+}
+
+static int vxge_ethtool_get_regs_len(struct net_device *dev)
+{
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+
+       return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath;
+}
+
+static u32 vxge_get_rx_csum(struct net_device *dev)
+{
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+
+       return vdev->rx_csum;
+}
+
+static int vxge_set_rx_csum(struct net_device *dev, u32 data)
+{
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+
+       if (data)
+               vdev->rx_csum = 1;
+       else
+               vdev->rx_csum = 0;
+
+       return 0;
+}
+
+static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data)
+{
+       if (data)
+               dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+       else
+               dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+       return 0;
+}
+
+static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset)
+{
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+
+       switch (sset) {
+       case ETH_SS_STATS:
+               return VXGE_TITLE_LEN +
+                       (vdev->no_of_vpath * VXGE_HW_VPATH_STATS_LEN) +
+                       (vdev->max_config_port * VXGE_HW_AGGR_STATS_LEN) +
+                       (vdev->max_config_port * VXGE_HW_PORT_STATS_LEN) +
+                       (vdev->no_of_vpath * VXGE_HW_VPATH_TX_STATS_LEN) +
+                       (vdev->no_of_vpath * VXGE_HW_VPATH_RX_STATS_LEN) +
+                       (vdev->no_of_vpath * VXGE_SW_STATS_LEN) +
+                       DRIVER_STAT_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static const struct ethtool_ops vxge_ethtool_ops = {
+       .get_settings           = vxge_ethtool_gset,
+       .set_settings           = vxge_ethtool_sset,
+       .get_drvinfo            = vxge_ethtool_gdrvinfo,
+       .get_regs_len           = vxge_ethtool_get_regs_len,
+       .get_regs               = vxge_ethtool_gregs,
+       .get_link               = ethtool_op_get_link,
+       .get_pauseparam         = vxge_ethtool_getpause_data,
+       .set_pauseparam         = vxge_ethtool_setpause_data,
+       .get_rx_csum            = vxge_get_rx_csum,
+       .set_rx_csum            = vxge_set_rx_csum,
+       .get_tx_csum            = ethtool_op_get_tx_csum,
+       .set_tx_csum            = ethtool_op_set_tx_hw_csum,
+       .get_sg                 = ethtool_op_get_sg,
+       .set_sg                 = ethtool_op_set_sg,
+       .get_tso                = ethtool_op_get_tso,
+       .set_tso                = vxge_ethtool_op_set_tso,
+       .get_strings            = vxge_ethtool_get_strings,
+       .phys_id                = vxge_ethtool_idnic,
+       .get_sset_count         = vxge_ethtool_get_sset_count,
+       .get_ethtool_stats      = vxge_get_ethtool_stats,
+};
+
+void initialize_ethtool_ops(struct net_device *ndev)
+{
+       SET_ETHTOOL_OPS(ndev, &vxge_ethtool_ops);
+}
diff --git a/drivers/net/vxge/vxge-ethtool.h b/drivers/net/vxge/vxge-ethtool.h
new file mode 100644 (file)
index 0000000..1c3df0a
--- /dev/null
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-ethtool.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                 Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#ifndef _VXGE_ETHTOOL_H
+#define _VXGE_ETHTOOL_H
+
+#include "vxge-main.h"
+
+/* Ethtool related variables and Macros. */
+static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset);
+
+static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
+       {"\n DRIVER STATISTICS"},
+       {"vpaths_opened"},
+       {"vpath_open_fail_cnt"},
+       {"link_up_cnt"},
+       {"link_down_cnt"},
+       {"tx_frms"},
+       {"tx_errors"},
+       {"tx_bytes"},
+       {"txd_not_free"},
+       {"txd_out_of_desc"},
+       {"rx_frms"},
+       {"rx_errors"},
+       {"rx_bytes"},
+       {"rx_mcast"},
+       {"pci_map_fail_cnt"},
+       {"skb_alloc_fail_cnt"}
+};
+
+#define VXGE_TITLE_LEN                 5
+#define VXGE_HW_VPATH_STATS_LEN        27
+#define VXGE_HW_AGGR_STATS_LEN         13
+#define VXGE_HW_PORT_STATS_LEN         94
+#define VXGE_HW_VPATH_TX_STATS_LEN     19
+#define VXGE_HW_VPATH_RX_STATS_LEN     42
+#define VXGE_SW_STATS_LEN              60
+#define VXGE_HW_STATS_LEN      (VXGE_HW_VPATH_STATS_LEN +\
+                               VXGE_HW_AGGR_STATS_LEN +\
+                               VXGE_HW_PORT_STATS_LEN +\
+                               VXGE_HW_VPATH_TX_STATS_LEN +\
+                               VXGE_HW_VPATH_RX_STATS_LEN)
+
+#define DRIVER_STAT_LEN (sizeof(ethtool_driver_stats_keys)/ETH_GSTRING_LEN)
+#define STAT_LEN (VXGE_HW_STATS_LEN + DRIVER_STAT_LEN + VXGE_SW_STATS_LEN)
+
+/* Maximum flicker time of adapter LED */
+#define VXGE_MAX_FLICKER_TIME (60 * HZ) /* 60 seconds */
+#define VXGE_FLICKER_ON                1
+#define VXGE_FLICKER_OFF       0
+
+#define vxge_add_string(fmt, size, buf, ...) {\
+       snprintf(buf + *size, ETH_GSTRING_LEN, fmt, __VA_ARGS__); \
+       *size += ETH_GSTRING_LEN; \
+}
+
+#endif /*_VXGE_ETHTOOL_H*/
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
new file mode 100644 (file)
index 0000000..61ef161
--- /dev/null
@@ -0,0 +1,4502 @@
+/******************************************************************************
+* This software may be used and distributed according to the terms of
+* the GNU General Public License (GPL), incorporated herein by reference.
+* Drivers based on or derived from this code fall under the GPL and must
+* retain the authorship, copyright and license notice.  This file is not
+* a complete program and may only be used when the entire operating
+* system is licensed under the GPL.
+* See the file COPYING in this distribution for more information.
+*
+* vxge-main.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+*              Virtualized Server Adapter.
+* Copyright(c) 2002-2009 Neterion Inc.
+*
+* The module loadable parameters that are supported by the driver and a brief
+* explanation of all the variables:
+* vlan_tag_strip:
+*      Strip VLAN Tag enable/disable. Instructs the device to remove
+*      the VLAN tag from all received tagged frames that are not
+*      replicated at the internal L2 switch.
+*              0 - Do not strip the VLAN tag.
+*              1 - Strip the VLAN tag.
+*
+* addr_learn_en:
+*      Enable learning the mac address of the guest OS interface in
+*      a virtualization environment.
+*              0 - DISABLE
+*              1 - ENABLE
+*
+* max_config_port:
+*      Maximum number of port to be supported.
+*              MIN -1 and MAX - 2
+*
+* max_config_vpath:
+*      This configures the maximum no of VPATH configures for each
+*      device function.
+*              MIN - 1 and MAX - 17
+*
+* max_config_dev:
+*      This configures maximum no of Device function to be enabled.
+*              MIN - 1 and MAX - 17
+*
+******************************************************************************/
+
+#include <linux/if_vlan.h>
+#include <linux/pci.h>
+#include <net/ip.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "vxge-main.h"
+#include "vxge-reg.h"
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("Neterion's X3100 Series 10GbE PCIe I/O"
+       "Virtualized Server Adapter");
+
+static struct pci_device_id vxge_id_table[] __devinitdata = {
+       {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_WIN, PCI_ANY_ID,
+       PCI_ANY_ID},
+       {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_UNI, PCI_ANY_ID,
+       PCI_ANY_ID},
+       {0}
+};
+
+MODULE_DEVICE_TABLE(pci, vxge_id_table);
+
+VXGE_MODULE_PARAM_INT(vlan_tag_strip, VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE);
+VXGE_MODULE_PARAM_INT(addr_learn_en, VXGE_HW_MAC_ADDR_LEARN_DEFAULT);
+VXGE_MODULE_PARAM_INT(max_config_port, VXGE_MAX_CONFIG_PORT);
+VXGE_MODULE_PARAM_INT(max_config_vpath, VXGE_USE_DEFAULT);
+VXGE_MODULE_PARAM_INT(max_mac_vpath, VXGE_MAX_MAC_ADDR_COUNT);
+VXGE_MODULE_PARAM_INT(max_config_dev, VXGE_MAX_CONFIG_DEV);
+
+static u16 vpath_selector[VXGE_HW_MAX_VIRTUAL_PATHS] =
+               {0, 1, 3, 3, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, 31};
+static unsigned int bw_percentage[VXGE_HW_MAX_VIRTUAL_PATHS] =
+       {[0 ...(VXGE_HW_MAX_VIRTUAL_PATHS - 1)] = 0xFF};
+module_param_array(bw_percentage, uint, NULL, 0);
+
+static struct vxge_drv_config *driver_config;
+
+static inline int is_vxge_card_up(struct vxgedev *vdev)
+{
+       return test_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+}
+
+static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
+{
+       unsigned long flags = 0;
+       struct sk_buff *skb_ptr = NULL;
+       struct sk_buff **temp, *head, *skb;
+
+       if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
+               vxge_hw_vpath_poll_tx(fifo->handle, (void **)&skb_ptr);
+               spin_unlock_irqrestore(&fifo->tx_lock, flags);
+       }
+       /* free SKBs */
+       head = skb_ptr;
+       while (head) {
+               skb = head;
+               temp = (struct sk_buff **)&skb->cb;
+               head = *temp;
+               *temp = NULL;
+               dev_kfree_skb_irq(skb);
+       }
+}
+
+static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev)
+{
+       int i;
+
+       /* Complete all transmits */
+       for (i = 0; i < vdev->no_of_vpath; i++)
+               VXGE_COMPLETE_VPATH_TX(&vdev->vpaths[i].fifo);
+}
+
+static inline void VXGE_COMPLETE_ALL_RX(struct vxgedev *vdev)
+{
+       int i;
+       struct vxge_ring *ring;
+
+       /* Complete all receives*/
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               ring = &vdev->vpaths[i].ring;
+               vxge_hw_vpath_poll_rx(ring->handle);
+       }
+}
+
+/*
+ * MultiQ manipulation helper functions
+ */
+void vxge_stop_all_tx_queue(struct vxgedev *vdev)
+{
+       int i;
+       struct net_device *dev = vdev->ndev;
+
+       if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_STOP;
+       }
+       netif_tx_stop_all_queues(dev);
+}
+
+void vxge_stop_tx_queue(struct vxge_fifo *fifo)
+{
+       struct net_device *dev = fifo->ndev;
+
+       struct netdev_queue *txq = NULL;
+       if (fifo->tx_steering_type == TX_MULTIQ_STEERING)
+               txq = netdev_get_tx_queue(dev, fifo->driver_id);
+       else {
+               txq = netdev_get_tx_queue(dev, 0);
+               fifo->queue_state = VPATH_QUEUE_STOP;
+       }
+
+       netif_tx_stop_queue(txq);
+}
+
+void vxge_start_all_tx_queue(struct vxgedev *vdev)
+{
+       int i;
+       struct net_device *dev = vdev->ndev;
+
+       if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START;
+       }
+       netif_tx_start_all_queues(dev);
+}
+
+static void vxge_wake_all_tx_queue(struct vxgedev *vdev)
+{
+       int i;
+       struct net_device *dev = vdev->ndev;
+
+       if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START;
+       }
+       netif_tx_wake_all_queues(dev);
+}
+
+void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb)
+{
+       struct net_device *dev = fifo->ndev;
+
+       int vpath_no = fifo->driver_id;
+       struct netdev_queue *txq = NULL;
+       if (fifo->tx_steering_type == TX_MULTIQ_STEERING) {
+               txq = netdev_get_tx_queue(dev, vpath_no);
+               if (netif_tx_queue_stopped(txq))
+                       netif_tx_wake_queue(txq);
+       } else {
+               txq = netdev_get_tx_queue(dev, 0);
+               if (fifo->queue_state == VPATH_QUEUE_STOP)
+                       if (netif_tx_queue_stopped(txq)) {
+                               fifo->queue_state = VPATH_QUEUE_START;
+                               netif_tx_wake_queue(txq);
+                       }
+       }
+}
+
+/*
+ * vxge_callback_link_up
+ *
+ * This function is called during interrupt context to notify link up state
+ * change.
+ */
+void
+vxge_callback_link_up(struct __vxge_hw_device *hldev)
+{
+       struct net_device *dev = hldev->ndev;
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+               vdev->ndev->name, __func__, __LINE__);
+       printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name);
+       vdev->stats.link_up++;
+
+       netif_carrier_on(vdev->ndev);
+       vxge_wake_all_tx_queue(vdev);
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
+}
+
+/*
+ * vxge_callback_link_down
+ *
+ * This function is called during interrupt context to notify link down state
+ * change.
+ */
+void
+vxge_callback_link_down(struct __vxge_hw_device *hldev)
+{
+       struct net_device *dev = hldev->ndev;
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
+       printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name);
+
+       vdev->stats.link_down++;
+       netif_carrier_off(vdev->ndev);
+       vxge_stop_all_tx_queue(vdev);
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
+}
+
+/*
+ * vxge_rx_alloc
+ *
+ * Allocate SKB.
+ */
+static struct sk_buff*
+vxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size)
+{
+       struct net_device    *dev;
+       struct sk_buff       *skb;
+       struct vxge_rx_priv *rx_priv;
+
+       dev = ring->ndev;
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+               ring->ndev->name, __func__, __LINE__);
+
+       rx_priv = vxge_hw_ring_rxd_private_get(dtrh);
+
+       /* try to allocate skb first. this one may fail */
+       skb = netdev_alloc_skb(dev, skb_size +
+       VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
+       if (skb == NULL) {
+               vxge_debug_mem(VXGE_ERR,
+                       "%s: out of memory to allocate SKB", dev->name);
+               ring->stats.skb_alloc_fail++;
+               return NULL;
+       }
+
+       vxge_debug_mem(VXGE_TRACE,
+               "%s: %s:%d  Skb : 0x%p", ring->ndev->name,
+               __func__, __LINE__, skb);
+
+       skb_reserve(skb, VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
+
+       rx_priv->skb = skb;
+       rx_priv->data_size = skb_size;
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
+
+       return skb;
+}
+
+/*
+ * vxge_rx_map
+ */
+static int vxge_rx_map(void *dtrh, struct vxge_ring *ring)
+{
+       struct vxge_rx_priv *rx_priv;
+       dma_addr_t dma_addr;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+               ring->ndev->name, __func__, __LINE__);
+       rx_priv = vxge_hw_ring_rxd_private_get(dtrh);
+
+       dma_addr = pci_map_single(ring->pdev, rx_priv->skb->data,
+                               rx_priv->data_size, PCI_DMA_FROMDEVICE);
+
+       if (dma_addr == 0) {
+               ring->stats.pci_map_fail++;
+               return -EIO;
+       }
+       vxge_debug_mem(VXGE_TRACE,
+               "%s: %s:%d  1 buffer mode dma_addr = 0x%llx",
+               ring->ndev->name, __func__, __LINE__,
+               (unsigned long long)dma_addr);
+       vxge_hw_ring_rxd_1b_set(dtrh, dma_addr, rx_priv->data_size);
+
+       rx_priv->data_dma = dma_addr;
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
+
+       return 0;
+}
+
+/*
+ * vxge_rx_initial_replenish
+ * Allocation of RxD as an initial replenish procedure.
+ */
+static enum vxge_hw_status
+vxge_rx_initial_replenish(void *dtrh, void *userdata)
+{
+       struct vxge_ring *ring = (struct vxge_ring *)userdata;
+       struct vxge_rx_priv *rx_priv;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+               ring->ndev->name, __func__, __LINE__);
+       if (vxge_rx_alloc(dtrh, ring,
+                         VXGE_LL_MAX_FRAME_SIZE(ring->ndev)) == NULL)
+               return VXGE_HW_FAIL;
+
+       if (vxge_rx_map(dtrh, ring)) {
+               rx_priv = vxge_hw_ring_rxd_private_get(dtrh);
+               dev_kfree_skb(rx_priv->skb);
+
+               return VXGE_HW_FAIL;
+       }
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
+
+       return VXGE_HW_OK;
+}
+
+static inline void
+vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
+                int pkt_length, struct vxge_hw_ring_rxd_info *ext_info)
+{
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+                       ring->ndev->name, __func__, __LINE__);
+       skb_record_rx_queue(skb, ring->driver_id);
+       skb->protocol = eth_type_trans(skb, ring->ndev);
+
+       ring->stats.rx_frms++;
+       ring->stats.rx_bytes += pkt_length;
+
+       if (skb->pkt_type == PACKET_MULTICAST)
+               ring->stats.rx_mcast++;
+
+       vxge_debug_rx(VXGE_TRACE,
+               "%s: %s:%d  skb protocol = %d",
+               ring->ndev->name, __func__, __LINE__, skb->protocol);
+
+       if (ring->gro_enable) {
+               if (ring->vlgrp && ext_info->vlan &&
+                       (ring->vlan_tag_strip ==
+                               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
+                       vlan_gro_receive(&ring->napi, ring->vlgrp,
+                                       ext_info->vlan, skb);
+               else
+                       napi_gro_receive(&ring->napi, skb);
+       } else {
+               if (ring->vlgrp && vlan &&
+                       (ring->vlan_tag_strip ==
+                               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
+                       vlan_hwaccel_receive_skb(skb, ring->vlgrp, vlan);
+               else
+                       netif_receive_skb(skb);
+       }
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
+}
+
+static inline void vxge_re_pre_post(void *dtr, struct vxge_ring *ring,
+                                   struct vxge_rx_priv *rx_priv)
+{
+       pci_dma_sync_single_for_device(ring->pdev,
+               rx_priv->data_dma, rx_priv->data_size, PCI_DMA_FROMDEVICE);
+
+       vxge_hw_ring_rxd_1b_set(dtr, rx_priv->data_dma, rx_priv->data_size);
+       vxge_hw_ring_rxd_pre_post(ring->handle, dtr);
+}
+
+static inline void vxge_post(int *dtr_cnt, void **first_dtr,
+                            void *post_dtr, struct __vxge_hw_ring *ringh)
+{
+       int dtr_count = *dtr_cnt;
+       if ((*dtr_cnt % VXGE_HW_RXSYNC_FREQ_CNT) == 0) {
+               if (*first_dtr)
+                       vxge_hw_ring_rxd_post_post_wmb(ringh, *first_dtr);
+               *first_dtr = post_dtr;
+       } else
+               vxge_hw_ring_rxd_post_post(ringh, post_dtr);
+       dtr_count++;
+       *dtr_cnt = dtr_count;
+}
+
+/*
+ * vxge_rx_1b_compl
+ *
+ * If the interrupt is because of a received frame or if the receive ring
+ * contains fresh as yet un-processed frames, this function is called.
+ */
+enum vxge_hw_status
+vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
+                u8 t_code, void *userdata)
+{
+       struct vxge_ring *ring = (struct vxge_ring *)userdata;
+       struct  net_device *dev = ring->ndev;
+       unsigned int dma_sizes;
+       void *first_dtr = NULL;
+       int dtr_cnt = 0;
+       int data_size;
+       dma_addr_t data_dma;
+       int pkt_length;
+       struct sk_buff *skb;
+       struct vxge_rx_priv *rx_priv;
+       struct vxge_hw_ring_rxd_info ext_info;
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+               ring->ndev->name, __func__, __LINE__);
+       ring->pkts_processed = 0;
+
+       vxge_hw_ring_replenish(ringh, 0);
+
+       do {
+               rx_priv = vxge_hw_ring_rxd_private_get(dtr);
+               skb = rx_priv->skb;
+               data_size = rx_priv->data_size;
+               data_dma = rx_priv->data_dma;
+
+               vxge_debug_rx(VXGE_TRACE,
+                       "%s: %s:%d  skb = 0x%p",
+                       ring->ndev->name, __func__, __LINE__, skb);
+
+               vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes);
+               pkt_length = dma_sizes;
+
+               vxge_debug_rx(VXGE_TRACE,
+                       "%s: %s:%d  Packet Length = %d",
+                       ring->ndev->name, __func__, __LINE__, pkt_length);
+
+               vxge_hw_ring_rxd_1b_info_get(ringh, dtr, &ext_info);
+
+               /* check skb validity */
+               vxge_assert(skb);
+
+               prefetch((char *)skb + L1_CACHE_BYTES);
+               if (unlikely(t_code)) {
+
+                       if (vxge_hw_ring_handle_tcode(ringh, dtr, t_code) !=
+                               VXGE_HW_OK) {
+
+                               ring->stats.rx_errors++;
+                               vxge_debug_rx(VXGE_TRACE,
+                                       "%s: %s :%d Rx T_code is %d",
+                                       ring->ndev->name, __func__,
+                                       __LINE__, t_code);
+
+                               /* If the t_code is not supported and if the
+                                * t_code is other than 0x5 (unparseable packet
+                                * such as unknown UPV6 header), Drop it !!!
+                                */
+                               vxge_re_pre_post(dtr, ring, rx_priv);
+
+                               vxge_post(&dtr_cnt, &first_dtr, dtr, ringh);
+                               ring->stats.rx_dropped++;
+                               continue;
+                       }
+               }
+
+               if (pkt_length > VXGE_LL_RX_COPY_THRESHOLD) {
+
+                       if (vxge_rx_alloc(dtr, ring, data_size) != NULL) {
+
+                               if (!vxge_rx_map(dtr, ring)) {
+                                       skb_put(skb, pkt_length);
+
+                                       pci_unmap_single(ring->pdev, data_dma,
+                                               data_size, PCI_DMA_FROMDEVICE);
+
+                                       vxge_hw_ring_rxd_pre_post(ringh, dtr);
+                                       vxge_post(&dtr_cnt, &first_dtr, dtr,
+                                               ringh);
+                               } else {
+                                       dev_kfree_skb(rx_priv->skb);
+                                       rx_priv->skb = skb;
+                                       rx_priv->data_size = data_size;
+                                       vxge_re_pre_post(dtr, ring, rx_priv);
+
+                                       vxge_post(&dtr_cnt, &first_dtr, dtr,
+                                               ringh);
+                                       ring->stats.rx_dropped++;
+                                       break;
+                               }
+                       } else {
+                               vxge_re_pre_post(dtr, ring, rx_priv);
+
+                               vxge_post(&dtr_cnt, &first_dtr, dtr, ringh);
+                               ring->stats.rx_dropped++;
+                               break;
+                       }
+               } else {
+                       struct sk_buff *skb_up;
+
+                       skb_up = netdev_alloc_skb(dev, pkt_length +
+                               VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
+                       if (skb_up != NULL) {
+                               skb_reserve(skb_up,
+                                   VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
+
+                               pci_dma_sync_single_for_cpu(ring->pdev,
+                                       data_dma, data_size,
+                                       PCI_DMA_FROMDEVICE);
+
+                               vxge_debug_mem(VXGE_TRACE,
+                                       "%s: %s:%d  skb_up = %p",
+                                       ring->ndev->name, __func__,
+                                       __LINE__, skb);
+                               memcpy(skb_up->data, skb->data, pkt_length);
+
+                               vxge_re_pre_post(dtr, ring, rx_priv);
+
+                               vxge_post(&dtr_cnt, &first_dtr, dtr,
+                                       ringh);
+                               /* will netif_rx small SKB instead */
+                               skb = skb_up;
+                               skb_put(skb, pkt_length);
+                       } else {
+                               vxge_re_pre_post(dtr, ring, rx_priv);
+
+                               vxge_post(&dtr_cnt, &first_dtr, dtr, ringh);
+                               vxge_debug_rx(VXGE_ERR,
+                                       "%s: vxge_rx_1b_compl: out of "
+                                       "memory", dev->name);
+                               ring->stats.skb_alloc_fail++;
+                               break;
+                       }
+               }
+
+               if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) &&
+                   !(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) &&
+                   ring->rx_csum && /* Offload Rx side CSUM */
+                   ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK &&
+                   ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb->ip_summed = CHECKSUM_NONE;
+
+               vxge_rx_complete(ring, skb, ext_info.vlan,
+                       pkt_length, &ext_info);
+
+               ring->budget--;
+               ring->pkts_processed++;
+               if (!ring->budget)
+                       break;
+
+       } while (vxge_hw_ring_rxd_next_completed(ringh, &dtr,
+               &t_code) == VXGE_HW_OK);
+
+       if (first_dtr)
+               vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr);
+
+       dev->last_rx = jiffies;
+
+       vxge_debug_entryexit(VXGE_TRACE,
+                               "%s:%d  Exiting...",
+                               __func__, __LINE__);
+       return VXGE_HW_OK;
+}
+
+/*
+ * vxge_xmit_compl
+ *
+ * If an interrupt was raised to indicate DMA complete of the Tx packet,
+ * this function is called. It identifies the last TxD whose buffer was
+ * freed and frees all skbs whose data have already DMA'ed into the NICs
+ * internal memory.
+ */
+enum vxge_hw_status
+vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
+               enum vxge_hw_fifo_tcode t_code, void *userdata,
+               void **skb_ptr)
+{
+       struct vxge_fifo *fifo = (struct vxge_fifo *)userdata;
+       struct sk_buff *skb, *head = NULL;
+       struct sk_buff **temp;
+       int pkt_cnt = 0;
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d Entered....", __func__, __LINE__);
+
+       do {
+               int frg_cnt;
+               skb_frag_t *frag;
+               int i = 0, j;
+               struct vxge_tx_priv *txd_priv =
+                       vxge_hw_fifo_txdl_private_get(dtr);
+
+               skb = txd_priv->skb;
+               frg_cnt = skb_shinfo(skb)->nr_frags;
+               frag = &skb_shinfo(skb)->frags[0];
+
+               vxge_debug_tx(VXGE_TRACE,
+                               "%s: %s:%d fifo_hw = %p dtr = %p "
+                               "tcode = 0x%x", fifo->ndev->name, __func__,
+                               __LINE__, fifo_hw, dtr, t_code);
+               /* check skb validity */
+               vxge_assert(skb);
+               vxge_debug_tx(VXGE_TRACE,
+                       "%s: %s:%d skb = %p itxd_priv = %p frg_cnt = %d",
+                       fifo->ndev->name, __func__, __LINE__,
+                       skb, txd_priv, frg_cnt);
+               if (unlikely(t_code)) {
+                       fifo->stats.tx_errors++;
+                       vxge_debug_tx(VXGE_ERR,
+                               "%s: tx: dtr %p completed due to "
+                               "error t_code %01x", fifo->ndev->name,
+                               dtr, t_code);
+                       vxge_hw_fifo_handle_tcode(fifo_hw, dtr, t_code);
+               }
+
+               /*  for unfragmented skb */
+               pci_unmap_single(fifo->pdev, txd_priv->dma_buffers[i++],
+                               skb_headlen(skb), PCI_DMA_TODEVICE);
+
+               for (j = 0; j < frg_cnt; j++) {
+                       pci_unmap_page(fifo->pdev,
+                                       txd_priv->dma_buffers[i++],
+                                       frag->size, PCI_DMA_TODEVICE);
+                       frag += 1;
+               }
+
+               vxge_hw_fifo_txdl_free(fifo_hw, dtr);
+
+               /* Updating the statistics block */
+               fifo->stats.tx_frms++;
+               fifo->stats.tx_bytes += skb->len;
+
+               temp = (struct sk_buff **)&skb->cb;
+               *temp = head;
+               head = skb;
+
+               pkt_cnt++;
+               if (pkt_cnt > fifo->indicate_max_pkts)
+                       break;
+
+       } while (vxge_hw_fifo_txdl_next_completed(fifo_hw,
+                               &dtr, &t_code) == VXGE_HW_OK);
+
+       vxge_wake_tx_queue(fifo, skb);
+
+       if (skb_ptr)
+               *skb_ptr = (void *) head;
+
+       vxge_debug_entryexit(VXGE_TRACE,
+                               "%s: %s:%d  Exiting...",
+                               fifo->ndev->name, __func__, __LINE__);
+       return VXGE_HW_OK;
+}
+
+/* select a vpath to trasmit the packet */
+static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb,
+       int *do_lock)
+{
+       u16 queue_len, counter = 0;
+       if (skb->protocol == htons(ETH_P_IP)) {
+               struct iphdr *ip;
+               struct tcphdr *th;
+
+               ip = ip_hdr(skb);
+
+               if ((ip->frag_off & htons(IP_OFFSET|IP_MF)) == 0) {
+                       th = (struct tcphdr *)(((unsigned char *)ip) +
+                                       ip->ihl*4);
+
+                       queue_len = vdev->no_of_vpath;
+                       counter = (ntohs(th->source) +
+                               ntohs(th->dest)) &
+                               vdev->vpath_selector[queue_len - 1];
+                       if (counter >= queue_len)
+                               counter = queue_len - 1;
+
+                       if (ip->protocol == IPPROTO_UDP) {
+#ifdef NETIF_F_LLTX
+                               *do_lock = 0;
+#endif
+                       }
+               }
+       }
+       return counter;
+}
+
+static enum vxge_hw_status vxge_search_mac_addr_in_list(
+       struct vxge_vpath *vpath, u64 del_mac)
+{
+       struct list_head *entry, *next;
+       list_for_each_safe(entry, next, &vpath->mac_addr_list) {
+               if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header)
+{
+       struct macInfo mac_info;
+       u8 *mac_address = NULL;
+       u64 mac_addr = 0, vpath_vector = 0;
+       int vpath_idx = 0;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_vpath *vpath = NULL;
+       struct __vxge_hw_device *hldev;
+
+       hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+
+       mac_address = (u8 *)&mac_addr;
+       memcpy(mac_address, mac_header, ETH_ALEN);
+
+       /* Is this mac address already in the list? */
+       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
+               vpath = &vdev->vpaths[vpath_idx];
+               if (vxge_search_mac_addr_in_list(vpath, mac_addr))
+                       return vpath_idx;
+       }
+
+       memset(&mac_info, 0, sizeof(struct macInfo));
+       memcpy(mac_info.macaddr, mac_header, ETH_ALEN);
+
+       /* Any vpath has room to add mac address to its da table? */
+       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
+               vpath = &vdev->vpaths[vpath_idx];
+               if (vpath->mac_addr_cnt < vpath->max_mac_addr_cnt) {
+                       /* Add this mac address to this vpath */
+                       mac_info.vpath_no = vpath_idx;
+                       mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE;
+                       status = vxge_add_mac_addr(vdev, &mac_info);
+                       if (status != VXGE_HW_OK)
+                               return -EPERM;
+                       return vpath_idx;
+               }
+       }
+
+       mac_info.state = VXGE_LL_MAC_ADDR_IN_LIST;
+       vpath_idx = 0;
+       mac_info.vpath_no = vpath_idx;
+       /* Is the first vpath already selected as catch-basin ? */
+       vpath = &vdev->vpaths[vpath_idx];
+       if (vpath->mac_addr_cnt > vpath->max_mac_addr_cnt) {
+               /* Add this mac address to this vpath */
+               if (FALSE == vxge_mac_list_add(vpath, &mac_info))
+                       return -EPERM;
+               return vpath_idx;
+       }
+
+       /* Select first vpath as catch-basin */
+       vpath_vector = vxge_mBIT(vpath->device_id);
+       status = vxge_hw_mgmt_reg_write(vpath->vdev->devh,
+                               vxge_hw_mgmt_reg_type_mrpcim,
+                               0,
+                               (ulong)offsetof(
+                                       struct vxge_hw_mrpcim_reg,
+                                       rts_mgr_cbasin_cfg),
+                               vpath_vector);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_tx(VXGE_ERR,
+                       "%s: Unable to set the vpath-%d in catch-basin mode",
+                       VXGE_DRIVER_NAME, vpath->device_id);
+               return -EPERM;
+       }
+
+       if (FALSE == vxge_mac_list_add(vpath, &mac_info))
+               return -EPERM;
+
+       return vpath_idx;
+}
+
+/**
+ * vxge_xmit
+ * @skb : the socket buffer containing the Tx data.
+ * @dev : device pointer.
+ *
+ * This function is the Tx entry point of the driver. Neterion NIC supports
+ * certain protocol assist features on Tx side, namely  CSO, S/G, LSO.
+ * NOTE: when device cant queue the pkt, just the trans_start variable will
+ * not be upadted.
+*/
+static int
+vxge_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct vxge_fifo *fifo = NULL;
+       void *dtr_priv;
+       void *dtr = NULL;
+       struct vxgedev *vdev = NULL;
+       enum vxge_hw_status status;
+       int frg_cnt, first_frg_len;
+       skb_frag_t *frag;
+       int i = 0, j = 0, avail;
+       u64 dma_pointer;
+       struct vxge_tx_priv *txdl_priv = NULL;
+       struct __vxge_hw_fifo *fifo_hw;
+       u32 max_mss = 0x0;
+       int offload_type;
+       unsigned long flags = 0;
+       int vpath_no = 0;
+       int do_spin_tx_lock = 1;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+                       dev->name, __func__, __LINE__);
+
+       /* A buffer with no data will be dropped */
+       if (unlikely(skb->len <= 0)) {
+               vxge_debug_tx(VXGE_ERR,
+                       "%s: Buffer has no data..", dev->name);
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+
+       if (unlikely(!is_vxge_card_up(vdev))) {
+               vxge_debug_tx(VXGE_ERR,
+                       "%s: vdev not initialized", dev->name);
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (vdev->config.addr_learn_en) {
+               vpath_no = vxge_learn_mac(vdev, skb->data + ETH_ALEN);
+               if (vpath_no == -EPERM) {
+                       vxge_debug_tx(VXGE_ERR,
+                               "%s: Failed to store the mac address",
+                               dev->name);
+                       dev_kfree_skb(skb);
+                       return NETDEV_TX_OK;
+               }
+       }
+
+       if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING)
+               vpath_no = skb_get_queue_mapping(skb);
+       else if (vdev->config.tx_steering_type == TX_PORT_STEERING)
+               vpath_no = vxge_get_vpath_no(vdev, skb, &do_spin_tx_lock);
+
+       vxge_debug_tx(VXGE_TRACE, "%s: vpath_no= %d", dev->name, vpath_no);
+
+       if (vpath_no >= vdev->no_of_vpath)
+               vpath_no = 0;
+
+       fifo = &vdev->vpaths[vpath_no].fifo;
+       fifo_hw = fifo->handle;
+
+       if (do_spin_tx_lock)
+               spin_lock_irqsave(&fifo->tx_lock, flags);
+       else {
+               if (unlikely(!spin_trylock_irqsave(&fifo->tx_lock, flags)))
+                       return NETDEV_TX_LOCKED;
+       }
+
+       if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING) {
+               if (netif_subqueue_stopped(dev, skb)) {
+                       spin_unlock_irqrestore(&fifo->tx_lock, flags);
+                       return NETDEV_TX_BUSY;
+               }
+       } else if (unlikely(fifo->queue_state == VPATH_QUEUE_STOP)) {
+               if (netif_queue_stopped(dev)) {
+                       spin_unlock_irqrestore(&fifo->tx_lock, flags);
+                       return NETDEV_TX_BUSY;
+               }
+       }
+       avail = vxge_hw_fifo_free_txdl_count_get(fifo_hw);
+       if (avail == 0) {
+               vxge_debug_tx(VXGE_ERR,
+                       "%s: No free TXDs available", dev->name);
+               fifo->stats.txd_not_free++;
+               vxge_stop_tx_queue(fifo);
+               goto _exit2;
+       }
+
+       status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv);
+       if (unlikely(status != VXGE_HW_OK)) {
+               vxge_debug_tx(VXGE_ERR,
+                  "%s: Out of descriptors .", dev->name);
+               fifo->stats.txd_out_of_desc++;
+               vxge_stop_tx_queue(fifo);
+               goto _exit2;
+       }
+
+       vxge_debug_tx(VXGE_TRACE,
+               "%s: %s:%d fifo_hw = %p dtr = %p dtr_priv = %p",
+               dev->name, __func__, __LINE__,
+               fifo_hw, dtr, dtr_priv);
+
+       if (vdev->vlgrp && vlan_tx_tag_present(skb)) {
+               u16 vlan_tag = vlan_tx_tag_get(skb);
+               vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag);
+       }
+
+       first_frg_len = skb_headlen(skb);
+
+       dma_pointer = pci_map_single(fifo->pdev, skb->data, first_frg_len,
+                               PCI_DMA_TODEVICE);
+
+       if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer))) {
+               vxge_hw_fifo_txdl_free(fifo_hw, dtr);
+               vxge_stop_tx_queue(fifo);
+               fifo->stats.pci_map_fail++;
+               goto _exit2;
+       }
+
+       txdl_priv = vxge_hw_fifo_txdl_private_get(dtr);
+       txdl_priv->skb = skb;
+       txdl_priv->dma_buffers[j] = dma_pointer;
+
+       frg_cnt = skb_shinfo(skb)->nr_frags;
+       vxge_debug_tx(VXGE_TRACE,
+                       "%s: %s:%d skb = %p txdl_priv = %p "
+                       "frag_cnt = %d dma_pointer = 0x%llx", dev->name,
+                       __func__, __LINE__, skb, txdl_priv,
+                       frg_cnt, (unsigned long long)dma_pointer);
+
+       vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer,
+               first_frg_len);
+
+       frag = &skb_shinfo(skb)->frags[0];
+       for (i = 0; i < frg_cnt; i++) {
+               /* ignore 0 length fragment */
+               if (!frag->size)
+                       continue;
+
+               dma_pointer =
+                       (u64)pci_map_page(fifo->pdev, frag->page,
+                               frag->page_offset, frag->size,
+                               PCI_DMA_TODEVICE);
+
+               if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer)))
+                       goto _exit0;
+               vxge_debug_tx(VXGE_TRACE,
+                       "%s: %s:%d frag = %d dma_pointer = 0x%llx",
+                               dev->name, __func__, __LINE__, i,
+                               (unsigned long long)dma_pointer);
+
+               txdl_priv->dma_buffers[j] = dma_pointer;
+               vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer,
+                                       frag->size);
+               frag += 1;
+       }
+
+       offload_type = vxge_offload_type(skb);
+
+       if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+
+               int mss = vxge_tcp_mss(skb);
+               if (mss) {
+                       max_mss = dev->mtu + ETH_HLEN -
+                               VXGE_HW_TCPIP_HEADER_MAX_SIZE;
+                       if (mss > max_mss)
+                               mss = max_mss;
+                       vxge_debug_tx(VXGE_TRACE,
+                               "%s: %s:%d mss = %d",
+                               dev->name, __func__, __LINE__, mss);
+                       vxge_hw_fifo_txdl_mss_set(dtr, mss);
+               } else {
+                       vxge_assert(skb->len <=
+                               dev->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE);
+                       vxge_assert(0);
+                       goto _exit1;
+               }
+       }
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               vxge_hw_fifo_txdl_cksum_set_bits(dtr,
+                                       VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN |
+                                       VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN |
+                                       VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN);
+
+       vxge_hw_fifo_txdl_post(fifo_hw, dtr);
+       dev->trans_start = jiffies;
+       spin_unlock_irqrestore(&fifo->tx_lock, flags);
+
+       VXGE_COMPLETE_VPATH_TX(fifo);
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d  Exiting...",
+               dev->name, __func__, __LINE__);
+       return 0;
+
+_exit0:
+       vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
+
+_exit1:
+       j = 0;
+       frag = &skb_shinfo(skb)->frags[0];
+
+       pci_unmap_single(fifo->pdev, txdl_priv->dma_buffers[j++],
+                       skb_headlen(skb), PCI_DMA_TODEVICE);
+
+       for (; j < i; j++) {
+               pci_unmap_page(fifo->pdev, txdl_priv->dma_buffers[j],
+                       frag->size, PCI_DMA_TODEVICE);
+               frag += 1;
+       }
+
+       vxge_hw_fifo_txdl_free(fifo_hw, dtr);
+_exit2:
+       dev_kfree_skb(skb);
+       spin_unlock_irqrestore(&fifo->tx_lock, flags);
+       VXGE_COMPLETE_VPATH_TX(fifo);
+
+       return 0;
+}
+
+/*
+ * vxge_rx_term
+ *
+ * Function will be called by hw function to abort all outstanding receive
+ * descriptors.
+ */
+static void
+vxge_rx_term(void *dtrh, enum vxge_hw_rxd_state state, void *userdata)
+{
+       struct vxge_ring *ring = (struct vxge_ring *)userdata;
+       struct vxge_rx_priv *rx_priv =
+               vxge_hw_ring_rxd_private_get(dtrh);
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+                       ring->ndev->name, __func__, __LINE__);
+       if (state != VXGE_HW_RXD_STATE_POSTED)
+               return;
+
+       pci_unmap_single(ring->pdev, rx_priv->data_dma,
+               rx_priv->data_size, PCI_DMA_FROMDEVICE);
+
+       dev_kfree_skb(rx_priv->skb);
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d  Exiting...",
+               ring->ndev->name, __func__, __LINE__);
+}
+
+/*
+ * vxge_tx_term
+ *
+ * Function will be called to abort all outstanding tx descriptors
+ */
+static void
+vxge_tx_term(void *dtrh, enum vxge_hw_txdl_state state, void *userdata)
+{
+       struct vxge_fifo *fifo = (struct vxge_fifo *)userdata;
+       skb_frag_t *frag;
+       int i = 0, j, frg_cnt;
+       struct vxge_tx_priv *txd_priv = vxge_hw_fifo_txdl_private_get(dtrh);
+       struct sk_buff *skb = txd_priv->skb;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       if (state != VXGE_HW_TXDL_STATE_POSTED)
+               return;
+
+       /* check skb validity */
+       vxge_assert(skb);
+       frg_cnt = skb_shinfo(skb)->nr_frags;
+       frag = &skb_shinfo(skb)->frags[0];
+
+       /*  for unfragmented skb */
+       pci_unmap_single(fifo->pdev, txd_priv->dma_buffers[i++],
+               skb_headlen(skb), PCI_DMA_TODEVICE);
+
+       for (j = 0; j < frg_cnt; j++) {
+               pci_unmap_page(fifo->pdev, txd_priv->dma_buffers[i++],
+                              frag->size, PCI_DMA_TODEVICE);
+               frag += 1;
+       }
+
+       dev_kfree_skb(skb);
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d  Exiting...", __func__, __LINE__);
+}
+
+/**
+ * vxge_set_multicast
+ * @dev: pointer to the device structure
+ *
+ * Entry point for multicast address enable/disable
+ * This function is a driver entry point which gets called by the kernel
+ * whenever multicast addresses must be enabled/disabled. This also gets
+ * called to set/reset promiscuous mode. Depending on the deivce flag, we
+ * determine, if multicast address must be enabled or if promiscuous mode
+ * is to be disabled etc.
+ */
+static void vxge_set_multicast(struct net_device *dev)
+{
+       struct dev_mc_list *mclist;
+       struct vxgedev *vdev;
+       int i, mcast_cnt = 0;
+       struct __vxge_hw_device  *hldev;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct macInfo mac_info;
+       int vpath_idx = 0;
+       struct vxge_mac_addrs *mac_entry;
+       struct list_head *list_head;
+       struct list_head *entry, *next;
+       u8 *mac_address = NULL;
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d", __func__, __LINE__);
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+       hldev = (struct __vxge_hw_device  *)vdev->devh;
+
+       if (unlikely(!is_vxge_card_up(vdev)))
+               return;
+
+       if ((dev->flags & IFF_ALLMULTI) && (!vdev->all_multi_flg)) {
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       vxge_assert(vdev->vpaths[i].is_open);
+                       status = vxge_hw_vpath_mcast_enable(
+                                               vdev->vpaths[i].handle);
+                       vdev->all_multi_flg = 1;
+               }
+       } else if ((dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) {
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       vxge_assert(vdev->vpaths[i].is_open);
+                       status = vxge_hw_vpath_mcast_disable(
+                                               vdev->vpaths[i].handle);
+                       vdev->all_multi_flg = 1;
+               }
+       }
+
+       if (status != VXGE_HW_OK)
+               vxge_debug_init(VXGE_ERR,
+                       "failed to %s multicast, status %d",
+                       dev->flags & IFF_ALLMULTI ?
+                       "enable" : "disable", status);
+
+       if (!vdev->config.addr_learn_en) {
+               if (dev->flags & IFF_PROMISC) {
+                       for (i = 0; i < vdev->no_of_vpath; i++) {
+                               vxge_assert(vdev->vpaths[i].is_open);
+                               status = vxge_hw_vpath_promisc_enable(
+                                               vdev->vpaths[i].handle);
+                       }
+               } else {
+                       for (i = 0; i < vdev->no_of_vpath; i++) {
+                               vxge_assert(vdev->vpaths[i].is_open);
+                               status = vxge_hw_vpath_promisc_disable(
+                                               vdev->vpaths[i].handle);
+                       }
+               }
+       }
+
+       memset(&mac_info, 0, sizeof(struct macInfo));
+       /* Update individual M_CAST address list */
+       if ((!vdev->all_multi_flg) && dev->mc_count) {
+
+               mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
+               list_head = &vdev->vpaths[0].mac_addr_list;
+               if ((dev->mc_count +
+                       (vdev->vpaths[0].mac_addr_cnt - mcast_cnt)) >
+                               vdev->vpaths[0].max_mac_addr_cnt)
+                       goto _set_all_mcast;
+
+               /* Delete previous MC's */
+               for (i = 0; i < mcast_cnt; i++) {
+                       if (!list_empty(list_head))
+                               mac_entry = (struct vxge_mac_addrs *)
+                                       list_first_entry(list_head,
+                                               struct vxge_mac_addrs,
+                                               item);
+
+                       list_for_each_safe(entry, next, list_head) {
+
+                               mac_entry = (struct vxge_mac_addrs *) entry;
+                               /* Copy the mac address to delete */
+                               mac_address = (u8 *)&mac_entry->macaddr;
+                               memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
+
+                               /* Is this a multicast address */
+                               if (0x01 & mac_info.macaddr[0]) {
+                                       for (vpath_idx = 0; vpath_idx <
+                                               vdev->no_of_vpath;
+                                               vpath_idx++) {
+                                               mac_info.vpath_no = vpath_idx;
+                                               status = vxge_del_mac_addr(
+                                                               vdev,
+                                                               &mac_info);
+                                       }
+                               }
+                       }
+               }
+
+               /* Add new ones */
+               for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+                       i++, mclist = mclist->next) {
+
+                       memcpy(mac_info.macaddr, mclist->dmi_addr, ETH_ALEN);
+                       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath;
+                                       vpath_idx++) {
+                               mac_info.vpath_no = vpath_idx;
+                               mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE;
+                               status = vxge_add_mac_addr(vdev, &mac_info);
+                               if (status != VXGE_HW_OK) {
+                                       vxge_debug_init(VXGE_ERR,
+                                               "%s:%d Setting individual"
+                                               "multicast address failed",
+                                               __func__, __LINE__);
+                                       goto _set_all_mcast;
+                               }
+                       }
+               }
+
+               return;
+_set_all_mcast:
+               mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
+               /* Delete previous MC's */
+               for (i = 0; i < mcast_cnt; i++) {
+
+                       list_for_each_safe(entry, next, list_head) {
+
+                               mac_entry = (struct vxge_mac_addrs *) entry;
+                               /* Copy the mac address to delete */
+                               mac_address = (u8 *)&mac_entry->macaddr;
+                               memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
+
+                               /* Is this a multicast address */
+                               if (0x01 & mac_info.macaddr[0])
+                                       break;
+                       }
+
+                       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath;
+                                       vpath_idx++) {
+                               mac_info.vpath_no = vpath_idx;
+                               status = vxge_del_mac_addr(vdev, &mac_info);
+                       }
+               }
+
+               /* Enable all multicast */
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       vxge_assert(vdev->vpaths[i].is_open);
+                       status = vxge_hw_vpath_mcast_enable(
+                                               vdev->vpaths[i].handle);
+                       if (status != VXGE_HW_OK) {
+                               vxge_debug_init(VXGE_ERR,
+                                       "%s:%d Enabling all multicasts failed",
+                                        __func__, __LINE__);
+                       }
+                       vdev->all_multi_flg = 1;
+               }
+               dev->flags |= IFF_ALLMULTI;
+       }
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d  Exiting...", __func__, __LINE__);
+}
+
+/**
+ * vxge_set_mac_addr
+ * @dev: pointer to the device structure
+ *
+ * Update entry "0" (default MAC addr)
+ */
+static int vxge_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+       struct vxgedev *vdev;
+       struct __vxge_hw_device  *hldev;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct macInfo mac_info_new, mac_info_old;
+       int vpath_idx = 0;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+       hldev = vdev->devh;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+
+       memset(&mac_info_new, 0, sizeof(struct macInfo));
+       memset(&mac_info_old, 0, sizeof(struct macInfo));
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d  Exiting...",
+               __func__, __LINE__);
+
+       /* Get the old address */
+       memcpy(mac_info_old.macaddr, dev->dev_addr, dev->addr_len);
+
+       /* Copy the new address */
+       memcpy(mac_info_new.macaddr, addr->sa_data, dev->addr_len);
+
+       /* First delete the old mac address from all the vpaths
+       as we can't specify the index while adding new mac address */
+       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
+               struct vxge_vpath *vpath = &vdev->vpaths[vpath_idx];
+               if (!vpath->is_open) {
+                       /* This can happen when this interface is added/removed
+                       to the bonding interface. Delete this station address
+                       from the linked list */
+                       vxge_mac_list_del(vpath, &mac_info_old);
+
+                       /* Add this new address to the linked list
+                       for later restoring */
+                       vxge_mac_list_add(vpath, &mac_info_new);
+
+                       continue;
+               }
+               /* Delete the station address */
+               mac_info_old.vpath_no = vpath_idx;
+               status = vxge_del_mac_addr(vdev, &mac_info_old);
+       }
+
+       if (unlikely(!is_vxge_card_up(vdev))) {
+               memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+               return VXGE_HW_OK;
+       }
+
+       /* Set this mac address to all the vpaths */
+       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
+               mac_info_new.vpath_no = vpath_idx;
+               mac_info_new.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE;
+               status = vxge_add_mac_addr(vdev, &mac_info_new);
+               if (status != VXGE_HW_OK)
+                       return -EINVAL;
+       }
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       return status;
+}
+
+/*
+ * vxge_vpath_intr_enable
+ * @vdev: pointer to vdev
+ * @vp_id: vpath for which to enable the interrupts
+ *
+ * Enables the interrupts for the vpath
+*/
+void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id)
+{
+       struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
+       int msix_id, alarm_msix_id;
+       int tim_msix_id[4] = {[0 ...3] = 0};
+
+       vxge_hw_vpath_intr_enable(vpath->handle);
+
+       if (vdev->config.intr_type == INTA)
+               vxge_hw_vpath_inta_unmask_tx_rx(vpath->handle);
+       else {
+               msix_id = vp_id * VXGE_HW_VPATH_MSIX_ACTIVE;
+               alarm_msix_id =
+                       VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
+
+               tim_msix_id[0] = msix_id;
+               tim_msix_id[1] = msix_id + 1;
+               vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id,
+                       alarm_msix_id);
+
+               vxge_hw_vpath_msix_unmask(vpath->handle, msix_id);
+               vxge_hw_vpath_msix_unmask(vpath->handle, msix_id + 1);
+
+               /* enable the alarm vector */
+               vxge_hw_vpath_msix_unmask(vpath->handle, alarm_msix_id);
+       }
+}
+
+/*
+ * vxge_vpath_intr_disable
+ * @vdev: pointer to vdev
+ * @vp_id: vpath for which to disable the interrupts
+ *
+ * Disables the interrupts for the vpath
+*/
+void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
+{
+       struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
+       int msix_id;
+
+       vxge_hw_vpath_intr_disable(vpath->handle);
+
+       if (vdev->config.intr_type == INTA)
+               vxge_hw_vpath_inta_mask_tx_rx(vpath->handle);
+       else {
+               msix_id = vp_id * VXGE_HW_VPATH_MSIX_ACTIVE;
+               vxge_hw_vpath_msix_mask(vpath->handle, msix_id);
+               vxge_hw_vpath_msix_mask(vpath->handle, msix_id + 1);
+
+               /* disable the alarm vector */
+               msix_id = VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
+               vxge_hw_vpath_msix_mask(vpath->handle, msix_id);
+       }
+}
+
+/*
+ * vxge_reset_vpath
+ * @vdev: pointer to vdev
+ * @vp_id: vpath to reset
+ *
+ * Resets the vpath
+*/
+static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       int ret = 0;
+
+       /* check if device is down already */
+       if (unlikely(!is_vxge_card_up(vdev)))
+               return 0;
+
+       /* is device reset already scheduled */
+       if (test_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
+               return 0;
+
+       if (vdev->vpaths[vp_id].handle) {
+               if (vxge_hw_vpath_reset(vdev->vpaths[vp_id].handle)
+                               == VXGE_HW_OK) {
+                       if (is_vxge_card_up(vdev) &&
+                               vxge_hw_vpath_recover_from_reset(
+                                       vdev->vpaths[vp_id].handle)
+                                       != VXGE_HW_OK) {
+                               vxge_debug_init(VXGE_ERR,
+                                       "vxge_hw_vpath_recover_from_reset"
+                                       "failed for vpath:%d", vp_id);
+                               return status;
+                       }
+               } else {
+                       vxge_debug_init(VXGE_ERR,
+                               "vxge_hw_vpath_reset failed for"
+                               "vpath:%d", vp_id);
+                               return status;
+               }
+       } else
+               return VXGE_HW_FAIL;
+
+       vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]);
+       vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]);
+
+       /* Enable all broadcast */
+       vxge_hw_vpath_bcast_enable(vdev->vpaths[vp_id].handle);
+
+       /* Enable the interrupts */
+       vxge_vpath_intr_enable(vdev, vp_id);
+
+       smp_wmb();
+
+       /* Enable the flow of traffic through the vpath */
+       vxge_hw_vpath_enable(vdev->vpaths[vp_id].handle);
+
+       smp_wmb();
+       vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[vp_id].handle);
+       vdev->vpaths[vp_id].ring.last_status = VXGE_HW_OK;
+
+       /* Vpath reset done */
+       clear_bit(vp_id, &vdev->vp_reset);
+
+       /* Start the vpath queue */
+       vxge_wake_tx_queue(&vdev->vpaths[vp_id].fifo, NULL);
+
+       return ret;
+}
+
+static int do_vxge_reset(struct vxgedev *vdev, int event)
+{
+       enum vxge_hw_status status;
+       int ret = 0, vp_id, i;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET)) {
+               /* check if device is down already */
+               if (unlikely(!is_vxge_card_up(vdev)))
+                       return 0;
+
+               /* is reset already scheduled */
+               if (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
+                       return 0;
+       }
+
+       if (event == VXGE_LL_FULL_RESET) {
+               /* wait for all the vpath reset to complete */
+               for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
+                       while (test_bit(vp_id, &vdev->vp_reset))
+                               msleep(50);
+               }
+
+               /* if execution mode is set to debug, don't reset the adapter */
+               if (unlikely(vdev->exec_mode)) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: execution mode is debug, returning..",
+                               vdev->ndev->name);
+               clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+               vxge_stop_all_tx_queue(vdev);
+               return 0;
+               }
+       }
+
+       if (event == VXGE_LL_FULL_RESET) {
+               vxge_hw_device_intr_disable(vdev->devh);
+
+               switch (vdev->cric_err_event) {
+               case VXGE_HW_EVENT_UNKNOWN:
+                       vxge_stop_all_tx_queue(vdev);
+                       vxge_debug_init(VXGE_ERR,
+                               "fatal: %s: Disabling device due to"
+                               "unknown error",
+                               vdev->ndev->name);
+                       ret = -EPERM;
+                       goto out;
+               case VXGE_HW_EVENT_RESET_START:
+                       break;
+               case VXGE_HW_EVENT_RESET_COMPLETE:
+               case VXGE_HW_EVENT_LINK_DOWN:
+               case VXGE_HW_EVENT_LINK_UP:
+               case VXGE_HW_EVENT_ALARM_CLEARED:
+               case VXGE_HW_EVENT_ECCERR:
+               case VXGE_HW_EVENT_MRPCIM_ECCERR:
+                       ret = -EPERM;
+                       goto out;
+               case VXGE_HW_EVENT_FIFO_ERR:
+               case VXGE_HW_EVENT_VPATH_ERR:
+                       break;
+               case VXGE_HW_EVENT_CRITICAL_ERR:
+                       vxge_stop_all_tx_queue(vdev);
+                       vxge_debug_init(VXGE_ERR,
+                               "fatal: %s: Disabling device due to"
+                               "serious error",
+                               vdev->ndev->name);
+                       /* SOP or device reset required */
+                       /* This event is not currently used */
+                       ret = -EPERM;
+                       goto out;
+               case VXGE_HW_EVENT_SERR:
+                       vxge_stop_all_tx_queue(vdev);
+                       vxge_debug_init(VXGE_ERR,
+                               "fatal: %s: Disabling device due to"
+                               "serious error",
+                               vdev->ndev->name);
+                       ret = -EPERM;
+                       goto out;
+               case VXGE_HW_EVENT_SRPCIM_SERR:
+               case VXGE_HW_EVENT_MRPCIM_SERR:
+                       ret = -EPERM;
+                       goto out;
+               case VXGE_HW_EVENT_SLOT_FREEZE:
+                       vxge_stop_all_tx_queue(vdev);
+                       vxge_debug_init(VXGE_ERR,
+                               "fatal: %s: Disabling device due to"
+                               "slot freeze",
+                               vdev->ndev->name);
+                       ret = -EPERM;
+                       goto out;
+               default:
+                       break;
+
+               }
+       }
+
+       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET))
+               vxge_stop_all_tx_queue(vdev);
+
+       if (event == VXGE_LL_FULL_RESET) {
+               status = vxge_reset_all_vpaths(vdev);
+               if (status != VXGE_HW_OK) {
+                       vxge_debug_init(VXGE_ERR,
+                               "fatal: %s: can not reset vpaths",
+                               vdev->ndev->name);
+                       ret = -EPERM;
+                       goto out;
+               }
+       }
+
+       if (event == VXGE_LL_COMPL_RESET) {
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       if (vdev->vpaths[i].handle) {
+                               if (vxge_hw_vpath_recover_from_reset(
+                                       vdev->vpaths[i].handle)
+                                               != VXGE_HW_OK) {
+                                       vxge_debug_init(VXGE_ERR,
+                                               "vxge_hw_vpath_recover_"
+                                               "from_reset failed for vpath: "
+                                               "%d", i);
+                                       ret = -EPERM;
+                                       goto out;
+                               }
+                               } else {
+                                       vxge_debug_init(VXGE_ERR,
+                                       "vxge_hw_vpath_reset failed for "
+                                               "vpath:%d", i);
+                                       ret = -EPERM;
+                                       goto out;
+                               }
+       }
+
+       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET)) {
+               /* Reprogram the DA table with populated mac addresses */
+               for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
+                       vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]);
+                       vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]);
+               }
+
+               /* enable vpath interrupts */
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       vxge_vpath_intr_enable(vdev, i);
+
+               vxge_hw_device_intr_enable(vdev->devh);
+
+               smp_wmb();
+
+               /* Indicate card up */
+               set_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+
+               /* Get the traffic to flow through the vpaths */
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       vxge_hw_vpath_enable(vdev->vpaths[i].handle);
+                       smp_wmb();
+                       vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle);
+               }
+
+               vxge_wake_all_tx_queue(vdev);
+       }
+
+out:
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d  Exiting...", __func__, __LINE__);
+
+       /* Indicate reset done */
+       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET))
+               clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state);
+       return ret;
+}
+
+/*
+ * vxge_reset
+ * @vdev: pointer to ll device
+ *
+ * driver may reset the chip on events of serr, eccerr, etc
+ */
+int vxge_reset(struct vxgedev *vdev)
+{
+       do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
+       return 0;
+}
+
+/**
+ * vxge_poll - Receive handler when Receive Polling is used.
+ * @dev: pointer to the device structure.
+ * @budget: Number of packets budgeted to be processed in this iteration.
+ *
+ * This function comes into picture only if Receive side is being handled
+ * through polling (called NAPI in linux). It mostly does what the normal
+ * Rx interrupt handler does in terms of descriptor and packet processing
+ * but not in an interrupt context. Also it will process a specified number
+ * of packets at most in one iteration. This value is passed down by the
+ * kernel as the function argument 'budget'.
+ */
+static int vxge_poll_msix(struct napi_struct *napi, int budget)
+{
+       struct vxge_ring *ring =
+               container_of(napi, struct vxge_ring, napi);
+       int budget_org = budget;
+       ring->budget = budget;
+
+       vxge_hw_vpath_poll_rx(ring->handle);
+
+       if (ring->pkts_processed < budget_org) {
+               napi_complete(napi);
+               /* Re enable the Rx interrupts for the vpath */
+               vxge_hw_channel_msix_unmask(
+                               (struct __vxge_hw_channel *)ring->handle,
+                               ring->rx_vector_no);
+       }
+
+       return ring->pkts_processed;
+}
+
+static int vxge_poll_inta(struct napi_struct *napi, int budget)
+{
+       struct vxgedev *vdev = container_of(napi, struct vxgedev, napi);
+       int pkts_processed = 0;
+       int i;
+       int budget_org = budget;
+       struct vxge_ring *ring;
+
+       struct __vxge_hw_device  *hldev = (struct __vxge_hw_device *)
+               pci_get_drvdata(vdev->pdev);
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               ring = &vdev->vpaths[i].ring;
+               ring->budget = budget;
+               vxge_hw_vpath_poll_rx(ring->handle);
+               pkts_processed += ring->pkts_processed;
+               budget -= ring->pkts_processed;
+               if (budget <= 0)
+                       break;
+       }
+
+       VXGE_COMPLETE_ALL_TX(vdev);
+
+       if (pkts_processed < budget_org) {
+               napi_complete(napi);
+               /* Re enable the Rx interrupts for the ring */
+               vxge_hw_device_unmask_all(hldev);
+               vxge_hw_device_flush_io(hldev);
+       }
+
+       return pkts_processed;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * vxge_netpoll - netpoll event handler entry point
+ * @dev : pointer to the device structure.
+ * Description:
+ *      This function will be called by upper layer to check for events on the
+ * interface in situations where interrupts are disabled. It is used for
+ * specific in-kernel networking tasks, such as remote consoles and kernel
+ * debugging over the network (example netdump in RedHat).
+ */
+static void vxge_netpoll(struct net_device *dev)
+{
+       struct __vxge_hw_device  *hldev;
+       struct vxgedev *vdev;
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+       hldev = (struct __vxge_hw_device  *)pci_get_drvdata(vdev->pdev);
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       if (pci_channel_offline(vdev->pdev))
+               return;
+
+       disable_irq(dev->irq);
+       vxge_hw_device_clear_tx_rx(hldev);
+
+       vxge_hw_device_clear_tx_rx(hldev);
+       VXGE_COMPLETE_ALL_RX(vdev);
+       VXGE_COMPLETE_ALL_TX(vdev);
+
+       enable_irq(dev->irq);
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d  Exiting...", __func__, __LINE__);
+       return;
+}
+#endif
+
+/* RTH configuration */
+static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_hw_rth_hash_types hash_types;
+       u8 itable[256] = {0}; /* indirection table */
+       u8 mtable[256] = {0}; /* CPU to vpath mapping  */
+       int index;
+
+       /*
+        * Filling
+        *      - itable with bucket numbers
+        *      - mtable with bucket-to-vpath mapping
+        */
+       for (index = 0; index < (1 << vdev->config.rth_bkt_sz); index++) {
+               itable[index] = index;
+               mtable[index] = index % vdev->no_of_vpath;
+       }
+
+       /* Fill RTH hash types */
+       hash_types.hash_type_tcpipv4_en   = vdev->config.rth_hash_type_tcpipv4;
+       hash_types.hash_type_ipv4_en      = vdev->config.rth_hash_type_ipv4;
+       hash_types.hash_type_tcpipv6_en   = vdev->config.rth_hash_type_tcpipv6;
+       hash_types.hash_type_ipv6_en      = vdev->config.rth_hash_type_ipv6;
+       hash_types.hash_type_tcpipv6ex_en =
+                                       vdev->config.rth_hash_type_tcpipv6ex;
+       hash_types.hash_type_ipv6ex_en    = vdev->config.rth_hash_type_ipv6ex;
+
+       /* set indirection table, bucket-to-vpath mapping */
+       status = vxge_hw_vpath_rts_rth_itable_set(vdev->vp_handles,
+                                               vdev->no_of_vpath,
+                                               mtable, itable,
+                                               vdev->config.rth_bkt_sz);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "RTH indirection table configuration failed "
+                       "for vpath:%d", vdev->vpaths[0].device_id);
+               return status;
+       }
+
+       /*
+       * Because the itable_set() method uses the active_table field
+       * for the target virtual path the RTH config should be updated
+       * for all VPATHs. The h/w only uses the lowest numbered VPATH
+       * when steering frames.
+       */
+        for (index = 0; index < vdev->no_of_vpath; index++) {
+               status = vxge_hw_vpath_rts_rth_set(
+                               vdev->vpaths[index].handle,
+                               vdev->config.rth_algorithm,
+                               &hash_types,
+                               vdev->config.rth_bkt_sz);
+
+                if (status != VXGE_HW_OK) {
+                       vxge_debug_init(VXGE_ERR,
+                               "RTH configuration failed for vpath:%d",
+                               vdev->vpaths[index].device_id);
+                       return status;
+                }
+        }
+
+       return status;
+}
+
+int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac)
+{
+       struct vxge_mac_addrs *new_mac_entry;
+       u8 *mac_address = NULL;
+
+       if (vpath->mac_addr_cnt >= VXGE_MAX_LEARN_MAC_ADDR_CNT)
+               return TRUE;
+
+       new_mac_entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_ATOMIC);
+       if (!new_mac_entry) {
+               vxge_debug_mem(VXGE_ERR,
+                       "%s: memory allocation failed",
+                       VXGE_DRIVER_NAME);
+               return FALSE;
+       }
+
+       list_add(&new_mac_entry->item, &vpath->mac_addr_list);
+
+       /* Copy the new mac address to the list */
+       mac_address = (u8 *)&new_mac_entry->macaddr;
+       memcpy(mac_address, mac->macaddr, ETH_ALEN);
+
+       new_mac_entry->state = mac->state;
+       vpath->mac_addr_cnt++;
+
+       /* Is this a multicast address */
+       if (0x01 & mac->macaddr[0])
+               vpath->mcast_addr_cnt++;
+
+       return TRUE;
+}
+
+/* Add a mac address to DA table */
+enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_vpath *vpath;
+       enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode;
+
+       if (0x01 & mac->macaddr[0]) /* multicast address */
+               duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE;
+       else
+               duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE;
+
+       vpath = &vdev->vpaths[mac->vpath_no];
+       status = vxge_hw_vpath_mac_addr_add(vpath->handle, mac->macaddr,
+                                               mac->macmask, duplicate_mode);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "DA config add entry failed for vpath:%d",
+                       vpath->device_id);
+       } else
+               if (FALSE == vxge_mac_list_add(vpath, mac))
+                       status = -EPERM;
+
+       return status;
+}
+
+int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac)
+{
+       struct list_head *entry, *next;
+       u64 del_mac = 0;
+       u8 *mac_address = (u8 *) (&del_mac);
+
+       /* Copy the mac address to delete from the list */
+       memcpy(mac_address, mac->macaddr, ETH_ALEN);
+
+       list_for_each_safe(entry, next, &vpath->mac_addr_list) {
+               if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) {
+                       list_del(entry);
+                       kfree((struct vxge_mac_addrs *)entry);
+                       vpath->mac_addr_cnt--;
+
+                       /* Is this a multicast address */
+                       if (0x01 & mac->macaddr[0])
+                               vpath->mcast_addr_cnt--;
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+/* delete a mac address from DA table */
+enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_vpath *vpath;
+
+       vpath = &vdev->vpaths[mac->vpath_no];
+       status = vxge_hw_vpath_mac_addr_delete(vpath->handle, mac->macaddr,
+                                               mac->macmask);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "DA config delete entry failed for vpath:%d",
+                       vpath->device_id);
+       } else
+               vxge_mac_list_del(vpath, mac);
+       return status;
+}
+
+/* list all mac addresses from DA table */
+enum vxge_hw_status
+static vxge_search_mac_addr_in_da_table(struct vxge_vpath *vpath,
+                                       struct macInfo *mac)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       unsigned char macmask[ETH_ALEN];
+       unsigned char macaddr[ETH_ALEN];
+
+       status = vxge_hw_vpath_mac_addr_get(vpath->handle,
+                               macaddr, macmask);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "DA config list entry failed for vpath:%d",
+                       vpath->device_id);
+               return status;
+       }
+
+       while (memcmp(mac->macaddr, macaddr, ETH_ALEN)) {
+
+               status = vxge_hw_vpath_mac_addr_get_next(vpath->handle,
+                               macaddr, macmask);
+               if (status != VXGE_HW_OK)
+                       break;
+       }
+
+       return status;
+}
+
+/* Store all vlan ids from the list to the vid table */
+enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxgedev *vdev = vpath->vdev;
+       u16 vid;
+
+       if (vdev->vlgrp && vpath->is_open) {
+
+               for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+                       if (!vlan_group_get_device(vdev->vlgrp, vid))
+                               continue;
+                       /* Add these vlan to the vid table */
+                       status = vxge_hw_vpath_vid_add(vpath->handle, vid);
+               }
+       }
+
+       return status;
+}
+
+/* Store all mac addresses from the list to the DA table */
+enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct macInfo mac_info;
+       u8 *mac_address = NULL;
+       struct list_head *entry, *next;
+
+       memset(&mac_info, 0, sizeof(struct macInfo));
+
+       if (vpath->is_open) {
+
+               list_for_each_safe(entry, next, &vpath->mac_addr_list) {
+                       mac_address =
+                               (u8 *)&
+                               ((struct vxge_mac_addrs *)entry)->macaddr;
+                       memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
+                       ((struct vxge_mac_addrs *)entry)->state =
+                               VXGE_LL_MAC_ADDR_IN_DA_TABLE;
+                       /* does this mac address already exist in da table? */
+                       status = vxge_search_mac_addr_in_da_table(vpath,
+                               &mac_info);
+                       if (status != VXGE_HW_OK) {
+                               /* Add this mac address to the DA table */
+                               status = vxge_hw_vpath_mac_addr_add(
+                                       vpath->handle, mac_info.macaddr,
+                                       mac_info.macmask,
+                                   VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE);
+                               if (status != VXGE_HW_OK) {
+                                       vxge_debug_init(VXGE_ERR,
+                                           "DA add entry failed for vpath:%d",
+                                           vpath->device_id);
+                                       ((struct vxge_mac_addrs *)entry)->state
+                                               = VXGE_LL_MAC_ADDR_IN_LIST;
+                               }
+                       }
+               }
+       }
+
+       return status;
+}
+
+/* reset vpaths */
+enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
+{
+       int i;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       for (i = 0; i < vdev->no_of_vpath; i++)
+               if (vdev->vpaths[i].handle) {
+                       if (vxge_hw_vpath_reset(vdev->vpaths[i].handle)
+                                       == VXGE_HW_OK) {
+                               if (is_vxge_card_up(vdev) &&
+                                       vxge_hw_vpath_recover_from_reset(
+                                               vdev->vpaths[i].handle)
+                                               != VXGE_HW_OK) {
+                                       vxge_debug_init(VXGE_ERR,
+                                               "vxge_hw_vpath_recover_"
+                                               "from_reset failed for vpath: "
+                                               "%d", i);
+                                       return status;
+                               }
+                       } else {
+                               vxge_debug_init(VXGE_ERR,
+                                       "vxge_hw_vpath_reset failed for "
+                                       "vpath:%d", i);
+                                       return status;
+                       }
+               }
+       return status;
+}
+
+/* close vpaths */
+void vxge_close_vpaths(struct vxgedev *vdev, int index)
+{
+       int i;
+       for (i = index; i < vdev->no_of_vpath; i++) {
+               if (vdev->vpaths[i].handle && vdev->vpaths[i].is_open) {
+                       vxge_hw_vpath_close(vdev->vpaths[i].handle);
+                       vdev->stats.vpaths_open--;
+               }
+               vdev->vpaths[i].is_open = 0;
+               vdev->vpaths[i].handle  = NULL;
+       }
+}
+
+/* open vpaths */
+int vxge_open_vpaths(struct vxgedev *vdev)
+{
+       enum vxge_hw_status status;
+       int i;
+       u32 vp_id = 0;
+       struct vxge_hw_vpath_attr attr;
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               vxge_assert(vdev->vpaths[i].is_configured);
+               attr.vp_id = vdev->vpaths[i].device_id;
+               attr.fifo_attr.callback = vxge_xmit_compl;
+               attr.fifo_attr.txdl_term = vxge_tx_term;
+               attr.fifo_attr.per_txdl_space = sizeof(struct vxge_tx_priv);
+               attr.fifo_attr.userdata = (void *)&vdev->vpaths[i].fifo;
+
+               attr.ring_attr.callback = vxge_rx_1b_compl;
+               attr.ring_attr.rxd_init = vxge_rx_initial_replenish;
+               attr.ring_attr.rxd_term = vxge_rx_term;
+               attr.ring_attr.per_rxd_space = sizeof(struct vxge_rx_priv);
+               attr.ring_attr.userdata = (void *)&vdev->vpaths[i].ring;
+
+               vdev->vpaths[i].ring.ndev = vdev->ndev;
+               vdev->vpaths[i].ring.pdev = vdev->pdev;
+               status = vxge_hw_vpath_open(vdev->devh, &attr,
+                               &(vdev->vpaths[i].handle));
+               if (status == VXGE_HW_OK) {
+                       vdev->vpaths[i].fifo.handle =
+                           (struct __vxge_hw_fifo *)attr.fifo_attr.userdata;
+                       vdev->vpaths[i].ring.handle =
+                           (struct __vxge_hw_ring *)attr.ring_attr.userdata;
+                       vdev->vpaths[i].fifo.tx_steering_type =
+                               vdev->config.tx_steering_type;
+                       vdev->vpaths[i].fifo.ndev = vdev->ndev;
+                       vdev->vpaths[i].fifo.pdev = vdev->pdev;
+                       vdev->vpaths[i].fifo.indicate_max_pkts =
+                               vdev->config.fifo_indicate_max_pkts;
+                       vdev->vpaths[i].ring.rx_vector_no = 0;
+                       vdev->vpaths[i].ring.rx_csum = vdev->rx_csum;
+                       vdev->vpaths[i].is_open = 1;
+                       vdev->vp_handles[i] = vdev->vpaths[i].handle;
+                       vdev->vpaths[i].ring.gro_enable =
+                                               vdev->config.gro_enable;
+                       vdev->vpaths[i].ring.vlan_tag_strip =
+                                               vdev->vlan_tag_strip;
+                       vdev->stats.vpaths_open++;
+               } else {
+                       vdev->stats.vpath_open_fail++;
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: vpath: %d failed to open "
+                               "with status: %d",
+                           vdev->ndev->name, vdev->vpaths[i].device_id,
+                               status);
+                       vxge_close_vpaths(vdev, 0);
+                       return -EPERM;
+               }
+
+               vp_id =
+                 ((struct __vxge_hw_vpath_handle *)vdev->vpaths[i].handle)->
+                 vpath->vp_id;
+               vdev->vpaths_deployed |= vxge_mBIT(vp_id);
+       }
+       return VXGE_HW_OK;
+}
+
+/*
+ *  vxge_isr_napi
+ *  @irq: the irq of the device.
+ *  @dev_id: a void pointer to the hldev structure of the Titan device
+ *  @ptregs: pointer to the registers pushed on the stack.
+ *
+ *  This function is the ISR handler of the device when napi is enabled. It
+ *  identifies the reason for the interrupt and calls the relevant service
+ *  routines.
+ */
+static irqreturn_t vxge_isr_napi(int irq, void *dev_id)
+{
+       struct __vxge_hw_device  *hldev = (struct __vxge_hw_device  *)dev_id;
+       struct vxgedev *vdev;
+       struct net_device *dev;
+       u64 reason;
+       enum vxge_hw_status status;
+
+       vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       dev = hldev->ndev;
+       vdev = netdev_priv(dev);
+
+       if (pci_channel_offline(vdev->pdev))
+               return IRQ_NONE;
+
+       if (unlikely(!is_vxge_card_up(vdev)))
+               return IRQ_NONE;
+
+       status = vxge_hw_device_begin_irq(hldev, vdev->exec_mode,
+                       &reason);
+       if (status == VXGE_HW_OK) {
+               vxge_hw_device_mask_all(hldev);
+
+               if (reason &
+                       VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(
+                       vdev->vpaths_deployed >>
+                       (64 - VXGE_HW_MAX_VIRTUAL_PATHS))) {
+
+                       vxge_hw_device_clear_tx_rx(hldev);
+                       napi_schedule(&vdev->napi);
+                       vxge_debug_intr(VXGE_TRACE,
+                               "%s:%d  Exiting...", __func__, __LINE__);
+                       return IRQ_HANDLED;
+               } else
+                       vxge_hw_device_unmask_all(hldev);
+       } else if (unlikely((status == VXGE_HW_ERR_VPATH) ||
+               (status == VXGE_HW_ERR_CRITICAL) ||
+               (status == VXGE_HW_ERR_FIFO))) {
+               vxge_hw_device_mask_all(hldev);
+               vxge_hw_device_flush_io(hldev);
+               return IRQ_HANDLED;
+       } else if (unlikely(status == VXGE_HW_ERR_SLOT_FREEZE))
+               return IRQ_HANDLED;
+
+       vxge_debug_intr(VXGE_TRACE, "%s:%d  Exiting...", __func__, __LINE__);
+       return IRQ_NONE;
+}
+
+#ifdef CONFIG_PCI_MSI
+
+static irqreturn_t
+vxge_tx_msix_handle(int irq, void *dev_id)
+{
+       struct vxge_fifo *fifo = (struct vxge_fifo *)dev_id;
+
+       VXGE_COMPLETE_VPATH_TX(fifo);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+vxge_rx_msix_napi_handle(int irq, void *dev_id)
+{
+       struct vxge_ring *ring = (struct vxge_ring *)dev_id;
+
+       /* MSIX_IDX for Rx is 1 */
+       vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)ring->handle,
+                                       ring->rx_vector_no);
+
+       napi_schedule(&ring->napi);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+vxge_alarm_msix_handle(int irq, void *dev_id)
+{
+       int i;
+       enum vxge_hw_status status;
+       struct vxge_vpath *vpath = (struct vxge_vpath *)dev_id;
+       struct vxgedev *vdev = vpath->vdev;
+       int alarm_msix_id =
+               VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               vxge_hw_vpath_msix_mask(vdev->vpaths[i].handle,
+                       alarm_msix_id);
+
+               status = vxge_hw_vpath_alarm_process(vdev->vpaths[i].handle,
+                       vdev->exec_mode);
+               if (status == VXGE_HW_OK) {
+
+                       vxge_hw_vpath_msix_unmask(vdev->vpaths[i].handle,
+                               alarm_msix_id);
+                       continue;
+               }
+               vxge_debug_intr(VXGE_ERR,
+                       "%s: vxge_hw_vpath_alarm_process failed %x ",
+                       VXGE_DRIVER_NAME, status);
+       }
+       return IRQ_HANDLED;
+}
+
+static int vxge_alloc_msix(struct vxgedev *vdev)
+{
+       int j, i, ret = 0;
+       int intr_cnt = 0;
+       int alarm_msix_id = 0, msix_intr_vect = 0;
+       vdev->intr_cnt = 0;
+
+       /* Tx/Rx MSIX Vectors count */
+       vdev->intr_cnt = vdev->no_of_vpath * 2;
+
+       /* Alarm MSIX Vectors count */
+       vdev->intr_cnt++;
+
+       intr_cnt = (vdev->max_vpath_supported * 2) + 1;
+       vdev->entries = kzalloc(intr_cnt * sizeof(struct msix_entry),
+                                               GFP_KERNEL);
+       if (!vdev->entries) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: memory allocation failed",
+                       VXGE_DRIVER_NAME);
+               return  -ENOMEM;
+       }
+
+       vdev->vxge_entries = kzalloc(intr_cnt * sizeof(struct vxge_msix_entry),
+                                                       GFP_KERNEL);
+       if (!vdev->vxge_entries) {
+               vxge_debug_init(VXGE_ERR, "%s: memory allocation failed",
+                       VXGE_DRIVER_NAME);
+               kfree(vdev->entries);
+               return -ENOMEM;
+       }
+
+       /* Last vector in the list is used for alarm */
+       alarm_msix_id = VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
+       for (i = 0, j = 0; i < vdev->max_vpath_supported; i++) {
+
+               msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE;
+
+               /* Initialize the fifo vector */
+               vdev->entries[j].entry = msix_intr_vect;
+               vdev->vxge_entries[j].entry = msix_intr_vect;
+               vdev->vxge_entries[j].in_use = 0;
+               j++;
+
+               /* Initialize the ring vector */
+               vdev->entries[j].entry = msix_intr_vect + 1;
+               vdev->vxge_entries[j].entry = msix_intr_vect + 1;
+               vdev->vxge_entries[j].in_use = 0;
+               j++;
+       }
+
+       /* Initialize the alarm vector */
+       vdev->entries[j].entry = alarm_msix_id;
+       vdev->vxge_entries[j].entry = alarm_msix_id;
+       vdev->vxge_entries[j].in_use = 0;
+
+       ret = pci_enable_msix(vdev->pdev, vdev->entries, intr_cnt);
+       /* if driver request exceeeds available irq's, request with a small
+        * number.
+       */
+       if (ret > 0) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: MSI-X enable failed for %d vectors, available: %d",
+                       VXGE_DRIVER_NAME, intr_cnt, ret);
+               vdev->max_vpath_supported = vdev->no_of_vpath;
+               intr_cnt = (vdev->max_vpath_supported * 2) + 1;
+
+               /* Reset the alarm vector setting */
+               vdev->entries[j].entry = 0;
+               vdev->vxge_entries[j].entry = 0;
+
+               /* Initialize the alarm vector with new setting */
+               vdev->entries[intr_cnt - 1].entry = alarm_msix_id;
+               vdev->vxge_entries[intr_cnt - 1].entry = alarm_msix_id;
+               vdev->vxge_entries[intr_cnt - 1].in_use = 0;
+
+               ret = pci_enable_msix(vdev->pdev, vdev->entries, intr_cnt);
+               if (!ret)
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: MSI-X enabled for %d vectors",
+                               VXGE_DRIVER_NAME, intr_cnt);
+       }
+
+       if (ret) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: MSI-X enable failed for %d vectors, ret: %d",
+                       VXGE_DRIVER_NAME, intr_cnt, ret);
+               kfree(vdev->entries);
+               kfree(vdev->vxge_entries);
+               vdev->entries = NULL;
+               vdev->vxge_entries = NULL;
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int vxge_enable_msix(struct vxgedev *vdev)
+{
+
+       int i, ret = 0;
+       enum vxge_hw_status status;
+       /* 0 - Tx, 1 - Rx  */
+       int tim_msix_id[4];
+       int alarm_msix_id = 0, msix_intr_vect = 0;;
+       vdev->intr_cnt = 0;
+
+       /* allocate msix vectors */
+       ret = vxge_alloc_msix(vdev);
+       if (!ret) {
+               /* Last vector in the list is used for alarm */
+               alarm_msix_id =
+                       VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+
+                       /* If fifo or ring are not enabled
+                          the MSIX vector for that should be set to 0
+                          Hence initializeing this array to all 0s.
+                       */
+                       memset(tim_msix_id, 0, sizeof(tim_msix_id));
+                       msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE;
+                       tim_msix_id[0] = msix_intr_vect;
+
+                       tim_msix_id[1] = msix_intr_vect + 1;
+                       vdev->vpaths[i].ring.rx_vector_no = tim_msix_id[1];
+
+                       status = vxge_hw_vpath_msix_set(
+                                               vdev->vpaths[i].handle,
+                                               tim_msix_id, alarm_msix_id);
+                       if (status != VXGE_HW_OK) {
+                               vxge_debug_init(VXGE_ERR,
+                                       "vxge_hw_vpath_msix_set "
+                                       "failed with status : %x", status);
+                               kfree(vdev->entries);
+                               kfree(vdev->vxge_entries);
+                               pci_disable_msix(vdev->pdev);
+                               return -ENODEV;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static void vxge_rem_msix_isr(struct vxgedev *vdev)
+{
+       int intr_cnt;
+
+       for (intr_cnt = 0; intr_cnt < (vdev->max_vpath_supported * 2 + 1);
+               intr_cnt++) {
+               if (vdev->vxge_entries[intr_cnt].in_use) {
+                       synchronize_irq(vdev->entries[intr_cnt].vector);
+                       free_irq(vdev->entries[intr_cnt].vector,
+                               vdev->vxge_entries[intr_cnt].arg);
+                       vdev->vxge_entries[intr_cnt].in_use = 0;
+               }
+       }
+
+       kfree(vdev->entries);
+       kfree(vdev->vxge_entries);
+       vdev->entries = NULL;
+       vdev->vxge_entries = NULL;
+
+       if (vdev->config.intr_type == MSI_X)
+               pci_disable_msix(vdev->pdev);
+}
+#endif
+
+static void vxge_rem_isr(struct vxgedev *vdev)
+{
+       struct __vxge_hw_device  *hldev;
+       hldev = (struct __vxge_hw_device  *) pci_get_drvdata(vdev->pdev);
+
+#ifdef CONFIG_PCI_MSI
+       if (vdev->config.intr_type == MSI_X) {
+               vxge_rem_msix_isr(vdev);
+       } else
+#endif
+       if (vdev->config.intr_type == INTA) {
+                       synchronize_irq(vdev->pdev->irq);
+                       free_irq(vdev->pdev->irq, hldev);
+       }
+}
+
+static int vxge_add_isr(struct vxgedev *vdev)
+{
+       int ret = 0;
+       struct __vxge_hw_device  *hldev =
+               (struct __vxge_hw_device  *) pci_get_drvdata(vdev->pdev);
+#ifdef CONFIG_PCI_MSI
+       int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;
+       u64 function_mode = vdev->config.device_hw_info.function_mode;
+       int pci_fun = PCI_FUNC(vdev->pdev->devfn);
+
+       if (vdev->config.intr_type == MSI_X)
+               ret = vxge_enable_msix(vdev);
+
+       if (ret) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: Enabling MSI-X Failed", VXGE_DRIVER_NAME);
+               if ((function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
+                       test_and_set_bit(__VXGE_STATE_CARD_UP,
+                               &driver_config->inta_dev_open))
+                       return VXGE_HW_FAIL;
+               else {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: Defaulting to INTA", VXGE_DRIVER_NAME);
+                       vdev->config.intr_type = INTA;
+                       vxge_hw_device_set_intr_type(vdev->devh,
+                               VXGE_HW_INTR_MODE_IRQLINE);
+                       vxge_close_vpaths(vdev, 1);
+                       vdev->no_of_vpath = 1;
+                       vdev->stats.vpaths_open = 1;
+               }
+       }
+
+       if (vdev->config.intr_type == MSI_X) {
+               for (intr_idx = 0;
+                    intr_idx < (vdev->no_of_vpath *
+                       VXGE_HW_VPATH_MSIX_ACTIVE); intr_idx++) {
+
+                       msix_idx = intr_idx % VXGE_HW_VPATH_MSIX_ACTIVE;
+                       irq_req = 0;
+
+                       switch (msix_idx) {
+                       case 0:
+                               snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
+                                       "%s:vxge fn: %d vpath: %d Tx MSI-X: %d",
+                                       vdev->ndev->name, pci_fun, vp_idx,
+                                       vdev->entries[intr_cnt].entry);
+                               ret = request_irq(
+                                   vdev->entries[intr_cnt].vector,
+                                       vxge_tx_msix_handle, 0,
+                                       vdev->desc[intr_cnt],
+                                       &vdev->vpaths[vp_idx].fifo);
+                                       vdev->vxge_entries[intr_cnt].arg =
+                                               &vdev->vpaths[vp_idx].fifo;
+                               irq_req = 1;
+                               break;
+                       case 1:
+                               snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
+                                       "%s:vxge fn: %d vpath: %d Rx MSI-X: %d",
+                                       vdev->ndev->name, pci_fun, vp_idx,
+                                       vdev->entries[intr_cnt].entry);
+                               ret = request_irq(
+                                   vdev->entries[intr_cnt].vector,
+                                       vxge_rx_msix_napi_handle,
+                                       0,
+                                       vdev->desc[intr_cnt],
+                                       &vdev->vpaths[vp_idx].ring);
+                                       vdev->vxge_entries[intr_cnt].arg =
+                                               &vdev->vpaths[vp_idx].ring;
+                               irq_req = 1;
+                               break;
+                       }
+
+                       if (ret) {
+                               vxge_debug_init(VXGE_ERR,
+                                       "%s: MSIX - %d  Registration failed",
+                                       vdev->ndev->name, intr_cnt);
+                               vxge_rem_msix_isr(vdev);
+                               if ((function_mode ==
+                                       VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
+                                       test_and_set_bit(__VXGE_STATE_CARD_UP,
+                                               &driver_config->inta_dev_open))
+                                       return VXGE_HW_FAIL;
+                               else {
+                                       vxge_hw_device_set_intr_type(
+                                               vdev->devh,
+                                               VXGE_HW_INTR_MODE_IRQLINE);
+                                               vdev->config.intr_type = INTA;
+                                       vxge_debug_init(VXGE_ERR,
+                                               "%s: Defaulting to INTA"
+                                               , vdev->ndev->name);
+                                       vxge_close_vpaths(vdev, 1);
+                                       vdev->no_of_vpath = 1;
+                                       vdev->stats.vpaths_open = 1;
+                                       goto INTA_MODE;
+                               }
+                       }
+
+                       if (irq_req) {
+                               /* We requested for this msix interrupt */
+                               vdev->vxge_entries[intr_cnt].in_use = 1;
+                               vxge_hw_vpath_msix_unmask(
+                                       vdev->vpaths[vp_idx].handle,
+                                       intr_idx);
+                               intr_cnt++;
+                       }
+
+                       /* Point to next vpath handler */
+                       if (((intr_idx + 1) % VXGE_HW_VPATH_MSIX_ACTIVE == 0)
+                               && (vp_idx < (vdev->no_of_vpath - 1)))
+                                       vp_idx++;
+               }
+
+               intr_cnt = vdev->max_vpath_supported * 2;
+               snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
+                       "%s:vxge Alarm fn: %d MSI-X: %d",
+                       vdev->ndev->name, pci_fun,
+                       vdev->entries[intr_cnt].entry);
+               /* For Alarm interrupts */
+               ret = request_irq(vdev->entries[intr_cnt].vector,
+                                       vxge_alarm_msix_handle, 0,
+                                       vdev->desc[intr_cnt],
+                                       &vdev->vpaths[vp_idx]);
+               if (ret) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: MSIX - %d Registration failed",
+                               vdev->ndev->name, intr_cnt);
+                       vxge_rem_msix_isr(vdev);
+                       if ((function_mode ==
+                               VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
+                               test_and_set_bit(__VXGE_STATE_CARD_UP,
+                                               &driver_config->inta_dev_open))
+                               return VXGE_HW_FAIL;
+                       else {
+                               vxge_hw_device_set_intr_type(vdev->devh,
+                                               VXGE_HW_INTR_MODE_IRQLINE);
+                               vdev->config.intr_type = INTA;
+                               vxge_debug_init(VXGE_ERR,
+                                       "%s: Defaulting to INTA",
+                                       vdev->ndev->name);
+                               vxge_close_vpaths(vdev, 1);
+                               vdev->no_of_vpath = 1;
+                               vdev->stats.vpaths_open = 1;
+                               goto INTA_MODE;
+                       }
+               }
+
+               vxge_hw_vpath_msix_unmask(vdev->vpaths[vp_idx].handle,
+                                       intr_idx - 2);
+               vdev->vxge_entries[intr_cnt].in_use = 1;
+               vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[vp_idx];
+       }
+INTA_MODE:
+#endif
+       snprintf(vdev->desc[0], VXGE_INTR_STRLEN, "%s:vxge", vdev->ndev->name);
+
+       if (vdev->config.intr_type == INTA) {
+               ret = request_irq((int) vdev->pdev->irq,
+                       vxge_isr_napi,
+                       IRQF_SHARED, vdev->desc[0], hldev);
+               if (ret) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s %s-%d: ISR registration failed",
+                               VXGE_DRIVER_NAME, "IRQ", vdev->pdev->irq);
+                       return -ENODEV;
+               }
+               vxge_debug_init(VXGE_TRACE,
+                       "new %s-%d line allocated",
+                       "IRQ", vdev->pdev->irq);
+       }
+
+       return VXGE_HW_OK;
+}
+
+static void vxge_poll_vp_reset(unsigned long data)
+{
+       struct vxgedev *vdev = (struct vxgedev *)data;
+       int i, j = 0;
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               if (test_bit(i, &vdev->vp_reset)) {
+                       vxge_reset_vpath(vdev, i);
+                       j++;
+               }
+       }
+       if (j && (vdev->config.intr_type != MSI_X)) {
+               vxge_hw_device_unmask_all(vdev->devh);
+               vxge_hw_device_flush_io(vdev->devh);
+       }
+
+       mod_timer(&vdev->vp_reset_timer, jiffies + HZ / 2);
+}
+
+static void vxge_poll_vp_lockup(unsigned long data)
+{
+       struct vxgedev *vdev = (struct vxgedev *)data;
+       int i;
+       struct vxge_ring *ring;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               ring = &vdev->vpaths[i].ring;
+               /* Did this vpath received any packets */
+               if (ring->stats.prev_rx_frms == ring->stats.rx_frms) {
+                       status = vxge_hw_vpath_check_leak(ring->handle);
+
+                       /* Did it received any packets last time */
+                       if ((VXGE_HW_FAIL == status) &&
+                               (VXGE_HW_FAIL == ring->last_status)) {
+
+                               /* schedule vpath reset */
+                               if (!test_and_set_bit(i, &vdev->vp_reset)) {
+
+                                       /* disable interrupts for this vpath */
+                                       vxge_vpath_intr_disable(vdev, i);
+
+                                       /* stop the queue for this vpath */
+                                       vxge_stop_tx_queue(&vdev->vpaths[i].
+                                                               fifo);
+                                       continue;
+                               }
+                       }
+               }
+               ring->stats.prev_rx_frms = ring->stats.rx_frms;
+               ring->last_status = status;
+       }
+
+       /* Check every 1 milli second */
+       mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000);
+}
+
+/**
+ * vxge_open
+ * @dev: pointer to the device structure.
+ *
+ * This function is the open entry point of the driver. It mainly calls a
+ * function to allocate Rx buffers and inserts them into the buffer
+ * descriptors and then enables the Rx part of the NIC.
+ * Return value: '0' on success and an appropriate (-)ve integer as
+ * defined in errno.h file on failure.
+ */
+int
+vxge_open(struct net_device *dev)
+{
+       enum vxge_hw_status status;
+       struct vxgedev *vdev;
+       struct __vxge_hw_device *hldev;
+       int ret = 0;
+       int i;
+       u64 val64, function_mode;
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d", dev->name, __func__, __LINE__);
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+       hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+       function_mode = vdev->config.device_hw_info.function_mode;
+
+       /* make sure you have link off by default every time Nic is
+        * initialized */
+       netif_carrier_off(dev);
+
+       /* Check for another device already opn with INTA */
+       if ((function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
+               test_bit(__VXGE_STATE_CARD_UP, &driver_config->inta_dev_open)) {
+               ret = -EPERM;
+               goto out0;
+       }
+
+       /* Open VPATHs */
+       status = vxge_open_vpaths(vdev);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: fatal: Vpath open failed", vdev->ndev->name);
+               ret = -EPERM;
+               goto out0;
+       }
+
+       vdev->mtu = dev->mtu;
+
+       status = vxge_add_isr(vdev);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: fatal: ISR add failed", dev->name);
+               ret = -EPERM;
+               goto out1;
+       }
+
+
+       if (vdev->config.intr_type != MSI_X) {
+               netif_napi_add(dev, &vdev->napi, vxge_poll_inta,
+                       vdev->config.napi_weight);
+               napi_enable(&vdev->napi);
+       } else {
+               for (i = 0; i < vdev->no_of_vpath; i++) {
+                       netif_napi_add(dev, &vdev->vpaths[i].ring.napi,
+                           vxge_poll_msix, vdev->config.napi_weight);
+                       napi_enable(&vdev->vpaths[i].ring.napi);
+               }
+       }
+
+       /* configure RTH */
+       if (vdev->config.rth_steering) {
+               status = vxge_rth_configure(vdev);
+               if (status != VXGE_HW_OK) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: fatal: RTH configuration failed",
+                               dev->name);
+                       ret = -EPERM;
+                       goto out2;
+               }
+       }
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               /* set initial mtu before enabling the device */
+               status = vxge_hw_vpath_mtu_set(vdev->vpaths[i].handle,
+                                               vdev->mtu);
+               if (status != VXGE_HW_OK) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: fatal: can not set new MTU", dev->name);
+                       ret = -EPERM;
+                       goto out2;
+               }
+       }
+
+       VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_TRACE, VXGE_COMPONENT_LL, vdev);
+       vxge_debug_init(vdev->level_trace,
+               "%s: MTU is %d", vdev->ndev->name, vdev->mtu);
+       VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_ERR, VXGE_COMPONENT_LL, vdev);
+
+       /* Reprogram the DA table with populated mac addresses */
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               vxge_restore_vpath_mac_addr(&vdev->vpaths[i]);
+               vxge_restore_vpath_vid_table(&vdev->vpaths[i]);
+       }
+
+       /* Enable vpath to sniff all unicast/multicast traffic that not
+        * addressed to them. We allow promiscous mode for PF only
+        */
+
+       val64 = 0;
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
+               val64 |= VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(i);
+
+       vxge_hw_mgmt_reg_write(vdev->devh,
+               vxge_hw_mgmt_reg_type_mrpcim,
+               0,
+               (ulong)offsetof(struct vxge_hw_mrpcim_reg,
+                       rxmac_authorize_all_addr),
+               val64);
+
+       vxge_hw_mgmt_reg_write(vdev->devh,
+               vxge_hw_mgmt_reg_type_mrpcim,
+               0,
+               (ulong)offsetof(struct vxge_hw_mrpcim_reg,
+                       rxmac_authorize_all_vid),
+               val64);
+
+       vxge_set_multicast(dev);
+
+       /* Enabling Bcast and mcast for all vpath */
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               status = vxge_hw_vpath_bcast_enable(vdev->vpaths[i].handle);
+               if (status != VXGE_HW_OK)
+                       vxge_debug_init(VXGE_ERR,
+                               "%s : Can not enable bcast for vpath "
+                               "id %d", dev->name, i);
+               if (vdev->config.addr_learn_en) {
+                       status =
+                           vxge_hw_vpath_mcast_enable(vdev->vpaths[i].handle);
+                       if (status != VXGE_HW_OK)
+                               vxge_debug_init(VXGE_ERR,
+                                       "%s : Can not enable mcast for vpath "
+                                       "id %d", dev->name, i);
+               }
+       }
+
+       vxge_hw_device_setpause_data(vdev->devh, 0,
+               vdev->config.tx_pause_enable,
+               vdev->config.rx_pause_enable);
+
+       if (vdev->vp_reset_timer.function == NULL)
+               vxge_os_timer(vdev->vp_reset_timer,
+                       vxge_poll_vp_reset, vdev, (HZ/2));
+
+       if (vdev->vp_lockup_timer.function == NULL)
+               vxge_os_timer(vdev->vp_lockup_timer,
+                       vxge_poll_vp_lockup, vdev, (HZ/2));
+
+       set_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+
+       smp_wmb();
+
+       if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) {
+               netif_carrier_on(vdev->ndev);
+               printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name);
+               vdev->stats.link_up++;
+       }
+
+       vxge_hw_device_intr_enable(vdev->devh);
+
+       smp_wmb();
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               vxge_hw_vpath_enable(vdev->vpaths[i].handle);
+               smp_wmb();
+               vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle);
+       }
+
+       vxge_start_all_tx_queue(vdev);
+       goto out0;
+
+out2:
+       vxge_rem_isr(vdev);
+
+       /* Disable napi */
+       if (vdev->config.intr_type != MSI_X)
+               napi_disable(&vdev->napi);
+       else {
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       napi_disable(&vdev->vpaths[i].ring.napi);
+       }
+
+out1:
+       vxge_close_vpaths(vdev, 0);
+out0:
+       vxge_debug_entryexit(VXGE_TRACE,
+                               "%s: %s:%d  Exiting...",
+                               dev->name, __func__, __LINE__);
+       return ret;
+}
+
+/* Loop throught the mac address list and delete all the entries */
+void vxge_free_mac_add_list(struct vxge_vpath *vpath)
+{
+
+       struct list_head *entry, *next;
+       if (list_empty(&vpath->mac_addr_list))
+               return;
+
+       list_for_each_safe(entry, next, &vpath->mac_addr_list) {
+               list_del(entry);
+               kfree((struct vxge_mac_addrs *)entry);
+       }
+}
+
+static void vxge_napi_del_all(struct vxgedev *vdev)
+{
+       int i;
+       if (vdev->config.intr_type != MSI_X)
+               netif_napi_del(&vdev->napi);
+       else {
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       netif_napi_del(&vdev->vpaths[i].ring.napi);
+       }
+       return;
+}
+
+int do_vxge_close(struct net_device *dev, int do_io)
+{
+       enum vxge_hw_status status;
+       struct vxgedev *vdev;
+       struct __vxge_hw_device *hldev;
+       int i;
+       u64 val64, vpath_vector;
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
+               dev->name, __func__, __LINE__);
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+       hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+
+       /* If vxge_handle_crit_err task is executing,
+        * wait till it completes. */
+       while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
+               msleep(50);
+
+       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+       if (do_io) {
+               /* Put the vpath back in normal mode */
+               vpath_vector = vxge_mBIT(vdev->vpaths[0].device_id);
+               status = vxge_hw_mgmt_reg_read(vdev->devh,
+                               vxge_hw_mgmt_reg_type_mrpcim,
+                               0,
+                               (ulong)offsetof(
+                                       struct vxge_hw_mrpcim_reg,
+                                       rts_mgr_cbasin_cfg),
+                               &val64);
+
+               if (status == VXGE_HW_OK) {
+                       val64 &= ~vpath_vector;
+                       status = vxge_hw_mgmt_reg_write(vdev->devh,
+                                       vxge_hw_mgmt_reg_type_mrpcim,
+                                       0,
+                                       (ulong)offsetof(
+                                               struct vxge_hw_mrpcim_reg,
+                                               rts_mgr_cbasin_cfg),
+                                       val64);
+               }
+
+               /* Remove the function 0 from promiscous mode */
+               vxge_hw_mgmt_reg_write(vdev->devh,
+                       vxge_hw_mgmt_reg_type_mrpcim,
+                       0,
+                       (ulong)offsetof(struct vxge_hw_mrpcim_reg,
+                               rxmac_authorize_all_addr),
+                       0);
+
+               vxge_hw_mgmt_reg_write(vdev->devh,
+                       vxge_hw_mgmt_reg_type_mrpcim,
+                       0,
+                       (ulong)offsetof(struct vxge_hw_mrpcim_reg,
+                               rxmac_authorize_all_vid),
+                       0);
+
+               smp_wmb();
+       }
+       del_timer_sync(&vdev->vp_lockup_timer);
+
+       del_timer_sync(&vdev->vp_reset_timer);
+
+       /* Disable napi */
+       if (vdev->config.intr_type != MSI_X)
+               napi_disable(&vdev->napi);
+       else {
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       napi_disable(&vdev->vpaths[i].ring.napi);
+       }
+
+       netif_carrier_off(vdev->ndev);
+       printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name);
+       vxge_stop_all_tx_queue(vdev);
+
+       /* Note that at this point xmit() is stopped by upper layer */
+       if (do_io)
+               vxge_hw_device_intr_disable(vdev->devh);
+
+       mdelay(1000);
+
+       vxge_rem_isr(vdev);
+
+       vxge_napi_del_all(vdev);
+
+       if (do_io)
+               vxge_reset_all_vpaths(vdev);
+
+       vxge_close_vpaths(vdev, 0);
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s: %s:%d  Exiting...", dev->name, __func__, __LINE__);
+
+       clear_bit(__VXGE_STATE_CARD_UP, &driver_config->inta_dev_open);
+       clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state);
+
+       return 0;
+}
+
+/**
+ * vxge_close
+ * @dev: device pointer.
+ *
+ * This is the stop entry point of the driver. It needs to undo exactly
+ * whatever was done by the open entry point, thus it's usually referred to
+ * as the close function.Among other things this function mainly stops the
+ * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
+ * Return value: '0' on success and an appropriate (-)ve integer as
+ * defined in errno.h file on failure.
+ */
+int
+vxge_close(struct net_device *dev)
+{
+       do_vxge_close(dev, 1);
+       return 0;
+}
+
+/**
+ * vxge_change_mtu
+ * @dev: net device pointer.
+ * @new_mtu :the new MTU size for the device.
+ *
+ * A driver entry point to change MTU size for the device. Before changing
+ * the MTU the device must be stopped.
+ */
+static int vxge_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct vxgedev *vdev = netdev_priv(dev);
+
+       vxge_debug_entryexit(vdev->level_trace,
+               "%s:%d", __func__, __LINE__);
+       if ((new_mtu < VXGE_HW_MIN_MTU) || (new_mtu > VXGE_HW_MAX_MTU)) {
+               vxge_debug_init(vdev->level_err,
+                       "%s: mtu size is invalid", dev->name);
+               return -EPERM;
+       }
+
+       /* check if device is down already */
+       if (unlikely(!is_vxge_card_up(vdev))) {
+               /* just store new value, will use later on open() */
+               dev->mtu = new_mtu;
+               vxge_debug_init(vdev->level_err,
+                       "%s", "device is down on MTU change");
+               return 0;
+       }
+
+       vxge_debug_init(vdev->level_trace,
+               "trying to apply new MTU %d", new_mtu);
+
+       if (vxge_close(dev))
+               return -EIO;
+
+       dev->mtu = new_mtu;
+       vdev->mtu = new_mtu;
+
+       if (vxge_open(dev))
+               return -EIO;
+
+       vxge_debug_init(vdev->level_trace,
+               "%s: MTU changed to %d", vdev->ndev->name, new_mtu);
+
+       vxge_debug_entryexit(vdev->level_trace,
+               "%s:%d  Exiting...", __func__, __LINE__);
+
+       return 0;
+}
+
+/**
+ * vxge_get_stats
+ * @dev: pointer to the device structure
+ *
+ * Updates the device statistics structure. This function updates the device
+ * statistics structure in the net_device structure and returns a pointer
+ * to the same.
+ */
+static struct net_device_stats *
+vxge_get_stats(struct net_device *dev)
+{
+       struct vxgedev *vdev;
+       struct net_device_stats *net_stats;
+       int k;
+
+       vdev = netdev_priv(dev);
+
+       net_stats = &vdev->stats.net_stats;
+
+       memset(net_stats, 0, sizeof(struct net_device_stats));
+
+       for (k = 0; k < vdev->no_of_vpath; k++) {
+               net_stats->rx_packets += vdev->vpaths[k].ring.stats.rx_frms;
+               net_stats->rx_bytes += vdev->vpaths[k].ring.stats.rx_bytes;
+               net_stats->rx_errors += vdev->vpaths[k].ring.stats.rx_errors;
+               net_stats->multicast += vdev->vpaths[k].ring.stats.rx_mcast;
+               net_stats->rx_dropped +=
+                       vdev->vpaths[k].ring.stats.rx_dropped;
+
+               net_stats->tx_packets += vdev->vpaths[k].fifo.stats.tx_frms;
+               net_stats->tx_bytes += vdev->vpaths[k].fifo.stats.tx_bytes;
+               net_stats->tx_errors += vdev->vpaths[k].fifo.stats.tx_errors;
+       }
+
+       return net_stats;
+}
+
+/**
+ * vxge_ioctl
+ * @dev: Device pointer.
+ * @ifr: An IOCTL specific structure, that can contain a pointer to
+ *       a proprietary structure used to pass information to the driver.
+ * @cmd: This is used to distinguish between the different commands that
+ *       can be passed to the IOCTL functions.
+ *
+ * Entry point for the Ioctl.
+ */
+static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ * vxge_tx_watchdog
+ * @dev: pointer to net device structure
+ *
+ * Watchdog for transmit side.
+ * This function is triggered if the Tx Queue is stopped
+ * for a pre-defined amount of time when the Interface is still up.
+ */
+static void
+vxge_tx_watchdog(struct net_device *dev)
+{
+       struct vxgedev *vdev;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+
+       vdev->cric_err_event = VXGE_HW_EVENT_RESET_START;
+
+       vxge_reset(vdev);
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d  Exiting...", __func__, __LINE__);
+}
+
+/**
+ * vxge_vlan_rx_register
+ * @dev: net device pointer.
+ * @grp: vlan group
+ *
+ * Vlan group registration
+ */
+static void
+vxge_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+       struct vxgedev *vdev;
+       struct vxge_vpath *vpath;
+       int vp;
+       u64 vid;
+       enum vxge_hw_status status;
+       int i;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+
+       vpath = &vdev->vpaths[0];
+       if ((NULL == grp) && (vpath->is_open)) {
+               /* Get the first vlan */
+               status = vxge_hw_vpath_vid_get(vpath->handle, &vid);
+
+               while (status == VXGE_HW_OK) {
+
+                       /* Delete this vlan from the vid table */
+                       for (vp = 0; vp < vdev->no_of_vpath; vp++) {
+                               vpath = &vdev->vpaths[vp];
+                               if (!vpath->is_open)
+                                       continue;
+
+                               vxge_hw_vpath_vid_delete(vpath->handle, vid);
+                       }
+
+                       /* Get the next vlan to be deleted */
+                       vpath = &vdev->vpaths[0];
+                       status = vxge_hw_vpath_vid_get(vpath->handle, &vid);
+               }
+       }
+
+       vdev->vlgrp = grp;
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               if (vdev->vpaths[i].is_configured)
+                       vdev->vpaths[i].ring.vlgrp = grp;
+       }
+
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d  Exiting...", __func__, __LINE__);
+}
+
+/**
+ * vxge_vlan_rx_add_vid
+ * @dev: net device pointer.
+ * @vid: vid
+ *
+ * Add the vlan id to the devices vlan id table
+ */
+static void
+vxge_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+       struct vxgedev *vdev;
+       struct vxge_vpath *vpath;
+       int vp_id;
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+
+       /* Add these vlan to the vid table */
+       for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
+               vpath = &vdev->vpaths[vp_id];
+               if (!vpath->is_open)
+                       continue;
+               vxge_hw_vpath_vid_add(vpath->handle, vid);
+       }
+}
+
+/**
+ * vxge_vlan_rx_add_vid
+ * @dev: net device pointer.
+ * @vid: vid
+ *
+ * Remove the vlan id from the device's vlan id table
+ */
+static void
+vxge_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+       struct vxgedev *vdev;
+       struct vxge_vpath *vpath;
+       int vp_id;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+
+       vdev = (struct vxgedev *)netdev_priv(dev);
+
+       vlan_group_set_device(vdev->vlgrp, vid, NULL);
+
+       /* Delete this vlan from the vid table */
+       for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
+               vpath = &vdev->vpaths[vp_id];
+               if (!vpath->is_open)
+                       continue;
+               vxge_hw_vpath_vid_delete(vpath->handle, vid);
+       }
+       vxge_debug_entryexit(VXGE_TRACE,
+               "%s:%d  Exiting...", __func__, __LINE__);
+}
+
+static const struct net_device_ops vxge_netdev_ops = {
+       .ndo_open               = vxge_open,
+       .ndo_stop               = vxge_close,
+       .ndo_get_stats          = vxge_get_stats,
+       .ndo_start_xmit         = vxge_xmit,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_multicast_list = vxge_set_multicast,
+
+       .ndo_do_ioctl           = vxge_ioctl,
+
+       .ndo_set_mac_address    = vxge_set_mac_addr,
+       .ndo_change_mtu         = vxge_change_mtu,
+       .ndo_vlan_rx_register   = vxge_vlan_rx_register,
+       .ndo_vlan_rx_kill_vid   = vxge_vlan_rx_kill_vid,
+       .ndo_vlan_rx_add_vid    = vxge_vlan_rx_add_vid,
+
+       .ndo_tx_timeout         = vxge_tx_watchdog,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = vxge_netpoll,
+#endif
+};
+
+int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
+                                  struct vxge_config *config,
+                                  int high_dma, int no_of_vpath,
+                                  struct vxgedev **vdev_out)
+{
+       struct net_device *ndev;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxgedev *vdev;
+       int i, ret = 0, no_of_queue = 1;
+       u64 stat;
+
+       *vdev_out = NULL;
+       if (config->tx_steering_type == TX_MULTIQ_STEERING)
+               no_of_queue = no_of_vpath;
+
+       ndev = alloc_etherdev_mq(sizeof(struct vxgedev),
+                       no_of_queue);
+       if (ndev == NULL) {
+               vxge_debug_init(
+                       vxge_hw_device_trace_level_get(hldev),
+               "%s : device allocation failed", __func__);
+               ret = -ENODEV;
+               goto _out0;
+       }
+
+       vxge_debug_entryexit(
+               vxge_hw_device_trace_level_get(hldev),
+               "%s: %s:%d  Entering...",
+               ndev->name, __func__, __LINE__);
+
+       vdev = netdev_priv(ndev);
+       memset(vdev, 0, sizeof(struct vxgedev));
+
+       vdev->ndev = ndev;
+       vdev->devh = hldev;
+       vdev->pdev = hldev->pdev;
+       memcpy(&vdev->config, config, sizeof(struct vxge_config));
+       vdev->rx_csum = 1;      /* Enable Rx CSUM by default. */
+
+       SET_NETDEV_DEV(ndev, &vdev->pdev->dev);
+
+       ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+                               NETIF_F_HW_VLAN_FILTER;
+       /*  Driver entry points */
+       ndev->irq = vdev->pdev->irq;
+       ndev->base_addr = (unsigned long) hldev->bar0;
+
+       ndev->netdev_ops = &vxge_netdev_ops;
+
+       ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT;
+
+       initialize_ethtool_ops(ndev);
+
+       /* Allocate memory for vpath */
+       vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) *
+                               no_of_vpath, GFP_KERNEL);
+       if (!vdev->vpaths) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: vpath memory allocation failed",
+                       vdev->ndev->name);
+               ret = -ENODEV;
+               goto _out1;
+       }
+
+       ndev->features |= NETIF_F_SG;
+
+       ndev->features |= NETIF_F_HW_CSUM;
+       vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
+               "%s : checksuming enabled", __func__);
+
+       if (high_dma) {
+               ndev->features |= NETIF_F_HIGHDMA;
+               vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
+                       "%s : using High DMA", __func__);
+       }
+
+       ndev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+
+       if (vdev->config.gro_enable)
+               ndev->features |= NETIF_F_GRO;
+
+       if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING)
+               ndev->real_num_tx_queues = no_of_vpath;
+
+#ifdef NETIF_F_LLTX
+       ndev->features |= NETIF_F_LLTX;
+#endif
+
+       for (i = 0; i < no_of_vpath; i++)
+               spin_lock_init(&vdev->vpaths[i].fifo.tx_lock);
+
+       if (register_netdev(ndev)) {
+               vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
+                       "%s: %s : device registration failed!",
+                       ndev->name, __func__);
+               ret = -ENODEV;
+               goto _out2;
+       }
+
+       /*  Set the factory defined MAC address initially */
+       ndev->addr_len = ETH_ALEN;
+
+       /* Make Link state as off at this point, when the Link change
+        * interrupt comes the state will be automatically changed to
+        * the right state.
+        */
+       netif_carrier_off(ndev);
+
+       vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
+               "%s: Ethernet device registered",
+               ndev->name);
+
+       *vdev_out = vdev;
+
+       /* Resetting the Device stats */
+       status = vxge_hw_mrpcim_stats_access(
+                               hldev,
+                               VXGE_HW_STATS_OP_CLEAR_ALL_STATS,
+                               0,
+                               0,
+                               &stat);
+
+       if (status == VXGE_HW_ERR_PRIVILAGED_OPEARATION)
+               vxge_debug_init(
+                       vxge_hw_device_trace_level_get(hldev),
+                       "%s: device stats clear returns"
+                       "VXGE_HW_ERR_PRIVILAGED_OPEARATION", ndev->name);
+
+       vxge_debug_entryexit(vxge_hw_device_trace_level_get(hldev),
+               "%s: %s:%d  Exiting...",
+               ndev->name, __func__, __LINE__);
+
+       return ret;
+_out2:
+       kfree(vdev->vpaths);
+_out1:
+       free_netdev(ndev);
+_out0:
+       return ret;
+}
+
+/*
+ * vxge_device_unregister
+ *
+ * This function will unregister and free network device
+ */
+void
+vxge_device_unregister(struct __vxge_hw_device *hldev)
+{
+       struct vxgedev *vdev;
+       struct net_device *dev;
+       char buf[IFNAMSIZ];
+#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
+       (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
+       u32 level_trace;
+#endif
+
+       dev = hldev->ndev;
+       vdev = netdev_priv(dev);
+#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
+       (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
+       level_trace = vdev->level_trace;
+#endif
+       vxge_debug_entryexit(level_trace,
+               "%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
+
+       memcpy(buf, vdev->ndev->name, IFNAMSIZ);
+
+       /* in 2.6 will call stop() if device is up */
+       unregister_netdev(dev);
+
+       flush_scheduled_work();
+
+       vxge_debug_init(level_trace, "%s: ethernet device unregistered", buf);
+       vxge_debug_entryexit(level_trace,
+               "%s: %s:%d  Exiting...", buf, __func__, __LINE__);
+}
+
+/*
+ * vxge_callback_crit_err
+ *
+ * This function is called by the alarm handler in interrupt context.
+ * Driver must analyze it based on the event type.
+ */
+static void
+vxge_callback_crit_err(struct __vxge_hw_device *hldev,
+                       enum vxge_hw_event type, u64 vp_id)
+{
+       struct net_device *dev = hldev->ndev;
+       struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+       int vpath_idx;
+
+       vxge_debug_entryexit(vdev->level_trace,
+               "%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
+
+       /* Note: This event type should be used for device wide
+        * indications only - Serious errors, Slot freeze and critical errors
+        */
+       vdev->cric_err_event = type;
+
+       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++)
+               if (vdev->vpaths[vpath_idx].device_id == vp_id)
+                       break;
+
+       if (!test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) {
+               if (type == VXGE_HW_EVENT_SLOT_FREEZE) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: Slot is frozen", vdev->ndev->name);
+               } else if (type == VXGE_HW_EVENT_SERR) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: Encountered Serious Error",
+                               vdev->ndev->name);
+               } else if (type == VXGE_HW_EVENT_CRITICAL_ERR)
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: Encountered Critical Error",
+                               vdev->ndev->name);
+       }
+
+       if ((type == VXGE_HW_EVENT_SERR) ||
+               (type == VXGE_HW_EVENT_SLOT_FREEZE)) {
+               if (unlikely(vdev->exec_mode))
+                       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+       } else if (type == VXGE_HW_EVENT_CRITICAL_ERR) {
+               vxge_hw_device_mask_all(hldev);
+               if (unlikely(vdev->exec_mode))
+                       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+       } else if ((type == VXGE_HW_EVENT_FIFO_ERR) ||
+                 (type == VXGE_HW_EVENT_VPATH_ERR)) {
+
+               if (unlikely(vdev->exec_mode))
+                       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+               else {
+                       /* check if this vpath is already set for reset */
+                       if (!test_and_set_bit(vpath_idx, &vdev->vp_reset)) {
+
+                               /* disable interrupts for this vpath */
+                               vxge_vpath_intr_disable(vdev, vpath_idx);
+
+                               /* stop the queue for this vpath */
+                               vxge_stop_tx_queue(&vdev->vpaths[vpath_idx].
+                                                       fifo);
+                       }
+               }
+       }
+
+       vxge_debug_entryexit(vdev->level_trace,
+               "%s: %s:%d  Exiting...",
+               vdev->ndev->name, __func__, __LINE__);
+}
+
+static void verify_bandwidth(void)
+{
+       int i, band_width, total = 0, equal_priority = 0;
+
+       /* 1. If user enters 0 for some fifo, give equal priority to all */
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               if (bw_percentage[i] == 0) {
+                       equal_priority = 1;
+                       break;
+               }
+       }
+
+       if (!equal_priority) {
+               /* 2. If sum exceeds 100, give equal priority to all */
+               for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+                       if (bw_percentage[i] == 0xFF)
+                               break;
+
+                       total += bw_percentage[i];
+                       if (total > VXGE_HW_VPATH_BANDWIDTH_MAX) {
+                               equal_priority = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!equal_priority) {
+               /* Is all the bandwidth consumed? */
+               if (total < VXGE_HW_VPATH_BANDWIDTH_MAX) {
+                       if (i < VXGE_HW_MAX_VIRTUAL_PATHS) {
+                               /* Split rest of bw equally among next VPs*/
+                               band_width =
+                                 (VXGE_HW_VPATH_BANDWIDTH_MAX  - total) /
+                                       (VXGE_HW_MAX_VIRTUAL_PATHS - i);
+                               if (band_width < 2) /* min of 2% */
+                                       equal_priority = 1;
+                               else {
+                                       for (; i < VXGE_HW_MAX_VIRTUAL_PATHS;
+                                               i++)
+                                               bw_percentage[i] =
+                                                       band_width;
+                               }
+                       }
+               } else if (i < VXGE_HW_MAX_VIRTUAL_PATHS)
+                       equal_priority = 1;
+       }
+
+       if (equal_priority) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: Assigning equal bandwidth to all the vpaths",
+                       VXGE_DRIVER_NAME);
+               bw_percentage[0] = VXGE_HW_VPATH_BANDWIDTH_MAX /
+                                       VXGE_HW_MAX_VIRTUAL_PATHS;
+               for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
+                       bw_percentage[i] = bw_percentage[0];
+       }
+
+       return;
+}
+
+/*
+ * Vpath configuration
+ */
+static int __devinit vxge_config_vpaths(
+                       struct vxge_hw_device_config *device_config,
+                       u64 vpath_mask, struct vxge_config *config_param)
+{
+       int i, no_of_vpaths = 0, default_no_vpath = 0, temp;
+       u32 txdl_size, txdl_per_memblock;
+
+       temp = driver_config->vpath_per_dev;
+       if ((driver_config->vpath_per_dev == VXGE_USE_DEFAULT) &&
+               (max_config_dev == VXGE_MAX_CONFIG_DEV)) {
+               /* No more CPU. Return vpath number as zero.*/
+               if (driver_config->g_no_cpus == -1)
+                       return 0;
+
+               if (!driver_config->g_no_cpus)
+                       driver_config->g_no_cpus = num_online_cpus();
+
+               driver_config->vpath_per_dev = driver_config->g_no_cpus >> 1;
+               if (!driver_config->vpath_per_dev)
+                       driver_config->vpath_per_dev = 1;
+
+               for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
+                       if (!vxge_bVALn(vpath_mask, i, 1))
+                               continue;
+                       else
+                               default_no_vpath++;
+               if (default_no_vpath < driver_config->vpath_per_dev)
+                       driver_config->vpath_per_dev = default_no_vpath;
+
+               driver_config->g_no_cpus = driver_config->g_no_cpus -
+                               (driver_config->vpath_per_dev * 2);
+               if (driver_config->g_no_cpus <= 0)
+                       driver_config->g_no_cpus = -1;
+       }
+
+       if (driver_config->vpath_per_dev == 1) {
+               vxge_debug_ll_config(VXGE_TRACE,
+                       "%s: Disable tx and rx steering, "
+                       "as single vpath is configured", VXGE_DRIVER_NAME);
+               config_param->rth_steering = NO_STEERING;
+               config_param->tx_steering_type = NO_STEERING;
+               device_config->rth_en = 0;
+       }
+
+       /* configure bandwidth */
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
+               device_config->vp_config[i].min_bandwidth = bw_percentage[i];
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               device_config->vp_config[i].vp_id = i;
+               device_config->vp_config[i].mtu = VXGE_HW_DEFAULT_MTU;
+               if (no_of_vpaths < driver_config->vpath_per_dev) {
+                       if (!vxge_bVALn(vpath_mask, i, 1)) {
+                               vxge_debug_ll_config(VXGE_TRACE,
+                                       "%s: vpath: %d is not available",
+                                       VXGE_DRIVER_NAME, i);
+                               continue;
+                       } else {
+                               vxge_debug_ll_config(VXGE_TRACE,
+                                       "%s: vpath: %d available",
+                                       VXGE_DRIVER_NAME, i);
+                               no_of_vpaths++;
+                       }
+               } else {
+                       vxge_debug_ll_config(VXGE_TRACE,
+                               "%s: vpath: %d is not configured, "
+                               "max_config_vpath exceeded",
+                               VXGE_DRIVER_NAME, i);
+                       break;
+               }
+
+               /* Configure Tx fifo's */
+               device_config->vp_config[i].fifo.enable =
+                                               VXGE_HW_FIFO_ENABLE;
+               device_config->vp_config[i].fifo.max_frags =
+                               MAX_SKB_FRAGS;
+               device_config->vp_config[i].fifo.memblock_size =
+                       VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE;
+
+               txdl_size = MAX_SKB_FRAGS * sizeof(struct vxge_hw_fifo_txd);
+               txdl_per_memblock = VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE / txdl_size;
+
+               device_config->vp_config[i].fifo.fifo_blocks =
+                       ((VXGE_DEF_FIFO_LENGTH - 1) / txdl_per_memblock) + 1;
+
+               device_config->vp_config[i].fifo.intr =
+                               VXGE_HW_FIFO_QUEUE_INTR_DISABLE;
+
+               /* Configure tti properties */
+               device_config->vp_config[i].tti.intr_enable =
+                                       VXGE_HW_TIM_INTR_ENABLE;
+
+               device_config->vp_config[i].tti.btimer_val =
+                       (VXGE_TTI_BTIMER_VAL * 1000) / 272;
+
+               device_config->vp_config[i].tti.timer_ac_en =
+                               VXGE_HW_TIM_TIMER_AC_ENABLE;
+
+               /* For msi-x with napi (each vector
+               has a handler of its own) -
+               Set CI to OFF for all vpaths */
+               device_config->vp_config[i].tti.timer_ci_en =
+                       VXGE_HW_TIM_TIMER_CI_DISABLE;
+
+               device_config->vp_config[i].tti.timer_ri_en =
+                               VXGE_HW_TIM_TIMER_RI_DISABLE;
+
+               device_config->vp_config[i].tti.util_sel =
+                       VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL;
+
+               device_config->vp_config[i].tti.ltimer_val =
+                       (VXGE_TTI_LTIMER_VAL * 1000) / 272;
+
+               device_config->vp_config[i].tti.rtimer_val =
+                       (VXGE_TTI_RTIMER_VAL * 1000) / 272;
+
+               device_config->vp_config[i].tti.urange_a = TTI_TX_URANGE_A;
+               device_config->vp_config[i].tti.urange_b = TTI_TX_URANGE_B;
+               device_config->vp_config[i].tti.urange_c = TTI_TX_URANGE_C;
+               device_config->vp_config[i].tti.uec_a = TTI_TX_UFC_A;
+               device_config->vp_config[i].tti.uec_b = TTI_TX_UFC_B;
+               device_config->vp_config[i].tti.uec_c = TTI_TX_UFC_C;
+               device_config->vp_config[i].tti.uec_d = TTI_TX_UFC_D;
+
+               /* Configure Rx rings */
+               device_config->vp_config[i].ring.enable  =
+                                               VXGE_HW_RING_ENABLE;
+
+               device_config->vp_config[i].ring.ring_blocks  =
+                                               VXGE_HW_DEF_RING_BLOCKS;
+               device_config->vp_config[i].ring.buffer_mode =
+                       VXGE_HW_RING_RXD_BUFFER_MODE_1;
+               device_config->vp_config[i].ring.rxds_limit  =
+                               VXGE_HW_DEF_RING_RXDS_LIMIT;
+               device_config->vp_config[i].ring.scatter_mode =
+                                       VXGE_HW_RING_SCATTER_MODE_A;
+
+               /* Configure rti properties */
+               device_config->vp_config[i].rti.intr_enable =
+                                       VXGE_HW_TIM_INTR_ENABLE;
+
+               device_config->vp_config[i].rti.btimer_val =
+                       (VXGE_RTI_BTIMER_VAL * 1000)/272;
+
+               device_config->vp_config[i].rti.timer_ac_en =
+                                               VXGE_HW_TIM_TIMER_AC_ENABLE;
+
+               device_config->vp_config[i].rti.timer_ci_en =
+                                               VXGE_HW_TIM_TIMER_CI_DISABLE;
+
+               device_config->vp_config[i].rti.timer_ri_en =
+                                               VXGE_HW_TIM_TIMER_RI_DISABLE;
+
+               device_config->vp_config[i].rti.util_sel =
+                               VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL;
+
+               device_config->vp_config[i].rti.urange_a =
+                                               RTI_RX_URANGE_A;
+               device_config->vp_config[i].rti.urange_b =
+                                               RTI_RX_URANGE_B;
+               device_config->vp_config[i].rti.urange_c =
+                                               RTI_RX_URANGE_C;
+               device_config->vp_config[i].rti.uec_a = RTI_RX_UFC_A;
+               device_config->vp_config[i].rti.uec_b = RTI_RX_UFC_B;
+               device_config->vp_config[i].rti.uec_c = RTI_RX_UFC_C;
+               device_config->vp_config[i].rti.uec_d = RTI_RX_UFC_D;
+
+               device_config->vp_config[i].rti.rtimer_val =
+                       (VXGE_RTI_RTIMER_VAL * 1000) / 272;
+
+               device_config->vp_config[i].rti.ltimer_val =
+                       (VXGE_RTI_LTIMER_VAL * 1000) / 272;
+
+               device_config->vp_config[i].rpa_strip_vlan_tag =
+                       vlan_tag_strip;
+       }
+
+       driver_config->vpath_per_dev = temp;
+       return no_of_vpaths;
+}
+
+/* initialize device configuratrions */
+static void __devinit vxge_device_config_init(
+                               struct vxge_hw_device_config *device_config,
+                               int *intr_type)
+{
+       /* Used for CQRQ/SRQ. */
+       device_config->dma_blockpool_initial =
+                       VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE;
+
+       device_config->dma_blockpool_max =
+                       VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE;
+
+       if (max_mac_vpath > VXGE_MAX_MAC_ADDR_COUNT)
+               max_mac_vpath = VXGE_MAX_MAC_ADDR_COUNT;
+
+#ifndef CONFIG_PCI_MSI
+       vxge_debug_init(VXGE_ERR,
+               "%s: This Kernel does not support "
+               "MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME);
+       *intr_type = INTA;
+#endif
+
+       /* Configure whether MSI-X or IRQL. */
+       switch (*intr_type) {
+       case INTA:
+               device_config->intr_mode = VXGE_HW_INTR_MODE_IRQLINE;
+               break;
+
+       case MSI_X:
+               device_config->intr_mode = VXGE_HW_INTR_MODE_MSIX;
+               break;
+       }
+       /* Timer period between device poll */
+       device_config->device_poll_millis = VXGE_TIMER_DELAY;
+
+       /* Configure mac based steering. */
+       device_config->rts_mac_en = addr_learn_en;
+
+       /* Configure Vpaths */
+       device_config->rth_it_type = VXGE_HW_RTH_IT_TYPE_MULTI_IT;
+
+       vxge_debug_ll_config(VXGE_TRACE, "%s : Device Config Params ",
+                       __func__);
+       vxge_debug_ll_config(VXGE_TRACE, "dma_blockpool_initial : %d",
+                       device_config->dma_blockpool_initial);
+       vxge_debug_ll_config(VXGE_TRACE, "dma_blockpool_max : %d",
+                       device_config->dma_blockpool_max);
+       vxge_debug_ll_config(VXGE_TRACE, "intr_mode : %d",
+                       device_config->intr_mode);
+       vxge_debug_ll_config(VXGE_TRACE, "device_poll_millis : %d",
+                       device_config->device_poll_millis);
+       vxge_debug_ll_config(VXGE_TRACE, "rts_mac_en : %d",
+                       device_config->rts_mac_en);
+       vxge_debug_ll_config(VXGE_TRACE, "rth_en : %d",
+                       device_config->rth_en);
+       vxge_debug_ll_config(VXGE_TRACE, "rth_it_type : %d",
+                       device_config->rth_it_type);
+}
+
+static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask)
+{
+       int i;
+
+       vxge_debug_init(VXGE_TRACE,
+               "%s: %d Vpath(s) opened",
+               vdev->ndev->name, vdev->no_of_vpath);
+
+       switch (vdev->config.intr_type) {
+       case INTA:
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Interrupt type INTA", vdev->ndev->name);
+               break;
+
+       case MSI_X:
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Interrupt type MSI-X", vdev->ndev->name);
+               break;
+       }
+
+       if (vdev->config.rth_steering) {
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: RTH steering enabled for TCP_IPV4",
+                       vdev->ndev->name);
+       } else {
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: RTH steering disabled", vdev->ndev->name);
+       }
+
+       switch (vdev->config.tx_steering_type) {
+       case NO_STEERING:
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Tx steering disabled", vdev->ndev->name);
+               break;
+       case TX_PRIORITY_STEERING:
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Unsupported tx steering option",
+                       vdev->ndev->name);
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Tx steering disabled", vdev->ndev->name);
+               vdev->config.tx_steering_type = 0;
+               break;
+       case TX_VLAN_STEERING:
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Unsupported tx steering option",
+                       vdev->ndev->name);
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Tx steering disabled", vdev->ndev->name);
+               vdev->config.tx_steering_type = 0;
+               break;
+       case TX_MULTIQ_STEERING:
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Tx multiqueue steering enabled",
+                       vdev->ndev->name);
+               break;
+       case TX_PORT_STEERING:
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Tx port steering enabled",
+                       vdev->ndev->name);
+               break;
+       default:
+               vxge_debug_init(VXGE_ERR,
+                       "%s: Unsupported tx steering type",
+                       vdev->ndev->name);
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Tx steering disabled", vdev->ndev->name);
+               vdev->config.tx_steering_type = 0;
+       }
+
+       if (vdev->config.gro_enable) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: Generic receive offload enabled",
+                       vdev->ndev->name);
+       } else
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Generic receive offload disabled",
+                       vdev->ndev->name);
+
+       if (vdev->config.addr_learn_en)
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: MAC Address learning enabled", vdev->ndev->name);
+
+       vxge_debug_init(VXGE_TRACE,
+               "%s: Rx doorbell mode enabled", vdev->ndev->name);
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               if (!vxge_bVALn(vpath_mask, i, 1))
+                       continue;
+               vxge_debug_ll_config(VXGE_TRACE,
+                       "%s: MTU size - %d", vdev->ndev->name,
+                       ((struct __vxge_hw_device  *)(vdev->devh))->
+                               config.vp_config[i].mtu);
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: VLAN tag stripping %s", vdev->ndev->name,
+                       ((struct __vxge_hw_device  *)(vdev->devh))->
+                               config.vp_config[i].rpa_strip_vlan_tag
+                       ? "Enabled" : "Disabled");
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Ring blocks : %d", vdev->ndev->name,
+                       ((struct __vxge_hw_device  *)(vdev->devh))->
+                               config.vp_config[i].ring.ring_blocks);
+               vxge_debug_init(VXGE_TRACE,
+                       "%s: Fifo blocks : %d", vdev->ndev->name,
+                       ((struct __vxge_hw_device  *)(vdev->devh))->
+                               config.vp_config[i].fifo.fifo_blocks);
+               vxge_debug_ll_config(VXGE_TRACE,
+                       "%s: Max frags : %d", vdev->ndev->name,
+                       ((struct __vxge_hw_device  *)(vdev->devh))->
+                               config.vp_config[i].fifo.max_frags);
+               break;
+       }
+}
+
+#ifdef CONFIG_PM
+/**
+ * vxge_pm_suspend - vxge power management suspend entry point
+ *
+ */
+static int vxge_pm_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       return -ENOSYS;
+}
+/**
+ * vxge_pm_resume - vxge power management resume entry point
+ *
+ */
+static int vxge_pm_resume(struct pci_dev *pdev)
+{
+       return -ENOSYS;
+}
+
+#endif
+
+/**
+ * vxge_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev,
+                                               pci_channel_state_t state)
+{
+       struct __vxge_hw_device  *hldev =
+               (struct __vxge_hw_device  *) pci_get_drvdata(pdev);
+       struct net_device *netdev = hldev->ndev;
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev)) {
+               /* Bring down the card, while avoiding PCI I/O */
+               do_vxge_close(netdev, 0);
+       }
+
+       pci_disable_device(pdev);
+
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * vxge_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ * At this point, the card has exprienced a hard reset,
+ * followed by fixups by BIOS, and has its config space
+ * set up identically to what it was at cold boot.
+ */
+static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev)
+{
+       struct __vxge_hw_device  *hldev =
+               (struct __vxge_hw_device  *) pci_get_drvdata(pdev);
+       struct net_device *netdev = hldev->ndev;
+
+       struct vxgedev *vdev = netdev_priv(netdev);
+
+       if (pci_enable_device(pdev)) {
+               printk(KERN_ERR "%s: "
+                       "Cannot re-enable device after reset\n",
+                       VXGE_DRIVER_NAME);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       pci_set_master(pdev);
+       vxge_reset(vdev);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * vxge_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells
+ * us that its OK to resume normal operation.
+ */
+static void vxge_io_resume(struct pci_dev *pdev)
+{
+       struct __vxge_hw_device  *hldev =
+               (struct __vxge_hw_device  *) pci_get_drvdata(pdev);
+       struct net_device *netdev = hldev->ndev;
+
+       if (netif_running(netdev)) {
+               if (vxge_open(netdev)) {
+                       printk(KERN_ERR "%s: "
+                               "Can't bring device back up after reset\n",
+                               VXGE_DRIVER_NAME);
+                       return;
+               }
+       }
+
+       netif_device_attach(netdev);
+}
+
+/**
+ * vxge_probe
+ * @pdev : structure containing the PCI related information of the device.
+ * @pre: List of PCI devices supported by the driver listed in vxge_id_table.
+ * Description:
+ * This function is called when a new PCI device gets detected and initializes
+ * it.
+ * Return value:
+ * returns 0 on success and negative on failure.
+ *
+ */
+static int __devinit
+vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
+{
+       struct __vxge_hw_device  *hldev;
+       enum vxge_hw_status status;
+       int ret;
+       int high_dma = 0;
+       u64 vpath_mask = 0;
+       struct vxgedev *vdev;
+       struct vxge_config ll_config;
+       struct vxge_hw_device_config *device_config = NULL;
+       struct vxge_hw_device_attr attr;
+       int i, j, no_of_vpath = 0, max_vpath_supported = 0;
+       u8 *macaddr;
+       struct vxge_mac_addrs *entry;
+       static int bus = -1, device = -1;
+       u8 new_device = 0;
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
+       attr.pdev = pdev;
+
+       if (bus != pdev->bus->number)
+               new_device = 1;
+       if (device != PCI_SLOT(pdev->devfn))
+               new_device = 1;
+
+       bus = pdev->bus->number;
+       device = PCI_SLOT(pdev->devfn);
+
+       if (new_device) {
+               if (driver_config->config_dev_cnt &&
+                  (driver_config->config_dev_cnt !=
+                       driver_config->total_dev_cnt))
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: Configured %d of %d devices",
+                               VXGE_DRIVER_NAME,
+                               driver_config->config_dev_cnt,
+                               driver_config->total_dev_cnt);
+               driver_config->config_dev_cnt = 0;
+               driver_config->total_dev_cnt = 0;
+               driver_config->g_no_cpus = 0;
+               driver_config->vpath_per_dev = max_config_vpath;
+       }
+
+       driver_config->total_dev_cnt++;
+       if (++driver_config->config_dev_cnt > max_config_dev) {
+               ret = 0;
+               goto _exit0;
+       }
+
+       device_config = kzalloc(sizeof(struct vxge_hw_device_config),
+               GFP_KERNEL);
+       if (!device_config) {
+               ret = -ENOMEM;
+               vxge_debug_init(VXGE_ERR,
+                       "device_config : malloc failed %s %d",
+                       __FILE__, __LINE__);
+               goto _exit0;
+       }
+
+       memset(&ll_config, 0, sizeof(struct vxge_config));
+       ll_config.tx_steering_type = TX_MULTIQ_STEERING;
+       ll_config.intr_type = MSI_X;
+       ll_config.napi_weight = NEW_NAPI_WEIGHT;
+       ll_config.rth_steering = RTH_STEERING;
+
+       /* get the default configuration parameters */
+       vxge_hw_device_config_default_get(device_config);
+
+       /* initialize configuration parameters */
+       vxge_device_config_init(device_config, &ll_config.intr_type);
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s : can not enable PCI device", __func__);
+               goto _exit0;
+       }
+
+       if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+               vxge_debug_ll_config(VXGE_TRACE,
+                       "%s : using 64bit DMA", __func__);
+
+               high_dma = 1;
+
+               if (pci_set_consistent_dma_mask(pdev,
+                                               0xffffffffffffffffULL)) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s : unable to obtain 64bit DMA for "
+                               "consistent allocations", __func__);
+                       ret = -ENOMEM;
+                       goto _exit1;
+               }
+       } else if (!pci_set_dma_mask(pdev, 0xffffffffUL)) {
+               vxge_debug_ll_config(VXGE_TRACE,
+                       "%s : using 32bit DMA", __func__);
+       } else {
+               ret = -ENOMEM;
+               goto _exit1;
+       }
+
+       if (pci_request_regions(pdev, VXGE_DRIVER_NAME)) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s : request regions failed", __func__);
+               ret = -ENODEV;
+               goto _exit1;
+       }
+
+       pci_set_master(pdev);
+
+       attr.bar0 = pci_ioremap_bar(pdev, 0);
+       if (!attr.bar0) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s : cannot remap io memory bar0", __func__);
+               ret = -ENODEV;
+               goto _exit2;
+       }
+       vxge_debug_ll_config(VXGE_TRACE,
+               "pci ioremap bar0: %p:0x%llx",
+               attr.bar0,
+               (unsigned long long)pci_resource_start(pdev, 0));
+
+       attr.bar1 = pci_ioremap_bar(pdev, 2);
+       if (!attr.bar1) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s : cannot remap io memory bar2", __func__);
+               ret = -ENODEV;
+               goto _exit3;
+       }
+       vxge_debug_ll_config(VXGE_TRACE,
+               "pci ioremap bar1: %p:0x%llx",
+               attr.bar1,
+               (unsigned long long)pci_resource_start(pdev, 2));
+
+       status = vxge_hw_device_hw_info_get(attr.bar0,
+                       &ll_config.device_hw_info);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "%s: Reading of hardware info failed."
+                       "Please try upgrading the firmware.", VXGE_DRIVER_NAME);
+               ret = -EINVAL;
+               goto _exit4;
+       }
+
+       if (ll_config.device_hw_info.fw_version.major !=
+               VXGE_DRIVER_VERSION_MAJOR) {
+               vxge_debug_init(VXGE_ERR,
+                       "FW Ver.(maj): %d not driver's expected version: %d",
+                       ll_config.device_hw_info.fw_version.major,
+                       VXGE_DRIVER_VERSION_MAJOR);
+               ret = -EINVAL;
+               goto _exit4;
+       }
+
+       vpath_mask = ll_config.device_hw_info.vpath_mask;
+       if (vpath_mask == 0) {
+               vxge_debug_ll_config(VXGE_TRACE,
+                       "%s: No vpaths available in device", VXGE_DRIVER_NAME);
+               ret = -EINVAL;
+               goto _exit4;
+       }
+
+       vxge_debug_ll_config(VXGE_TRACE,
+               "%s:%d  Vpath mask = %llx", __func__, __LINE__,
+               (unsigned long long)vpath_mask);
+
+       /* Check how many vpaths are available */
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               if (!((vpath_mask) & vxge_mBIT(i)))
+                       continue;
+               max_vpath_supported++;
+       }
+
+       /*
+        * Configure vpaths and get driver configured number of vpaths
+        * which is less than or equal to the maximum vpaths per function.
+        */
+       no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, &ll_config);
+       if (!no_of_vpath) {
+               vxge_debug_ll_config(VXGE_ERR,
+                       "%s: No more vpaths to configure", VXGE_DRIVER_NAME);
+               ret = 0;
+               goto _exit4;
+       }
+
+       /* Setting driver callbacks */
+       attr.uld_callbacks.link_up = vxge_callback_link_up;
+       attr.uld_callbacks.link_down = vxge_callback_link_down;
+       attr.uld_callbacks.crit_err = vxge_callback_crit_err;
+
+       status = vxge_hw_device_initialize(&hldev, &attr, device_config);
+       if (status != VXGE_HW_OK) {
+               vxge_debug_init(VXGE_ERR,
+                       "Failed to initialize device (%d)", status);
+                       ret = -EINVAL;
+                       goto _exit4;
+       }
+
+       vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
+
+       /* set private device info */
+       pci_set_drvdata(pdev, hldev);
+
+       ll_config.gro_enable = VXGE_GRO_ALWAYS_AGGREGATE;
+       ll_config.fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
+       ll_config.addr_learn_en = addr_learn_en;
+       ll_config.rth_algorithm = RTH_ALG_JENKINS;
+       ll_config.rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
+       ll_config.rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
+       ll_config.rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+       ll_config.rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+       ll_config.rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+       ll_config.rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+       ll_config.rth_bkt_sz = RTH_BUCKET_SIZE;
+       ll_config.tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+       ll_config.rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+
+       if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
+               &vdev)) {
+               ret = -EINVAL;
+               goto _exit5;
+       }
+
+       vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL);
+       VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
+               vxge_hw_device_trace_level_get(hldev));
+
+       /* set private HW device info */
+       hldev->ndev = vdev->ndev;
+       vdev->mtu = VXGE_HW_DEFAULT_MTU;
+       vdev->bar0 = attr.bar0;
+       vdev->bar1 = attr.bar1;
+       vdev->max_vpath_supported = max_vpath_supported;
+       vdev->no_of_vpath = no_of_vpath;
+
+       /* Virtual Path count */
+       for (i = 0, j = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+               if (!vxge_bVALn(vpath_mask, i, 1))
+                       continue;
+               if (j >= vdev->no_of_vpath)
+                       break;
+
+               vdev->vpaths[j].is_configured = 1;
+               vdev->vpaths[j].device_id = i;
+               vdev->vpaths[j].fifo.driver_id = j;
+               vdev->vpaths[j].ring.driver_id = j;
+               vdev->vpaths[j].vdev = vdev;
+               vdev->vpaths[j].max_mac_addr_cnt = max_mac_vpath;
+               memcpy((u8 *)vdev->vpaths[j].macaddr,
+                               (u8 *)ll_config.device_hw_info.mac_addrs[i],
+                               ETH_ALEN);
+
+               /* Initialize the mac address list header */
+               INIT_LIST_HEAD(&vdev->vpaths[j].mac_addr_list);
+
+               vdev->vpaths[j].mac_addr_cnt = 0;
+               vdev->vpaths[j].mcast_addr_cnt = 0;
+               j++;
+       }
+       vdev->exec_mode = VXGE_EXEC_MODE_DISABLE;
+       vdev->max_config_port = max_config_port;
+
+       vdev->vlan_tag_strip = vlan_tag_strip;
+
+       /* map the hashing selector table to the configured vpaths */
+       for (i = 0; i < vdev->no_of_vpath; i++)
+               vdev->vpath_selector[i] = vpath_selector[i];
+
+       macaddr = (u8 *)vdev->vpaths[0].macaddr;
+
+       ll_config.device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
+       ll_config.device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
+       ll_config.device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
+
+       vxge_debug_init(VXGE_TRACE, "%s: SERIAL NUMBER: %s",
+               vdev->ndev->name, ll_config.device_hw_info.serial_number);
+
+       vxge_debug_init(VXGE_TRACE, "%s: PART NUMBER: %s",
+               vdev->ndev->name, ll_config.device_hw_info.part_number);
+
+       vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter",
+               vdev->ndev->name, ll_config.device_hw_info.product_desc);
+
+       vxge_debug_init(VXGE_TRACE,
+               "%s: MAC ADDR: %02X:%02X:%02X:%02X:%02X:%02X",
+               vdev->ndev->name, macaddr[0], macaddr[1], macaddr[2],
+               macaddr[3], macaddr[4], macaddr[5]);
+
+       vxge_debug_init(VXGE_TRACE, "%s: Link Width x%d",
+               vdev->ndev->name, vxge_hw_device_link_width_get(hldev));
+
+       vxge_debug_init(VXGE_TRACE,
+               "%s: Firmware version : %s Date : %s", vdev->ndev->name,
+               ll_config.device_hw_info.fw_version.version,
+               ll_config.device_hw_info.fw_date.date);
+
+       vxge_print_parm(vdev, vpath_mask);
+
+       /* Store the fw version for ethttool option */
+       strcpy(vdev->fw_version, ll_config.device_hw_info.fw_version.version);
+       memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN);
+       memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN);
+
+       /* Copy the station mac address to the list */
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               entry = (struct vxge_mac_addrs *)
+                               kzalloc(sizeof(struct vxge_mac_addrs),
+                                       GFP_KERNEL);
+               if (NULL == entry) {
+                       vxge_debug_init(VXGE_ERR,
+                               "%s: mac_addr_list : memory allocation failed",
+                               vdev->ndev->name);
+                       ret = -EPERM;
+                       goto _exit6;
+               }
+               macaddr = (u8 *)&entry->macaddr;
+               memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN);
+               list_add(&entry->item, &vdev->vpaths[i].mac_addr_list);
+               vdev->vpaths[i].mac_addr_cnt = 1;
+       }
+
+       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d  Exiting...",
+               vdev->ndev->name, __func__, __LINE__);
+
+       vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
+       VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
+               vxge_hw_device_trace_level_get(hldev));
+
+       return 0;
+
+_exit6:
+       for (i = 0; i < vdev->no_of_vpath; i++)
+               vxge_free_mac_add_list(&vdev->vpaths[i]);
+
+       vxge_device_unregister(hldev);
+_exit5:
+       vxge_hw_device_terminate(hldev);
+_exit4:
+       iounmap(attr.bar1);
+_exit3:
+       iounmap(attr.bar0);
+_exit2:
+       pci_release_regions(pdev);
+_exit1:
+       pci_disable_device(pdev);
+_exit0:
+       kfree(device_config);
+       driver_config->config_dev_cnt--;
+       pci_set_drvdata(pdev, NULL);
+       return ret;
+}
+
+/**
+ * vxge_rem_nic - Free the PCI device
+ * @pdev: structure containing the PCI related information of the device.
+ * Description: This function is called by the Pci subsystem to release a
+ * PCI device and free up all resource held up by the device.
+ */
+static void __devexit
+vxge_remove(struct pci_dev *pdev)
+{
+       struct __vxge_hw_device  *hldev;
+       struct vxgedev *vdev = NULL;
+       struct net_device *dev;
+       int i = 0;
+#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
+       (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
+       u32 level_trace;
+#endif
+
+       hldev = (struct __vxge_hw_device  *) pci_get_drvdata(pdev);
+
+       if (hldev == NULL)
+               return;
+       dev = hldev->ndev;
+       vdev = netdev_priv(dev);
+
+#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
+       (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
+       level_trace = vdev->level_trace;
+#endif
+       vxge_debug_entryexit(level_trace,
+               "%s:%d", __func__, __LINE__);
+
+       vxge_debug_init(level_trace,
+               "%s : removing PCI device...", __func__);
+       vxge_device_unregister(hldev);
+
+       for (i = 0; i < vdev->no_of_vpath; i++) {
+               vxge_free_mac_add_list(&vdev->vpaths[i]);
+               vdev->vpaths[i].mcast_addr_cnt = 0;
+               vdev->vpaths[i].mac_addr_cnt = 0;
+       }
+
+       kfree(vdev->vpaths);
+
+       iounmap(vdev->bar0);
+       iounmap(vdev->bar1);
+
+       /* we are safe to free it now */
+       free_netdev(dev);
+
+       vxge_debug_init(level_trace,
+               "%s:%d  Device unregistered", __func__, __LINE__);
+
+       vxge_hw_device_terminate(hldev);
+
+       pci_disable_device(pdev);
+       pci_release_regions(pdev);
+       pci_set_drvdata(pdev, NULL);
+       vxge_debug_entryexit(level_trace,
+               "%s:%d  Exiting...", __func__, __LINE__);
+}
+
+static struct pci_error_handlers vxge_err_handler = {
+       .error_detected = vxge_io_error_detected,
+       .slot_reset = vxge_io_slot_reset,
+       .resume = vxge_io_resume,
+};
+
+static struct pci_driver vxge_driver = {
+       .name = VXGE_DRIVER_NAME,
+       .id_table = vxge_id_table,
+       .probe = vxge_probe,
+       .remove = __devexit_p(vxge_remove),
+#ifdef CONFIG_PM
+       .suspend = vxge_pm_suspend,
+       .resume = vxge_pm_resume,
+#endif
+       .err_handler = &vxge_err_handler,
+};
+
+static int __init
+vxge_starter(void)
+{
+       int ret = 0;
+       char version[32];
+       snprintf(version, 32, "%s", DRV_VERSION);
+
+       printk(KERN_CRIT "%s: Copyright(c) 2002-2009 Neterion Inc\n",
+               VXGE_DRIVER_NAME);
+       printk(KERN_CRIT "%s: Driver version: %s\n",
+                       VXGE_DRIVER_NAME, version);
+
+       verify_bandwidth();
+
+       driver_config = kzalloc(sizeof(struct vxge_drv_config), GFP_KERNEL);
+       if (!driver_config)
+               return -ENOMEM;
+
+       ret = pci_register_driver(&vxge_driver);
+
+       if (driver_config->config_dev_cnt &&
+          (driver_config->config_dev_cnt != driver_config->total_dev_cnt))
+               vxge_debug_init(VXGE_ERR,
+                       "%s: Configured %d of %d devices",
+                       VXGE_DRIVER_NAME, driver_config->config_dev_cnt,
+                       driver_config->total_dev_cnt);
+
+       if (ret)
+               kfree(driver_config);
+
+       return ret;
+}
+
+static void __exit
+vxge_closer(void)
+{
+       pci_unregister_driver(&vxge_driver);
+       kfree(driver_config);
+}
+module_init(vxge_starter);
+module_exit(vxge_closer);
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
new file mode 100644 (file)
index 0000000..9704b2b
--- /dev/null
@@ -0,0 +1,557 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-main.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *              Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#ifndef VXGE_MAIN_H
+#define VXGE_MAIN_H
+
+#include "vxge-traffic.h"
+#include "vxge-config.h"
+#include "vxge-version.h"
+#include <linux/list.h>
+
+#define VXGE_DRIVER_NAME               "vxge"
+#define VXGE_DRIVER_VENDOR             "Neterion, Inc"
+#define VXGE_DRIVER_VERSION_MAJOR 0
+
+#define DRV_VERSION    VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\
+       VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\
+       VXGE_VERSION_FOR
+
+#define PCI_DEVICE_ID_TITAN_WIN                0x5733
+#define PCI_DEVICE_ID_TITAN_UNI                0x5833
+#define        VXGE_USE_DEFAULT                0xffffffff
+#define VXGE_HW_VPATH_MSIX_ACTIVE      4
+#define VXGE_HW_RXSYNC_FREQ_CNT                4
+#define VXGE_LL_WATCH_DOG_TIMEOUT      (15 * HZ)
+#define VXGE_LL_RX_COPY_THRESHOLD      256
+#define VXGE_DEF_FIFO_LENGTH           84
+
+#define NO_STEERING            0
+#define PORT_STEERING          0x1
+#define RTH_STEERING           0x2
+#define RX_TOS_STEERING                0x3
+#define RX_VLAN_STEERING       0x4
+#define RTH_BUCKET_SIZE                4
+
+#define        TX_PRIORITY_STEERING    1
+#define        TX_VLAN_STEERING        2
+#define        TX_PORT_STEERING        3
+#define        TX_MULTIQ_STEERING      4
+
+#define VXGE_HW_MAC_ADDR_LEARN_DEFAULT VXGE_HW_RTS_MAC_DISABLE
+
+#define VXGE_TTI_BTIMER_VAL 250000
+
+#define VXGE_TTI_LTIMER_VAL 1000
+#define VXGE_TTI_RTIMER_VAL 0
+#define VXGE_RTI_BTIMER_VAL 250
+#define VXGE_RTI_LTIMER_VAL 100
+#define VXGE_RTI_RTIMER_VAL 0
+#define VXGE_FIFO_INDICATE_MAX_PKTS VXGE_DEF_FIFO_LENGTH
+#define VXGE_ISR_POLLING_CNT   8
+#define VXGE_MAX_CONFIG_DEV    0xFF
+#define VXGE_EXEC_MODE_DISABLE 0
+#define VXGE_EXEC_MODE_ENABLE  1
+#define VXGE_MAX_CONFIG_PORT   1
+#define VXGE_ALL_VID_DISABLE   0
+#define VXGE_ALL_VID_ENABLE    1
+#define VXGE_PAUSE_CTRL_DISABLE        0
+#define VXGE_PAUSE_CTRL_ENABLE 1
+
+#define TTI_TX_URANGE_A        5
+#define TTI_TX_URANGE_B        15
+#define TTI_TX_URANGE_C        40
+#define TTI_TX_UFC_A   5
+#define TTI_TX_UFC_B   40
+#define TTI_TX_UFC_C   60
+#define TTI_TX_UFC_D   100
+
+#define RTI_RX_URANGE_A        5
+#define RTI_RX_URANGE_B        15
+#define RTI_RX_URANGE_C        40
+#define RTI_RX_UFC_A   1
+#define RTI_RX_UFC_B   5
+#define RTI_RX_UFC_C   10
+#define RTI_RX_UFC_D   15
+
+/* Milli secs timer period */
+#define VXGE_TIMER_DELAY               10000
+
+#define VXGE_LL_MAX_FRAME_SIZE(dev) ((dev)->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE)
+
+enum vxge_reset_event {
+       /* reset events */
+       VXGE_LL_VPATH_RESET     = 0,
+       VXGE_LL_DEVICE_RESET    = 1,
+       VXGE_LL_FULL_RESET      = 2,
+       VXGE_LL_START_RESET     = 3,
+       VXGE_LL_COMPL_RESET     = 4
+};
+/* These flags represent the devices temporary state */
+enum vxge_device_state_t {
+__VXGE_STATE_RESET_CARD = 0,
+__VXGE_STATE_CARD_UP
+};
+
+enum vxge_mac_addr_state {
+       /* mac address states */
+       VXGE_LL_MAC_ADDR_IN_LIST        = 0,
+       VXGE_LL_MAC_ADDR_IN_DA_TABLE    = 1
+};
+
+struct vxge_drv_config {
+       int config_dev_cnt;
+       int total_dev_cnt;
+       unsigned long inta_dev_open;
+       int g_no_cpus;
+       unsigned int vpath_per_dev;
+};
+
+struct macInfo {
+       unsigned char macaddr[ETH_ALEN];
+       unsigned char macmask[ETH_ALEN];
+       unsigned int vpath_no;
+       enum vxge_mac_addr_state state;
+};
+
+struct vxge_config {
+       int             tx_pause_enable;
+       int             rx_pause_enable;
+
+#define        NEW_NAPI_WEIGHT 64
+       int             napi_weight;
+#define VXGE_GRO_DONOT_AGGREGATE               0
+#define VXGE_GRO_ALWAYS_AGGREGATE              1
+       int             gro_enable;
+       int             intr_type;
+#define INTA   0
+#define MSI    1
+#define MSI_X  2
+
+       int             addr_learn_en;
+
+       int             rth_steering;
+       int             rth_algorithm;
+       int             rth_hash_type_tcpipv4;
+       int             rth_hash_type_ipv4;
+       int             rth_hash_type_tcpipv6;
+       int             rth_hash_type_ipv6;
+       int             rth_hash_type_tcpipv6ex;
+       int             rth_hash_type_ipv6ex;
+       int             rth_bkt_sz;
+       int             rth_jhash_golden_ratio;
+       int             tx_steering_type;
+       int     fifo_indicate_max_pkts;
+       struct vxge_hw_device_hw_info device_hw_info;
+};
+
+struct vxge_msix_entry {
+       /* Mimicing the msix_entry struct of Kernel. */
+       u16 vector;
+       u16 entry;
+       u16 in_use;
+       void *arg;
+};
+
+/* Software Statistics */
+
+struct vxge_sw_stats {
+       /* Network Stats (interface stats) */
+       struct net_device_stats net_stats;
+
+       /* Tx */
+       u64 tx_frms;
+       u64 tx_errors;
+       u64 tx_bytes;
+       u64 txd_not_free;
+       u64 txd_out_of_desc;
+
+       /* Virtual Path */
+       u64 vpaths_open;
+       u64 vpath_open_fail;
+
+       /* Rx */
+       u64 rx_frms;
+       u64 rx_errors;
+       u64 rx_bytes;
+       u64 rx_mcast;
+
+       /* Misc. */
+       u64 link_up;
+       u64 link_down;
+       u64 pci_map_fail;
+       u64 skb_alloc_fail;
+};
+
+struct vxge_mac_addrs {
+       struct list_head item;
+       u64 macaddr;
+       u64 macmask;
+       enum vxge_mac_addr_state state;
+};
+
+struct vxgedev;
+
+struct vxge_fifo_stats {
+       u64 tx_frms;
+       u64 tx_errors;
+       u64 tx_bytes;
+       u64 txd_not_free;
+       u64 txd_out_of_desc;
+       u64 pci_map_fail;
+};
+
+struct vxge_fifo {
+       struct net_device       *ndev;
+       struct pci_dev          *pdev;
+       struct __vxge_hw_fifo *handle;
+
+       /* The vpath id maintained in the driver -
+        * 0 to 'maximum_vpaths_in_function - 1'
+        */
+       int driver_id;
+       int tx_steering_type;
+       int indicate_max_pkts;
+       spinlock_t tx_lock;
+       /* flag used to maintain queue state when MULTIQ is not enabled */
+#define VPATH_QUEUE_START       0
+#define VPATH_QUEUE_STOP        1
+       int queue_state;
+
+       /* Tx stats */
+       struct vxge_fifo_stats stats;
+} ____cacheline_aligned;
+
+struct vxge_ring_stats {
+       u64 prev_rx_frms;
+       u64 rx_frms;
+       u64 rx_errors;
+       u64 rx_dropped;
+       u64 rx_bytes;
+       u64 rx_mcast;
+       u64 pci_map_fail;
+       u64 skb_alloc_fail;
+};
+
+struct vxge_ring {
+       struct net_device       *ndev;
+       struct pci_dev          *pdev;
+       struct __vxge_hw_ring   *handle;
+       /* The vpath id maintained in the driver -
+        * 0 to 'maximum_vpaths_in_function - 1'
+        */
+       int driver_id;
+
+        /* copy of the flag indicating whether rx_csum is to be used */
+       u32 rx_csum;
+
+       int pkts_processed;
+       int budget;
+       int gro_enable;
+
+       struct napi_struct napi;
+
+#define VXGE_MAX_MAC_ADDR_COUNT                30
+
+       int vlan_tag_strip;
+       struct vlan_group *vlgrp;
+       int rx_vector_no;
+       enum vxge_hw_status last_status;
+
+       /* Rx stats */
+       struct vxge_ring_stats stats;
+} ____cacheline_aligned;
+
+struct vxge_vpath {
+
+       struct vxge_fifo fifo;
+       struct vxge_ring ring;
+
+       struct __vxge_hw_vpath_handle *handle;
+
+       /* Actual vpath id for this vpath in the device - 0 to 16 */
+       int device_id;
+       int max_mac_addr_cnt;
+       int is_configured;
+       int is_open;
+       struct vxgedev *vdev;
+       u8 (macaddr)[ETH_ALEN];
+       u8 (macmask)[ETH_ALEN];
+
+#define VXGE_MAX_LEARN_MAC_ADDR_CNT    2048
+       /* mac addresses currently programmed into NIC */
+       u16 mac_addr_cnt;
+       u16 mcast_addr_cnt;
+       struct list_head mac_addr_list;
+
+       u32 level_err;
+       u32 level_trace;
+};
+#define VXGE_COPY_DEBUG_INFO_TO_LL(vdev, err, trace) { \
+       for (i = 0; i < vdev->no_of_vpath; i++) {               \
+               vdev->vpaths[i].level_err = err;                \
+               vdev->vpaths[i].level_trace = trace;            \
+       }                                                       \
+       vdev->level_err = err;                                  \
+       vdev->level_trace = trace;                              \
+}
+
+struct vxgedev {
+       struct net_device       *ndev;
+       struct pci_dev          *pdev;
+       struct __vxge_hw_device *devh;
+       struct vlan_group       *vlgrp;
+       int vlan_tag_strip;
+       struct vxge_config      config;
+       unsigned long   state;
+
+       /* Indicates which vpath to reset */
+       unsigned long  vp_reset;
+
+       /* Timer used for polling vpath resets */
+       struct timer_list vp_reset_timer;
+
+       /* Timer used for polling vpath lockup */
+       struct timer_list vp_lockup_timer;
+
+       /*
+        * Flags to track whether device is in All Multicast
+        * or in promiscuous mode.
+        */
+       u16             all_multi_flg;
+
+        /* A flag indicating whether rx_csum is to be used or not. */
+       u32     rx_csum;
+
+       struct vxge_msix_entry *vxge_entries;
+       struct msix_entry *entries;
+       /*
+        * 4 for each vpath * 17;
+        * total is 68
+        */
+#define        VXGE_MAX_REQUESTED_MSIX 68
+#define VXGE_INTR_STRLEN 80
+       char desc[VXGE_MAX_REQUESTED_MSIX][VXGE_INTR_STRLEN];
+
+       enum vxge_hw_event cric_err_event;
+
+       int max_vpath_supported;
+       int no_of_vpath;
+
+       struct napi_struct napi;
+       /* A debug option, when enabled and if error condition occurs,
+        * the driver will do following steps:
+        * - mask all interrupts
+        * - Not clear the source of the alarm
+        * - gracefully stop all I/O
+        * A diagnostic dump of register and stats at this point
+        * reveals very useful information.
+        */
+       int exec_mode;
+       int max_config_port;
+       struct vxge_vpath       *vpaths;
+
+       struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS];
+       void __iomem *bar0;
+       void __iomem *bar1;
+       struct vxge_sw_stats    stats;
+       int             mtu;
+       /* Below variables are used for vpath selection to transmit a packet */
+       u8              vpath_selector[VXGE_HW_MAX_VIRTUAL_PATHS];
+       u64             vpaths_deployed;
+
+       u32             intr_cnt;
+       u32             level_err;
+       u32             level_trace;
+       char            fw_version[VXGE_HW_FW_STRLEN];
+};
+
+struct vxge_rx_priv {
+       struct sk_buff          *skb;
+       dma_addr_t              data_dma;
+       dma_addr_t              data_size;
+};
+
+struct vxge_tx_priv {
+       struct sk_buff          *skb;
+       dma_addr_t              dma_buffers[MAX_SKB_FRAGS+1];
+};
+
+#define VXGE_MODULE_PARAM_INT(p, val) \
+       static int p = val; \
+       module_param(p, int, 0)
+
+#define vxge_os_bug(fmt...)            { printk(fmt); BUG(); }
+
+#define vxge_os_timer(timer, handle, arg, exp) do { \
+               init_timer(&timer); \
+               timer.function = handle; \
+               timer.data = (unsigned long) arg; \
+               mod_timer(&timer, (jiffies + exp)); \
+       } while (0);
+
+int __devinit vxge_device_register(struct __vxge_hw_device *devh,
+                                   struct vxge_config *config,
+                                   int high_dma, int no_of_vpath,
+                                   struct vxgedev **vdev);
+
+void vxge_device_unregister(struct __vxge_hw_device *devh);
+
+void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id);
+
+void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id);
+
+void vxge_callback_link_up(struct __vxge_hw_device *devh);
+
+void vxge_callback_link_down(struct __vxge_hw_device *devh);
+
+enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
+       struct macInfo *mac);
+
+int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac);
+
+int vxge_reset(struct vxgedev *vdev);
+
+enum vxge_hw_status
+vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
+       u8 t_code, void *userdata);
+
+enum vxge_hw_status
+vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
+       enum vxge_hw_fifo_tcode t_code, void *userdata, void **skb_ptr);
+
+int vxge_close(struct net_device *dev);
+
+int vxge_open(struct net_device *dev);
+
+void vxge_close_vpaths(struct vxgedev *vdev, int index);
+
+int vxge_open_vpaths(struct vxgedev *vdev);
+
+enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
+
+void vxge_stop_all_tx_queue(struct vxgedev *vdev);
+
+void vxge_stop_tx_queue(struct vxge_fifo *fifo);
+
+void vxge_start_all_tx_queue(struct vxgedev *vdev);
+
+void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb);
+
+enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
+       struct macInfo *mac);
+
+enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev,
+       struct macInfo *mac);
+
+int vxge_mac_list_add(struct vxge_vpath *vpath,
+       struct macInfo *mac);
+
+void vxge_free_mac_add_list(struct vxge_vpath *vpath);
+
+enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath);
+
+enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath);
+
+int do_vxge_close(struct net_device *dev, int do_io);
+extern void initialize_ethtool_ops(struct net_device *ndev);
+/**
+ * #define VXGE_DEBUG_INIT: debug for initialization functions
+ * #define VXGE_DEBUG_TX        : debug transmit related functions
+ * #define VXGE_DEBUG_RX  : debug recevice related functions
+ * #define VXGE_DEBUG_MEM : debug memory module
+ * #define VXGE_DEBUG_LOCK: debug locks
+ * #define VXGE_DEBUG_SEM : debug semaphore
+ * #define VXGE_DEBUG_ENTRYEXIT: debug functions by adding entry exit statements
+*/
+#define VXGE_DEBUG_INIT                0x00000001
+#define VXGE_DEBUG_TX          0x00000002
+#define VXGE_DEBUG_RX          0x00000004
+#define VXGE_DEBUG_MEM         0x00000008
+#define VXGE_DEBUG_LOCK                0x00000010
+#define VXGE_DEBUG_SEM         0x00000020
+#define VXGE_DEBUG_ENTRYEXIT   0x00000040
+#define VXGE_DEBUG_INTR                0x00000080
+#define VXGE_DEBUG_LL_CONFIG   0x00000100
+
+/* Debug tracing for VXGE driver */
+#ifndef VXGE_DEBUG_MASK
+#define VXGE_DEBUG_MASK        0x0
+#endif
+
+#if (VXGE_DEBUG_LL_CONFIG & VXGE_DEBUG_MASK)
+#define vxge_debug_ll_config(level, fmt, ...) \
+       vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, __VA_ARGS__)
+#else
+#define vxge_debug_ll_config(level, fmt, ...)
+#endif
+
+#if (VXGE_DEBUG_INIT & VXGE_DEBUG_MASK)
+#define vxge_debug_init(level, fmt, ...) \
+       vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, __VA_ARGS__)
+#else
+#define vxge_debug_init(level, fmt, ...)
+#endif
+
+#if (VXGE_DEBUG_TX & VXGE_DEBUG_MASK)
+#define vxge_debug_tx(level, fmt, ...) \
+       vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, __VA_ARGS__)
+#else
+#define vxge_debug_tx(level, fmt, ...)
+#endif
+
+#if (VXGE_DEBUG_RX & VXGE_DEBUG_MASK)
+#define vxge_debug_rx(level, fmt, ...) \
+       vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, __VA_ARGS__)
+#else
+#define vxge_debug_rx(level, fmt, ...)
+#endif
+
+#if (VXGE_DEBUG_MEM & VXGE_DEBUG_MASK)
+#define vxge_debug_mem(level, fmt, ...) \
+       vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, __VA_ARGS__)
+#else
+#define vxge_debug_mem(level, fmt, ...)
+#endif
+
+#if (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)
+#define vxge_debug_entryexit(level, fmt, ...) \
+       vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, __VA_ARGS__)
+#else
+#define vxge_debug_entryexit(level, fmt, ...)
+#endif
+
+#if (VXGE_DEBUG_INTR & VXGE_DEBUG_MASK)
+#define vxge_debug_intr(level, fmt, ...) \
+       vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, __VA_ARGS__)
+#else
+#define vxge_debug_intr(level, fmt, ...)
+#endif
+
+#define VXGE_DEVICE_DEBUG_LEVEL_SET(level, mask, vdev) {\
+       vxge_hw_device_debug_set((struct __vxge_hw_device  *)vdev->devh, \
+               level, mask);\
+       VXGE_COPY_DEBUG_INFO_TO_LL(vdev, \
+               vxge_hw_device_error_level_get((struct __vxge_hw_device  *) \
+                       vdev->devh), \
+               vxge_hw_device_trace_level_get((struct __vxge_hw_device  *) \
+                       vdev->devh));\
+}
+
+#ifdef NETIF_F_GSO
+#define vxge_tcp_mss(skb) (skb_shinfo(skb)->gso_size)
+#define vxge_udp_mss(skb) (skb_shinfo(skb)->gso_size)
+#define vxge_offload_type(skb) (skb_shinfo(skb)->gso_type)
+#endif
+
+#endif
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
new file mode 100644 (file)
index 0000000..10f4da3
--- /dev/null
@@ -0,0 +1,4608 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-reg.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized
+ *             Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#ifndef VXGE_REG_H
+#define VXGE_REG_H
+
+/*
+ * vxge_mBIT(loc) - set bit at offset
+ */
+#define vxge_mBIT(loc)         (0x8000000000000000ULL >> (loc))
+
+/*
+ * vxge_vBIT(val, loc, sz) - set bits at offset
+ */
+#define vxge_vBIT(val, loc, sz)        (((u64)(val)) << (64-(loc)-(sz)))
+#define vxge_vBIT32(val, loc, sz)      (((u32)(val)) << (32-(loc)-(sz)))
+
+/*
+ * vxge_bVALn(bits, loc, n) - Get the value of n bits at location
+ */
+#define vxge_bVALn(bits, loc, n) \
+       ((((u64)bits) >> (64-(loc+n))) & ((0x1ULL << n) - 1))
+
+#define        VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(bits) \
+                                                       vxge_bVALn(bits, 0, 16)
+#define        VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(bits) \
+                                                       vxge_bVALn(bits, 48, 8)
+#define        VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(bits) \
+                                                       vxge_bVALn(bits, 56, 8)
+
+#define        VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(bits) \
+                                                       vxge_bVALn(bits, 3, 5)
+#define        VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(bits) \
+                                                       vxge_bVALn(bits, 5, 3)
+#define VXGE_HW_PF_SW_RESET_COMMAND                            0xA5
+
+#define VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES            17
+#define VXGE_HW_TITAN_SRPCIM_REG_SPACES                        17
+#define VXGE_HW_TITAN_VPMGMT_REG_SPACES                        17
+#define VXGE_HW_TITAN_VPATH_REG_SPACES                 17
+
+#define VXGE_HW_ASIC_MODE_RESERVED                             0
+#define VXGE_HW_ASIC_MODE_NO_IOV                               1
+#define VXGE_HW_ASIC_MODE_SR_IOV                               2
+#define VXGE_HW_ASIC_MODE_MR_IOV                               3
+
+#define        VXGE_HW_TXMAC_GEN_CFG1_TMAC_PERMA_STOP_EN               vxge_mBIT(3)
+#define        VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_WIRE              vxge_mBIT(19)
+#define        VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_SWITCH    vxge_mBIT(23)
+#define        VXGE_HW_TXMAC_GEN_CFG1_HOST_APPEND_FCS                  vxge_mBIT(31)
+
+#define        VXGE_HW_VPATH_IS_FIRST_GET_VPATH_IS_FIRST(bits) vxge_bVALn(bits, 3, 1)
+
+#define        VXGE_HW_TIM_VPATH_ASSIGNMENT_GET_BMAP_ROOT(bits) \
+                                               vxge_bVALn(bits, 0, 32)
+
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN(bits) \
+                                                       vxge_bVALn(bits, 50, 14)
+
+#define        VXGE_HW_XMAC_VSPORT_CHOICES_VP_GET_VSPORT_VECTOR(bits) \
+                                                       vxge_bVALn(bits, 0, 17)
+
+#define        VXGE_HW_XMAC_VPATH_TO_VSPORT_VPMGMT_CLONE_GET_VSPORT_NUMBER(bits) \
+                                                       vxge_bVALn(bits, 3, 5)
+
+#define        VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE(bits) \
+                                                       vxge_bVALn(bits, 17, 15)
+
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_LEGACY_MODE                 0
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY            1
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_MULTI_OP_MODE               2
+
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MESSAGES_ONLY               0
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MULTI_OP_MODE               1
+
+#define        VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val) \
+                               (val&~VXGE_HW_TOC_KDFC_INITIAL_BIR(7))
+#define        VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val) \
+                               vxge_bVALn(val, 61, 3)
+#define        VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET(val) \
+                               (val&~VXGE_HW_TOC_USDC_INITIAL_BIR(7))
+#define        VXGE_HW_TOC_GET_USDC_INITIAL_BIR(val) \
+                               vxge_bVALn(val, 61, 3)
+
+#define        VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE(bits)   bits
+#define        VXGE_HW_TOC_KDFC_FIFO_STRIDE_GET_TOC_KDFC_FIFO_STRIDE(bits)     bits
+
+#define        VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR0(bits) \
+                                               vxge_bVALn(bits, 1, 15)
+#define        VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR1(bits) \
+                                               vxge_bVALn(bits, 17, 15)
+#define        VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR2(bits) \
+                                               vxge_bVALn(bits, 33, 15)
+
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_VAPTH_NUM(val) vxge_vBIT(val, 42, 5)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_NUM(val) vxge_vBIT(val, 47, 2)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_OFFSET(val) \
+                                       vxge_vBIT(val, 49, 15)
+
+#define VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER                  0
+#define VXGE_HW_PRC_CFG4_RING_MODE_THREE_BUFFER                        1
+#define VXGE_HW_PRC_CFG4_RING_MODE_FIVE_BUFFER                 2
+
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE_A                                0
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE_B                                2
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE_C                                1
+
+#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_READ                             0
+#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_WRITE                            1
+
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DA                  0
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_VID                 1
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_ETYPE               2
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_PN                  3
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RANGE_PN            4
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG         5
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT         6
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG       7
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK            8
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY             9
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_QOS                 10
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DS                  11
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT        12
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_FW_VERSION          13
+
+#define VXGE_HW_RTS_MGR_STEER_DATA0_GET_DA_MAC_ADDR(bits) \
+                                                       vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_MGR_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
+
+#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \
+                                                       vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MASK(val) vxge_vBIT(val, 0, 48)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_PRIVILEGED_MODE \
+                                                               vxge_mBIT(54)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_VPATH(bits) \
+                                                       vxge_bVALn(bits, 55, 5)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_VPATH(val) \
+                                                       vxge_vBIT(val, 55, 5)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_MODE(bits) \
+                                                       vxge_bVALn(bits, 62, 2)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MODE(val) vxge_vBIT(val, 62, 2)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY                  0
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY               1
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY           2
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY            3
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY                 0
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY                1
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY           3
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL                4
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ALL_CLEAR                  172
+
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA                0
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID               1
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_ETYPE             2
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_PN                3
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG       5
+#define        VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT  6
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG     7
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK          8
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY           9
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_QOS               10
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DS                11
+#define        VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT 12
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO           13
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(bits) \
+                                                       vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(bits) vxge_bVALn(bits, 0, 12)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(val) vxge_vBIT(val, 0, 12)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_ETYPE(bits)  vxge_bVALn(bits, 0, 11)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_ETYPE(val) vxge_vBIT(val, 0, 16)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_SRC_DEST_SEL(bits) \
+                                                       vxge_bVALn(bits, 3, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_SRC_DEST_SEL          vxge_mBIT(3)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_TCP_UDP_SEL(bits) \
+                                                       vxge_bVALn(bits, 7, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_TCP_UDP_SEL           vxge_mBIT(7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_PORT_NUM(bits) \
+                                                       vxge_bVALn(bits, 8, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_PORT_NUM(val) vxge_vBIT(val, 8, 16)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_EN(bits) \
+                                                       vxge_bVALn(bits, 3, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_EN           vxge_mBIT(3)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_BUCKET_SIZE(bits) \
+                                                       vxge_bVALn(bits, 4, 4)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(val) \
+                                                       vxge_vBIT(val, 4, 4)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ALG_SEL(bits) \
+                                                       vxge_bVALn(bits, 10, 2)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(val) \
+                                                       vxge_vBIT(val, 10, 2)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_JENKINS  0
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_MS_RSS   1
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_CRC32C   2
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV4_EN(bits) \
+                                                       vxge_bVALn(bits, 15, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV4_EN  vxge_mBIT(15)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV4_EN(bits) \
+                                                       vxge_bVALn(bits, 19, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV4_EN      vxge_mBIT(19)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EN(bits) \
+                                                       vxge_bVALn(bits, 23, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EN  vxge_mBIT(23)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EN(bits) \
+                                                       vxge_bVALn(bits, 27, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EN      vxge_mBIT(27)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EX_EN(bits) \
+                                                       vxge_bVALn(bits, 31, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EX_EN vxge_mBIT(31)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EX_EN(bits) \
+                                                       vxge_bVALn(bits, 35, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EX_EN   vxge_mBIT(35)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ACTIVE_TABLE(bits) \
+                                                       vxge_bVALn(bits, 39, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE     vxge_mBIT(39)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_REPL_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 43, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_REPL_ENTRY_EN    vxge_mBIT(43)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 3, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_ENTRY_EN     vxge_mBIT(3)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 9, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 9, 7)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 0, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 0, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 8, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN       vxge_mBIT(8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 9, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 9, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 16, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 16, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 24, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN       vxge_mBIT(24)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 25, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 25, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 0, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 0, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 8, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN       vxge_mBIT(8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 9, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 9, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 16, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 16, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 24, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN       vxge_mBIT(24)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 25, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 25, 7)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_GOLDEN_RATIO(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_GOLDEN_RATIO(val) \
+                                                       vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_INIT_VALUE(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_INIT_VALUE(val) \
+                                                       vxge_vBIT(val, 32, 32)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_SA_MASK(bits) \
+                                                       vxge_bVALn(bits, 0, 16)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_SA_MASK(val) \
+                                                       vxge_vBIT(val, 0, 16)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_DA_MASK(bits) \
+                                                       vxge_bVALn(bits, 16, 16)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_DA_MASK(val) \
+                                                       vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_SA_MASK(bits) \
+                                                       vxge_bVALn(bits, 32, 4)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_SA_MASK(val) \
+                                                       vxge_vBIT(val, 32, 4)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_DA_MASK(bits) \
+                                                       vxge_bVALn(bits, 36, 4)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_DA_MASK(val) \
+                                                       vxge_vBIT(val, 36, 4)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4SP_MASK(bits) \
+                                                       vxge_bVALn(bits, 40, 2)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4SP_MASK(val) \
+                                                       vxge_vBIT(val, 40, 2)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4DP_MASK(bits) \
+                                                       vxge_bVALn(bits, 42, 2)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4DP_MASK(val) \
+                                                       vxge_vBIT(val, 42, 2)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_KEY_KEY(bits) \
+                                                       vxge_bVALn(bits, 0, 64)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_KEY_KEY vxge_vBIT(val, 0, 64)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_QOS_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 3, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_QOS_ENTRY_EN             vxge_mBIT(3)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DS_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 3, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_DS_ENTRY_EN              vxge_mBIT(3)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \
+                                                       vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(val) \
+                                                       vxge_vBIT(val, 0, 48)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MODE(val) \
+                                                       vxge_vBIT(val, 62, 2)
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 0, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 0, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 8, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_ENTRY_EN       vxge_mBIT(8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 9, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 9, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 16, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 16, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 24, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_ENTRY_EN       vxge_mBIT(24)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 25, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 25, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 32, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 32, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 40, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_ENTRY_EN       vxge_mBIT(40)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 41, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 41, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_NUM(bits) \
+                                                       vxge_bVALn(bits, 48, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_NUM(val) \
+                                                       vxge_vBIT(val, 48, 8)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_ENTRY_EN(bits) \
+                                                       vxge_bVALn(bits, 56, 1)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_ENTRY_EN       vxge_mBIT(56)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_DATA(bits) \
+                                                       vxge_bVALn(bits, 57, 7)
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_DATA(val) \
+                                                       vxge_vBIT(val, 57, 7)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER           0
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER         1
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_VERSION               2
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE              3
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0                4
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_1                5
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_2                6
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3                7
+
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_ON                   1
+#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_OFF                  0
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(bits) \
+                                                       vxge_bVALn(bits, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_DAY(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(bits) \
+                                                       vxge_bVALn(bits, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MONTH(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(bits) \
+                                               vxge_bVALn(bits, 16, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_YEAR(val) \
+                                                       vxge_vBIT(val, 16, 16)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(bits) \
+                                               vxge_bVALn(bits, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MAJOR vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(bits) \
+                                               vxge_bVALn(bits, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MINOR vxge_vBIT(val, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(bits) \
+                                               vxge_bVALn(bits, 48, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_BUILD vxge_vBIT(val, 48, 16)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(bits) \
+                                               vxge_bVALn(bits, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_DAY(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(bits) \
+                                                       vxge_bVALn(bits, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MONTH(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(bits) \
+                                                       vxge_bVALn(bits, 16, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_YEAR(val) \
+                                                       vxge_vBIT(val, 16, 16)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(bits) \
+                                                       vxge_bVALn(bits, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MAJOR vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(bits) \
+                                                       vxge_bVALn(bits, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MINOR vxge_vBIT(val, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(bits) \
+                                                       vxge_bVALn(bits, 48, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_BUILD vxge_vBIT(val, 48, 16)
+
+#define        VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_GET_PPIF_SRPCIM_TO_VPATH_ALARM(bits)\
+                                                       vxge_bVALn(bits, 0, 18)
+
+#define        VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(bits) \
+                                                       vxge_bVALn(bits, 48, 16)
+#define        VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(bits)     vxge_bVALn(bits, 48, 16)
+#define        VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(bits)      (bits)
+#define        VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(bits)      (bits)
+#define        VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(bits\
+) vxge_bVALn(bits, 48, 16)
+#define        VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(bits) vxge_bVALn(bits, 0, 16)
+#define        VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(bits) \
+                                                       vxge_bVALn(bits, 16, 16)
+#define        VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(bits) \
+                                                       vxge_bVALn(bits, 32, 16)
+#define        VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(bits)  vxge_bVALn(bits, 0, 16)
+#define        VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(bits) \
+                                                       vxge_bVALn(bits, 16, 16)
+#define        VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(bits) \
+                                                       vxge_bVALn(bits, 32, 16)
+
+#define        VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_WR_DROP(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_RD_DROP(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_MRPCIM_DEBUG_STATS1_GET_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(bits\
+) vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_MRPCIM_DEBUG_STATS2_GET_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(bits\
+) vxge_bVALn(bits, 32, 32)
+#define \
+VXGE_HW_MRPCIM_DEBUG_STATS3_GET_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(bits) \
+       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_WR_VPIN_DROP(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_RD_VPIN_DROP(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT1(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT0(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT3(bits) \
+                                                       vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT2(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_GENSTATS_COUNT4_GET_GENSTATS_COUNT4(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_GENSTATS_COUNT5_GET_GENSTATS_COUNT5(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+
+#define        VXGE_HW_DEBUG_STATS0_GET_RSTDROP_MSG(bits)      vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_DEBUG_STATS0_GET_RSTDROP_CPL(bits)      vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT0(bits)  vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT1(bits)  vxge_bVALn(bits, 32, 32)
+#define        VXGE_HW_DEBUG_STATS2_GET_RSTDROP_CLIENT2(bits)  vxge_bVALn(bits, 0, 32)
+#define        VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_PH(bits)   vxge_bVALn(bits, 0, 16)
+#define        VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_NPH(bits)  vxge_bVALn(bits, 16, 16)
+#define        VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_CPLH(bits) vxge_bVALn(bits, 32, 16)
+#define        VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_PD(bits)   vxge_bVALn(bits, 0, 16)
+#define        VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_NPD(bits)  bVAL(bits, 16, 16)
+#define        VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_CPLD(bits) vxge_bVALn(bits, 32, 16)
+
+#define        VXGE_HW_DBG_STATS_TPA_TX_PATH_GET_TX_PERMITTED_FRMS(bits) \
+                                                       vxge_bVALn(bits, 32, 32)
+
+#define        VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT0_TX_ANY_FRMS(bits) \
+                                                       vxge_bVALn(bits, 0, 8)
+#define        VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT1_TX_ANY_FRMS(bits) \
+                                                       vxge_bVALn(bits, 8, 8)
+#define        VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT2_TX_ANY_FRMS(bits) \
+                                                       vxge_bVALn(bits, 16, 8)
+
+#define        VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT0_RX_ANY_FRMS(bits) \
+                                                       vxge_bVALn(bits, 0, 8)
+#define        VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT1_RX_ANY_FRMS(bits) \
+                                                       vxge_bVALn(bits, 8, 8)
+#define        VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT2_RX_ANY_FRMS(bits) \
+                                                       vxge_bVALn(bits, 16, 8)
+
+#define VXGE_HW_CONFIG_PRIV_H
+
+#define VXGE_HW_SWAPPER_INITIAL_VALUE                  0x0123456789abcdefULL
+#define VXGE_HW_SWAPPER_BYTE_SWAPPED                   0xefcdab8967452301ULL
+#define VXGE_HW_SWAPPER_BIT_FLIPPED                    0x80c4a2e691d5b3f7ULL
+#define VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED       0xf7b3d591e6a2c480ULL
+
+#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE          0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_DISABLE         0x0000000000000000ULL
+
+#define VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE           0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_READ_BIT_FLAP_DISABLE          0x0000000000000000ULL
+
+#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE         0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_DISABLE                0x0000000000000000ULL
+
+#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE          0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_DISABLE         0x0000000000000000ULL
+
+/*
+ * The registers are memory mapped and are native big-endian byte order. The
+ * little-endian hosts are handled by enabling hardware byte-swapping for
+ * register and dma operations.
+ */
+struct vxge_hw_legacy_reg {
+
+       u8      unused00010[0x00010];
+
+/*0x00010*/    u64     toc_swapper_fb;
+#define VXGE_HW_TOC_SWAPPER_FB_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00018*/    u64     pifm_rd_swap_en;
+#define VXGE_HW_PIFM_RD_SWAP_EN_PIFM_RD_SWAP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00020*/    u64     pifm_rd_flip_en;
+#define VXGE_HW_PIFM_RD_FLIP_EN_PIFM_RD_FLIP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00028*/    u64     pifm_wr_swap_en;
+#define VXGE_HW_PIFM_WR_SWAP_EN_PIFM_WR_SWAP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00030*/    u64     pifm_wr_flip_en;
+#define VXGE_HW_PIFM_WR_FLIP_EN_PIFM_WR_FLIP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00038*/    u64     toc_first_pointer;
+#define VXGE_HW_TOC_FIRST_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00040*/    u64     host_access_en;
+#define VXGE_HW_HOST_ACCESS_EN_HOST_ACCESS_EN(val) vxge_vBIT(val, 0, 64)
+
+} __packed;
+
+struct vxge_hw_toc_reg {
+
+       u8      unused00050[0x00050];
+
+/*0x00050*/    u64     toc_common_pointer;
+#define VXGE_HW_TOC_COMMON_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00058*/    u64     toc_memrepair_pointer;
+#define VXGE_HW_TOC_MEMREPAIR_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00060*/    u64     toc_pcicfgmgmt_pointer[17];
+#define VXGE_HW_TOC_PCICFGMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+       u8      unused001e0[0x001e0-0x000e8];
+
+/*0x001e0*/    u64     toc_mrpcim_pointer;
+#define VXGE_HW_TOC_MRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x001e8*/    u64     toc_srpcim_pointer[17];
+#define VXGE_HW_TOC_SRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+       u8      unused00278[0x00278-0x00270];
+
+/*0x00278*/    u64     toc_vpmgmt_pointer[17];
+#define VXGE_HW_TOC_VPMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+       u8      unused00390[0x00390-0x00300];
+
+/*0x00390*/    u64     toc_vpath_pointer[17];
+#define VXGE_HW_TOC_VPATH_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+       u8      unused004a0[0x004a0-0x00418];
+
+/*0x004a0*/    u64     toc_kdfc;
+#define VXGE_HW_TOC_KDFC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61)
+#define VXGE_HW_TOC_KDFC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3)
+/*0x004a8*/    u64     toc_usdc;
+#define VXGE_HW_TOC_USDC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61)
+#define VXGE_HW_TOC_USDC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3)
+/*0x004b0*/    u64     toc_kdfc_vpath_stride;
+#define        VXGE_HW_TOC_KDFC_VPATH_STRIDE_INITIAL_TOC_KDFC_VPATH_STRIDE(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x004b8*/    u64     toc_kdfc_fifo_stride;
+#define        VXGE_HW_TOC_KDFC_FIFO_STRIDE_INITIAL_TOC_KDFC_FIFO_STRIDE(val) \
+                                                       vxge_vBIT(val, 0, 64)
+
+} __packed;
+
+struct vxge_hw_common_reg {
+
+       u8      unused00a00[0x00a00];
+
+/*0x00a00*/    u64     prc_status1;
+#define VXGE_HW_PRC_STATUS1_PRC_VP_QUIESCENT(n)        vxge_mBIT(n)
+/*0x00a08*/    u64     rxdcm_reset_in_progress;
+#define VXGE_HW_RXDCM_RESET_IN_PROGRESS_PRC_VP(n)      vxge_mBIT(n)
+/*0x00a10*/    u64     replicq_flush_in_progress;
+#define VXGE_HW_REPLICQ_FLUSH_IN_PROGRESS_NOA_VP(n)    vxge_mBIT(n)
+/*0x00a18*/    u64     rxpe_cmds_reset_in_progress;
+#define VXGE_HW_RXPE_CMDS_RESET_IN_PROGRESS_NOA_VP(n)  vxge_mBIT(n)
+/*0x00a20*/    u64     mxp_cmds_reset_in_progress;
+#define VXGE_HW_MXP_CMDS_RESET_IN_PROGRESS_NOA_VP(n)   vxge_mBIT(n)
+/*0x00a28*/    u64     noffload_reset_in_progress;
+#define VXGE_HW_NOFFLOAD_RESET_IN_PROGRESS_PRC_VP(n)   vxge_mBIT(n)
+/*0x00a30*/    u64     rd_req_in_progress;
+#define VXGE_HW_RD_REQ_IN_PROGRESS_VP(n)       vxge_mBIT(n)
+/*0x00a38*/    u64     rd_req_outstanding;
+#define VXGE_HW_RD_REQ_OUTSTANDING_VP(n)       vxge_mBIT(n)
+/*0x00a40*/    u64     kdfc_reset_in_progress;
+#define VXGE_HW_KDFC_RESET_IN_PROGRESS_NOA_VP(n)       vxge_mBIT(n)
+       u8      unused00b00[0x00b00-0x00a48];
+
+/*0x00b00*/    u64     one_cfg_vp;
+#define VXGE_HW_ONE_CFG_VP_RDY(n)      vxge_mBIT(n)
+/*0x00b08*/    u64     one_common;
+#define VXGE_HW_ONE_COMMON_PET_VPATH_RESET_IN_PROGRESS(n)      vxge_mBIT(n)
+       u8      unused00b80[0x00b80-0x00b10];
+
+/*0x00b80*/    u64     tim_int_en;
+#define VXGE_HW_TIM_INT_EN_TIM_VP(n)   vxge_mBIT(n)
+/*0x00b88*/    u64     tim_set_int_en;
+#define VXGE_HW_TIM_SET_INT_EN_VP(n)   vxge_mBIT(n)
+/*0x00b90*/    u64     tim_clr_int_en;
+#define VXGE_HW_TIM_CLR_INT_EN_VP(n)   vxge_mBIT(n)
+/*0x00b98*/    u64     tim_mask_int_during_reset;
+#define VXGE_HW_TIM_MASK_INT_DURING_RESET_VPATH(n)     vxge_mBIT(n)
+/*0x00ba0*/    u64     tim_reset_in_progress;
+#define VXGE_HW_TIM_RESET_IN_PROGRESS_TIM_VPATH(n)     vxge_mBIT(n)
+/*0x00ba8*/    u64     tim_outstanding_bmap;
+#define VXGE_HW_TIM_OUTSTANDING_BMAP_TIM_VPATH(n)      vxge_mBIT(n)
+       u8      unused00c00[0x00c00-0x00bb0];
+
+/*0x00c00*/    u64     msg_reset_in_progress;
+#define VXGE_HW_MSG_RESET_IN_PROGRESS_MSG_COMPOSITE(val) vxge_vBIT(val, 0, 17)
+/*0x00c08*/    u64     msg_mxp_mr_ready;
+#define VXGE_HW_MSG_MXP_MR_READY_MP_BOOTED(n)  vxge_mBIT(n)
+/*0x00c10*/    u64     msg_uxp_mr_ready;
+#define VXGE_HW_MSG_UXP_MR_READY_UP_BOOTED(n)  vxge_mBIT(n)
+/*0x00c18*/    u64     msg_dmq_noni_rtl_prefetch;
+#define VXGE_HW_MSG_DMQ_NONI_RTL_PREFETCH_BYPASS_ENABLE(n)     vxge_mBIT(n)
+/*0x00c20*/    u64     msg_umq_rtl_bwr;
+#define VXGE_HW_MSG_UMQ_RTL_BWR_PREFETCH_DISABLE(n)    vxge_mBIT(n)
+       u8      unused00d00[0x00d00-0x00c28];
+
+/*0x00d00*/    u64     cmn_rsthdlr_cfg0;
+#define VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(val) vxge_vBIT(val, 0, 17)
+/*0x00d08*/    u64     cmn_rsthdlr_cfg1;
+#define VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET(val) vxge_vBIT(val, 0, 17)
+/*0x00d10*/    u64     cmn_rsthdlr_cfg2;
+#define VXGE_HW_CMN_RSTHDLR_CFG2_SW_RESET_FIFO0(val) vxge_vBIT(val, 0, 17)
+/*0x00d18*/    u64     cmn_rsthdlr_cfg3;
+#define VXGE_HW_CMN_RSTHDLR_CFG3_SW_RESET_FIFO1(val) vxge_vBIT(val, 0, 17)
+/*0x00d20*/    u64     cmn_rsthdlr_cfg4;
+#define VXGE_HW_CMN_RSTHDLR_CFG4_SW_RESET_FIFO2(val) vxge_vBIT(val, 0, 17)
+       u8      unused00d40[0x00d40-0x00d28];
+
+/*0x00d40*/    u64     cmn_rsthdlr_cfg8;
+#define VXGE_HW_CMN_RSTHDLR_CFG8_INCR_VPATH_INST_NUM(val) vxge_vBIT(val, 0, 17)
+/*0x00d48*/    u64     stats_cfg0;
+#define VXGE_HW_STATS_CFG0_STATS_ENABLE(val) vxge_vBIT(val, 0, 17)
+       u8      unused00da8[0x00da8-0x00d50];
+
+/*0x00da8*/    u64     clear_msix_mask_vect[4];
+#define VXGE_HW_CLEAR_MSIX_MASK_VECT_CLEAR_MSIX_MASK_VECT(val) \
+                                               vxge_vBIT(val, 0, 17)
+/*0x00dc8*/    u64     set_msix_mask_vect[4];
+#define VXGE_HW_SET_MSIX_MASK_VECT_SET_MSIX_MASK_VECT(val) vxge_vBIT(val, 0, 17)
+/*0x00de8*/    u64     clear_msix_mask_all_vect;
+#define        VXGE_HW_CLEAR_MSIX_MASK_ALL_VECT_CLEAR_MSIX_MASK_ALL_VECT(val)  \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x00df0*/    u64     set_msix_mask_all_vect;
+#define        VXGE_HW_SET_MSIX_MASK_ALL_VECT_SET_MSIX_MASK_ALL_VECT(val) \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x00df8*/    u64     mask_vector[4];
+#define VXGE_HW_MASK_VECTOR_MASK_VECTOR(val) vxge_vBIT(val, 0, 17)
+/*0x00e18*/    u64     msix_pending_vector[4];
+#define VXGE_HW_MSIX_PENDING_VECTOR_MSIX_PENDING_VECTOR(val) \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x00e38*/    u64     clr_msix_one_shot_vec[4];
+#define        VXGE_HW_CLR_MSIX_ONE_SHOT_VEC_CLR_MSIX_ONE_SHOT_VEC(val) \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x00e58*/    u64     titan_asic_id;
+#define VXGE_HW_TITAN_ASIC_ID_INITIAL_DEVICE_ID(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MAJOR_REVISION(val) vxge_vBIT(val, 48, 8)
+#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MINOR_REVISION(val) vxge_vBIT(val, 56, 8)
+/*0x00e60*/    u64     titan_general_int_status;
+#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_MRPCIM_ALARM_INT       vxge_mBIT(0)
+#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_SRPCIM_ALARM_INT       vxge_mBIT(1)
+#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT        vxge_mBIT(2)
+#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(val) \
+                                                       vxge_vBIT(val, 3, 17)
+       u8      unused00e70[0x00e70-0x00e68];
+
+/*0x00e70*/    u64     titan_mask_all_int;
+#define        VXGE_HW_TITAN_MASK_ALL_INT_ALARM        vxge_mBIT(7)
+#define        VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC      vxge_mBIT(15)
+       u8      unused00e80[0x00e80-0x00e78];
+
+/*0x00e80*/    u64     tim_int_status0;
+#define VXGE_HW_TIM_INT_STATUS0_TIM_INT_STATUS0(val) vxge_vBIT(val, 0, 64)
+/*0x00e88*/    u64     tim_int_mask0;
+#define VXGE_HW_TIM_INT_MASK0_TIM_INT_MASK0(val) vxge_vBIT(val, 0, 64)
+/*0x00e90*/    u64     tim_int_status1;
+#define VXGE_HW_TIM_INT_STATUS1_TIM_INT_STATUS1(val) vxge_vBIT(val, 0, 4)
+/*0x00e98*/    u64     tim_int_mask1;
+#define VXGE_HW_TIM_INT_MASK1_TIM_INT_MASK1(val) vxge_vBIT(val, 0, 4)
+/*0x00ea0*/    u64     rti_int_status;
+#define VXGE_HW_RTI_INT_STATUS_RTI_INT_STATUS(val) vxge_vBIT(val, 0, 17)
+/*0x00ea8*/    u64     rti_int_mask;
+#define VXGE_HW_RTI_INT_MASK_RTI_INT_MASK(val) vxge_vBIT(val, 0, 17)
+/*0x00eb0*/    u64     adapter_status;
+#define        VXGE_HW_ADAPTER_STATUS_RTDMA_RTDMA_READY        vxge_mBIT(0)
+#define        VXGE_HW_ADAPTER_STATUS_WRDMA_WRDMA_READY        vxge_mBIT(1)
+#define        VXGE_HW_ADAPTER_STATUS_KDFC_KDFC_READY  vxge_mBIT(2)
+#define        VXGE_HW_ADAPTER_STATUS_TPA_TMAC_BUF_EMPTY       vxge_mBIT(3)
+#define        VXGE_HW_ADAPTER_STATUS_RDCTL_PIC_QUIESCENT      vxge_mBIT(4)
+#define        VXGE_HW_ADAPTER_STATUS_XGMAC_NETWORK_FAULT      vxge_mBIT(5)
+#define        VXGE_HW_ADAPTER_STATUS_ROCRC_OFFLOAD_QUIESCENT  vxge_mBIT(6)
+#define        VXGE_HW_ADAPTER_STATUS_G3IF_FB_G3IF_FB_GDDR3_READY      vxge_mBIT(7)
+#define        VXGE_HW_ADAPTER_STATUS_G3IF_CM_G3IF_CM_GDDR3_READY      vxge_mBIT(8)
+#define        VXGE_HW_ADAPTER_STATUS_RIC_RIC_RUNNING  vxge_mBIT(9)
+#define        VXGE_HW_ADAPTER_STATUS_CMG_C_PLL_IN_LOCK        vxge_mBIT(10)
+#define        VXGE_HW_ADAPTER_STATUS_XGMAC_X_PLL_IN_LOCK      vxge_mBIT(11)
+#define        VXGE_HW_ADAPTER_STATUS_FBIF_M_PLL_IN_LOCK       vxge_mBIT(12)
+#define VXGE_HW_ADAPTER_STATUS_PCC_PCC_IDLE(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_ADAPTER_STATUS_ROCRC_RC_PRC_QUIESCENT(val) vxge_vBIT(val, 44, 8)
+/*0x00eb8*/    u64     gen_ctrl;
+#define        VXGE_HW_GEN_CTRL_SPI_MRPCIM_WR_DIS      vxge_mBIT(0)
+#define        VXGE_HW_GEN_CTRL_SPI_MRPCIM_RD_DIS      vxge_mBIT(1)
+#define        VXGE_HW_GEN_CTRL_SPI_SRPCIM_WR_DIS      vxge_mBIT(2)
+#define        VXGE_HW_GEN_CTRL_SPI_SRPCIM_RD_DIS      vxge_mBIT(3)
+#define        VXGE_HW_GEN_CTRL_SPI_DEBUG_DIS  vxge_mBIT(4)
+#define        VXGE_HW_GEN_CTRL_SPI_APP_LTSSM_TIMER_DIS        vxge_mBIT(5)
+#define VXGE_HW_GEN_CTRL_SPI_NOT_USED(val) vxge_vBIT(val, 6, 4)
+       u8      unused00ed0[0x00ed0-0x00ec0];
+
+/*0x00ed0*/    u64     adapter_ready;
+#define        VXGE_HW_ADAPTER_READY_ADAPTER_READY     vxge_mBIT(63)
+/*0x00ed8*/    u64     outstanding_read;
+#define VXGE_HW_OUTSTANDING_READ_OUTSTANDING_READ(val) vxge_vBIT(val, 0, 17)
+/*0x00ee0*/    u64     vpath_rst_in_prog;
+#define VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(val) vxge_vBIT(val, 0, 17)
+/*0x00ee8*/    u64     vpath_reg_modified;
+#define VXGE_HW_VPATH_REG_MODIFIED_VPATH_REG_MODIFIED(val) vxge_vBIT(val, 0, 17)
+       u8      unused00fc0[0x00fc0-0x00ef0];
+
+/*0x00fc0*/    u64     cp_reset_in_progress;
+#define VXGE_HW_CP_RESET_IN_PROGRESS_CP_VPATH(n)       vxge_mBIT(n)
+       u8      unused01080[0x01080-0x00fc8];
+
+/*0x01080*/    u64     xgmac_ready;
+#define VXGE_HW_XGMAC_READY_XMACJ_READY(val) vxge_vBIT(val, 0, 17)
+       u8      unused010c0[0x010c0-0x01088];
+
+/*0x010c0*/    u64     fbif_ready;
+#define VXGE_HW_FBIF_READY_FAU_READY(val) vxge_vBIT(val, 0, 17)
+       u8      unused01100[0x01100-0x010c8];
+
+/*0x01100*/    u64     vplane_assignments;
+#define VXGE_HW_VPLANE_ASSIGNMENTS_VPLANE_ASSIGNMENTS(val) vxge_vBIT(val, 3, 5)
+/*0x01108*/    u64     vpath_assignments;
+#define VXGE_HW_VPATH_ASSIGNMENTS_VPATH_ASSIGNMENTS(val) vxge_vBIT(val, 0, 17)
+/*0x01110*/    u64     resource_assignments;
+#define VXGE_HW_RESOURCE_ASSIGNMENTS_RESOURCE_ASSIGNMENTS(val) \
+                                               vxge_vBIT(val, 0, 17)
+/*0x01118*/    u64     host_type_assignments;
+#define        VXGE_HW_HOST_TYPE_ASSIGNMENTS_HOST_TYPE_ASSIGNMENTS(val) \
+                                                       vxge_vBIT(val, 5, 3)
+       u8      unused01128[0x01128-0x01120];
+
+/*0x01128*/    u64     max_resource_assignments;
+#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPLANE(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPATHS(val) \
+                                               vxge_vBIT(val, 11, 5)
+/*0x01130*/    u64     pf_vpath_assignments;
+#define VXGE_HW_PF_VPATH_ASSIGNMENTS_PF_VPATH_ASSIGNMENTS(val) \
+                                               vxge_vBIT(val, 0, 17)
+       u8      unused01200[0x01200-0x01138];
+
+/*0x01200*/    u64     rts_access_icmp;
+#define VXGE_HW_RTS_ACCESS_ICMP_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01208*/    u64     rts_access_tcpsyn;
+#define VXGE_HW_RTS_ACCESS_TCPSYN_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01210*/    u64     rts_access_zl4pyld;
+#define VXGE_HW_RTS_ACCESS_ZL4PYLD_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01218*/    u64     rts_access_l4prtcl_tcp;
+#define VXGE_HW_RTS_ACCESS_L4PRTCL_TCP_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01220*/    u64     rts_access_l4prtcl_udp;
+#define VXGE_HW_RTS_ACCESS_L4PRTCL_UDP_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01228*/    u64     rts_access_l4prtcl_flex;
+#define VXGE_HW_RTS_ACCESS_L4PRTCL_FLEX_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01230*/    u64     rts_access_ipfrag;
+#define VXGE_HW_RTS_ACCESS_IPFRAG_EN(val) vxge_vBIT(val, 0, 17)
+
+} __packed;
+
+struct vxge_hw_memrepair_reg {
+       u64     unused1;
+       u64     unused2;
+} __packed;
+
+struct vxge_hw_pcicfgmgmt_reg {
+
+/*0x00000*/    u64     resource_no;
+#define        VXGE_HW_RESOURCE_NO_PFN_OR_VF   BIT(3)
+/*0x00008*/    u64     bargrp_pf_or_vf_bar0_mask;
+#define        VXGE_HW_BARGRP_PF_OR_VF_BAR0_MASK_BARGRP_PF_OR_VF_BAR0_MASK(val) \
+                                                       vxge_vBIT(val, 2, 6)
+/*0x00010*/    u64     bargrp_pf_or_vf_bar1_mask;
+#define        VXGE_HW_BARGRP_PF_OR_VF_BAR1_MASK_BARGRP_PF_OR_VF_BAR1_MASK(val) \
+                                                       vxge_vBIT(val, 2, 6)
+/*0x00018*/    u64     bargrp_pf_or_vf_bar2_mask;
+#define        VXGE_HW_BARGRP_PF_OR_VF_BAR2_MASK_BARGRP_PF_OR_VF_BAR2_MASK(val) \
+                                                       vxge_vBIT(val, 2, 6)
+/*0x00020*/    u64     msixgrp_no;
+#define VXGE_HW_MSIXGRP_NO_TABLE_SIZE(val) vxge_vBIT(val, 5, 11)
+
+} __packed;
+
+struct vxge_hw_mrpcim_reg {
+/*0x00000*/    u64     g3fbct_int_status;
+#define        VXGE_HW_G3FBCT_INT_STATUS_ERR_G3IF_INT  vxge_mBIT(0)
+/*0x00008*/    u64     g3fbct_int_mask;
+/*0x00010*/    u64     g3fbct_err_reg;
+#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_SM_ERR      vxge_mBIT(4)
+#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_DECC  vxge_mBIT(5)
+#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_DECC        vxge_mBIT(6)
+#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_DECC      vxge_mBIT(7)
+#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_SECC  vxge_mBIT(29)
+#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_SECC        vxge_mBIT(30)
+#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_SECC      vxge_mBIT(31)
+/*0x00018*/    u64     g3fbct_err_mask;
+/*0x00020*/    u64     g3fbct_err_alarm;
+
+       u8      unused00a00[0x00a00-0x00028];
+
+/*0x00a00*/    u64     wrdma_int_status;
+#define        VXGE_HW_WRDMA_INT_STATUS_RC_ALARM_RC_INT        vxge_mBIT(0)
+#define        VXGE_HW_WRDMA_INT_STATUS_RXDRM_SM_ERR_RXDRM_INT vxge_mBIT(1)
+#define        VXGE_HW_WRDMA_INT_STATUS_RXDCM_SM_ERR_RXDCM_SM_INT      vxge_mBIT(2)
+#define        VXGE_HW_WRDMA_INT_STATUS_RXDWM_SM_ERR_RXDWM_INT vxge_mBIT(3)
+#define        VXGE_HW_WRDMA_INT_STATUS_RDA_ERR_RDA_INT        vxge_mBIT(6)
+#define        VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_DB_RDA_ECC_DB_INT      vxge_mBIT(8)
+#define        VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_SG_RDA_ECC_SG_INT      vxge_mBIT(9)
+#define        VXGE_HW_WRDMA_INT_STATUS_FRF_ALARM_FRF_INT      vxge_mBIT(12)
+#define        VXGE_HW_WRDMA_INT_STATUS_ROCRC_ALARM_ROCRC_INT  vxge_mBIT(13)
+#define        VXGE_HW_WRDMA_INT_STATUS_WDE0_ALARM_WDE0_INT    vxge_mBIT(14)
+#define        VXGE_HW_WRDMA_INT_STATUS_WDE1_ALARM_WDE1_INT    vxge_mBIT(15)
+#define        VXGE_HW_WRDMA_INT_STATUS_WDE2_ALARM_WDE2_INT    vxge_mBIT(16)
+#define        VXGE_HW_WRDMA_INT_STATUS_WDE3_ALARM_WDE3_INT    vxge_mBIT(17)
+/*0x00a08*/    u64     wrdma_int_mask;
+/*0x00a10*/    u64     rc_alarm_reg;
+#define        VXGE_HW_RC_ALARM_REG_FTC_SM_ERR vxge_mBIT(0)
+#define        VXGE_HW_RC_ALARM_REG_FTC_SM_PHASE_ERR   vxge_mBIT(1)
+#define        VXGE_HW_RC_ALARM_REG_BTDWM_SM_ERR       vxge_mBIT(2)
+#define        VXGE_HW_RC_ALARM_REG_BTC_SM_ERR vxge_mBIT(3)
+#define        VXGE_HW_RC_ALARM_REG_BTDCM_SM_ERR       vxge_mBIT(4)
+#define        VXGE_HW_RC_ALARM_REG_BTDRM_SM_ERR       vxge_mBIT(5)
+#define        VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_DB_ERR      vxge_mBIT(6)
+#define        VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_SG_ERR      vxge_mBIT(7)
+#define        VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_DB_ERR     vxge_mBIT(8)
+#define        VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_SG_ERR     vxge_mBIT(9)
+#define        VXGE_HW_RC_ALARM_REG_RMM_SM_ERR vxge_mBIT(10)
+#define        VXGE_HW_RC_ALARM_REG_BTC_VPATH_MISMATCH_ERR     vxge_mBIT(12)
+/*0x00a18*/    u64     rc_alarm_mask;
+/*0x00a20*/    u64     rc_alarm_alarm;
+/*0x00a28*/    u64     rxdrm_sm_err_reg;
+#define VXGE_HW_RXDRM_SM_ERR_REG_PRC_VP(n)     vxge_mBIT(n)
+/*0x00a30*/    u64     rxdrm_sm_err_mask;
+/*0x00a38*/    u64     rxdrm_sm_err_alarm;
+/*0x00a40*/    u64     rxdcm_sm_err_reg;
+#define VXGE_HW_RXDCM_SM_ERR_REG_PRC_VP(n)     vxge_mBIT(n)
+/*0x00a48*/    u64     rxdcm_sm_err_mask;
+/*0x00a50*/    u64     rxdcm_sm_err_alarm;
+/*0x00a58*/    u64     rxdwm_sm_err_reg;
+#define VXGE_HW_RXDWM_SM_ERR_REG_PRC_VP(n)     vxge_mBIT(n)
+/*0x00a60*/    u64     rxdwm_sm_err_mask;
+/*0x00a68*/    u64     rxdwm_sm_err_alarm;
+/*0x00a70*/    u64     rda_err_reg;
+#define        VXGE_HW_RDA_ERR_REG_RDA_SM0_ERR_ALARM   vxge_mBIT(0)
+#define        VXGE_HW_RDA_ERR_REG_RDA_MISC_ERR        vxge_mBIT(1)
+#define        VXGE_HW_RDA_ERR_REG_RDA_PCIX_ERR        vxge_mBIT(2)
+#define        VXGE_HW_RDA_ERR_REG_RDA_RXD_ECC_DB_ERR  vxge_mBIT(3)
+#define        VXGE_HW_RDA_ERR_REG_RDA_FRM_ECC_DB_ERR  vxge_mBIT(4)
+#define        VXGE_HW_RDA_ERR_REG_RDA_UQM_ECC_DB_ERR  vxge_mBIT(5)
+#define        VXGE_HW_RDA_ERR_REG_RDA_IMM_ECC_DB_ERR  vxge_mBIT(6)
+#define        VXGE_HW_RDA_ERR_REG_RDA_TIM_ECC_DB_ERR  vxge_mBIT(7)
+/*0x00a78*/    u64     rda_err_mask;
+/*0x00a80*/    u64     rda_err_alarm;
+/*0x00a88*/    u64     rda_ecc_db_reg;
+#define VXGE_HW_RDA_ECC_DB_REG_RDA_RXD_ERR(n)  vxge_mBIT(n)
+/*0x00a90*/    u64     rda_ecc_db_mask;
+/*0x00a98*/    u64     rda_ecc_db_alarm;
+/*0x00aa0*/    u64     rda_ecc_sg_reg;
+#define VXGE_HW_RDA_ECC_SG_REG_RDA_RXD_ERR(n)  vxge_mBIT(n)
+/*0x00aa8*/    u64     rda_ecc_sg_mask;
+/*0x00ab0*/    u64     rda_ecc_sg_alarm;
+/*0x00ab8*/    u64     rqa_err_reg;
+#define        VXGE_HW_RQA_ERR_REG_RQA_SM_ERR_ALARM    vxge_mBIT(0)
+/*0x00ac0*/    u64     rqa_err_mask;
+/*0x00ac8*/    u64     rqa_err_alarm;
+/*0x00ad0*/    u64     frf_alarm_reg;
+#define VXGE_HW_FRF_ALARM_REG_PRC_VP_FRF_SM_ERR(n)     vxge_mBIT(n)
+/*0x00ad8*/    u64     frf_alarm_mask;
+/*0x00ae0*/    u64     frf_alarm_alarm;
+/*0x00ae8*/    u64     rocrc_alarm_reg;
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_DB      vxge_mBIT(0)
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_SG      vxge_mBIT(1)
+#define        VXGE_HW_ROCRC_ALARM_REG_NOA_NMA_SM_ERR  vxge_mBIT(2)
+#define        VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_DB vxge_mBIT(3)
+#define        VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_SG vxge_mBIT(4)
+#define        VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_DB vxge_mBIT(5)
+#define        VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_SG vxge_mBIT(6)
+#define        VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_DB vxge_mBIT(11)
+#define        VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_SG vxge_mBIT(12)
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_RSVD_ERR  vxge_mBIT(13)
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_OWN_ERR   vxge_mBIT(14)
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_BYP_OWN_ERR   vxge_mBIT(15)
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_NOT_ASSIGNED_ERR        vxge_mBIT(16)
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_RSVD_SYNC_ERR   vxge_mBIT(17)
+#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_LOST_EGB_ERR        vxge_mBIT(18)
+#define        VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ0_OVERFLOW      vxge_mBIT(19)
+#define        VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ1_OVERFLOW      vxge_mBIT(20)
+#define        VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ2_OVERFLOW      vxge_mBIT(21)
+#define        VXGE_HW_ROCRC_ALARM_REG_NOA_WCT_CMD_FIFO_ERR    vxge_mBIT(22)
+/*0x00af0*/    u64     rocrc_alarm_mask;
+/*0x00af8*/    u64     rocrc_alarm_alarm;
+/*0x00b00*/    u64     wde0_alarm_reg;
+#define        VXGE_HW_WDE0_ALARM_REG_WDE0_DCC_SM_ERR  vxge_mBIT(0)
+#define        VXGE_HW_WDE0_ALARM_REG_WDE0_PRM_SM_ERR  vxge_mBIT(1)
+#define        VXGE_HW_WDE0_ALARM_REG_WDE0_CP_SM_ERR   vxge_mBIT(2)
+#define        VXGE_HW_WDE0_ALARM_REG_WDE0_CP_CMD_ERR  vxge_mBIT(3)
+#define        VXGE_HW_WDE0_ALARM_REG_WDE0_PCR_SM_ERR  vxge_mBIT(4)
+/*0x00b08*/    u64     wde0_alarm_mask;
+/*0x00b10*/    u64     wde0_alarm_alarm;
+/*0x00b18*/    u64     wde1_alarm_reg;
+#define        VXGE_HW_WDE1_ALARM_REG_WDE1_DCC_SM_ERR  vxge_mBIT(0)
+#define        VXGE_HW_WDE1_ALARM_REG_WDE1_PRM_SM_ERR  vxge_mBIT(1)
+#define        VXGE_HW_WDE1_ALARM_REG_WDE1_CP_SM_ERR   vxge_mBIT(2)
+#define        VXGE_HW_WDE1_ALARM_REG_WDE1_CP_CMD_ERR  vxge_mBIT(3)
+#define        VXGE_HW_WDE1_ALARM_REG_WDE1_PCR_SM_ERR  vxge_mBIT(4)
+/*0x00b20*/    u64     wde1_alarm_mask;
+/*0x00b28*/    u64     wde1_alarm_alarm;
+/*0x00b30*/    u64     wde2_alarm_reg;
+#define        VXGE_HW_WDE2_ALARM_REG_WDE2_DCC_SM_ERR  vxge_mBIT(0)
+#define        VXGE_HW_WDE2_ALARM_REG_WDE2_PRM_SM_ERR  vxge_mBIT(1)
+#define        VXGE_HW_WDE2_ALARM_REG_WDE2_CP_SM_ERR   vxge_mBIT(2)
+#define        VXGE_HW_WDE2_ALARM_REG_WDE2_CP_CMD_ERR  vxge_mBIT(3)
+#define        VXGE_HW_WDE2_ALARM_REG_WDE2_PCR_SM_ERR  vxge_mBIT(4)
+/*0x00b38*/    u64     wde2_alarm_mask;
+/*0x00b40*/    u64     wde2_alarm_alarm;
+/*0x00b48*/    u64     wde3_alarm_reg;
+#define        VXGE_HW_WDE3_ALARM_REG_WDE3_DCC_SM_ERR  vxge_mBIT(0)
+#define        VXGE_HW_WDE3_ALARM_REG_WDE3_PRM_SM_ERR  vxge_mBIT(1)
+#define        VXGE_HW_WDE3_ALARM_REG_WDE3_CP_SM_ERR   vxge_mBIT(2)
+#define        VXGE_HW_WDE3_ALARM_REG_WDE3_CP_CMD_ERR  vxge_mBIT(3)
+#define        VXGE_HW_WDE3_ALARM_REG_WDE3_PCR_SM_ERR  vxge_mBIT(4)
+/*0x00b50*/    u64     wde3_alarm_mask;
+/*0x00b58*/    u64     wde3_alarm_alarm;
+
+       u8      unused00be8[0x00be8-0x00b60];
+
+/*0x00be8*/    u64     rx_w_round_robin_0;
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7(val) vxge_vBIT(val, 59, 5)
+/*0x00bf0*/    u64     rx_w_round_robin_1;
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_8(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_9(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_10(val) \
+                                               vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_11(val) \
+                                               vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_12(val) \
+                                               vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_13(val) \
+                                               vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_14(val) \
+                                               vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_15(val) \
+                                               vxge_vBIT(val, 59, 5)
+/*0x00bf8*/    u64     rx_w_round_robin_2;
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_16(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_17(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_18(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_19(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_20(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_21(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_22(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_23(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c00*/    u64     rx_w_round_robin_3;
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_24(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_25(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_26(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_27(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_28(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_29(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_30(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_31(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c08*/    u64     rx_w_round_robin_4;
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_32(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_33(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_34(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_35(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_36(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_37(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_38(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_39(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c10*/    u64     rx_w_round_robin_5;
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_40(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_41(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_42(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_43(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_44(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_45(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_46(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_47(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c18*/    u64     rx_w_round_robin_6;
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_48(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_49(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_50(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_51(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_52(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_53(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_54(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_55(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c20*/    u64     rx_w_round_robin_7;
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_56(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_57(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_58(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_59(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_60(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_61(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_62(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_63(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c28*/    u64     rx_w_round_robin_8;
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_64(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_65(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_66(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_67(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_68(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_69(val) \
+                                               vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_70(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_71(val) \
+                                               vxge_vBIT(val, 59, 5)
+/*0x00c30*/    u64     rx_w_round_robin_9;
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_72(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_73(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_74(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_75(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_76(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_77(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_78(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_79(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c38*/    u64     rx_w_round_robin_10;
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_80(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_81(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_82(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_83(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_84(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_85(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_86(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_87(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c40*/    u64     rx_w_round_robin_11;
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_88(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_89(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_90(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_91(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_92(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_93(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_94(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_95(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c48*/    u64     rx_w_round_robin_12;
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_96(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_97(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_98(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_99(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_100(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_101(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_102(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_103(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c50*/    u64     rx_w_round_robin_13;
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_104(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_105(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_106(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_107(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_108(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_109(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_110(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_111(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c58*/    u64     rx_w_round_robin_14;
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_112(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_113(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_114(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_115(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_116(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_117(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_118(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_119(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c60*/    u64     rx_w_round_robin_15;
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_120(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_121(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_122(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_123(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_124(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_125(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_126(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_127(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c68*/    u64     rx_w_round_robin_16;
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_128(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_129(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_130(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_131(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_132(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_133(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_134(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_135(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c70*/    u64     rx_w_round_robin_17;
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_136(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_137(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_138(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_139(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_140(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_141(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_142(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_143(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c78*/    u64     rx_w_round_robin_18;
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_144(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_145(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_146(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_147(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_148(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_149(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_150(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_151(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c80*/    u64     rx_w_round_robin_19;
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_152(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_153(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_154(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_155(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_156(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_157(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_158(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_159(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c88*/    u64     rx_w_round_robin_20;
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_160(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_161(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_162(val) \
+                                                       vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_163(val) \
+                                                       vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_164(val) \
+                                                       vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_165(val) \
+                                                       vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_166(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_167(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00c90*/    u64     rx_w_round_robin_21;
+#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_168(val) \
+                                                       vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_169(val) \
+                                                       vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_170(val) \
+                                                       vxge_vBIT(val, 19, 5)
+
+#define VXGE_HW_WRR_RING_SERVICE_STATES                        171
+#define VXGE_HW_WRR_RING_COUNT                         22
+
+/*0x00c98*/    u64     rx_queue_priority_0;
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+/*0x00ca0*/    u64     rx_queue_priority_1;
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(val) vxge_vBIT(val, 59, 5)
+/*0x00ca8*/    u64     rx_queue_priority_2;
+#define VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(val) vxge_vBIT(val, 3, 5)
+       u8      unused00cc8[0x00cc8-0x00cb0];
+
+/*0x00cc8*/    u64     replication_queue_priority;
+#define        VXGE_HW_REPLICATION_QUEUE_PRIORITY_REPLICATION_QUEUE_PRIORITY(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00cd0*/    u64     rx_queue_select;
+#define VXGE_HW_RX_QUEUE_SELECT_NUMBER(n)      vxge_mBIT(n)
+#define        VXGE_HW_RX_QUEUE_SELECT_ENABLE_CODE     vxge_mBIT(15)
+#define        VXGE_HW_RX_QUEUE_SELECT_ENABLE_HIERARCHICAL_PRTY        vxge_mBIT(23)
+/*0x00cd8*/    u64     rqa_vpbp_ctrl;
+#define        VXGE_HW_RQA_VPBP_CTRL_WR_XON_DIS        vxge_mBIT(15)
+#define        VXGE_HW_RQA_VPBP_CTRL_ROCRC_DIS vxge_mBIT(23)
+#define        VXGE_HW_RQA_VPBP_CTRL_TXPE_DIS  vxge_mBIT(31)
+/*0x00ce0*/    u64     rx_multi_cast_ctrl;
+#define        VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_DIS vxge_mBIT(0)
+#define        VXGE_HW_RX_MULTI_CAST_CTRL_FRM_DROP_DIS vxge_mBIT(1)
+#define VXGE_HW_RX_MULTI_CAST_CTRL_NO_RXD_TIME_OUT_CNT(val) \
+                                                       vxge_vBIT(val, 2, 30)
+#define VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_CNT(val) vxge_vBIT(val, 32, 32)
+/*0x00ce8*/    u64     wde_prm_ctrl;
+#define VXGE_HW_WDE_PRM_CTRL_SPAV_THRESHOLD(val) vxge_vBIT(val, 2, 10)
+#define VXGE_HW_WDE_PRM_CTRL_SPLIT_THRESHOLD(val) vxge_vBIT(val, 18, 14)
+#define        VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_1ST_ROW   vxge_mBIT(32)
+#define        VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_ROW_BNDRY vxge_mBIT(33)
+#define VXGE_HW_WDE_PRM_CTRL_FB_ROW_SIZE(val) vxge_vBIT(val, 46, 2)
+/*0x00cf0*/    u64     noa_ctrl;
+#define VXGE_HW_NOA_CTRL_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_NOA_CTRL_NON_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 11, 5)
+#define        VXGE_HW_NOA_CTRL_IGNORE_KDFC_IF_STATUS  vxge_mBIT(16)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE0(val) vxge_vBIT(val, 37, 4)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE1(val) vxge_vBIT(val, 45, 4)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE2(val) vxge_vBIT(val, 53, 4)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE3(val) vxge_vBIT(val, 60, 4)
+/*0x00cf8*/    u64     phase_cfg;
+#define        VXGE_HW_PHASE_CFG_QCC_WR_PHASE_EN       vxge_mBIT(0)
+#define        VXGE_HW_PHASE_CFG_QCC_RD_PHASE_EN       vxge_mBIT(3)
+#define        VXGE_HW_PHASE_CFG_IMMM_WR_PHASE_EN      vxge_mBIT(7)
+#define        VXGE_HW_PHASE_CFG_IMMM_RD_PHASE_EN      vxge_mBIT(11)
+#define        VXGE_HW_PHASE_CFG_UMQM_WR_PHASE_EN      vxge_mBIT(15)
+#define        VXGE_HW_PHASE_CFG_UMQM_RD_PHASE_EN      vxge_mBIT(19)
+#define        VXGE_HW_PHASE_CFG_RCBM_WR_PHASE_EN      vxge_mBIT(23)
+#define        VXGE_HW_PHASE_CFG_RCBM_RD_PHASE_EN      vxge_mBIT(27)
+#define        VXGE_HW_PHASE_CFG_RXD_RC_WR_PHASE_EN    vxge_mBIT(31)
+#define        VXGE_HW_PHASE_CFG_RXD_RC_RD_PHASE_EN    vxge_mBIT(35)
+#define        VXGE_HW_PHASE_CFG_RXD_RHS_WR_PHASE_EN   vxge_mBIT(39)
+#define        VXGE_HW_PHASE_CFG_RXD_RHS_RD_PHASE_EN   vxge_mBIT(43)
+/*0x00d00*/    u64     rcq_bypq_cfg;
+#define VXGE_HW_RCQ_BYPQ_CFG_OVERFLOW_THRESHOLD(val) vxge_vBIT(val, 10, 22)
+#define VXGE_HW_RCQ_BYPQ_CFG_BYP_ON_THRESHOLD(val) vxge_vBIT(val, 39, 9)
+#define VXGE_HW_RCQ_BYPQ_CFG_BYP_OFF_THRESHOLD(val) vxge_vBIT(val, 55, 9)
+       u8      unused00e00[0x00e00-0x00d08];
+
+/*0x00e00*/    u64     doorbell_int_status;
+#define        VXGE_HW_DOORBELL_INT_STATUS_KDFC_ERR_REG_TXDMA_KDFC_INT vxge_mBIT(7)
+#define        VXGE_HW_DOORBELL_INT_STATUS_USDC_ERR_REG_TXDMA_USDC_INT vxge_mBIT(15)
+/*0x00e08*/    u64     doorbell_int_mask;
+/*0x00e10*/    u64     kdfc_err_reg;
+#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_SG_ERR       vxge_mBIT(7)
+#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_DB_ERR       vxge_mBIT(15)
+#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_SM_ERR_ALARM     vxge_mBIT(23)
+#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_MISC_ERR_1       vxge_mBIT(32)
+#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_PCIX_ERR vxge_mBIT(39)
+/*0x00e18*/    u64     kdfc_err_mask;
+/*0x00e20*/    u64     kdfc_err_reg_alarm;
+#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_SG_ERR vxge_mBIT(7)
+#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_DB_ERR vxge_mBIT(15)
+#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_SM_ERR_ALARM       vxge_mBIT(23)
+#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_MISC_ERR_1 vxge_mBIT(32)
+#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_PCIX_ERR   vxge_mBIT(39)
+       u8      unused00e40[0x00e40-0x00e28];
+/*0x00e40*/    u64     kdfc_vp_partition_0;
+#define        VXGE_HW_KDFC_VP_PARTITION_0_ENABLE      vxge_mBIT(0)
+#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_0(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_0(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_1(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_1(val) vxge_vBIT(val, 49, 15)
+/*0x00e48*/    u64     kdfc_vp_partition_1;
+#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_2(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_2(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_3(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_3(val) vxge_vBIT(val, 49, 15)
+/*0x00e50*/    u64     kdfc_vp_partition_2;
+#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_4(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_4(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_5(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_5(val) vxge_vBIT(val, 49, 15)
+/*0x00e58*/    u64     kdfc_vp_partition_3;
+#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_6(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_6(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_7(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_7(val) vxge_vBIT(val, 49, 15)
+/*0x00e60*/    u64     kdfc_vp_partition_4;
+#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_8(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_9(val) vxge_vBIT(val, 49, 15)
+/*0x00e68*/    u64     kdfc_vp_partition_5;
+#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_10(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_11(val) vxge_vBIT(val, 49, 15)
+/*0x00e70*/    u64     kdfc_vp_partition_6;
+#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_12(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_13(val) vxge_vBIT(val, 49, 15)
+/*0x00e78*/    u64     kdfc_vp_partition_7;
+#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_14(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_15(val) vxge_vBIT(val, 49, 15)
+/*0x00e80*/    u64     kdfc_vp_partition_8;
+#define VXGE_HW_KDFC_VP_PARTITION_8_LENGTH_16(val) vxge_vBIT(val, 17, 15)
+/*0x00e88*/    u64     kdfc_w_round_robin_0;
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+
+       u8      unused0f28[0x0f28-0x0e90];
+
+/*0x00f28*/    u64     kdfc_w_round_robin_20;
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+
+#define VXGE_HW_WRR_FIFO_COUNT                         20
+
+       u8      unused0fc8[0x0fc8-0x0f30];
+
+/*0x00fc8*/    u64     kdfc_w_round_robin_40;
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+
+       u8      unused1068[0x01068-0x0fd0];
+
+/*0x01068*/    u64     kdfc_entry_type_sel_0;
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(val) vxge_vBIT(val, 6, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(val) vxge_vBIT(val, 14, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(val) vxge_vBIT(val, 22, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(val) vxge_vBIT(val, 30, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(val) vxge_vBIT(val, 38, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(val) vxge_vBIT(val, 46, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(val) vxge_vBIT(val, 54, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(val) vxge_vBIT(val, 62, 2)
+/*0x01070*/    u64     kdfc_entry_type_sel_1;
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(val) vxge_vBIT(val, 6, 2)
+/*0x01078*/    u64     kdfc_fifo_0_ctrl;
+#define VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_WEIGHTED_RR_SERVICE_STATES             176
+#define VXGE_HW_WRR_FIFO_SERVICE_STATES                        153
+
+       u8      unused1100[0x01100-0x1080];
+
+/*0x01100*/    u64     kdfc_fifo_17_ctrl;
+#define VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5)
+
+       u8      unused1600[0x01600-0x1108];
+
+/*0x01600*/    u64     rxmac_int_status;
+#define        VXGE_HW_RXMAC_INT_STATUS_RXMAC_GEN_ERR_RXMAC_GEN_INT    vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_INT_STATUS_RXMAC_ECC_ERR_RXMAC_ECC_INT    vxge_mBIT(7)
+#define        VXGE_HW_RXMAC_INT_STATUS_RXMAC_VARIOUS_ERR_RXMAC_VARIOUS_INT \
+                                                               vxge_mBIT(11)
+/*0x01608*/    u64     rxmac_int_mask;
+       u8      unused01618[0x01618-0x01610];
+
+/*0x01618*/    u64     rxmac_gen_err_reg;
+/*0x01620*/    u64     rxmac_gen_err_mask;
+/*0x01628*/    u64     rxmac_gen_err_alarm;
+/*0x01630*/    u64     rxmac_ecc_err_reg;
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_SG_ERR(val) \
+                                                       vxge_vBIT(val, 0, 4)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_DB_ERR(val) \
+                                                       vxge_vBIT(val, 4, 4)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_SG_ERR(val) \
+                                                       vxge_vBIT(val, 8, 4)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_DB_ERR(val) \
+                                                       vxge_vBIT(val, 12, 4)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_SG_ERR(val) \
+                                                       vxge_vBIT(val, 16, 4)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_DB_ERR(val) \
+                                                       vxge_vBIT(val, 20, 4)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_SG_ERR(val) \
+                                                       vxge_vBIT(val, 24, 2)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_DB_ERR(val) \
+                                                       vxge_vBIT(val, 26, 2)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_SG_ERR(val) \
+                                                       vxge_vBIT(val, 28, 2)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_DB_ERR(val) \
+                                                       vxge_vBIT(val, 30, 2)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_SG_ERR      vxge_mBIT(32)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_DB_ERR      vxge_mBIT(33)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_SG_ERR  vxge_mBIT(34)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_DB_ERR  vxge_mBIT(35)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_SG_ERR  vxge_mBIT(36)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_DB_ERR  vxge_mBIT(37)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_SG_ERR  vxge_mBIT(38)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_DB_ERR  vxge_mBIT(39)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_SG_ERR(val) \
+                                                       vxge_vBIT(val, 40, 7)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_DB_ERR(val) \
+                                                       vxge_vBIT(val, 47, 7)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_SG_ERR(val) \
+                                                       vxge_vBIT(val, 54, 3)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_DB_ERR(val) \
+                                                       vxge_vBIT(val, 57, 3)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_SG_ERR \
+                                                       vxge_mBIT(60)
+#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_DB_ERR \
+                                                       vxge_mBIT(61)
+/*0x01638*/    u64     rxmac_ecc_err_mask;
+/*0x01640*/    u64     rxmac_ecc_err_alarm;
+/*0x01648*/    u64     rxmac_various_err_reg;
+#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT0_FSM_ERR   vxge_mBIT(0)
+#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT1_FSM_ERR   vxge_mBIT(1)
+#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT2_FSM_ERR   vxge_mBIT(2)
+#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMACJ_RMACJ_FSM_ERR       vxge_mBIT(3)
+/*0x01650*/    u64     rxmac_various_err_mask;
+/*0x01658*/    u64     rxmac_various_err_alarm;
+/*0x01660*/    u64     rxmac_gen_cfg;
+#define        VXGE_HW_RXMAC_GEN_CFG_SCALE_RMAC_UTIL   vxge_mBIT(11)
+/*0x01668*/    u64     rxmac_authorize_all_addr;
+#define VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(n) vxge_mBIT(n)
+/*0x01670*/    u64     rxmac_authorize_all_vid;
+#define VXGE_HW_RXMAC_AUTHORIZE_ALL_VID_VP(n)  vxge_mBIT(n)
+       u8      unused016c0[0x016c0-0x01678];
+
+/*0x016c0*/    u64     rxmac_red_rate_repl_queue;
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR0(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR1(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR2(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR3(val) vxge_vBIT(val, 12, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR0(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR1(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR2(val) vxge_vBIT(val, 24, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR3(val) vxge_vBIT(val, 28, 4)
+#define        VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_TRICKLE_EN    vxge_mBIT(35)
+       u8      unused016e0[0x016e0-0x016c8];
+
+/*0x016e0*/    u64     rxmac_cfg0_port[3];
+#define        VXGE_HW_RXMAC_CFG0_PORT_RMAC_EN vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_CFG0_PORT_STRIP_FCS       vxge_mBIT(7)
+#define        VXGE_HW_RXMAC_CFG0_PORT_DISCARD_PFRM    vxge_mBIT(11)
+#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_FCS_ERR  vxge_mBIT(15)
+#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LONG_ERR vxge_mBIT(19)
+#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_USIZED_ERR       vxge_mBIT(23)
+#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LEN_MISMATCH     vxge_mBIT(27)
+#define VXGE_HW_RXMAC_CFG0_PORT_MAX_PYLD_LEN(val) vxge_vBIT(val, 50, 14)
+       u8      unused01710[0x01710-0x016f8];
+
+/*0x01710*/    u64     rxmac_cfg2_port[3];
+#define        VXGE_HW_RXMAC_CFG2_PORT_PROM_EN vxge_mBIT(3)
+/*0x01728*/    u64     rxmac_pause_cfg_port[3];
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN     vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN     vxge_mBIT(7)
+#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_ACCEL_SEND(val) vxge_vBIT(val, 9, 3)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_DUAL_THR   vxge_mBIT(15)
+#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_HIGH_PTIME(val) vxge_vBIT(val, 20, 16)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_FCS_ERR  vxge_mBIT(39)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_LEN_ERR  vxge_mBIT(43)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_LIMITER_EN vxge_mBIT(47)
+#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_MAX_LIMIT(val) vxge_vBIT(val, 48, 8)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_PERMIT_RATEMGMT_CTRL       vxge_mBIT(59)
+       u8      unused01758[0x01758-0x01740];
+
+/*0x01758*/    u64     rxmac_red_cfg0_port[3];
+#define VXGE_HW_RXMAC_RED_CFG0_PORT_RED_EN_VP(n)       vxge_mBIT(n)
+/*0x01770*/    u64     rxmac_red_cfg1_port[3];
+#define        VXGE_HW_RXMAC_RED_CFG1_PORT_FINE_EN     vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_RED_CFG1_PORT_RED_EN_REPL_QUEUE   vxge_mBIT(11)
+/*0x01788*/    u64     rxmac_red_cfg2_port[3];
+#define VXGE_HW_RXMAC_RED_CFG2_PORT_TRICKLE_EN_VP(n)   vxge_mBIT(n)
+/*0x017a0*/    u64     rxmac_link_util_port[3];
+#define        VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_UTILIZATION(val) \
+                                                       vxge_vBIT(val, 1, 7)
+#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_FRAC_UTIL(val) \
+                                                       vxge_vBIT(val, 12, 4)
+#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4)
+#define        VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_SCALE_FACTOR     vxge_mBIT(23)
+       u8      unused017d0[0x017d0-0x017b8];
+
+/*0x017d0*/    u64     rxmac_status_port[3];
+#define        VXGE_HW_RXMAC_STATUS_PORT_RMAC_RX_FRM_RCVD      vxge_mBIT(3)
+       u8      unused01800[0x01800-0x017e8];
+
+/*0x01800*/    u64     rxmac_rx_pa_cfg0;
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_IGNORE_FRAME_ERR       vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_SNAP_AB_N      vxge_mBIT(7)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_HAO vxge_mBIT(18)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_MOBILE_IPV6_HDRS       vxge_mBIT(19)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_IPV6_STOP_SEARCHING    vxge_mBIT(23)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_NO_PS_IF_UNKNOWN       vxge_mBIT(27)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_ETYPE       vxge_mBIT(35)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L3_CSUM_ERR    vxge_mBIT(39)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR  vxge_mBIT(43)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L4_CSUM_ERR    vxge_mBIT(47)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR  vxge_mBIT(51)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_RPA_ERR        vxge_mBIT(55)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_RPA_ERR      vxge_mBIT(59)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_JUMBO_SNAP_EN  vxge_mBIT(63)
+/*0x01808*/    u64     rxmac_rx_pa_cfg1;
+#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_TCP_INCL_PH  vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_TCP_INCL_PH  vxge_mBIT(7)
+#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_UDP_INCL_PH  vxge_mBIT(11)
+#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_UDP_INCL_PH  vxge_mBIT(15)
+#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_L4_INCL_CF        vxge_mBIT(19)
+#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_STRIP_VLAN_TAG    vxge_mBIT(23)
+       u8      unused01828[0x01828-0x01810];
+
+/*0x01828*/    u64     rts_mgr_cfg0;
+#define        VXGE_HW_RTS_MGR_CFG0_RTS_DP_SP_PRIORITY vxge_mBIT(3)
+#define VXGE_HW_RTS_MGR_CFG0_FLEX_L4PRTCL_VALUE(val) vxge_vBIT(val, 24, 8)
+#define        VXGE_HW_RTS_MGR_CFG0_ICMP_TRASH vxge_mBIT(35)
+#define        VXGE_HW_RTS_MGR_CFG0_TCPSYN_TRASH       vxge_mBIT(39)
+#define        VXGE_HW_RTS_MGR_CFG0_ZL4PYLD_TRASH      vxge_mBIT(43)
+#define        VXGE_HW_RTS_MGR_CFG0_L4PRTCL_TCP_TRASH  vxge_mBIT(47)
+#define        VXGE_HW_RTS_MGR_CFG0_L4PRTCL_UDP_TRASH  vxge_mBIT(51)
+#define        VXGE_HW_RTS_MGR_CFG0_L4PRTCL_FLEX_TRASH vxge_mBIT(55)
+#define        VXGE_HW_RTS_MGR_CFG0_IPFRAG_TRASH       vxge_mBIT(59)
+/*0x01830*/    u64     rts_mgr_cfg1;
+#define        VXGE_HW_RTS_MGR_CFG1_DA_ACTIVE_TABLE    vxge_mBIT(3)
+#define        VXGE_HW_RTS_MGR_CFG1_PN_ACTIVE_TABLE    vxge_mBIT(7)
+/*0x01838*/    u64     rts_mgr_criteria_priority;
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ETYPE(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ICMP_TCPSYN(val) vxge_vBIT(val, 9, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PN(val) vxge_vBIT(val, 13, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RANGE_L4PN(val) vxge_vBIT(val, 17, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RTH_IT(val) vxge_vBIT(val, 21, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_DS(val) vxge_vBIT(val, 25, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_QOS(val) vxge_vBIT(val, 29, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ZL4PYLD(val) vxge_vBIT(val, 33, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PRTCL(val) vxge_vBIT(val, 37, 3)
+/*0x01840*/    u64     rts_mgr_da_pause_cfg;
+#define VXGE_HW_RTS_MGR_DA_PAUSE_CFG_VPATH_VECTOR(val) vxge_vBIT(val, 0, 17)
+/*0x01848*/    u64     rts_mgr_da_slow_proto_cfg;
+#define VXGE_HW_RTS_MGR_DA_SLOW_PROTO_CFG_VPATH_VECTOR(val) \
+                                                       vxge_vBIT(val, 0, 17)
+       u8      unused01890[0x01890-0x01850];
+/*0x01890*/     u64     rts_mgr_cbasin_cfg;
+       u8      unused01968[0x01968-0x01898];
+
+/*0x01968*/    u64     dbg_stat_rx_any_frms;
+#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT0_RX_ANY_FRMS(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT1_RX_ANY_FRMS(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT2_RX_ANY_FRMS(val) \
+                                                       vxge_vBIT(val, 16, 8)
+       u8      unused01a00[0x01a00-0x01970];
+
+/*0x01a00*/    u64     rxmac_red_rate_vp[17];
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR0(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR1(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR2(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR3(val) vxge_vBIT(val, 12, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR0(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR1(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR2(val) vxge_vBIT(val, 24, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR3(val) vxge_vBIT(val, 28, 4)
+       u8      unused01e00[0x01e00-0x01a88];
+
+/*0x01e00*/    u64     xgmac_int_status;
+#define        VXGE_HW_XGMAC_INT_STATUS_XMAC_GEN_ERR_XMAC_GEN_INT      vxge_mBIT(3)
+#define        VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT0_XMAC_LINK_INT_PORT0 \
+                                                               vxge_mBIT(7)
+#define        VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT1_XMAC_LINK_INT_PORT1 \
+                                                               vxge_mBIT(11)
+#define        VXGE_HW_XGMAC_INT_STATUS_XGXS_GEN_ERR_XGXS_GEN_INT      vxge_mBIT(15)
+#define        VXGE_HW_XGMAC_INT_STATUS_ASIC_NTWK_ERR_ASIC_NTWK_INT    vxge_mBIT(19)
+#define        VXGE_HW_XGMAC_INT_STATUS_ASIC_GPIO_ERR_ASIC_GPIO_INT    vxge_mBIT(23)
+/*0x01e08*/    u64     xgmac_int_mask;
+/*0x01e10*/    u64     xmac_gen_err_reg;
+#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_ACTOR_CHURN_DETECTED \
+                                                               vxge_mBIT(7)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_PARTNER_CHURN_DETECTED \
+                                                               vxge_mBIT(11)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_RECEIVED_LACPDU vxge_mBIT(15)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_ACTOR_CHURN_DETECTED \
+                                                               vxge_mBIT(19)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_PARTNER_CHURN_DETECTED \
+                                                               vxge_mBIT(23)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_RECEIVED_LACPDU vxge_mBIT(27)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XLCM_LAG_FAILOVER_DETECTED     vxge_mBIT(31)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_SG_ERR(val) \
+                                                       vxge_vBIT(val, 40, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_DB_ERR(val) \
+                                                       vxge_vBIT(val, 42, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_SG_ERR(val) \
+                                                       vxge_vBIT(val, 44, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_DB_ERR(val) \
+                                                       vxge_vBIT(val, 46, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_SG_ERR(val) \
+                                                       vxge_vBIT(val, 48, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_DB_ERR(val) \
+                                                       vxge_vBIT(val, 50, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_SG_ERR(val) \
+                                                       vxge_vBIT(val, 52, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_DB_ERR(val) \
+                                                       vxge_vBIT(val, 54, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_SG_ERR(val) \
+                                                       vxge_vBIT(val, 56, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_DB_ERR(val) \
+                                                       vxge_vBIT(val, 58, 2)
+#define        VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR     vxge_mBIT(63)
+/*0x01e18*/    u64     xmac_gen_err_mask;
+/*0x01e20*/    u64     xmac_gen_err_alarm;
+/*0x01e28*/    u64     xmac_link_err_port_reg[2];
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN  vxge_mBIT(3)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP    vxge_mBIT(7)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN     vxge_mBIT(11)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_UP       vxge_mBIT(15)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_FAULT \
+                                                               vxge_mBIT(19)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_OK vxge_mBIT(23)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_DOWN  vxge_mBIT(27)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_UP    vxge_mBIT(31)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_RATE_CHANGE     vxge_mBIT(35)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV        vxge_mBIT(39)
+#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \
+                                                               vxge_mBIT(47)
+/*0x01e30*/    u64     xmac_link_err_port_mask[2];
+/*0x01e38*/    u64     xmac_link_err_port_alarm[2];
+/*0x01e58*/    u64     xgxs_gen_err_reg;
+#define        VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR      vxge_mBIT(63)
+/*0x01e60*/    u64     xgxs_gen_err_mask;
+/*0x01e68*/    u64     xgxs_gen_err_alarm;
+/*0x01e70*/    u64     asic_ntwk_err_reg;
+#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_DOWN       vxge_mBIT(3)
+#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_UP vxge_mBIT(7)
+#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_DOWN  vxge_mBIT(11)
+#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_UP    vxge_mBIT(15)
+#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT   vxge_mBIT(19)
+#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK      vxge_mBIT(23)
+/*0x01e78*/    u64     asic_ntwk_err_mask;
+/*0x01e80*/    u64     asic_ntwk_err_alarm;
+/*0x01e88*/    u64     asic_gpio_err_reg;
+#define VXGE_HW_ASIC_GPIO_ERR_REG_XMACJ_GPIO_INT(n)    vxge_mBIT(n)
+/*0x01e90*/    u64     asic_gpio_err_mask;
+/*0x01e98*/    u64     asic_gpio_err_alarm;
+/*0x01ea0*/    u64     xgmac_gen_status;
+#define        VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_OK  vxge_mBIT(3)
+#define        VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_DATA_RATE   vxge_mBIT(11)
+/*0x01ea8*/    u64     xgmac_gen_fw_memo_status;
+#define        VXGE_HW_XGMAC_GEN_FW_MEMO_STATUS_XMACJ_EVENTS_PENDING(val) \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x01eb0*/    u64     xgmac_gen_fw_memo_mask;
+#define VXGE_HW_XGMAC_GEN_FW_MEMO_MASK_MASK(val) vxge_vBIT(val, 0, 64)
+/*0x01eb8*/    u64     xgmac_gen_fw_vpath_to_vsport_status;
+#define        VXGE_HW_XGMAC_GEN_FW_VPATH_TO_VSPORT_STATUS_XMACJ_EVENTS_PENDING(val) \
+                                               vxge_vBIT(val, 0, 17)
+/*0x01ec0*/    u64     xgmac_main_cfg_port[2];
+#define        VXGE_HW_XGMAC_MAIN_CFG_PORT_PORT_EN     vxge_mBIT(3)
+       u8      unused01f40[0x01f40-0x01ed0];
+
+/*0x01f40*/    u64     xmac_gen_cfg;
+#define VXGE_HW_XMAC_GEN_CFG_RATEMGMT_MAC_RATE_SEL(val) vxge_vBIT(val, 2, 2)
+#define        VXGE_HW_XMAC_GEN_CFG_TX_HEAD_DROP_WHEN_FAULT    vxge_mBIT(7)
+#define        VXGE_HW_XMAC_GEN_CFG_FAULT_BEHAVIOUR    vxge_mBIT(27)
+#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_UP(val) vxge_vBIT(val, 28, 4)
+#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_DOWN(val) vxge_vBIT(val, 32, 4)
+/*0x01f48*/    u64     xmac_timestamp;
+#define        VXGE_HW_XMAC_TIMESTAMP_EN       vxge_mBIT(3)
+#define VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(val) vxge_vBIT(val, 6, 2)
+#define VXGE_HW_XMAC_TIMESTAMP_INTERVAL(val) vxge_vBIT(val, 12, 4)
+#define        VXGE_HW_XMAC_TIMESTAMP_TIMER_RESTART    vxge_mBIT(19)
+#define VXGE_HW_XMAC_TIMESTAMP_XMACJ_ROLLOVER_CNT(val) vxge_vBIT(val, 32, 16)
+/*0x01f50*/    u64     xmac_stats_gen_cfg;
+#define VXGE_HW_XMAC_STATS_GEN_CFG_PRTAGGR_CUM_TIMER(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_XMAC_STATS_GEN_CFG_VPATH_CUM_TIMER(val) vxge_vBIT(val, 8, 4)
+#define        VXGE_HW_XMAC_STATS_GEN_CFG_VLAN_HANDLING        vxge_mBIT(15)
+/*0x01f58*/    u64     xmac_stats_sys_cmd;
+#define VXGE_HW_XMAC_STATS_SYS_CMD_OP(val) vxge_vBIT(val, 5, 3)
+#define        VXGE_HW_XMAC_STATS_SYS_CMD_STROBE       vxge_mBIT(15)
+#define VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8)
+/*0x01f60*/    u64     xmac_stats_sys_data;
+#define VXGE_HW_XMAC_STATS_SYS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64)
+       u8      unused01f80[0x01f80-0x01f68];
+
+/*0x01f80*/    u64     asic_ntwk_ctrl;
+#define        VXGE_HW_ASIC_NTWK_CTRL_REQ_TEST_NTWK    vxge_mBIT(3)
+#define        VXGE_HW_ASIC_NTWK_CTRL_PORT0_REQ_TEST_PORT      vxge_mBIT(11)
+#define        VXGE_HW_ASIC_NTWK_CTRL_PORT1_REQ_TEST_PORT      vxge_mBIT(15)
+/*0x01f88*/    u64     asic_ntwk_cfg_show_port_info;
+#define VXGE_HW_ASIC_NTWK_CFG_SHOW_PORT_INFO_VP(n)     vxge_mBIT(n)
+/*0x01f90*/    u64     asic_ntwk_cfg_port_num;
+#define VXGE_HW_ASIC_NTWK_CFG_PORT_NUM_VP(n)   vxge_mBIT(n)
+/*0x01f98*/    u64     xmac_cfg_port[3];
+#define        VXGE_HW_XMAC_CFG_PORT_XGMII_LOOPBACK    vxge_mBIT(3)
+#define        VXGE_HW_XMAC_CFG_PORT_XGMII_REVERSE_LOOPBACK    vxge_mBIT(7)
+#define        VXGE_HW_XMAC_CFG_PORT_XGMII_TX_BEHAV    vxge_mBIT(11)
+#define        VXGE_HW_XMAC_CFG_PORT_XGMII_RX_BEHAV    vxge_mBIT(15)
+/*0x01fb0*/    u64     xmac_station_addr_port[2];
+#define VXGE_HW_XMAC_STATION_ADDR_PORT_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
+       u8      unused02020[0x02020-0x01fc0];
+
+/*0x02020*/    u64     lag_cfg;
+#define        VXGE_HW_LAG_CFG_EN      vxge_mBIT(3)
+#define VXGE_HW_LAG_CFG_MODE(val) vxge_vBIT(val, 6, 2)
+#define        VXGE_HW_LAG_CFG_TX_DISCARD_BEHAV        vxge_mBIT(11)
+#define        VXGE_HW_LAG_CFG_RX_DISCARD_BEHAV        vxge_mBIT(15)
+#define        VXGE_HW_LAG_CFG_PREF_INDIV_PORT_NUM     vxge_mBIT(19)
+/*0x02028*/    u64     lag_status;
+#define        VXGE_HW_LAG_STATUS_XLCM_WAITING_TO_FAILBACK     vxge_mBIT(3)
+#define VXGE_HW_LAG_STATUS_XLCM_TIMER_VAL_COLD_FAILOVER(val) \
+                                                       vxge_vBIT(val, 8, 8)
+/*0x02030*/    u64     lag_active_passive_cfg;
+#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_HOT_STANDBY      vxge_mBIT(3)
+#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_LACP_DECIDES     vxge_mBIT(7)
+#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_PREF_ACTIVE_PORT_NUM     vxge_mBIT(11)
+#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_AUTO_FAILBACK    vxge_mBIT(15)
+#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_FAILBACK_EN      vxge_mBIT(19)
+#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_COLD_FAILOVER_TIMEOUT(val) \
+                                                       vxge_vBIT(val, 32, 16)
+       u8      unused02040[0x02040-0x02038];
+
+/*0x02040*/    u64     lag_lacp_cfg;
+#define        VXGE_HW_LAG_LACP_CFG_EN vxge_mBIT(3)
+#define        VXGE_HW_LAG_LACP_CFG_LACP_BEGIN vxge_mBIT(7)
+#define        VXGE_HW_LAG_LACP_CFG_DISCARD_LACP       vxge_mBIT(11)
+#define        VXGE_HW_LAG_LACP_CFG_LIBERAL_LEN_CHK    vxge_mBIT(15)
+/*0x02048*/    u64     lag_timer_cfg_1;
+#define VXGE_HW_LAG_TIMER_CFG_1_FAST_PER(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_TIMER_CFG_1_SLOW_PER(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_LAG_TIMER_CFG_1_SHORT_TIMEOUT(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_LAG_TIMER_CFG_1_LONG_TIMEOUT(val) vxge_vBIT(val, 48, 16)
+/*0x02050*/    u64     lag_timer_cfg_2;
+#define VXGE_HW_LAG_TIMER_CFG_2_CHURN_DET(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_TIMER_CFG_2_AGGR_WAIT(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_LAG_TIMER_CFG_2_SHORT_TIMER_SCALE(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_LAG_TIMER_CFG_2_LONG_TIMER_SCALE(val)  vxge_vBIT(val, 48, 16)
+/*0x02058*/    u64     lag_sys_id;
+#define VXGE_HW_LAG_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48)
+#define        VXGE_HW_LAG_SYS_ID_USE_PORT_ADDR        vxge_mBIT(51)
+#define        VXGE_HW_LAG_SYS_ID_ADDR_SEL     vxge_mBIT(55)
+/*0x02060*/    u64     lag_sys_cfg;
+#define VXGE_HW_LAG_SYS_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16)
+       u8      unused02070[0x02070-0x02068];
+
+/*0x02070*/    u64     lag_aggr_addr_cfg[2];
+#define VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR(val) vxge_vBIT(val, 0, 48)
+#define        VXGE_HW_LAG_AGGR_ADDR_CFG_USE_PORT_ADDR vxge_mBIT(51)
+#define        VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR_SEL      vxge_mBIT(55)
+/*0x02080*/    u64     lag_aggr_id_cfg[2];
+#define VXGE_HW_LAG_AGGR_ID_CFG_ID(val) vxge_vBIT(val, 0, 16)
+/*0x02090*/    u64     lag_aggr_admin_key[2];
+#define VXGE_HW_LAG_AGGR_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16)
+/*0x020a0*/    u64     lag_aggr_alt_admin_key;
+#define VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16)
+#define        VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_ALT_AGGR vxge_mBIT(19)
+/*0x020a8*/    u64     lag_aggr_oper_key[2];
+#define VXGE_HW_LAG_AGGR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16)
+/*0x020b8*/    u64     lag_aggr_partner_sys_id[2];
+#define VXGE_HW_LAG_AGGR_PARTNER_SYS_ID_LAGC_ADDR(val) vxge_vBIT(val, 0, 48)
+/*0x020c8*/    u64     lag_aggr_partner_info[2];
+#define VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_SYS_PRI(val) vxge_vBIT(val, 0, 16)
+#define        VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_OPER_KEY(val) \
+                                               vxge_vBIT(val, 16, 16)
+/*0x020d8*/    u64     lag_aggr_state[2];
+#define        VXGE_HW_LAG_AGGR_STATE_LAGC_TX  vxge_mBIT(3)
+#define        VXGE_HW_LAG_AGGR_STATE_LAGC_RX  vxge_mBIT(7)
+#define        VXGE_HW_LAG_AGGR_STATE_LAGC_READY       vxge_mBIT(11)
+#define        VXGE_HW_LAG_AGGR_STATE_LAGC_INDIVIDUAL  vxge_mBIT(15)
+       u8      unused020f0[0x020f0-0x020e8];
+
+/*0x020f0*/    u64     lag_port_cfg[2];
+#define        VXGE_HW_LAG_PORT_CFG_EN vxge_mBIT(3)
+#define        VXGE_HW_LAG_PORT_CFG_DISCARD_SLOW_PROTO vxge_mBIT(7)
+#define        VXGE_HW_LAG_PORT_CFG_HOST_CHOSEN_AGGR   vxge_mBIT(11)
+#define        VXGE_HW_LAG_PORT_CFG_DISCARD_UNKNOWN_SLOW_PROTO vxge_mBIT(15)
+/*0x02100*/    u64     lag_port_actor_admin_cfg[2];
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_NUM(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_PRI(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_10G(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_1G(val) vxge_vBIT(val, 48, 16)
+/*0x02110*/    u64     lag_port_actor_admin_state[2];
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_ACTIVITY        vxge_mBIT(3)
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_TIMEOUT vxge_mBIT(7)
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_AGGREGATION  vxge_mBIT(11)
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_SYNCHRONIZATION      vxge_mBIT(15)
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_COLLECTING   vxge_mBIT(19)
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DISTRIBUTING vxge_mBIT(23)
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DEFAULTED    vxge_mBIT(27)
+#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_EXPIRED      vxge_mBIT(31)
+/*0x02120*/    u64     lag_port_partner_admin_sys_id[2];
+#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48)
+/*0x02130*/    u64     lag_port_partner_admin_cfg[2];
+#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_KEY(val) vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_NUM(val) \
+                                                       vxge_vBIT(val, 32, 16)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_PRI(val) \
+                                                       vxge_vBIT(val, 48, 16)
+/*0x02140*/    u64     lag_port_partner_admin_state[2];
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_ACTIVITY      vxge_mBIT(3)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_TIMEOUT       vxge_mBIT(7)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_AGGREGATION        vxge_mBIT(11)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_SYNCHRONIZATION    vxge_mBIT(15)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_COLLECTING vxge_mBIT(19)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DISTRIBUTING       vxge_mBIT(23)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DEFAULTED  vxge_mBIT(27)
+#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_EXPIRED    vxge_mBIT(31)
+/*0x02150*/    u64     lag_port_to_aggr[2];
+#define VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_ID(val) vxge_vBIT(val, 0, 16)
+#define        VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_VLD_ID       vxge_mBIT(19)
+/*0x02160*/    u64     lag_port_actor_oper_key[2];
+#define VXGE_HW_LAG_PORT_ACTOR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16)
+/*0x02170*/    u64     lag_port_actor_oper_state[2];
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_ACTIVITY    vxge_mBIT(3)
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_TIMEOUT     vxge_mBIT(7)
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_AGGREGATION      vxge_mBIT(11)
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_SYNCHRONIZATION  vxge_mBIT(15)
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_COLLECTING       vxge_mBIT(19)
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DISTRIBUTING     vxge_mBIT(23)
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DEFAULTED        vxge_mBIT(27)
+#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_EXPIRED  vxge_mBIT(31)
+/*0x02180*/    u64     lag_port_partner_oper_sys_id[2];
+#define VXGE_HW_LAG_PORT_PARTNER_OPER_SYS_ID_LAGC_ADDR(val) \
+                                               vxge_vBIT(val, 0, 48)
+/*0x02190*/    u64     lag_port_partner_oper_info[2];
+#define VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_SYS_PRI(val) \
+                                               vxge_vBIT(val, 0, 16)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_KEY(val) \
+                                               vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_NUM(val) \
+                                               vxge_vBIT(val, 32, 16)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_PRI(val) \
+                                               vxge_vBIT(val, 48, 16)
+/*0x021a0*/    u64     lag_port_partner_oper_state[2];
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_ACTIVITY  vxge_mBIT(3)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_TIMEOUT   vxge_mBIT(7)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_AGGREGATION    vxge_mBIT(11)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_SYNCHRONIZATION \
+                                                               vxge_mBIT(15)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_COLLECTING     vxge_mBIT(19)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DISTRIBUTING   vxge_mBIT(23)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DEFAULTED      vxge_mBIT(27)
+#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_EXPIRED        vxge_mBIT(31)
+/*0x021b0*/    u64     lag_port_state_vars[2];
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_READY  vxge_mBIT(3)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_SELECTED(val) vxge_vBIT(val, 6, 2)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_AGGR_NUM       vxge_mBIT(11)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_MOVED     vxge_mBIT(15)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_ENABLED   vxge_mBIT(18)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_DISABLED  vxge_mBIT(19)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_NTT    vxge_mBIT(23)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN    vxge_mBIT(27)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN  vxge_mBIT(31)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_INFO_LEN_MISMATCH \
+                                                               vxge_mBIT(32)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_INFO_LEN_MISMATCH \
+                                                               vxge_mBIT(33)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_COLL_INFO_LEN_MISMATCH vxge_mBIT(34)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_TERM_INFO_LEN_MISMATCH vxge_mBIT(35)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_RX_FSM_STATE(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_FSM_STATE(val) \
+                                                       vxge_vBIT(val, 41, 3)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_REASON(val) vxge_vBIT(val, 44, 4)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_STATE      vxge_mBIT(54)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_STATE    vxge_mBIT(55)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_COUNT(val) \
+                                                       vxge_vBIT(val, 56, 4)
+#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_COUNT(val) \
+                                                       vxge_vBIT(val, 60, 4)
+/*0x021c0*/    u64     lag_port_timer_cntr[2];
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_CURRENT_WHILE(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PERIODIC_WHILE(val) \
+                                                       vxge_vBIT(val, 8, 8)
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_WAIT_WHILE(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_TX_LACP(val) vxge_vBIT(val, 24, 8)
+#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_SYNC_TRANSITION_COUNT(val) \
+                                                       vxge_vBIT(val, 32, 8)
+#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_SYNC_TRANSITION_COUNT(val) \
+                                                       vxge_vBIT(val, 40, 8)
+#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_CHANGE_COUNT(val) \
+                                                       vxge_vBIT(val, 48, 8)
+#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_CHANGE_COUNT(val) \
+                                                       vxge_vBIT(val, 56, 8)
+       u8      unused02208[0x02700-0x021d0];
+
+/*0x02700*/    u64     rtdma_int_status;
+#define        VXGE_HW_RTDMA_INT_STATUS_PDA_ALARM_PDA_INT      vxge_mBIT(1)
+#define        VXGE_HW_RTDMA_INT_STATUS_PCC_ERROR_PCC_INT      vxge_mBIT(2)
+#define        VXGE_HW_RTDMA_INT_STATUS_LSO_ERROR_LSO_INT      vxge_mBIT(4)
+#define        VXGE_HW_RTDMA_INT_STATUS_SM_ERROR_SM_INT        vxge_mBIT(5)
+/*0x02708*/    u64     rtdma_int_mask;
+/*0x02710*/    u64     pda_alarm_reg;
+#define        VXGE_HW_PDA_ALARM_REG_PDA_HSC_FIFO_ERR  vxge_mBIT(0)
+#define        VXGE_HW_PDA_ALARM_REG_PDA_SM_ERR        vxge_mBIT(1)
+/*0x02718*/    u64     pda_alarm_mask;
+/*0x02720*/    u64     pda_alarm_alarm;
+/*0x02728*/    u64     pcc_error_reg;
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_SBE(n)   vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_SBE(n)      vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_DBE(n)   vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_DBE(n)      vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FSM_ERR_ALARM(n) vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_SERR(n)  vxge_mBIT(n)
+/*0x02730*/    u64     pcc_error_mask;
+/*0x02738*/    u64     pcc_error_alarm;
+/*0x02740*/    u64     lso_error_reg;
+#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_ABORT(n) vxge_mBIT(n)
+#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_FSM_ERR_ALARM(n) vxge_mBIT(n)
+/*0x02748*/    u64     lso_error_mask;
+/*0x02750*/    u64     lso_error_alarm;
+/*0x02758*/    u64     sm_error_reg;
+#define        VXGE_HW_SM_ERROR_REG_SM_FSM_ERR_ALARM   vxge_mBIT(15)
+/*0x02760*/    u64     sm_error_mask;
+/*0x02768*/    u64     sm_error_alarm;
+
+       u8      unused027a8[0x027a8-0x02770];
+
+/*0x027a8*/    u64     txd_ownership_ctrl;
+#define        VXGE_HW_TXD_OWNERSHIP_CTRL_KEEP_OWNERSHIP       vxge_mBIT(7)
+/*0x027b0*/    u64     pcc_cfg;
+#define VXGE_HW_PCC_CFG_PCC_ENABLE(n)  vxge_mBIT(n)
+#define VXGE_HW_PCC_CFG_PCC_ECC_ENABLE_N(n)    vxge_mBIT(n)
+/*0x027b8*/    u64     pcc_control;
+#define VXGE_HW_PCC_CONTROL_FE_ENABLE(val) vxge_vBIT(val, 6, 2)
+#define        VXGE_HW_PCC_CONTROL_EARLY_ASSIGN_EN     vxge_mBIT(15)
+#define        VXGE_HW_PCC_CONTROL_UNBLOCK_DB_ERR      vxge_mBIT(31)
+/*0x027c0*/    u64     pda_status1;
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_0_CTR(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_1_CTR(val) vxge_vBIT(val, 12, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_2_CTR(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_3_CTR(val) vxge_vBIT(val, 28, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_4_CTR(val) vxge_vBIT(val, 36, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_5_CTR(val) vxge_vBIT(val, 44, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_6_CTR(val) vxge_vBIT(val, 52, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_7_CTR(val) vxge_vBIT(val, 60, 4)
+/*0x027c8*/    u64     rtdma_bw_timer;
+#define VXGE_HW_RTDMA_BW_TIMER_TIMER_CTRL(val) vxge_vBIT(val, 12, 4)
+
+       u8      unused02900[0x02900-0x027d0];
+/*0x02900*/    u64     g3cmct_int_status;
+#define        VXGE_HW_G3CMCT_INT_STATUS_ERR_G3IF_INT  vxge_mBIT(0)
+/*0x02908*/    u64     g3cmct_int_mask;
+/*0x02910*/    u64     g3cmct_err_reg;
+#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_SM_ERR      vxge_mBIT(4)
+#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_DECC  vxge_mBIT(5)
+#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_DECC        vxge_mBIT(6)
+#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_DECC      vxge_mBIT(7)
+#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_SECC  vxge_mBIT(29)
+#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_SECC        vxge_mBIT(30)
+#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_SECC      vxge_mBIT(31)
+/*0x02918*/    u64     g3cmct_err_mask;
+/*0x02920*/    u64     g3cmct_err_alarm;
+       u8      unused03000[0x03000-0x02928];
+
+/*0x03000*/    u64     mc_int_status;
+#define        VXGE_HW_MC_INT_STATUS_MC_ERR_MC_INT     vxge_mBIT(3)
+#define        VXGE_HW_MC_INT_STATUS_GROCRC_ALARM_ROCRC_INT    vxge_mBIT(7)
+#define        VXGE_HW_MC_INT_STATUS_FAU_GEN_ERR_FAU_GEN_INT   vxge_mBIT(11)
+#define        VXGE_HW_MC_INT_STATUS_FAU_ECC_ERR_FAU_ECC_INT   vxge_mBIT(15)
+/*0x03008*/    u64     mc_int_mask;
+/*0x03010*/    u64     mc_err_reg;
+#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_A     vxge_mBIT(3)
+#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_B     vxge_mBIT(4)
+#define        VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_SG_ERR   vxge_mBIT(5)
+#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_0 vxge_mBIT(6)
+#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_1 vxge_mBIT(7)
+#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_A     vxge_mBIT(10)
+#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_B     vxge_mBIT(11)
+#define        VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_DB_ERR   vxge_mBIT(12)
+#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_0 vxge_mBIT(13)
+#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_1 vxge_mBIT(14)
+#define        VXGE_HW_MC_ERR_REG_MC_SM_ERR    vxge_mBIT(15)
+/*0x03018*/    u64     mc_err_mask;
+/*0x03020*/    u64     mc_err_alarm;
+/*0x03028*/    u64     grocrc_alarm_reg;
+#define        VXGE_HW_GROCRC_ALARM_REG_XFMD_WR_FIFO_ERR       vxge_mBIT(3)
+#define        VXGE_HW_GROCRC_ALARM_REG_WDE2MSR_RD_FIFO_ERR    vxge_mBIT(7)
+/*0x03030*/    u64     grocrc_alarm_mask;
+/*0x03038*/    u64     grocrc_alarm_alarm;
+       u8      unused03100[0x03100-0x03040];
+
+/*0x03100*/    u64     rx_thresh_cfg_repl;
+#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_0(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_1(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_2(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_3(val) vxge_vBIT(val, 40, 8)
+#define        VXGE_HW_RX_THRESH_CFG_REPL_GLOBAL_WOL_EN        vxge_mBIT(62)
+#define        VXGE_HW_RX_THRESH_CFG_REPL_EXACT_VP_MATCH_REQ   vxge_mBIT(63)
+       u8      unused033b8[0x033b8-0x03108];
+
+/*0x033b8*/    u64     fbmc_ecc_cfg;
+#define VXGE_HW_FBMC_ECC_CFG_ENABLE(val) vxge_vBIT(val, 3, 5)
+       u8      unused03400[0x03400-0x033c0];
+
+/*0x03400*/    u64     pcipif_int_status;
+#define        VXGE_HW_PCIPIF_INT_STATUS_DBECC_ERR_DBECC_ERR_INT       vxge_mBIT(3)
+#define        VXGE_HW_PCIPIF_INT_STATUS_SBECC_ERR_SBECC_ERR_INT       vxge_mBIT(7)
+#define        VXGE_HW_PCIPIF_INT_STATUS_GENERAL_ERR_GENERAL_ERR_INT   vxge_mBIT(11)
+#define        VXGE_HW_PCIPIF_INT_STATUS_SRPCIM_MSG_SRPCIM_MSG_INT     vxge_mBIT(15)
+#define        VXGE_HW_PCIPIF_INT_STATUS_MRPCIM_SPARE_R1_MRPCIM_SPARE_R1_INT \
+                                                               vxge_mBIT(19)
+/*0x03408*/    u64     pcipif_int_mask;
+/*0x03410*/    u64     dbecc_err_reg;
+#define        VXGE_HW_DBECC_ERR_REG_PCI_RETRY_BUF_DB_ERR      vxge_mBIT(3)
+#define        VXGE_HW_DBECC_ERR_REG_PCI_RETRY_SOT_DB_ERR      vxge_mBIT(7)
+#define        VXGE_HW_DBECC_ERR_REG_PCI_P_HDR_DB_ERR  vxge_mBIT(11)
+#define        VXGE_HW_DBECC_ERR_REG_PCI_P_DATA_DB_ERR vxge_mBIT(15)
+#define        VXGE_HW_DBECC_ERR_REG_PCI_NP_HDR_DB_ERR vxge_mBIT(19)
+#define        VXGE_HW_DBECC_ERR_REG_PCI_NP_DATA_DB_ERR        vxge_mBIT(23)
+/*0x03418*/    u64     dbecc_err_mask;
+/*0x03420*/    u64     dbecc_err_alarm;
+/*0x03428*/    u64     sbecc_err_reg;
+#define        VXGE_HW_SBECC_ERR_REG_PCI_RETRY_BUF_SG_ERR      vxge_mBIT(3)
+#define        VXGE_HW_SBECC_ERR_REG_PCI_RETRY_SOT_SG_ERR      vxge_mBIT(7)
+#define        VXGE_HW_SBECC_ERR_REG_PCI_P_HDR_SG_ERR  vxge_mBIT(11)
+#define        VXGE_HW_SBECC_ERR_REG_PCI_P_DATA_SG_ERR vxge_mBIT(15)
+#define        VXGE_HW_SBECC_ERR_REG_PCI_NP_HDR_SG_ERR vxge_mBIT(19)
+#define        VXGE_HW_SBECC_ERR_REG_PCI_NP_DATA_SG_ERR        vxge_mBIT(23)
+/*0x03430*/    u64     sbecc_err_mask;
+/*0x03438*/    u64     sbecc_err_alarm;
+/*0x03440*/    u64     general_err_reg;
+#define        VXGE_HW_GENERAL_ERR_REG_PCI_DROPPED_ILLEGAL_CFG vxge_mBIT(3)
+#define        VXGE_HW_GENERAL_ERR_REG_PCI_ILLEGAL_MEM_MAP_PROG        vxge_mBIT(7)
+#define        VXGE_HW_GENERAL_ERR_REG_PCI_LINK_RST_FSM_ERR    vxge_mBIT(11)
+#define        VXGE_HW_GENERAL_ERR_REG_PCI_RX_ILLEGAL_TLP_VPLANE       vxge_mBIT(15)
+#define        VXGE_HW_GENERAL_ERR_REG_PCI_TRAINING_RESET_DET  vxge_mBIT(19)
+#define        VXGE_HW_GENERAL_ERR_REG_PCI_PCI_LINK_DOWN_DET   vxge_mBIT(23)
+#define        VXGE_HW_GENERAL_ERR_REG_PCI_RESET_ACK_DLLP      vxge_mBIT(27)
+/*0x03448*/    u64     general_err_mask;
+/*0x03450*/    u64     general_err_alarm;
+/*0x03458*/    u64     srpcim_msg_reg;
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE0_RMSG_INT \
+                                                               vxge_mBIT(0)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE1_RMSG_INT \
+                                                               vxge_mBIT(1)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE2_RMSG_INT \
+                                                               vxge_mBIT(2)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE3_RMSG_INT \
+                                                               vxge_mBIT(3)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE4_RMSG_INT \
+                                                               vxge_mBIT(4)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE5_RMSG_INT \
+                                                               vxge_mBIT(5)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE6_RMSG_INT \
+                                                               vxge_mBIT(6)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE7_RMSG_INT \
+                                                               vxge_mBIT(7)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE8_RMSG_INT \
+                                                               vxge_mBIT(8)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE9_RMSG_INT \
+                                                               vxge_mBIT(9)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE10_RMSG_INT \
+                                                               vxge_mBIT(10)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE11_RMSG_INT \
+                                                               vxge_mBIT(11)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE12_RMSG_INT \
+                                                               vxge_mBIT(12)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE13_RMSG_INT \
+                                                               vxge_mBIT(13)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE14_RMSG_INT \
+                                                               vxge_mBIT(14)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE15_RMSG_INT \
+                                                               vxge_mBIT(15)
+#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE16_RMSG_INT \
+                                                               vxge_mBIT(16)
+/*0x03460*/    u64     srpcim_msg_mask;
+/*0x03468*/    u64     srpcim_msg_alarm;
+       u8      unused03600[0x03600-0x03470];
+
+/*0x03600*/    u64     gcmg1_int_status;
+#define        VXGE_HW_GCMG1_INT_STATUS_GSSCC_ERR_GSSCC_INT    vxge_mBIT(0)
+#define        VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR0_GSSC0_0_INT vxge_mBIT(1)
+#define        VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR1_GSSC0_1_INT vxge_mBIT(2)
+#define        VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR0_GSSC1_0_INT vxge_mBIT(3)
+#define        VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR1_GSSC1_1_INT vxge_mBIT(4)
+#define        VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR0_GSSC2_0_INT vxge_mBIT(5)
+#define        VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR1_GSSC2_1_INT vxge_mBIT(6)
+#define        VXGE_HW_GCMG1_INT_STATUS_UQM_ERR_UQM_INT        vxge_mBIT(7)
+#define        VXGE_HW_GCMG1_INT_STATUS_GQCC_ERR_GQCC_INT      vxge_mBIT(8)
+/*0x03608*/    u64     gcmg1_int_mask;
+       u8      unused03a00[0x03a00-0x03610];
+
+/*0x03a00*/    u64     pcmg1_int_status;
+#define        VXGE_HW_PCMG1_INT_STATUS_PSSCC_ERR_PSSCC_INT    vxge_mBIT(0)
+#define        VXGE_HW_PCMG1_INT_STATUS_PQCC_ERR_PQCC_INT      vxge_mBIT(1)
+#define        VXGE_HW_PCMG1_INT_STATUS_PQCC_CQM_ERR_PQCC_CQM_INT      vxge_mBIT(2)
+#define        VXGE_HW_PCMG1_INT_STATUS_PQCC_SQM_ERR_PQCC_SQM_INT      vxge_mBIT(3)
+/*0x03a08*/    u64     pcmg1_int_mask;
+       u8      unused04000[0x04000-0x03a10];
+
+/*0x04000*/    u64     one_int_status;
+#define        VXGE_HW_ONE_INT_STATUS_RXPE_ERR_RXPE_INT        vxge_mBIT(7)
+#define        VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_SG_ECC_ERR_TXPE_BCC_MEM_SG_ECC_INT \
+                                                       vxge_mBIT(13)
+#define        VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_DB_ECC_ERR_TXPE_BCC_MEM_DB_ECC_INT \
+                                                       vxge_mBIT(14)
+#define        VXGE_HW_ONE_INT_STATUS_TXPE_ERR_TXPE_INT        vxge_mBIT(15)
+#define        VXGE_HW_ONE_INT_STATUS_DLM_ERR_DLM_INT  vxge_mBIT(23)
+#define        VXGE_HW_ONE_INT_STATUS_PE_ERR_PE_INT    vxge_mBIT(31)
+#define        VXGE_HW_ONE_INT_STATUS_RPE_ERR_RPE_INT  vxge_mBIT(39)
+#define        VXGE_HW_ONE_INT_STATUS_RPE_FSM_ERR_RPE_FSM_INT  vxge_mBIT(47)
+#define        VXGE_HW_ONE_INT_STATUS_OES_ERR_OES_INT  vxge_mBIT(55)
+/*0x04008*/    u64     one_int_mask;
+       u8      unused04818[0x04818-0x04010];
+
+/*0x04818*/    u64     noa_wct_ctrl;
+#define        VXGE_HW_NOA_WCT_CTRL_VP_INT_NUM vxge_mBIT(0)
+/*0x04820*/    u64     rc_cfg2;
+#define VXGE_HW_RC_CFG2_BUFF1_SIZE(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_RC_CFG2_BUFF2_SIZE(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_RC_CFG2_BUFF3_SIZE(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_RC_CFG2_BUFF4_SIZE(val) vxge_vBIT(val, 48, 16)
+/*0x04828*/    u64     rc_cfg3;
+#define VXGE_HW_RC_CFG3_BUFF5_SIZE(val) vxge_vBIT(val, 0, 16)
+/*0x04830*/    u64     rx_multi_cast_ctrl1;
+#define        VXGE_HW_RX_MULTI_CAST_CTRL1_ENABLE      vxge_mBIT(7)
+#define VXGE_HW_RX_MULTI_CAST_CTRL1_DELAY_COUNT(val) vxge_vBIT(val, 11, 5)
+/*0x04838*/    u64     rxdm_dbg_rd;
+#define VXGE_HW_RXDM_DBG_RD_ADDR(val) vxge_vBIT(val, 0, 12)
+#define        VXGE_HW_RXDM_DBG_RD_ENABLE      vxge_mBIT(31)
+/*0x04840*/    u64     rxdm_dbg_rd_data;
+#define VXGE_HW_RXDM_DBG_RD_DATA_RMC_RXDM_DBG_RD_DATA(val) vxge_vBIT(val, 0, 64)
+/*0x04848*/    u64     rqa_top_prty_for_vh[17];
+#define VXGE_HW_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \
+                                                       vxge_vBIT(val, 59, 5)
+       u8      unused04900[0x04900-0x048d0];
+
+/*0x04900*/    u64     tim_status;
+#define        VXGE_HW_TIM_STATUS_TIM_RESET_IN_PROGRESS        vxge_mBIT(0)
+/*0x04908*/    u64     tim_ecc_enable;
+#define        VXGE_HW_TIM_ECC_ENABLE_VBLS_N   vxge_mBIT(7)
+#define        VXGE_HW_TIM_ECC_ENABLE_BMAP_N   vxge_mBIT(15)
+#define        VXGE_HW_TIM_ECC_ENABLE_BMAP_MSG_N       vxge_mBIT(23)
+/*0x04910*/    u64     tim_bp_ctrl;
+#define        VXGE_HW_TIM_BP_CTRL_RD_XON      vxge_mBIT(7)
+#define        VXGE_HW_TIM_BP_CTRL_WR_XON      vxge_mBIT(15)
+#define        VXGE_HW_TIM_BP_CTRL_ROCRC_BYP   vxge_mBIT(23)
+/*0x04918*/    u64     tim_resource_assignment_vh[17];
+#define VXGE_HW_TIM_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
+/*0x049a0*/    u64     tim_bmap_mapping_vp_err[17];
+#define VXGE_HW_TIM_BMAP_MAPPING_VP_ERR_TIM_DEST_VPATH(val) vxge_vBIT(val, 3, 5)
+       u8      unused04b00[0x04b00-0x04a28];
+
+/*0x04b00*/    u64     gcmg2_int_status;
+#define        VXGE_HW_GCMG2_INT_STATUS_GXTMC_ERR_GXTMC_INT    vxge_mBIT(7)
+#define        VXGE_HW_GCMG2_INT_STATUS_GCP_ERR_GCP_INT        vxge_mBIT(15)
+#define        VXGE_HW_GCMG2_INT_STATUS_CMC_ERR_CMC_INT        vxge_mBIT(23)
+/*0x04b08*/    u64     gcmg2_int_mask;
+/*0x04b10*/    u64     gxtmc_err_reg;
+#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_DB_ERR(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_SG_ERR(val) vxge_vBIT(val, 4, 4)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMC_RD_DATA_DB_ERR   vxge_mBIT(8)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_FIFO_ERR vxge_mBIT(9)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR    vxge_mBIT(10)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR      vxge_mBIT(11)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR      vxge_mBIT(12)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_FIFO_ERR     vxge_mBIT(13)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_ERR  vxge_mBIT(14)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_FIFO_ERR     vxge_mBIT(15)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_ERR  vxge_mBIT(16)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_DATA_SM_ERR      vxge_mBIT(17)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_CMC0_IF_ERR      vxge_mBIT(18)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_ARB_SM_ERR   vxge_mBIT(19)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_CFC_SM_ERR   vxge_mBIT(20)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_OVERFLOW \
+                                                       vxge_mBIT(21)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_UNDERFLOW \
+                                                       vxge_mBIT(22)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_SM_ERR        vxge_mBIT(23)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_OVERFLOW \
+                                                       vxge_mBIT(24)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_UNDERFLOW \
+                                                       vxge_mBIT(25)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_SM_ERR vxge_mBIT(26)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_SM_ERR        vxge_mBIT(27)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_TAG_ERR       vxge_mBIT(28)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_SM_ERR  vxge_mBIT(29)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_FIFO_ERR        vxge_mBIT(30)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_POP_ERR vxge_mBIT(31)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_CMI_OP_ERR  vxge_mBIT(32)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFETCH_OP_ERR       vxge_mBIT(33)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFIFO_ERR   vxge_mBIT(34)
+#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_ARB_SM_ERR       vxge_mBIT(35)
+/*0x04b18*/    u64     gxtmc_err_mask;
+/*0x04b20*/    u64     gxtmc_err_alarm;
+/*0x04b28*/    u64     cmc_err_reg;
+#define        VXGE_HW_CMC_ERR_REG_CMC_CMC_SM_ERR      vxge_mBIT(0)
+/*0x04b30*/    u64     cmc_err_mask;
+/*0x04b38*/    u64     cmc_err_alarm;
+/*0x04b40*/    u64     gcp_err_reg;
+#define        VXGE_HW_GCP_ERR_REG_CP_H2L2CP_FIFO_ERR  vxge_mBIT(0)
+#define        VXGE_HW_GCP_ERR_REG_CP_STC2CP_FIFO_ERR  vxge_mBIT(1)
+#define        VXGE_HW_GCP_ERR_REG_CP_STE2CP_FIFO_ERR  vxge_mBIT(2)
+#define        VXGE_HW_GCP_ERR_REG_CP_TTE2CP_FIFO_ERR  vxge_mBIT(3)
+/*0x04b48*/    u64     gcp_err_mask;
+/*0x04b50*/    u64     gcp_err_alarm;
+       u8      unused04f00[0x04f00-0x04b58];
+
+/*0x04f00*/    u64     pcmg2_int_status;
+#define        VXGE_HW_PCMG2_INT_STATUS_PXTMC_ERR_PXTMC_INT    vxge_mBIT(7)
+#define        VXGE_HW_PCMG2_INT_STATUS_CP_EXC_CP_XT_EXC_INT   vxge_mBIT(15)
+#define        VXGE_HW_PCMG2_INT_STATUS_CP_ERR_CP_ERR_INT      vxge_mBIT(23)
+/*0x04f08*/    u64     pcmg2_int_mask;
+/*0x04f10*/    u64     pxtmc_err_reg;
+#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_DB_ERR(val) vxge_vBIT(val, 0, 2)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FIFO_ERR     vxge_mBIT(2)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_PRSP_FIFO_ERR    vxge_mBIT(3)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_WRSP_FIFO_ERR    vxge_mBIT(4)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FIFO_ERR     vxge_mBIT(5)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_PRSP_FIFO_ERR    vxge_mBIT(6)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_WRSP_FIFO_ERR    vxge_mBIT(7)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FIFO_ERR     vxge_mBIT(8)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_PRSP_FIFO_ERR    vxge_mBIT(9)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_WRSP_FIFO_ERR    vxge_mBIT(10)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_FIFO_ERR vxge_mBIT(11)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR    vxge_mBIT(12)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR      vxge_mBIT(13)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR      vxge_mBIT(14)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_SHADOW_ERR   vxge_mBIT(15)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_SHADOW_ERR   vxge_mBIT(16)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_SHADOW_ERR   vxge_mBIT(17)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_SHADOW_ERR   vxge_mBIT(18)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_SHADOW_ERR   vxge_mBIT(19)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_SHADOW_ERR   vxge_mBIT(20)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_SHADOW_ERR       vxge_mBIT(21)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_SHADOW_ERR       vxge_mBIT(22)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_RAM_SHADOW_ERR       vxge_mBIT(23)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_SHADOW_ERR       vxge_mBIT(24)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_SHADOW_ERR       vxge_mBIT(25)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FSM_ERR      vxge_mBIT(26)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_FSM_ERR      vxge_mBIT(27)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FSM_ERR      vxge_mBIT(28)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_FSM_ERR      vxge_mBIT(29)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FSM_ERR      vxge_mBIT(30)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_FSM_ERR      vxge_mBIT(31)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_FSM_ERR  vxge_mBIT(32)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_FSM_ERR  vxge_mBIT(33)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_FSM_ERR  vxge_mBIT(34)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_FSM_ERR  vxge_mBIT(35)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_ERR      vxge_mBIT(36)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_ERR      vxge_mBIT(37)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_ERR      vxge_mBIT(38)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_ERR      vxge_mBIT(39)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_ERR      vxge_mBIT(40)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_ERR      vxge_mBIT(41)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_ERR     vxge_mBIT(42)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_ERR     vxge_mBIT(43)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_ERR     vxge_mBIT(44)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_INFO_ERR vxge_mBIT(45)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_INFO_ERR vxge_mBIT(46)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_INFO_ERR vxge_mBIT(47)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_INFO_ERR vxge_mBIT(48)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_INFO_ERR vxge_mBIT(49)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_INFO_ERR vxge_mBIT(50)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_INFO_ERR        vxge_mBIT(51)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_INFO_ERR        vxge_mBIT(52)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_INFO_ERR        vxge_mBIT(53)
+#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_SG_ERR(val) vxge_vBIT(val, 54, 2)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_DFIFO_PUSH_ERR        vxge_mBIT(56)
+#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_PUSH_ERR        vxge_mBIT(57)
+/*0x04f18*/    u64     pxtmc_err_mask;
+/*0x04f20*/    u64     pxtmc_err_alarm;
+/*0x04f28*/    u64     cp_err_reg;
+#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_SG_ERR(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_SG_ERR(val) vxge_vBIT(val, 8, 2)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_DTAG_SG_ERR    vxge_mBIT(10)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_ITAG_SG_ERR    vxge_mBIT(11)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_TRACE_SG_ERR   vxge_mBIT(12)
+#define        VXGE_HW_CP_ERR_REG_CP_DMA2CP_SG_ERR     vxge_mBIT(13)
+#define        VXGE_HW_CP_ERR_REG_CP_MP2CP_SG_ERR      vxge_mBIT(14)
+#define        VXGE_HW_CP_ERR_REG_CP_QCC2CP_SG_ERR     vxge_mBIT(15)
+#define VXGE_HW_CP_ERR_REG_CP_STC2CP_SG_ERR(val) vxge_vBIT(val, 16, 2)
+#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_DB_ERR(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_DB_ERR(val) vxge_vBIT(val, 32, 2)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_DTAG_DB_ERR    vxge_mBIT(34)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_ITAG_DB_ERR    vxge_mBIT(35)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_TRACE_DB_ERR   vxge_mBIT(36)
+#define        VXGE_HW_CP_ERR_REG_CP_DMA2CP_DB_ERR     vxge_mBIT(37)
+#define        VXGE_HW_CP_ERR_REG_CP_MP2CP_DB_ERR      vxge_mBIT(38)
+#define        VXGE_HW_CP_ERR_REG_CP_QCC2CP_DB_ERR     vxge_mBIT(39)
+#define VXGE_HW_CP_ERR_REG_CP_STC2CP_DB_ERR(val) vxge_vBIT(val, 40, 2)
+#define        VXGE_HW_CP_ERR_REG_CP_H2L2CP_FIFO_ERR   vxge_mBIT(48)
+#define        VXGE_HW_CP_ERR_REG_CP_STC2CP_FIFO_ERR   vxge_mBIT(49)
+#define        VXGE_HW_CP_ERR_REG_CP_STE2CP_FIFO_ERR   vxge_mBIT(50)
+#define        VXGE_HW_CP_ERR_REG_CP_TTE2CP_FIFO_ERR   vxge_mBIT(51)
+#define        VXGE_HW_CP_ERR_REG_CP_SWIF2CP_FIFO_ERR  vxge_mBIT(52)
+#define        VXGE_HW_CP_ERR_REG_CP_CP2DMA_FIFO_ERR   vxge_mBIT(53)
+#define        VXGE_HW_CP_ERR_REG_CP_DAM2CP_FIFO_ERR   vxge_mBIT(54)
+#define        VXGE_HW_CP_ERR_REG_CP_MP2CP_FIFO_ERR    vxge_mBIT(55)
+#define        VXGE_HW_CP_ERR_REG_CP_QCC2CP_FIFO_ERR   vxge_mBIT(56)
+#define        VXGE_HW_CP_ERR_REG_CP_DMA2CP_FIFO_ERR   vxge_mBIT(57)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_WAKE_FSM_INTEGRITY_ERR vxge_mBIT(60)
+#define        VXGE_HW_CP_ERR_REG_CP_CP_PMON_FSM_INTEGRITY_ERR vxge_mBIT(61)
+#define        VXGE_HW_CP_ERR_REG_CP_DMA_RD_SHADOW_ERR vxge_mBIT(62)
+#define        VXGE_HW_CP_ERR_REG_CP_PIFT_CREDIT_ERR   vxge_mBIT(63)
+/*0x04f30*/    u64     cp_err_mask;
+/*0x04f38*/    u64     cp_err_alarm;
+       u8      unused04fe8[0x04f50-0x04f40];
+
+/*0x04f50*/    u64     cp_exc_reg;
+#define        VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_INFO_INT vxge_mBIT(47)
+#define        VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_CRIT_INT vxge_mBIT(55)
+#define        VXGE_HW_CP_EXC_REG_CP_CP_SERR   vxge_mBIT(63)
+/*0x04f58*/    u64     cp_exc_mask;
+/*0x04f60*/    u64     cp_exc_alarm;
+/*0x04f68*/    u64     cp_exc_cause;
+#define VXGE_HW_CP_EXC_CAUSE_CP_CP_CAUSE(val) vxge_vBIT(val, 32, 32)
+       u8      unused05200[0x05200-0x04f70];
+
+/*0x05200*/    u64     msg_int_status;
+#define        VXGE_HW_MSG_INT_STATUS_TIM_ERR_TIM_INT  vxge_mBIT(7)
+#define        VXGE_HW_MSG_INT_STATUS_MSG_EXC_MSG_XT_EXC_INT   vxge_mBIT(60)
+#define        VXGE_HW_MSG_INT_STATUS_MSG_ERR3_MSG_ERR3_INT    vxge_mBIT(61)
+#define        VXGE_HW_MSG_INT_STATUS_MSG_ERR2_MSG_ERR2_INT    vxge_mBIT(62)
+#define        VXGE_HW_MSG_INT_STATUS_MSG_ERR_MSG_ERR_INT      vxge_mBIT(63)
+/*0x05208*/    u64     msg_int_mask;
+/*0x05210*/    u64     tim_err_reg;
+#define        VXGE_HW_TIM_ERR_REG_TIM_VBLS_SG_ERR     vxge_mBIT(4)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_SG_ERR  vxge_mBIT(5)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_SG_ERR  vxge_mBIT(6)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_SG_ERR vxge_mBIT(7)
+#define        VXGE_HW_TIM_ERR_REG_TIM_VBLS_DB_ERR     vxge_mBIT(12)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_DB_ERR  vxge_mBIT(13)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_DB_ERR  vxge_mBIT(14)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_DB_ERR vxge_mBIT(15)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MEM_CNTRL_SM_ERR   vxge_mBIT(18)
+#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_MEM_CNTRL_SM_ERR       vxge_mBIT(19)
+#define        VXGE_HW_TIM_ERR_REG_TIM_MPIF_PCIWR_ERR  vxge_mBIT(20)
+#define        VXGE_HW_TIM_ERR_REG_TIM_ROCRC_BMAP_UPDT_FIFO_ERR        vxge_mBIT(22)
+#define        VXGE_HW_TIM_ERR_REG_TIM_CREATE_BMAPMSG_FIFO_ERR vxge_mBIT(23)
+#define        VXGE_HW_TIM_ERR_REG_TIM_ROCRCIF_MISMATCH        vxge_mBIT(46)
+#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MAPPING_VP_ERR(n) vxge_mBIT(n)
+/*0x05218*/    u64     tim_err_mask;
+/*0x05220*/    u64     tim_err_alarm;
+/*0x05228*/    u64     msg_err_reg;
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_WAKE_FSM_INTEGRITY_ERR       vxge_mBIT(0)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_WAKE_FSM_INTEGRITY_ERR       vxge_mBIT(1)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_READ_CMD_FSM_INTEGRITY_ERR \
+                                                               vxge_mBIT(2)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_RESP_FSM_INTEGRITY_ERR \
+                                                               vxge_mBIT(3)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_OWN_FSM_INTEGRITY_ERR   vxge_mBIT(4)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_PDA_ACC_FSM_INTEGRITY_ERR   vxge_mBIT(5)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_PMON_FSM_INTEGRITY_ERR       vxge_mBIT(6)
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_PMON_FSM_INTEGRITY_ERR       vxge_mBIT(7)
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_SG_ERR  vxge_mBIT(8)
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_SG_ERR  vxge_mBIT(10)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_SG_ERR  vxge_mBIT(12)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_SG_ERR  vxge_mBIT(14)
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_SG_ERR vxge_mBIT(16)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_SG_ERR vxge_mBIT(17)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_SG_ERR      vxge_mBIT(18)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_SG_ERR     vxge_mBIT(19)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_SG_ERR     vxge_mBIT(20)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_SG_ERR      vxge_mBIT(21)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_SG_ERR  vxge_mBIT(26)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_SG_ERR       vxge_mBIT(27)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_SG_ERR      vxge_mBIT(29)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_SG_ERR vxge_mBIT(31)
+#define        VXGE_HW_MSG_ERR_REG_MSG_XFMDQRY_FSM_INTEGRITY_ERR       vxge_mBIT(33)
+#define        VXGE_HW_MSG_ERR_REG_MSG_FRMQRY_FSM_INTEGRITY_ERR        vxge_mBIT(34)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_WRITE_FSM_INTEGRITY_ERR vxge_mBIT(35)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_BWR_PF_FSM_INTEGRITY_ERR \
+                                                               vxge_mBIT(36)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_RESP_FIFO_ERR   vxge_mBIT(38)
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_DB_ERR  vxge_mBIT(39)
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_DB_ERR  vxge_mBIT(41)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_DB_ERR  vxge_mBIT(43)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_DB_ERR  vxge_mBIT(45)
+#define        VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_DB_ERR vxge_mBIT(47)
+#define        VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_DB_ERR vxge_mBIT(48)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_DB_ERR      vxge_mBIT(49)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_DB_ERR     vxge_mBIT(50)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_DB_ERR     vxge_mBIT(51)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_DB_ERR      vxge_mBIT(52)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_READ_FIFO_ERR   vxge_mBIT(53)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_MXP2UXP_FIFO_ERR    vxge_mBIT(54)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_KDFC_SIF_FIFO_ERR   vxge_mBIT(55)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_CXP2SWIF_FIFO_ERR   vxge_mBIT(56)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_DB_ERR  vxge_mBIT(57)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_DB_ERR       vxge_mBIT(58)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_SIF_FIFO_ERR    vxge_mBIT(59)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_DB_ERR      vxge_mBIT(60)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_READ_FIFO_ERR   vxge_mBIT(61)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_DB_ERR vxge_mBIT(62)
+#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UXP2MXP_FIFO_ERR    vxge_mBIT(63)
+/*0x05230*/    u64     msg_err_mask;
+/*0x05238*/    u64     msg_err_alarm;
+       u8      unused05340[0x05340-0x05240];
+
+/*0x05340*/    u64     msg_exc_reg;
+#define        VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_INFO_INT       vxge_mBIT(50)
+#define        VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_CRIT_INT       vxge_mBIT(51)
+#define        VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_INFO_INT       vxge_mBIT(54)
+#define        VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_CRIT_INT       vxge_mBIT(55)
+#define        VXGE_HW_MSG_EXC_REG_MP_MXP_SERR vxge_mBIT(62)
+#define        VXGE_HW_MSG_EXC_REG_UP_UXP_SERR vxge_mBIT(63)
+/*0x05348*/    u64     msg_exc_mask;
+/*0x05350*/    u64     msg_exc_alarm;
+/*0x05358*/    u64     msg_exc_cause;
+#define VXGE_HW_MSG_EXC_CAUSE_MP_MXP(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_MSG_EXC_CAUSE_UP_UXP(val) vxge_vBIT(val, 32, 32)
+       u8      unused05368[0x05380-0x05360];
+
+/*0x05380*/    u64     msg_err2_reg;
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_CMG2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(0)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMQ_DISPATCH_FSM_INTEGRITY_ERR \
+                                                               vxge_mBIT(1)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_DISPATCH_FSM_INTEGRITY_ERR \
+                                                               vxge_mBIT(2)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_PIC_WRITE_FSM_INTEGRITY_ERR \
+                                                               vxge_mBIT(3)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIFREG_FSM_INTEGRITY_ERR  vxge_mBIT(4)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_TIM_WRITE_FSM_INTEGRITY_ERR \
+                                                               vxge_mBIT(5)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ_TA_FSM_INTEGRITY_ERR   vxge_mBIT(6)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE_TA_FSM_INTEGRITY_ERR  vxge_mBIT(7)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE_TA_FSM_INTEGRITY_ERR  vxge_mBIT(8)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_TA_FSM_INTEGRITY_ERR  vxge_mBIT(9)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMA_TA_FSM_INTEGRITY_ERR   vxge_mBIT(10)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_CP_TA_FSM_INTEGRITY_ERR    vxge_mBIT(11)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA16_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(12)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA15_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(13)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA14_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(14)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA13_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(15)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA12_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(16)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA11_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(17)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA10_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(18)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA9_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(19)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA8_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(20)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA7_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(21)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA6_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(22)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA5_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(23)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA4_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(24)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA3_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(25)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA2_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(26)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA1_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(27)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA0_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(28)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_FBMC_OWN_FSM_INTEGRITY_ERR vxge_mBIT(29)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(30)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(31)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_RPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+                                                       vxge_mBIT(32)
+#define        VXGE_HW_MSG_ERR2_REG_MP_MP_PIFT_IF_CREDIT_CNT_ERR       vxge_mBIT(33)
+#define        VXGE_HW_MSG_ERR2_REG_UP_UP_PIFT_IF_CREDIT_CNT_ERR       vxge_mBIT(34)
+#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ2PIC_CMD_FIFO_ERR       vxge_mBIT(62)
+#define        VXGE_HW_MSG_ERR2_REG_TIM_TIM2MSG_CMD_FIFO_ERR   vxge_mBIT(63)
+/*0x05388*/    u64     msg_err2_mask;
+/*0x05390*/    u64     msg_err2_alarm;
+/*0x05398*/    u64     msg_err3_reg;
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR0      vxge_mBIT(0)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR1      vxge_mBIT(1)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR2      vxge_mBIT(2)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR3      vxge_mBIT(3)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR4      vxge_mBIT(4)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR5      vxge_mBIT(5)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR6      vxge_mBIT(6)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR7      vxge_mBIT(7)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR0      vxge_mBIT(8)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR1      vxge_mBIT(9)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR0      vxge_mBIT(16)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR1      vxge_mBIT(17)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR2      vxge_mBIT(18)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR3      vxge_mBIT(19)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR4      vxge_mBIT(20)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR5      vxge_mBIT(21)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR6      vxge_mBIT(22)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR7      vxge_mBIT(23)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR0      vxge_mBIT(24)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR1      vxge_mBIT(25)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR0      vxge_mBIT(32)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR1      vxge_mBIT(33)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR2      vxge_mBIT(34)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR3      vxge_mBIT(35)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR4      vxge_mBIT(36)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR5      vxge_mBIT(37)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR6      vxge_mBIT(38)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR7      vxge_mBIT(39)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR0      vxge_mBIT(40)
+#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR1      vxge_mBIT(41)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR0      vxge_mBIT(48)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR1      vxge_mBIT(49)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR2      vxge_mBIT(50)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR3      vxge_mBIT(51)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR4      vxge_mBIT(52)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR5      vxge_mBIT(53)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR6      vxge_mBIT(54)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR7      vxge_mBIT(55)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR0      vxge_mBIT(56)
+#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR1      vxge_mBIT(57)
+/*0x053a0*/    u64     msg_err3_mask;
+/*0x053a8*/    u64     msg_err3_alarm;
+       u8      unused05600[0x05600-0x053b0];
+
+/*0x05600*/    u64     fau_gen_err_reg;
+#define        VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT0_PERMANENT_STOP       vxge_mBIT(3)
+#define        VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT1_PERMANENT_STOP       vxge_mBIT(7)
+#define        VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT2_PERMANENT_STOP       vxge_mBIT(11)
+#define        VXGE_HW_FAU_GEN_ERR_REG_FALR_AUTO_LRO_NOTIFICATION      vxge_mBIT(15)
+/*0x05608*/    u64     fau_gen_err_mask;
+/*0x05610*/    u64     fau_gen_err_alarm;
+/*0x05618*/    u64     fau_ecc_err_reg;
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_SG_ERR    vxge_mBIT(0)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_DB_ERR    vxge_mBIT(1)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_SG_ERR(val) \
+                                                       vxge_vBIT(val, 2, 2)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_DB_ERR(val) \
+                                                       vxge_vBIT(val, 4, 2)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_SG_ERR    vxge_mBIT(6)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_DB_ERR    vxge_mBIT(7)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_SG_ERR(val) \
+                                                       vxge_vBIT(val, 8, 2)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_DB_ERR(val) \
+                                                       vxge_vBIT(val, 10, 2)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_SG_ERR    vxge_mBIT(12)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_DB_ERR    vxge_mBIT(13)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_SG_ERR(val) \
+                                                       vxge_vBIT(val, 14, 2)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_DB_ERR(val) \
+                                                       vxge_vBIT(val, 16, 2)
+#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_SG_ERR(val) \
+                                                       vxge_vBIT(val, 18, 2)
+#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_DB_ERR(val) \
+                                                       vxge_vBIT(val, 20, 2)
+#define        VXGE_HW_FAU_ECC_ERR_REG_FAUJ_FAU_FSM_ERR        vxge_mBIT(31)
+/*0x05620*/    u64     fau_ecc_err_mask;
+/*0x05628*/    u64     fau_ecc_err_alarm;
+       u8      unused05658[0x05658-0x05630];
+/*0x05658*/    u64     fau_pa_cfg;
+#define        VXGE_HW_FAU_PA_CFG_REPL_L4_COMP_CSUM    vxge_mBIT(3)
+#define        VXGE_HW_FAU_PA_CFG_REPL_L3_INCL_CF      vxge_mBIT(7)
+#define        VXGE_HW_FAU_PA_CFG_REPL_L3_COMP_CSUM    vxge_mBIT(11)
+       u8      unused05668[0x05668-0x05660];
+
+/*0x05668*/    u64     dbg_stats_fau_rx_path;
+#define        VXGE_HW_DBG_STATS_FAU_RX_PATH_RX_PERMITTED_FRMS(val) \
+                                               vxge_vBIT(val, 32, 32)
+       u8      unused056c0[0x056c0-0x05670];
+
+/*0x056c0*/    u64     fau_lag_cfg;
+#define VXGE_HW_FAU_LAG_CFG_COLL_ALG(val) vxge_vBIT(val, 2, 2)
+#define        VXGE_HW_FAU_LAG_CFG_INCR_RX_AGGR_STATS  vxge_mBIT(7)
+       u8      unused05800[0x05800-0x056c8];
+
+/*0x05800*/    u64     tpa_int_status;
+#define        VXGE_HW_TPA_INT_STATUS_ORP_ERR_ORP_INT  vxge_mBIT(15)
+#define        VXGE_HW_TPA_INT_STATUS_PTM_ALARM_PTM_INT        vxge_mBIT(23)
+#define        VXGE_HW_TPA_INT_STATUS_TPA_ERROR_TPA_INT        vxge_mBIT(31)
+/*0x05808*/    u64     tpa_int_mask;
+/*0x05810*/    u64     orp_err_reg;
+#define        VXGE_HW_ORP_ERR_REG_ORP_FIFO_SG_ERR     vxge_mBIT(3)
+#define        VXGE_HW_ORP_ERR_REG_ORP_FIFO_DB_ERR     vxge_mBIT(7)
+#define        VXGE_HW_ORP_ERR_REG_ORP_XFMD_FIFO_UFLOW_ERR     vxge_mBIT(11)
+#define        VXGE_HW_ORP_ERR_REG_ORP_FRM_FIFO_UFLOW_ERR      vxge_mBIT(15)
+#define        VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_FSM_ERR        vxge_mBIT(19)
+#define        VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_FSM_ERR vxge_mBIT(23)
+#define        VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_FSM_ERR  vxge_mBIT(27)
+#define        VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_SHADOW_ERR     vxge_mBIT(31)
+#define        VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_SHADOW_ERR      vxge_mBIT(35)
+#define        VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_SHADOW_ERR       vxge_mBIT(39)
+#define        VXGE_HW_ORP_ERR_REG_ORP_OUTFRM_SHADOW_ERR       vxge_mBIT(43)
+#define        VXGE_HW_ORP_ERR_REG_ORP_OPTPRS_SHADOW_ERR       vxge_mBIT(47)
+/*0x05818*/    u64     orp_err_mask;
+/*0x05820*/    u64     orp_err_alarm;
+/*0x05828*/    u64     ptm_alarm_reg;
+#define        VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_SYNC_ERR       vxge_mBIT(3)
+#define        VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_FIFO_ERR       vxge_mBIT(7)
+#define        VXGE_HW_PTM_ALARM_REG_XFMD_RD_FIFO_ERR  vxge_mBIT(11)
+#define        VXGE_HW_PTM_ALARM_REG_WDE2MSR_WR_FIFO_ERR       vxge_mBIT(15)
+#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_DB_ERR(val) vxge_vBIT(val, 18, 2)
+#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_SG_ERR(val) vxge_vBIT(val, 22, 2)
+/*0x05830*/    u64     ptm_alarm_mask;
+/*0x05838*/    u64     ptm_alarm_alarm;
+/*0x05840*/    u64     tpa_error_reg;
+#define        VXGE_HW_TPA_ERROR_REG_TPA_FSM_ERR_ALARM vxge_mBIT(3)
+#define        VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_DB_ERR       vxge_mBIT(7)
+#define        VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_SG_ERR       vxge_mBIT(11)
+/*0x05848*/    u64     tpa_error_mask;
+/*0x05850*/    u64     tpa_error_alarm;
+/*0x05858*/    u64     tpa_global_cfg;
+#define        VXGE_HW_TPA_GLOBAL_CFG_SUPPORT_SNAP_AB_N        vxge_mBIT(7)
+#define        VXGE_HW_TPA_GLOBAL_CFG_ECC_ENABLE_N     vxge_mBIT(35)
+       u8      unused05868[0x05870-0x05860];
+
+/*0x05870*/    u64     ptm_ecc_cfg;
+#define        VXGE_HW_PTM_ECC_CFG_PTM_FRMM_ECC_EN_N   vxge_mBIT(3)
+/*0x05878*/    u64     ptm_phase_cfg;
+#define        VXGE_HW_PTM_PHASE_CFG_FRMM_WR_PHASE_EN  vxge_mBIT(3)
+#define        VXGE_HW_PTM_PHASE_CFG_FRMM_RD_PHASE_EN  vxge_mBIT(7)
+       u8      unused05898[0x05898-0x05880];
+
+/*0x05898*/    u64     dbg_stats_tpa_tx_path;
+#define        VXGE_HW_DBG_STATS_TPA_TX_PATH_TX_PERMITTED_FRMS(val) \
+                                                       vxge_vBIT(val, 32, 32)
+       u8      unused05900[0x05900-0x058a0];
+
+/*0x05900*/    u64     tmac_int_status;
+#define        VXGE_HW_TMAC_INT_STATUS_TXMAC_GEN_ERR_TXMAC_GEN_INT     vxge_mBIT(3)
+#define        VXGE_HW_TMAC_INT_STATUS_TXMAC_ECC_ERR_TXMAC_ECC_INT     vxge_mBIT(7)
+/*0x05908*/    u64     tmac_int_mask;
+/*0x05910*/    u64     txmac_gen_err_reg;
+#define        VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_PERMANENT_STOP  vxge_mBIT(3)
+#define        VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_NO_VALID_VSPORT vxge_mBIT(7)
+/*0x05918*/    u64     txmac_gen_err_mask;
+/*0x05920*/    u64     txmac_gen_err_alarm;
+/*0x05928*/    u64     txmac_ecc_err_reg;
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_SG_ERR     vxge_mBIT(3)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_DB_ERR     vxge_mBIT(7)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_SG_ERR    vxge_mBIT(11)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_DB_ERR    vxge_mBIT(15)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_SG_ERR    vxge_mBIT(19)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_DB_ERR    vxge_mBIT(23)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT0_FSM_ERR       vxge_mBIT(27)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT1_FSM_ERR       vxge_mBIT(31)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT2_FSM_ERR       vxge_mBIT(35)
+#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMACJ_FSM_ERR   vxge_mBIT(39)
+/*0x05930*/    u64     txmac_ecc_err_mask;
+/*0x05938*/    u64     txmac_ecc_err_alarm;
+       u8      unused05978[0x05978-0x05940];
+
+/*0x05978*/    u64     dbg_stat_tx_any_frms;
+#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT0_TX_ANY_FRMS(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT1_TX_ANY_FRMS(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT2_TX_ANY_FRMS(val) \
+                                                       vxge_vBIT(val, 16, 8)
+       u8      unused059a0[0x059a0-0x05980];
+
+/*0x059a0*/    u64     txmac_link_util_port[3];
+#define        VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_UTILIZATION(val) \
+                                                       vxge_vBIT(val, 1, 7)
+#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_FRAC_UTIL(val) \
+                                                       vxge_vBIT(val, 12, 4)
+#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4)
+#define        VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_SCALE_FACTOR     vxge_mBIT(23)
+/*0x059b8*/    u64     txmac_cfg0_port[3];
+#define        VXGE_HW_TXMAC_CFG0_PORT_TMAC_EN vxge_mBIT(3)
+#define        VXGE_HW_TXMAC_CFG0_PORT_APPEND_PAD      vxge_mBIT(7)
+#define VXGE_HW_TXMAC_CFG0_PORT_PAD_BYTE(val) vxge_vBIT(val, 8, 8)
+/*0x059d0*/    u64     txmac_cfg1_port[3];
+#define VXGE_HW_TXMAC_CFG1_PORT_AVG_IPG(val) vxge_vBIT(val, 40, 8)
+/*0x059e8*/    u64     txmac_status_port[3];
+#define        VXGE_HW_TXMAC_STATUS_PORT_TMAC_TX_FRM_SENT      vxge_mBIT(3)
+       u8      unused05a20[0x05a20-0x05a00];
+
+/*0x05a20*/    u64     lag_distrib_dest;
+#define VXGE_HW_LAG_DISTRIB_DEST_MAP_VPATH(n)  vxge_mBIT(n)
+/*0x05a28*/    u64     lag_marker_cfg;
+#define        VXGE_HW_LAG_MARKER_CFG_GEN_RCVR_EN      vxge_mBIT(3)
+#define        VXGE_HW_LAG_MARKER_CFG_RESP_EN  vxge_mBIT(7)
+#define VXGE_HW_LAG_MARKER_CFG_RESP_TIMEOUT(val) vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_LAG_MARKER_CFG_SLOW_PROTO_MRKR_MIN_INTERVAL(val) \
+                                                       vxge_vBIT(val, 32, 16)
+#define        VXGE_HW_LAG_MARKER_CFG_THROTTLE_MRKR_RESP       vxge_mBIT(51)
+/*0x05a30*/    u64     lag_tx_cfg;
+#define        VXGE_HW_LAG_TX_CFG_INCR_TX_AGGR_STATS   vxge_mBIT(3)
+#define VXGE_HW_LAG_TX_CFG_DISTRIB_ALG_SEL(val) vxge_vBIT(val, 6, 2)
+#define        VXGE_HW_LAG_TX_CFG_DISTRIB_REMAP_IF_FAIL        vxge_mBIT(11)
+#define VXGE_HW_LAG_TX_CFG_COLL_MAX_DELAY(val) vxge_vBIT(val, 16, 16)
+/*0x05a38*/    u64     lag_tx_status;
+#define VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_EMPTIED_LINK(val) \
+                                                       vxge_vBIT(val, 0, 8)
+#define        VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKR(val) \
+                                                       vxge_vBIT(val, 8, 8)
+#define        VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKRRESP(val) \
+                                                       vxge_vBIT(val, 16, 8)
+       u8      unused05d48[0x05d48-0x05a40];
+
+/*0x05d48*/    u64     srpcim_to_mrpcim_vplane_rmsg[17];
+#define        \
+VXGE_HAL_SRPCIM_TO_MRPCIM_VPLANE_RMSG_SWIF_SRPCIM_TO_MRPCIM_VPLANE_RMSG(val)\
+ vxge_vBIT(val, 0, 64)
+               u8      unused06420[0x06420-0x05dd0];
+
+/*0x06420*/    u64     mrpcim_to_srpcim_vplane_wmsg[17];
+#define        VXGE_HW_MRPCIM_TO_SRPCIM_VPLANE_WMSG_MRPCIM_TO_SRPCIM_VPLANE_WMSG(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x064a8*/    u64     mrpcim_to_srpcim_vplane_wmsg_trig[17];
+
+/*0x06530*/    u64     debug_stats0;
+#define VXGE_HW_DEBUG_STATS0_RSTDROP_MSG(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_DEBUG_STATS0_RSTDROP_CPL(val) vxge_vBIT(val, 32, 32)
+/*0x06538*/    u64     debug_stats1;
+#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT0(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT1(val) vxge_vBIT(val, 32, 32)
+/*0x06540*/    u64     debug_stats2;
+#define VXGE_HW_DEBUG_STATS2_RSTDROP_CLIENT2(val) vxge_vBIT(val, 0, 32)
+/*0x06548*/    u64     debug_stats3_vplane[17];
+#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_PH(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_NPH(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_CPLH(val) vxge_vBIT(val, 32, 16)
+/*0x065d0*/    u64     debug_stats4_vplane[17];
+#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_PD(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_NPD(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_CPLD(val) vxge_vBIT(val, 32, 16)
+
+       u8      unused07000[0x07000-0x06658];
+
+/*0x07000*/    u64     mrpcim_general_int_status;
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PIC_INT       vxge_mBIT(0)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCI_INT       vxge_mBIT(1)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RTDMA_INT     vxge_mBIT(2)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_WRDMA_INT     vxge_mBIT(3)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMCT_INT    vxge_mBIT(4)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG1_INT     vxge_mBIT(5)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG2_INT     vxge_mBIT(6)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG3_INT     vxge_mBIT(7)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFL_INT   vxge_mBIT(8)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFU_INT   vxge_mBIT(9)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG1_INT     vxge_mBIT(10)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG2_INT     vxge_mBIT(11)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG3_INT     vxge_mBIT(12)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_XMAC_INT      vxge_mBIT(13)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RXMAC_INT     vxge_mBIT(14)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TMAC_INT      vxge_mBIT(15)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBIF_INT    vxge_mBIT(16)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_FBMC_INT      vxge_mBIT(17)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBCT_INT    vxge_mBIT(18)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TPA_INT       vxge_mBIT(19)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_DRBELL_INT    vxge_mBIT(20)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_ONE_INT       vxge_mBIT(21)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_MSG_INT       vxge_mBIT(22)
+/*0x07008*/    u64     mrpcim_general_int_mask;
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PIC_INT vxge_mBIT(0)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCI_INT vxge_mBIT(1)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_RTDMA_INT       vxge_mBIT(2)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_WRDMA_INT       vxge_mBIT(3)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMCT_INT      vxge_mBIT(4)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG1_INT       vxge_mBIT(5)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG2_INT       vxge_mBIT(6)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG3_INT       vxge_mBIT(7)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFL_INT     vxge_mBIT(8)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFU_INT     vxge_mBIT(9)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG1_INT       vxge_mBIT(10)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG2_INT       vxge_mBIT(11)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG3_INT       vxge_mBIT(12)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_XMAC_INT        vxge_mBIT(13)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_RXMAC_INT       vxge_mBIT(14)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_TMAC_INT        vxge_mBIT(15)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBIF_INT      vxge_mBIT(16)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_FBMC_INT        vxge_mBIT(17)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBCT_INT      vxge_mBIT(18)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_TPA_INT vxge_mBIT(19)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_DRBELL_INT      vxge_mBIT(20)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_ONE_INT vxge_mBIT(21)
+#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_MSG_INT vxge_mBIT(22)
+/*0x07010*/    u64     mrpcim_ppif_int_status;
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_INI_ERRORS_INI_INT       vxge_mBIT(3)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_DMA_ERRORS_DMA_INT       vxge_mBIT(7)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_TGT_ERRORS_TGT_INT       vxge_mBIT(11)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CONFIG_ERRORS_CONFIG_INT vxge_mBIT(15)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_CRDT_INT     vxge_mBIT(19)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_PLL_ERRORS_PLL_INT       vxge_mBIT(27)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE0_CRD_INT_VPLANE0_INT\
+                                                       vxge_mBIT(31)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE1_CRD_INT_VPLANE1_INT\
+                                                       vxge_mBIT(32)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE2_CRD_INT_VPLANE2_INT\
+                                                       vxge_mBIT(33)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE3_CRD_INT_VPLANE3_INT\
+                                                       vxge_mBIT(34)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE4_CRD_INT_VPLANE4_INT\
+                                                       vxge_mBIT(35)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE5_CRD_INT_VPLANE5_INT\
+                                                       vxge_mBIT(36)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE6_CRD_INT_VPLANE6_INT\
+                                                       vxge_mBIT(37)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE7_CRD_INT_VPLANE7_INT\
+                                                       vxge_mBIT(38)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE8_CRD_INT_VPLANE8_INT\
+                                                       vxge_mBIT(39)
+#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE9_CRD_INT_VPLANE9_INT\
+                                                       vxge_mBIT(40)
+#define \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE10_CRD_INT_VPLANE10_INT \
+                                                       vxge_mBIT(41)
+#define \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE11_CRD_INT_VPLANE11_INT \
+                                                       vxge_mBIT(42)
+#define        \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE12_CRD_INT_VPLANE12_INT \
+                                                       vxge_mBIT(43)
+#define        \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE13_CRD_INT_VPLANE13_INT \
+                                                       vxge_mBIT(44)
+#define        \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE14_CRD_INT_VPLANE14_INT \
+                                                       vxge_mBIT(45)
+#define        \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE15_CRD_INT_VPLANE15_INT \
+                                                       vxge_mBIT(46)
+#define        \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE16_CRD_INT_VPLANE16_INT \
+                                                       vxge_mBIT(47)
+#define        \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_VPATH_TO_MRPCIM_ALARM_VPATH_TO_MRPCIM_ALARM_INT \
+                                                       vxge_mBIT(55)
+/*0x07018*/    u64     mrpcim_ppif_int_mask;
+       u8      unused07028[0x07028-0x07020];
+
+/*0x07028*/    u64     ini_errors_reg;
+#define        VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT_UNUSED_TAG      vxge_mBIT(3)
+#define        VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT vxge_mBIT(7)
+#define        VXGE_HW_INI_ERRORS_REG_DCPL_FSM_ERR     vxge_mBIT(11)
+#define        VXGE_HW_INI_ERRORS_REG_DCPL_POISON      vxge_mBIT(12)
+#define        VXGE_HW_INI_ERRORS_REG_DCPL_UNSUPPORTED vxge_mBIT(15)
+#define        VXGE_HW_INI_ERRORS_REG_DCPL_ABORT       vxge_mBIT(19)
+#define        VXGE_HW_INI_ERRORS_REG_INI_TLP_ABORT    vxge_mBIT(23)
+#define        VXGE_HW_INI_ERRORS_REG_INI_DLLP_ABORT   vxge_mBIT(27)
+#define        VXGE_HW_INI_ERRORS_REG_INI_ECRC_ERR     vxge_mBIT(31)
+#define        VXGE_HW_INI_ERRORS_REG_INI_BUF_DB_ERR   vxge_mBIT(35)
+#define        VXGE_HW_INI_ERRORS_REG_INI_BUF_SG_ERR   vxge_mBIT(39)
+#define        VXGE_HW_INI_ERRORS_REG_INI_DATA_OVERFLOW        vxge_mBIT(43)
+#define        VXGE_HW_INI_ERRORS_REG_INI_HDR_OVERFLOW vxge_mBIT(47)
+#define        VXGE_HW_INI_ERRORS_REG_INI_MRD_SYS_DROP vxge_mBIT(51)
+#define        VXGE_HW_INI_ERRORS_REG_INI_MWR_SYS_DROP vxge_mBIT(55)
+#define        VXGE_HW_INI_ERRORS_REG_INI_MRD_CLIENT_DROP      vxge_mBIT(59)
+#define        VXGE_HW_INI_ERRORS_REG_INI_MWR_CLIENT_DROP      vxge_mBIT(63)
+/*0x07030*/    u64     ini_errors_mask;
+/*0x07038*/    u64     ini_errors_alarm;
+/*0x07040*/    u64     dma_errors_reg;
+#define        VXGE_HW_DMA_ERRORS_REG_RDARB_FSM_ERR    vxge_mBIT(3)
+#define        VXGE_HW_DMA_ERRORS_REG_WRARB_FSM_ERR    vxge_mBIT(7)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_OVERFLOW        vxge_mBIT(8)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_UNDERFLOW       vxge_mBIT(9)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_OVERFLOW       vxge_mBIT(10)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_UNDERFLOW      vxge_mBIT(11)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_OVERFLOW  vxge_mBIT(12)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_UNDERFLOW vxge_mBIT(13)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_OVERFLOW vxge_mBIT(14)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_UNDERFLOW        vxge_mBIT(15)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_OVERFLOW        vxge_mBIT(16)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_UNDERFLOW       vxge_mBIT(17)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_OVERFLOW       vxge_mBIT(18)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_UNDERFLOW      vxge_mBIT(19)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_OVERFLOW        vxge_mBIT(20)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_UNDERFLOW       vxge_mBIT(21)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_OVERFLOW       vxge_mBIT(22)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_UNDERFLOW      vxge_mBIT(23)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_OVERFLOW        vxge_mBIT(24)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_UNDERFLOW       vxge_mBIT(25)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_OVERFLOW        vxge_mBIT(28)
+#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_UNDERFLOW       vxge_mBIT(29)
+#define        VXGE_HW_DMA_ERRORS_REG_DBLGEN_FSM_ERR   vxge_mBIT(32)
+#define        VXGE_HW_DMA_ERRORS_REG_DBLGEN_CREDIT_FSM_ERR    vxge_mBIT(33)
+#define        VXGE_HW_DMA_ERRORS_REG_DBLGEN_DMA_WRR_SM_ERR    vxge_mBIT(34)
+/*0x07048*/    u64     dma_errors_mask;
+/*0x07050*/    u64     dma_errors_alarm;
+/*0x07058*/    u64     tgt_errors_reg;
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_VENDOR_MSG   vxge_mBIT(0)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_MSG_UNLOCK   vxge_mBIT(1)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_ILLEGAL_TLP_BE       vxge_mBIT(2)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_BOOT_WRITE   vxge_mBIT(3)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_PIF_WR_CROSS_QWRANGE vxge_mBIT(4)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_PIF_READ_CROSS_QWRANGE       vxge_mBIT(5)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_READ    vxge_mBIT(6)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_USDC_READ    vxge_mBIT(7)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_USDC_WR_CROSS_QWRANGE        vxge_mBIT(8)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_MSIX_BEYOND_RANGE    vxge_mBIT(9)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_KDFC_POISON    vxge_mBIT(10)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_USDC_POISON    vxge_mBIT(11)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_PIF_POISON     vxge_mBIT(12)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MSIX_POISON    vxge_mBIT(13)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MRIOV_POISON   vxge_mBIT(14)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_NOT_MEM_TLP  vxge_mBIT(15)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_UNKNOWN_MEM_TLP      vxge_mBIT(16)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_REQ_FSM_ERR  vxge_mBIT(17)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_CPL_FSM_ERR  vxge_mBIT(18)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_PROT_ERR        vxge_mBIT(19)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_SWIF_PROT_ERR        vxge_mBIT(20)
+#define        VXGE_HW_TGT_ERRORS_REG_TGT_MRIOV_MEM_MAP_CFG_ERR        vxge_mBIT(21)
+/*0x07060*/    u64     tgt_errors_mask;
+/*0x07068*/    u64     tgt_errors_alarm;
+/*0x07070*/    u64     config_errors_reg;
+#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_STOP_COND vxge_mBIT(3)
+#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_START_COND        vxge_mBIT(7)
+#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_EXP_RD_CNT        vxge_mBIT(11)
+#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_EXTRA_CYCLE       vxge_mBIT(15)
+#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_MAIN_FSM_ERR      vxge_mBIT(19)
+#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_REQ_COLLISION     vxge_mBIT(23)
+#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_REG_FSM_ERR       vxge_mBIT(27)
+#define        VXGE_HW_CONFIG_ERRORS_REG_CFGM_I2C_TIMEOUT      vxge_mBIT(31)
+#define        VXGE_HW_CONFIG_ERRORS_REG_RIC_I2C_TIMEOUT       vxge_mBIT(35)
+#define        VXGE_HW_CONFIG_ERRORS_REG_CFGM_FSM_ERR  vxge_mBIT(39)
+#define        VXGE_HW_CONFIG_ERRORS_REG_RIC_FSM_ERR   vxge_mBIT(43)
+#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_ILLEGAL_ACCESS   vxge_mBIT(47)
+#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_TIMEOUT  vxge_mBIT(51)
+#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_FSM_ERR  vxge_mBIT(55)
+#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_TO_FSM_ERR       vxge_mBIT(59)
+#define        VXGE_HW_CONFIG_ERRORS_REG_RIC_RIC_RD_TIMEOUT    vxge_mBIT(63)
+/*0x07078*/    u64     config_errors_mask;
+/*0x07080*/    u64     config_errors_alarm;
+       u8      unused07090[0x07090-0x07088];
+
+/*0x07090*/    u64     crdt_errors_reg;
+#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_FSM_ERR       vxge_mBIT(11)
+#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_INTCTL_ILLEGAL_CRD_DEAL \
+                                                       vxge_mBIT(15)
+#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PDA_ILLEGAL_CRD_DEAL  vxge_mBIT(19)
+#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PCI_MSG_ILLEGAL_CRD_DEAL \
+                                                       vxge_mBIT(23)
+#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_FSM_ERR       vxge_mBIT(35)
+#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_RDA_ILLEGAL_CRD_DEAL  vxge_mBIT(39)
+#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_PDA_ILLEGAL_CRD_DEAL  vxge_mBIT(43)
+#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_DBLGEN_ILLEGAL_CRD_DEAL \
+                                                       vxge_mBIT(47)
+/*0x07098*/    u64     crdt_errors_mask;
+/*0x070a0*/    u64     crdt_errors_alarm;
+       u8      unused070b0[0x070b0-0x070a8];
+
+/*0x070b0*/    u64     mrpcim_general_errors_reg;
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_STATSB_FSM_ERR        vxge_mBIT(3)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XGEN_FSM_ERR  vxge_mBIT(7)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XMEM_FSM_ERR  vxge_mBIT(11)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_KDFCCTL_FSM_ERR       vxge_mBIT(15)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_MRIOVCTL_FSM_ERR      vxge_mBIT(19)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_FLSH_ERR  vxge_mBIT(23)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_ACK_ERR       vxge_mBIT(27)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_CHKSUM_ERR    vxge_mBIT(31)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INI_SERR_DET  vxge_mBIT(35)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSIX_FSM_ERR   vxge_mBIT(39)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSI_OVERFLOW   vxge_mBIT(43)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_PCI_NOT_FLUSH_DURING_SW_RESET \
+                                                       vxge_mBIT(47)
+#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_SW_RESET_FSM_ERR vxge_mBIT(51)
+/*0x070b8*/    u64     mrpcim_general_errors_mask;
+/*0x070c0*/    u64     mrpcim_general_errors_alarm;
+       u8      unused070d0[0x070d0-0x070c8];
+
+/*0x070d0*/    u64     pll_errors_reg;
+#define        VXGE_HW_PLL_ERRORS_REG_CORE_CMG_PLL_OOL vxge_mBIT(3)
+#define        VXGE_HW_PLL_ERRORS_REG_CORE_FB_PLL_OOL  vxge_mBIT(7)
+#define        VXGE_HW_PLL_ERRORS_REG_CORE_X_PLL_OOL   vxge_mBIT(11)
+/*0x070d8*/    u64     pll_errors_mask;
+/*0x070e0*/    u64     pll_errors_alarm;
+/*0x070e8*/    u64     srpcim_to_mrpcim_alarm_reg;
+#define        VXGE_HW_SRPCIM_TO_MRPCIM_ALARM_REG_PPIF_SRPCIM_TO_MRPCIM_ALARM(val) \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x070f0*/    u64     srpcim_to_mrpcim_alarm_mask;
+/*0x070f8*/    u64     srpcim_to_mrpcim_alarm_alarm;
+/*0x07100*/    u64     vpath_to_mrpcim_alarm_reg;
+#define        VXGE_HW_VPATH_TO_MRPCIM_ALARM_REG_PPIF_VPATH_TO_MRPCIM_ALARM(val) \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x07108*/    u64     vpath_to_mrpcim_alarm_mask;
+/*0x07110*/    u64     vpath_to_mrpcim_alarm_alarm;
+       u8      unused07128[0x07128-0x07118];
+
+/*0x07128*/    u64     crdt_errors_vplane_reg[17];
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_CONSUME_CRDT_ERR \
+                                                       vxge_mBIT(3)
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_CONSUME_CRDT_ERR \
+                                                       vxge_mBIT(7)
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_RETURN_CRDT_ERR \
+                                                       vxge_mBIT(11)
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_RETURN_CRDT_ERR \
+                                                       vxge_mBIT(15)
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_CONSUME_CRDT_ERR \
+                                                       vxge_mBIT(19)
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_RETURN_CRDT_ERR \
+                                                       vxge_mBIT(23)
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_CONSUME_TAG_ERR \
+                                                       vxge_mBIT(27)
+#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_RETURN_TAG_ERR \
+                                                       vxge_mBIT(31)
+/*0x07130*/    u64     crdt_errors_vplane_mask[17];
+/*0x07138*/    u64     crdt_errors_vplane_alarm[17];
+       u8      unused072f0[0x072f0-0x072c0];
+
+/*0x072f0*/    u64     mrpcim_rst_in_prog;
+#define        VXGE_HW_MRPCIM_RST_IN_PROG_MRPCIM_RST_IN_PROG   vxge_mBIT(7)
+/*0x072f8*/    u64     mrpcim_reg_modified;
+#define        VXGE_HW_MRPCIM_REG_MODIFIED_MRPCIM_REG_MODIFIED vxge_mBIT(7)
+
+       u8      unused07378[0x07378-0x07300];
+
+/*0x07378*/    u64     write_arb_pending;
+#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_WRDMA   vxge_mBIT(3)
+#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_RTDMA   vxge_mBIT(7)
+#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_MSG     vxge_mBIT(11)
+#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_STATSB  vxge_mBIT(15)
+#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_INTCTL  vxge_mBIT(19)
+/*0x07380*/    u64     read_arb_pending;
+#define        VXGE_HW_READ_ARB_PENDING_RDARB_WRDMA    vxge_mBIT(3)
+#define        VXGE_HW_READ_ARB_PENDING_RDARB_RTDMA    vxge_mBIT(7)
+#define        VXGE_HW_READ_ARB_PENDING_RDARB_DBLGEN   vxge_mBIT(11)
+/*0x07388*/    u64     dmaif_dmadbl_pending;
+#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_WR     vxge_mBIT(0)
+#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_RD     vxge_mBIT(1)
+#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_WR     vxge_mBIT(2)
+#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_RD     vxge_mBIT(3)
+#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_MSG_WR       vxge_mBIT(4)
+#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_STATS_WR     vxge_mBIT(5)
+#define        VXGE_HW_DMAIF_DMADBL_PENDING_DBLGEN_IN_PROG(val) \
+                                                       vxge_vBIT(val, 13, 51)
+/*0x07390*/    u64     wrcrdtarb_status0_vplane[17];
+#define        VXGE_HW_WRCRDTARB_STATUS0_VPLANE_WRCRDTARB_ABS_AVAIL_P_H(val) \
+                                                       vxge_vBIT(val, 0, 8)
+/*0x07418*/    u64     wrcrdtarb_status1_vplane[17];
+#define        VXGE_HW_WRCRDTARB_STATUS1_VPLANE_WRCRDTARB_ABS_AVAIL_P_D(val) \
+                                                       vxge_vBIT(val, 4, 12)
+       u8      unused07500[0x07500-0x074a0];
+
+/*0x07500*/    u64     mrpcim_general_cfg1;
+#define        VXGE_HW_MRPCIM_GENERAL_CFG1_CLEAR_SERR  vxge_mBIT(7)
+/*0x07508*/    u64     mrpcim_general_cfg2;
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_WR_TD        vxge_mBIT(3)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_RD_TD        vxge_mBIT(7)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_CPL_TD       vxge_mBIT(11)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MWR  vxge_mBIT(15)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MRD  vxge_mBIT(19)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_IGNORE_VPATH_RST_FOR_MSIX   vxge_mBIT(23)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_FLASH_READ_MSB      vxge_mBIT(27)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_HOST_PIPELINE_WR        vxge_mBIT(31)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_ENABLE vxge_mBIT(43)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_MAP_TO_VPATH(val) \
+                                                       vxge_vBIT(val, 47, 5)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_EN_BLOCK_MSIX_DUE_TO_SERR   vxge_mBIT(55)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_FORCE_SENDING_INTA  vxge_mBIT(59)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_SWIF_PROT_ON_RDS        vxge_mBIT(63)
+/*0x07510*/    u64     mrpcim_general_cfg3;
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_PROTECTION_CA_OR_UNSUPN     vxge_mBIT(0)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_ILLEGAL_RD_CA_OR_UNSUPN     vxge_mBIT(3)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BYTE_SWAPEN      vxge_mBIT(7)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BIT_FLIPEN       vxge_mBIT(11)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BYTE_SWAPEN      vxge_mBIT(15)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BIT_FLIPEN       vxge_mBIT(19)
+#define VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MAX_MVFS(val) vxge_vBIT(val, 20, 16)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MVF_TBL_SIZE(val) \
+                                                       vxge_vBIT(val, 36, 16)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_PF0_SW_RESET_EN     vxge_mBIT(55)
+#define VXGE_HW_MRPCIM_GENERAL_CFG3_REG_MODIFIED_CFG(val) vxge_vBIT(val, 56, 2)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_CPL_ECC_ENABLE_N    vxge_mBIT(59)
+#define        VXGE_HW_MRPCIM_GENERAL_CFG3_BYPASS_DAISY_CHAIN  vxge_mBIT(63)
+/*0x07518*/    u64     mrpcim_stats_start_host_addr;
+#define        VXGE_HW_MRPCIM_STATS_START_HOST_ADDR_MRPCIM_STATS_START_HOST_ADDR(val)\
+                                                       vxge_vBIT(val, 0, 57)
+
+       u8      unused07950[0x07950-0x07520];
+
+/*0x07950*/    u64     rdcrdtarb_cfg0;
+#define VXGE_HW_RDCRDTARB_CFG0_RDA_MAX_OUTSTANDING_RDS(val) \
+                                               vxge_vBIT(val, 18, 6)
+#define VXGE_HW_RDCRDTARB_CFG0_PDA_MAX_OUTSTANDING_RDS(val) \
+                                               vxge_vBIT(val, 26, 6)
+#define VXGE_HW_RDCRDTARB_CFG0_DBLGEN_MAX_OUTSTANDING_RDS(val) \
+                                               vxge_vBIT(val, 34, 6)
+#define VXGE_HW_RDCRDTARB_CFG0_WAIT_CNT(val) vxge_vBIT(val, 48, 4)
+#define VXGE_HW_RDCRDTARB_CFG0_MAX_OUTSTANDING_RDS(val) vxge_vBIT(val, 54, 6)
+#define        VXGE_HW_RDCRDTARB_CFG0_EN_XON   vxge_mBIT(63)
+       u8      unused07be8[0x07be8-0x07958];
+
+/*0x07be8*/    u64     bf_sw_reset;
+#define VXGE_HW_BF_SW_RESET_BF_SW_RESET(val) vxge_vBIT(val, 0, 8)
+/*0x07bf0*/    u64     sw_reset_status;
+#define        VXGE_HW_SW_RESET_STATUS_RESET_CMPLT     vxge_mBIT(7)
+#define        VXGE_HW_SW_RESET_STATUS_INIT_CMPLT      vxge_mBIT(15)
+       u8      unused07d30[0x07d30-0x07bf8];
+
+/*0x07d30*/    u64     mrpcim_debug_stats0;
+#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_WR_DROP(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_RD_DROP(val) vxge_vBIT(val, 32, 32)
+/*0x07d38*/    u64     mrpcim_debug_stats1_vplane[17];
+#define        VXGE_HW_MRPCIM_DEBUG_STATS1_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x07dc0*/    u64     mrpcim_debug_stats2_vplane[17];
+#define        VXGE_HW_MRPCIM_DEBUG_STATS2_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x07e48*/    u64     mrpcim_debug_stats3_vplane[17];
+#define        VXGE_HW_MRPCIM_DEBUG_STATS3_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x07ed0*/    u64     mrpcim_debug_stats4;
+#define VXGE_HW_MRPCIM_DEBUG_STATS4_INI_WR_VPIN_DROP(val) vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_MRPCIM_DEBUG_STATS4_INI_RD_VPIN_DROP(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x07ed8*/    u64     genstats_count01;
+#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT1(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT0(val) vxge_vBIT(val, 32, 32)
+/*0x07ee0*/    u64     genstats_count23;
+#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT3(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT2(val) vxge_vBIT(val, 32, 32)
+/*0x07ee8*/    u64     genstats_count4;
+#define VXGE_HW_GENSTATS_COUNT4_GENSTATS_COUNT4(val) vxge_vBIT(val, 32, 32)
+/*0x07ef0*/    u64     genstats_count5;
+#define VXGE_HW_GENSTATS_COUNT5_GENSTATS_COUNT5(val) vxge_vBIT(val, 32, 32)
+
+       u8      unused07f08[0x07f08-0x07ef8];
+
+/*0x07f08*/    u64     genstats_cfg[6];
+#define VXGE_HW_GENSTATS_CFG_DTYPE_SEL(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_GENSTATS_CFG_CLIENT_NO_SEL(val) vxge_vBIT(val, 9, 3)
+#define VXGE_HW_GENSTATS_CFG_WR_RD_CPL_SEL(val) vxge_vBIT(val, 14, 2)
+#define VXGE_HW_GENSTATS_CFG_VPATH_SEL(val) vxge_vBIT(val, 31, 17)
+/*0x07f38*/    u64     genstat_64bit_cfg;
+#define        VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS0      vxge_mBIT(3)
+#define        VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS2      vxge_mBIT(7)
+       u8      unused08000[0x08000-0x07f40];
+/*0x08000*/    u64     gcmg3_int_status;
+#define        VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR0_GSTC0_INT    vxge_mBIT(0)
+#define        VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR1_GSTC1_INT    vxge_mBIT(1)
+#define        VXGE_HW_GCMG3_INT_STATUS_GH2L_ERR0_GH2L0_INT    vxge_mBIT(2)
+#define        VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR_GH2L1_INT     vxge_mBIT(3)
+#define        VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR2_GH2L2_INT    vxge_mBIT(4)
+#define        VXGE_HW_GCMG3_INT_STATUS_GH2L_SMERR0_GH2L3_INT  vxge_mBIT(5)
+#define        VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR3_GH2L4_INT    vxge_mBIT(6)
+/*0x08008*/    u64     gcmg3_int_mask;
+       u8      unused09000[0x09000-0x8010];
+
+/*0x09000*/    u64     g3ifcmd_fb_int_status;
+#define        VXGE_HW_G3IFCMD_FB_INT_STATUS_ERR_G3IF_INT      vxge_mBIT(0)
+/*0x09008*/    u64     g3ifcmd_fb_int_mask;
+/*0x09010*/    u64     g3ifcmd_fb_err_reg;
+#define        VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_CK_DLL_LOCK     vxge_mBIT(6)
+#define        VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_SM_ERR  vxge_mBIT(7)
+#define VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
+                                               vxge_vBIT(val, 24, 8)
+#define        VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_IOCAL_FAULT     vxge_mBIT(55)
+/*0x09018*/    u64     g3ifcmd_fb_err_mask;
+/*0x09020*/    u64     g3ifcmd_fb_err_alarm;
+
+       u8      unused09400[0x09400-0x09028];
+
+/*0x09400*/    u64     g3ifcmd_cmu_int_status;
+#define        VXGE_HW_G3IFCMD_CMU_INT_STATUS_ERR_G3IF_INT     vxge_mBIT(0)
+/*0x09408*/    u64     g3ifcmd_cmu_int_mask;
+/*0x09410*/    u64     g3ifcmd_cmu_err_reg;
+#define        VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_CK_DLL_LOCK    vxge_mBIT(6)
+#define        VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_SM_ERR vxge_mBIT(7)
+#define VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
+                                                       vxge_vBIT(val, 24, 8)
+#define        VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_IOCAL_FAULT    vxge_mBIT(55)
+/*0x09418*/    u64     g3ifcmd_cmu_err_mask;
+/*0x09420*/    u64     g3ifcmd_cmu_err_alarm;
+
+       u8      unused09800[0x09800-0x09428];
+
+/*0x09800*/    u64     g3ifcmd_cml_int_status;
+#define        VXGE_HW_G3IFCMD_CML_INT_STATUS_ERR_G3IF_INT     vxge_mBIT(0)
+/*0x09808*/    u64     g3ifcmd_cml_int_mask;
+/*0x09810*/    u64     g3ifcmd_cml_err_reg;
+#define        VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_CK_DLL_LOCK    vxge_mBIT(6)
+#define        VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_SM_ERR vxge_mBIT(7)
+#define VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
+                                               vxge_vBIT(val, 24, 8)
+#define        VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_IOCAL_FAULT    vxge_mBIT(55)
+/*0x09818*/    u64     g3ifcmd_cml_err_mask;
+/*0x09820*/    u64     g3ifcmd_cml_err_alarm;
+       u8      unused09b00[0x09b00-0x09828];
+
+/*0x09b00*/    u64     vpath_to_vplane_map[17];
+#define VXGE_HW_VPATH_TO_VPLANE_MAP_VPATH_TO_VPLANE_MAP(val) \
+                                                       vxge_vBIT(val, 3, 5)
+       u8      unused09c30[0x09c30-0x09b88];
+
+/*0x09c30*/    u64     xgxs_cfg_port[2];
+#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_LOS(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_VALID(val) vxge_vBIT(val, 20, 4)
+#define        VXGE_HW_XGXS_CFG_PORT_SEL_INFO_0        vxge_mBIT(27)
+#define VXGE_HW_XGXS_CFG_PORT_SEL_INFO_1(val) vxge_vBIT(val, 29, 3)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE0_SKEW(val) vxge_vBIT(val, 32, 4)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE1_SKEW(val) vxge_vBIT(val, 36, 4)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE2_SKEW(val) vxge_vBIT(val, 40, 4)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE3_SKEW(val) vxge_vBIT(val, 44, 4)
+/*0x09c40*/    u64     xgxs_rxber_cfg_port[2];
+#define VXGE_HW_XGXS_RXBER_CFG_PORT_INTERVAL_DUR(val) vxge_vBIT(val, 0, 4)
+#define        VXGE_HW_XGXS_RXBER_CFG_PORT_RXGXS_INTERVAL_CNT(val) \
+                                                       vxge_vBIT(val, 16, 48)
+/*0x09c50*/    u64     xgxs_rxber_status_port[2];
+#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_A_ERR_CNT(val)  \
+                                                       vxge_vBIT(val, 0, 16)
+#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_B_ERR_CNT(val)  \
+                                                       vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_C_ERR_CNT(val)  \
+                                                       vxge_vBIT(val, 32, 16)
+#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_D_ERR_CNT(val)  \
+                                                       vxge_vBIT(val, 48, 16)
+/*0x09c60*/    u64     xgxs_status_port[2];
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_TX_ACTIVITY(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_RX_ACTIVITY(val) vxge_vBIT(val, 4, 4)
+#define        VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_FIFO_ERR BIT(11)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_BYTE_SYNC_LOST(val) \
+                                                       vxge_vBIT(val, 12, 4)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_ERR(val) vxge_vBIT(val, 16, 4)
+#define        VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_ALIGNMENT_ERR        vxge_mBIT(23)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_DEC_ERR(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_INS_REQ(val) \
+                                                       vxge_vBIT(val, 32, 4)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_DEL_REQ(val) \
+                                                       vxge_vBIT(val, 36, 4)
+/*0x09c70*/    u64     xgxs_pma_reset_port[2];
+#define VXGE_HW_XGXS_PMA_RESET_PORT_SERDES_RESET(val) vxge_vBIT(val, 0, 8)
+       u8      unused09c90[0x09c90-0x09c80];
+
+/*0x09c90*/    u64     xgxs_static_cfg_port[2];
+#define        VXGE_HW_XGXS_STATIC_CFG_PORT_FW_CTRL_SERDES     vxge_mBIT(3)
+       u8      unused09d40[0x09d40-0x09ca0];
+
+/*0x09d40*/    u64     xgxs_info_port[2];
+#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_0(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_1(val) vxge_vBIT(val, 32, 32)
+/*0x09d50*/    u64     ratemgmt_cfg_port[2];
+#define VXGE_HW_RATEMGMT_CFG_PORT_MODE(val) vxge_vBIT(val, 2, 2)
+#define        VXGE_HW_RATEMGMT_CFG_PORT_RATE  vxge_mBIT(7)
+#define        VXGE_HW_RATEMGMT_CFG_PORT_FIXED_USE_FSM vxge_mBIT(11)
+#define        VXGE_HW_RATEMGMT_CFG_PORT_ANTP_USE_FSM  vxge_mBIT(15)
+#define        VXGE_HW_RATEMGMT_CFG_PORT_ANBE_USE_FSM  vxge_mBIT(19)
+/*0x09d60*/    u64     ratemgmt_status_port[2];
+#define        VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_COMPLETE  vxge_mBIT(3)
+#define        VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_RATE      vxge_mBIT(7)
+#define        VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_MAC_MATCHES_PHY   vxge_mBIT(11)
+       u8      unused09d80[0x09d80-0x09d70];
+
+/*0x09d80*/    u64     ratemgmt_fixed_cfg_port[2];
+#define        VXGE_HW_RATEMGMT_FIXED_CFG_PORT_RESTART vxge_mBIT(7)
+/*0x09d90*/    u64     ratemgmt_antp_cfg_port[2];
+#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_RESTART  vxge_mBIT(7)
+#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_PREAMBLE_EXT_PHY     vxge_mBIT(11)
+#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_ACT_SEL      vxge_mBIT(15)
+#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_RETRY_PHY_QUERY(val) \
+                                                       vxge_vBIT(val, 16, 4)
+#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_WAIT_MDIO_RESPONSE(val) \
+                                                       vxge_vBIT(val, 20, 4)
+#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_LDOWN_REAUTO_RESPONSE(val) \
+                                                       vxge_vBIT(val, 24, 4)
+#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_10G    vxge_mBIT(31)
+#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_1G     vxge_mBIT(35)
+/*0x09da0*/    u64     ratemgmt_anbe_cfg_port[2];
+#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_RESTART  vxge_mBIT(7)
+#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_10G_KX4_ENABLE \
+                                                               vxge_mBIT(11)
+#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_1G_KX_ENABLE \
+                                                               vxge_mBIT(15)
+#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_10G_KX4(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_1G_KX(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_DME_EXCHANGE(val) vxge_vBIT(val, 24, 4)
+#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_10G_KX4        vxge_mBIT(31)
+#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_1G_KX  vxge_mBIT(35)
+/*0x09db0*/    u64     anbe_cfg_port[2];
+#define VXGE_HW_ANBE_CFG_PORT_RESET_CFG_REGS(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_ANBE_CFG_PORT_ALIGN_10G_KX4_OVERRIDE(val) vxge_vBIT(val, 10, 2)
+#define VXGE_HW_ANBE_CFG_PORT_SYNC_1G_KX_OVERRIDE(val) vxge_vBIT(val, 14, 2)
+/*0x09dc0*/    u64     anbe_mgr_ctrl_port[2];
+#define        VXGE_HW_ANBE_MGR_CTRL_PORT_WE   vxge_mBIT(3)
+#define        VXGE_HW_ANBE_MGR_CTRL_PORT_STROBE       vxge_mBIT(7)
+#define VXGE_HW_ANBE_MGR_CTRL_PORT_ADDR(val) vxge_vBIT(val, 15, 9)
+#define VXGE_HW_ANBE_MGR_CTRL_PORT_DATA(val) vxge_vBIT(val, 32, 32)
+       u8      unused09de0[0x09de0-0x09dd0];
+
+/*0x09de0*/    u64     anbe_fw_mstr_port[2];
+#define        VXGE_HW_ANBE_FW_MSTR_PORT_CONNECT_BEAN_TO_SERDES        vxge_mBIT(3)
+#define        VXGE_HW_ANBE_FW_MSTR_PORT_TX_ZEROES_TO_SERDES   vxge_mBIT(7)
+/*0x09df0*/    u64     anbe_hwfsm_gen_status_port[2];
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_PD \
+                                                       vxge_mBIT(3)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_DME \
+                                                       vxge_mBIT(7)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_PD \
+                                                       vxge_mBIT(11)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_DME \
+                                                       vxge_mBIT(15)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANBEFSM_STATE(val)  \
+                                                       vxge_vBIT(val, 18, 6)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_NEXT_PAGE_RECEIVED \
+                                                       vxge_mBIT(27)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_BASE_PAGE_RECEIVED \
+                                                       vxge_mBIT(35)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_AUTONEG_COMPLETE \
+                                                       vxge_mBIT(39)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NP_BEFORE_BP \
+                                                       vxge_mBIT(43)
+#define        \
+VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_BP \
+                                                       vxge_mBIT(47)
+#define        \
+VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_NP \
+vxge_mBIT(51)
+#define        \
+VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MODE_WHEN_AN_COMPLETE \
+                                                       vxge_mBIT(55)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_BP(val) \
+                                                       vxge_vBIT(val, 56, 4)
+#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_NP(val) \
+                                                       vxge_vBIT(val, 60, 4)
+/*0x09e00*/    u64     anbe_hwfsm_bp_status_port[2];
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ENABLE \
+                                                       vxge_mBIT(32)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ABILITY \
+                                                       vxge_mBIT(33)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KR_CAPABLE \
+                                                       vxge_mBIT(40)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KX4_CAPABLE \
+                                                       vxge_mBIT(41)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_1G_KX_CAPABLE \
+                                                       vxge_mBIT(42)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_TX_NONCE(val)     \
+                                                       vxge_vBIT(val, 43, 5)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP        vxge_mBIT(48)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK       vxge_mBIT(49)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_REMOTE_FAULT \
+                                                       vxge_mBIT(50)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ASM_DIR   vxge_mBIT(51)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_PAUSE     vxge_mBIT(53)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ECHOED_NONCE(val) \
+                                                       vxge_vBIT(val, 54, 5)
+#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x09e10*/    u64     anbe_hwfsm_np_status_port[2];
+#define        VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_47_TO_32(val) \
+                                                       vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_31_TO_0(val) \
+                                                       vxge_vBIT(val, 32, 32)
+       u8      unused09e30[0x09e30-0x09e20];
+
+/*0x09e30*/    u64     antp_gen_cfg_port[2];
+/*0x09e40*/    u64     antp_hwfsm_gen_status_port[2];
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G   vxge_mBIT(3)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G    vxge_mBIT(7)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANTPFSM_STATE(val)  \
+                                                       vxge_vBIT(val, 10, 6)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_AUTONEG_COMPLETE \
+                                                               vxge_mBIT(23)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_LP_XNP \
+                                                       vxge_mBIT(27)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_GOT_LP_XNP  vxge_mBIT(31)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MESSAGE_CODE \
+                                                       vxge_mBIT(35)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_HCD \
+                                                       vxge_mBIT(43)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_FOUND_HCD   vxge_mBIT(47)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_INVALID_RATE \
+                                                       vxge_mBIT(51)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_VALID_RATE  vxge_mBIT(55)
+#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_PERSISTENT_LDOWN \
+                                                       vxge_mBIT(59)
+/*0x09e50*/    u64     antp_hwfsm_bp_status_port[2];
+#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP        vxge_mBIT(0)
+#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK       vxge_mBIT(1)
+#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_RF        vxge_mBIT(2)
+#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_XNP       vxge_mBIT(3)
+#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ABILITY_FIELD(val) \
+                                                       vxge_vBIT(val, 4, 7)
+#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \
+                                                       vxge_vBIT(val, 11, 5)
+/*0x09e60*/    u64     antp_hwfsm_xnp_status_port[2];
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_NP      vxge_mBIT(0)
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK     vxge_mBIT(1)
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MP      vxge_mBIT(2)
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK2    vxge_mBIT(3)
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_TOGGLE  vxge_mBIT(4)
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MESSAGE_CODE(val) \
+                                                       vxge_vBIT(val, 5, 11)
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD1(val) \
+                                                       vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD2(val) \
+                                                       vxge_vBIT(val, 32, 16)
+/*0x09e70*/    u64     mdio_mgr_access_port[2];
+#define        VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_ONE BIT(3)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_OP_TYPE(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DEVAD(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ADDR(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DATA(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ST_PATTERN(val) vxge_vBIT(val, 49, 2)
+#define        VXGE_HW_MDIO_MGR_ACCESS_PORT_PREAMBLE   vxge_mBIT(51)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_PRTAD(val) vxge_vBIT(val, 55, 5)
+#define        VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_TWO vxge_mBIT(63)
+       u8      unused0a200[0x0a200-0x09e80];
+/*0x0a200*/    u64     xmac_vsport_choices_vh[17];
+#define VXGE_HW_XMAC_VSPORT_CHOICES_VH_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17)
+       u8      unused0a400[0x0a400-0x0a288];
+
+/*0x0a400*/    u64     rx_thresh_cfg_vp[17];
+#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_0(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_1(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_2(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_3(val) vxge_vBIT(val, 40, 8)
+       u8      unused0ac90[0x0ac90-0x0a488];
+} __packed;
+
+/*VXGE_HW_SRPCIM_REGS_H*/
+struct vxge_hw_srpcim_reg {
+
+/*0x00000*/    u64     tim_mr2sr_resource_assignment_vh;
+#define        VXGE_HW_TIM_MR2SR_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) \
+                                                       vxge_vBIT(val, 0, 32)
+       u8      unused00100[0x00100-0x00008];
+
+/*0x00100*/    u64     srpcim_pcipif_int_status;
+#define        VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_MRPCIM_MSG_MRPCIM_MSG_INT      BIT(3)
+#define        VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_VPATH_MSG_VPATH_MSG_INT        BIT(7)
+#define        VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_SRPCIM_SPARE_R1_SRPCIM_SPARE_R1_INT \
+                                                                       BIT(11)
+/*0x00108*/    u64     srpcim_pcipif_int_mask;
+/*0x00110*/    u64     mrpcim_msg_reg;
+#define        VXGE_HW_MRPCIM_MSG_REG_SWIF_MRPCIM_TO_SRPCIM_RMSG_INT   BIT(3)
+/*0x00118*/    u64     mrpcim_msg_mask;
+/*0x00120*/    u64     mrpcim_msg_alarm;
+/*0x00128*/    u64     vpath_msg_reg;
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH0_TO_SRPCIM_RMSG_INT    BIT(0)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH1_TO_SRPCIM_RMSG_INT    BIT(1)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH2_TO_SRPCIM_RMSG_INT    BIT(2)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH3_TO_SRPCIM_RMSG_INT    BIT(3)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH4_TO_SRPCIM_RMSG_INT    BIT(4)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH5_TO_SRPCIM_RMSG_INT    BIT(5)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH6_TO_SRPCIM_RMSG_INT    BIT(6)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH7_TO_SRPCIM_RMSG_INT    BIT(7)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH8_TO_SRPCIM_RMSG_INT    BIT(8)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH9_TO_SRPCIM_RMSG_INT    BIT(9)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH10_TO_SRPCIM_RMSG_INT   BIT(10)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH11_TO_SRPCIM_RMSG_INT   BIT(11)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH12_TO_SRPCIM_RMSG_INT   BIT(12)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH13_TO_SRPCIM_RMSG_INT   BIT(13)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH14_TO_SRPCIM_RMSG_INT   BIT(14)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH15_TO_SRPCIM_RMSG_INT   BIT(15)
+#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH16_TO_SRPCIM_RMSG_INT   BIT(16)
+/*0x00130*/    u64     vpath_msg_mask;
+/*0x00138*/    u64     vpath_msg_alarm;
+       u8      unused00160[0x00160-0x00140];
+
+/*0x00160*/    u64     srpcim_to_mrpcim_wmsg;
+#define        VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_SRPCIM_TO_MRPCIM_WMSG(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x00168*/    u64     srpcim_to_mrpcim_wmsg_trig;
+#define        VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_TRIG_SRPCIM_TO_MRPCIM_WMSG_TRIG   BIT(0)
+/*0x00170*/    u64     mrpcim_to_srpcim_rmsg;
+#define        VXGE_HW_MRPCIM_TO_SRPCIM_RMSG_SWIF_MRPCIM_TO_SRPCIM_RMSG(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x00178*/    u64     vpath_to_srpcim_rmsg_sel;
+#define        VXGE_HW_VPATH_TO_SRPCIM_RMSG_SEL_VPATH_TO_SRPCIM_RMSG_SEL(val) \
+                                                       vxge_vBIT(val, 0, 5)
+/*0x00180*/    u64     vpath_to_srpcim_rmsg;
+#define        VXGE_HW_VPATH_TO_SRPCIM_RMSG_SWIF_VPATH_TO_SRPCIM_RMSG(val) \
+                                                       vxge_vBIT(val, 0, 64)
+       u8      unused00200[0x00200-0x00188];
+
+/*0x00200*/    u64     srpcim_general_int_status;
+#define        VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PIC_INT       BIT(0)
+#define        VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PCI_INT       BIT(3)
+#define        VXGE_HW_SRPCIM_GENERAL_INT_STATUS_XMAC_INT      BIT(7)
+       u8      unused00210[0x00210-0x00208];
+
+/*0x00210*/    u64     srpcim_general_int_mask;
+#define        VXGE_HW_SRPCIM_GENERAL_INT_MASK_PIC_INT BIT(0)
+#define        VXGE_HW_SRPCIM_GENERAL_INT_MASK_PCI_INT BIT(3)
+#define        VXGE_HW_SRPCIM_GENERAL_INT_MASK_XMAC_INT        BIT(7)
+       u8      unused00220[0x00220-0x00218];
+
+/*0x00220*/    u64     srpcim_ppif_int_status;
+
+/*0x00228*/    u64     srpcim_ppif_int_mask;
+/*0x00230*/    u64     srpcim_gen_errors_reg;
+#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_STATUS_ERR   BIT(3)
+#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_UNCOR_ERR    BIT(7)
+#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_COR_ERR      BIT(11)
+#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_INTCTRL_SCHED_INT BIT(15)
+#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_INI_SERR_DET      BIT(19)
+#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_TGT_PF_ILLEGAL_ACCESS     BIT(23)
+/*0x00238*/    u64     srpcim_gen_errors_mask;
+/*0x00240*/    u64     srpcim_gen_errors_alarm;
+/*0x00248*/    u64     mrpcim_to_srpcim_alarm_reg;
+#define        VXGE_HW_MRPCIM_TO_SRPCIM_ALARM_REG_PPIF_MRPCIM_TO_SRPCIM_ALARM  BIT(3)
+/*0x00250*/    u64     mrpcim_to_srpcim_alarm_mask;
+/*0x00258*/    u64     mrpcim_to_srpcim_alarm_alarm;
+/*0x00260*/    u64     vpath_to_srpcim_alarm_reg;
+
+/*0x00268*/    u64     vpath_to_srpcim_alarm_mask;
+/*0x00270*/    u64     vpath_to_srpcim_alarm_alarm;
+       u8      unused00280[0x00280-0x00278];
+
+/*0x00280*/    u64     pf_sw_reset;
+#define VXGE_HW_PF_SW_RESET_PF_SW_RESET(val) vxge_vBIT(val, 0, 8)
+/*0x00288*/    u64     srpcim_general_cfg1;
+#define        VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BYTE_SWAPEN    BIT(19)
+#define        VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BIT_FLIPEN     BIT(23)
+#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_SWAPEN    BIT(27)
+#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_FLIPEN    BIT(31)
+#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_SWAPEN    BIT(35)
+#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_FLIPEN    BIT(39)
+/*0x00290*/    u64     srpcim_interrupt_cfg1;
+#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7)
+#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_TRAFFIC_CLASS(val) vxge_vBIT(val, 9, 3)
+       u8      unused002a8[0x002a8-0x00298];
+
+/*0x002a8*/    u64     srpcim_clear_msix_mask;
+#define        VXGE_HW_SRPCIM_CLEAR_MSIX_MASK_SRPCIM_CLEAR_MSIX_MASK   BIT(0)
+/*0x002b0*/    u64     srpcim_set_msix_mask;
+#define        VXGE_HW_SRPCIM_SET_MSIX_MASK_SRPCIM_SET_MSIX_MASK       BIT(0)
+/*0x002b8*/    u64     srpcim_clr_msix_one_shot;
+#define        VXGE_HW_SRPCIM_CLR_MSIX_ONE_SHOT_SRPCIM_CLR_MSIX_ONE_SHOT       BIT(0)
+/*0x002c0*/    u64     srpcim_rst_in_prog;
+#define        VXGE_HW_SRPCIM_RST_IN_PROG_SRPCIM_RST_IN_PROG   BIT(7)
+/*0x002c8*/    u64     srpcim_reg_modified;
+#define        VXGE_HW_SRPCIM_REG_MODIFIED_SRPCIM_REG_MODIFIED BIT(7)
+/*0x002d0*/    u64     tgt_pf_illegal_access;
+#define VXGE_HW_TGT_PF_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7)
+/*0x002d8*/    u64     srpcim_msix_status;
+#define        VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_MASK      BIT(3)
+#define        VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_PENDING_VECTOR    BIT(7)
+       u8      unused00880[0x00880-0x002e0];
+
+/*0x00880*/    u64     xgmac_sr_int_status;
+#define        VXGE_HW_XGMAC_SR_INT_STATUS_ASIC_NTWK_SR_ERR_ASIC_NTWK_SR_INT   BIT(3)
+/*0x00888*/    u64     xgmac_sr_int_mask;
+/*0x00890*/    u64     asic_ntwk_sr_err_reg;
+#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT BIT(3)
+#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK    BIT(7)
+#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT_OCCURRED \
+                                                                       BIT(11)
+#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK_OCCURRED   BIT(15)
+/*0x00898*/    u64     asic_ntwk_sr_err_mask;
+/*0x008a0*/    u64     asic_ntwk_sr_err_alarm;
+       u8      unused008c0[0x008c0-0x008a8];
+
+/*0x008c0*/    u64     xmac_vsport_choices_sr_clone;
+#define        VXGE_HW_XMAC_VSPORT_CHOICES_SR_CLONE_VSPORT_VECTOR(val) \
+                                                       vxge_vBIT(val, 0, 17)
+       u8      unused00900[0x00900-0x008c8];
+
+/*0x00900*/    u64     mr_rqa_top_prty_for_vh;
+#define        VXGE_HW_MR_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00908*/    u64     umq_vh_data_list_empty;
+#define        VXGE_HW_UMQ_VH_DATA_LIST_EMPTY_ROCRC_UMQ_VH_DATA_LIST_EMPTY \
+                                                       BIT(0)
+/*0x00910*/    u64     wde_cfg;
+#define        VXGE_HW_WDE_CFG_NS0_FORCE_MWB_START     BIT(0)
+#define        VXGE_HW_WDE_CFG_NS0_FORCE_MWB_END       BIT(1)
+#define        VXGE_HW_WDE_CFG_NS0_FORCE_QB_START      BIT(2)
+#define        VXGE_HW_WDE_CFG_NS0_FORCE_QB_END        BIT(3)
+#define        VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_START    BIT(4)
+#define        VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_END      BIT(5)
+#define        VXGE_HW_WDE_CFG_NS0_MWB_OPT_EN  BIT(6)
+#define        VXGE_HW_WDE_CFG_NS0_QB_OPT_EN   BIT(7)
+#define        VXGE_HW_WDE_CFG_NS0_MPSB_OPT_EN BIT(8)
+#define        VXGE_HW_WDE_CFG_NS1_FORCE_MWB_START     BIT(9)
+#define        VXGE_HW_WDE_CFG_NS1_FORCE_MWB_END       BIT(10)
+#define        VXGE_HW_WDE_CFG_NS1_FORCE_QB_START      BIT(11)
+#define        VXGE_HW_WDE_CFG_NS1_FORCE_QB_END        BIT(12)
+#define        VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_START    BIT(13)
+#define        VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_END      BIT(14)
+#define        VXGE_HW_WDE_CFG_NS1_MWB_OPT_EN  BIT(15)
+#define        VXGE_HW_WDE_CFG_NS1_QB_OPT_EN   BIT(16)
+#define        VXGE_HW_WDE_CFG_NS1_MPSB_OPT_EN BIT(17)
+#define        VXGE_HW_WDE_CFG_DISABLE_QPAD_FOR_UNALIGNED_ADDR BIT(19)
+#define VXGE_HW_WDE_CFG_ALIGNMENT_PREFERENCE(val) vxge_vBIT(val, 30, 2)
+#define VXGE_HW_WDE_CFG_MEM_WORD_SIZE(val) vxge_vBIT(val, 46, 2)
+
+} __packed;
+
+/*VXGE_HW_VPMGMT_REGS_H*/
+struct vxge_hw_vpmgmt_reg {
+
+       u8      unused00040[0x00040-0x00000];
+
+/*0x00040*/    u64     vpath_to_func_map_cfg1;
+#define        VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_VPATH_TO_FUNC_MAP_CFG1(val) \
+                                                       vxge_vBIT(val, 3, 5)
+/*0x00048*/    u64     vpath_is_first;
+#define        VXGE_HW_VPATH_IS_FIRST_VPATH_IS_FIRST   vxge_mBIT(3)
+/*0x00050*/    u64     srpcim_to_vpath_wmsg;
+#define        VXGE_HW_SRPCIM_TO_VPATH_WMSG_SRPCIM_TO_VPATH_WMSG(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x00058*/    u64     srpcim_to_vpath_wmsg_trig;
+#define        VXGE_HW_SRPCIM_TO_VPATH_WMSG_TRIG_SRPCIM_TO_VPATH_WMSG_TRIG \
+                                                               vxge_mBIT(0)
+       u8      unused00100[0x00100-0x00060];
+
+/*0x00100*/    u64     tim_vpath_assignment;
+#define VXGE_HW_TIM_VPATH_ASSIGNMENT_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
+       u8      unused00140[0x00140-0x00108];
+
+/*0x00140*/    u64     rqa_top_prty_for_vp;
+#define VXGE_HW_RQA_TOP_PRTY_FOR_VP_RQA_TOP_PRTY_FOR_VP(val) \
+                                                       vxge_vBIT(val, 59, 5)
+       u8      unused001c0[0x001c0-0x00148];
+
+/*0x001c0*/    u64     rxmac_rx_pa_cfg0_vpmgmt_clone;
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IGNORE_FRAME_ERR  vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_SNAP_AB_N vxge_mBIT(7)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_HAO    vxge_mBIT(18)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_MOBILE_IPV6_HDRS \
+                                                               vxge_mBIT(19)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IPV6_STOP_SEARCHING \
+                                                               vxge_mBIT(23)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_NO_PS_IF_UNKNOWN  vxge_mBIT(27)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_ETYPE  vxge_mBIT(35)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L3_CSUM_ERR \
+                                                               vxge_mBIT(39)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR \
+                                                               vxge_mBIT(43)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L4_CSUM_ERR \
+                                                               vxge_mBIT(47)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR \
+                                                               vxge_mBIT(51)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_RPA_ERR \
+                                                               vxge_mBIT(55)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_RPA_ERR \
+                                                               vxge_mBIT(59)
+#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_JUMBO_SNAP_EN     vxge_mBIT(63)
+/*0x001c8*/    u64     rts_mgr_cfg0_vpmgmt_clone;
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_RTS_DP_SP_PRIORITY    vxge_mBIT(3)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_FLEX_L4PRTCL_VALUE(val) \
+                                                       vxge_vBIT(val, 24, 8)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ICMP_TRASH    vxge_mBIT(35)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_TCPSYN_TRASH  vxge_mBIT(39)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ZL4PYLD_TRASH vxge_mBIT(43)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_TCP_TRASH     vxge_mBIT(47)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_UDP_TRASH     vxge_mBIT(51)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_FLEX_TRASH    vxge_mBIT(55)
+#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_IPFRAG_TRASH  vxge_mBIT(59)
+/*0x001d0*/    u64     rts_mgr_criteria_priority_vpmgmt_clone;
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ETYPE(val) \
+                                                       vxge_vBIT(val, 5, 3)
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ICMP_TCPSYN(val) \
+                                                       vxge_vBIT(val, 9, 3)
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PN(val) \
+                                                       vxge_vBIT(val, 13, 3)
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RANGE_L4PN(val) \
+                                                       vxge_vBIT(val, 17, 3)
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RTH_IT(val) \
+                                                       vxge_vBIT(val, 21, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_DS(val) \
+                                                       vxge_vBIT(val, 25, 3)
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_QOS(val) \
+                                                       vxge_vBIT(val, 29, 3)
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ZL4PYLD(val) \
+                                                       vxge_vBIT(val, 33, 3)
+#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PRTCL(val) \
+                                                       vxge_vBIT(val, 37, 3)
+/*0x001d8*/    u64     rxmac_cfg0_port_vpmgmt_clone[3];
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_RMAC_EN    vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_STRIP_FCS  vxge_mBIT(7)
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_DISCARD_PFRM       vxge_mBIT(11)
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_FCS_ERR     vxge_mBIT(15)
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LONG_ERR    vxge_mBIT(19)
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_USIZED_ERR  vxge_mBIT(23)
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LEN_MISMATCH \
+                                                               vxge_mBIT(27)
+#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_MAX_PYLD_LEN(val) \
+                                                       vxge_vBIT(val, 50, 14)
+/*0x001f0*/    u64     rxmac_pause_cfg_port_vpmgmt_clone[3];
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_GEN_EN        vxge_mBIT(3)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_RCV_EN        vxge_mBIT(7)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_ACCEL_SEND(val) \
+                                                       vxge_vBIT(val, 9, 3)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_DUAL_THR      vxge_mBIT(15)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_HIGH_PTIME(val) \
+                                                       vxge_vBIT(val, 20, 16)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_FCS_ERR \
+                                                               vxge_mBIT(39)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_LEN_ERR \
+                                                               vxge_mBIT(43)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_LIMITER_EN    vxge_mBIT(47)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_MAX_LIMIT(val) \
+                                                       vxge_vBIT(val, 48, 8)
+#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_PERMIT_RATEMGMT_CTRL \
+                                                       vxge_mBIT(59)
+       u8      unused00240[0x00240-0x00208];
+
+/*0x00240*/    u64     xmac_vsport_choices_vp;
+#define VXGE_HW_XMAC_VSPORT_CHOICES_VP_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17)
+       u8      unused00260[0x00260-0x00248];
+
+/*0x00260*/    u64     xgmac_gen_status_vpmgmt_clone;
+#define        VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK     vxge_mBIT(3)
+#define        VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_DATA_RATE \
+                                                               vxge_mBIT(11)
+/*0x00268*/    u64     xgmac_status_port_vpmgmt_clone[2];
+#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_REMOTE_FAULT \
+                                                               vxge_mBIT(3)
+#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_LOCAL_FAULT vxge_mBIT(7)
+#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_MAC_PHY_LAYER_AVAIL \
+                                                               vxge_mBIT(11)
+#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_PORT_OK    vxge_mBIT(15)
+/*0x00278*/    u64     xmac_gen_cfg_vpmgmt_clone;
+#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_RATEMGMT_MAC_RATE_SEL(val) \
+                                                       vxge_vBIT(val, 2, 2)
+#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_TX_HEAD_DROP_WHEN_FAULT \
+                                                       vxge_mBIT(7)
+#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_FAULT_BEHAVIOUR       vxge_mBIT(27)
+#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_UP(val) \
+                                                       vxge_vBIT(val, 28, 4)
+#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_DOWN(val) \
+                                                       vxge_vBIT(val, 32, 4)
+/*0x00280*/    u64     xmac_timestamp_vpmgmt_clone;
+#define        VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_EN  vxge_mBIT(3)
+#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_USE_LINK_ID(val) \
+                                                       vxge_vBIT(val, 6, 2)
+#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_INTERVAL(val) vxge_vBIT(val, 12, 4)
+#define        VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_TIMER_RESTART       vxge_mBIT(19)
+#define        VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_XMACJ_ROLLOVER_CNT(val) \
+                                                       vxge_vBIT(val, 32, 16)
+/*0x00288*/    u64     xmac_stats_gen_cfg_vpmgmt_clone;
+#define        VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_PRTAGGR_CUM_TIMER(val) \
+                                                       vxge_vBIT(val, 4, 4)
+#define        VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VPATH_CUM_TIMER(val) \
+                                                       vxge_vBIT(val, 8, 4)
+#define        VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VLAN_HANDLING   vxge_mBIT(15)
+/*0x00290*/    u64     xmac_cfg_port_vpmgmt_clone[3];
+#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_LOOPBACK       vxge_mBIT(3)
+#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_REVERSE_LOOPBACK \
+                                                               vxge_mBIT(7)
+#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_TX_BEHAV       vxge_mBIT(11)
+#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_RX_BEHAV       vxge_mBIT(15)
+       u8      unused002c0[0x002c0-0x002a8];
+
+/*0x002c0*/    u64     txmac_gen_cfg0_vpmgmt_clone;
+#define        VXGE_HW_TXMAC_GEN_CFG0_VPMGMT_CLONE_CHOSEN_TX_PORT      vxge_mBIT(7)
+/*0x002c8*/    u64     txmac_cfg0_port_vpmgmt_clone[3];
+#define        VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_TMAC_EN    vxge_mBIT(3)
+#define        VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_APPEND_PAD vxge_mBIT(7)
+#define VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_PAD_BYTE(val) vxge_vBIT(val, 8, 8)
+       u8      unused00300[0x00300-0x002e0];
+
+/*0x00300*/    u64     wol_mp_crc;
+#define VXGE_HW_WOL_MP_CRC_CRC(val) vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_WOL_MP_CRC_RC_EN        vxge_mBIT(63)
+/*0x00308*/    u64     wol_mp_mask_a;
+#define VXGE_HW_WOL_MP_MASK_A_MASK(val) vxge_vBIT(val, 0, 64)
+/*0x00310*/    u64     wol_mp_mask_b;
+#define VXGE_HW_WOL_MP_MASK_B_MASK(val) vxge_vBIT(val, 0, 64)
+       u8      unused00360[0x00360-0x00318];
+
+/*0x00360*/    u64     fau_pa_cfg_vpmgmt_clone;
+#define        VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L4_COMP_CSUM       vxge_mBIT(3)
+#define        VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_INCL_CF vxge_mBIT(7)
+#define        VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_COMP_CSUM       vxge_mBIT(11)
+/*0x00368*/    u64     rx_datapath_util_vp_clone;
+#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_UTILIZATION(val) \
+                                                       vxge_vBIT(val, 7, 9)
+#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_UTIL_CFG(val) \
+                                                       vxge_vBIT(val, 16, 4)
+#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_FRAC_UTIL(val) \
+                                                       vxge_vBIT(val, 20, 4)
+#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_PKT_WEIGHT(val) \
+                                                       vxge_vBIT(val, 24, 4)
+       u8      unused00380[0x00380-0x00370];
+
+/*0x00380*/    u64     tx_datapath_util_vp_clone;
+#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_UTILIZATION(val) \
+                                                       vxge_vBIT(val, 7, 9)
+#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_UTIL_CFG(val) \
+                                                       vxge_vBIT(val, 16, 4)
+#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_FRAC_UTIL(val) \
+                                                       vxge_vBIT(val, 20, 4)
+#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_PKT_WEIGHT(val) \
+                                                       vxge_vBIT(val, 24, 4)
+
+} __packed;
+
+struct vxge_hw_vpath_reg {
+
+       u8      unused00300[0x00300];
+
+/*0x00300*/    u64     usdc_vpath;
+#define VXGE_HW_USDC_VPATH_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 32)
+       u8      unused00a00[0x00a00-0x00308];
+
+/*0x00a00*/    u64     wrdma_alarm_status;
+#define        VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT    vxge_mBIT(1)
+/*0x00a08*/    u64     wrdma_alarm_mask;
+       u8      unused00a30[0x00a30-0x00a10];
+
+/*0x00a30*/    u64     prc_alarm_reg;
+#define        VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP     vxge_mBIT(0)
+#define        VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR  vxge_mBIT(1)
+#define        VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT        vxge_mBIT(2)
+#define        VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR       vxge_mBIT(3)
+/*0x00a38*/    u64     prc_alarm_mask;
+/*0x00a40*/    u64     prc_alarm_alarm;
+/*0x00a48*/    u64     prc_cfg1;
+#define VXGE_HW_PRC_CFG1_RX_TIMER_VAL(val) vxge_vBIT(val, 3, 29)
+#define        VXGE_HW_PRC_CFG1_TIM_RING_BUMP_INT_ENABLE       vxge_mBIT(34)
+#define        VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE       vxge_mBIT(35)
+#define        VXGE_HW_PRC_CFG1_GREEDY_RETURN  vxge_mBIT(36)
+#define        VXGE_HW_PRC_CFG1_QUICK_SHOT     vxge_mBIT(37)
+#define        VXGE_HW_PRC_CFG1_RX_TIMER_CI    vxge_mBIT(39)
+#define VXGE_HW_PRC_CFG1_RESET_TIMER_ON_RXD_RET(val) vxge_vBIT(val, 40, 2)
+       u8      unused00a60[0x00a60-0x00a50];
+
+/*0x00a60*/    u64     prc_cfg4;
+#define        VXGE_HW_PRC_CFG4_IN_SVC vxge_mBIT(7)
+#define VXGE_HW_PRC_CFG4_RING_MODE(val) vxge_vBIT(val, 14, 2)
+#define        VXGE_HW_PRC_CFG4_RXD_NO_SNOOP   vxge_mBIT(22)
+#define        VXGE_HW_PRC_CFG4_FRM_NO_SNOOP   vxge_mBIT(23)
+#define        VXGE_HW_PRC_CFG4_RTH_DISABLE    vxge_mBIT(31)
+#define        VXGE_HW_PRC_CFG4_IGNORE_OWNERSHIP       vxge_mBIT(32)
+#define        VXGE_HW_PRC_CFG4_SIGNAL_BENIGN_OVFLW    vxge_mBIT(36)
+#define        VXGE_HW_PRC_CFG4_BIMODAL_INTERRUPT      vxge_mBIT(37)
+#define VXGE_HW_PRC_CFG4_BACKOFF_INTERVAL(val) vxge_vBIT(val, 40, 24)
+/*0x00a68*/    u64     prc_cfg5;
+#define VXGE_HW_PRC_CFG5_RXD0_ADD(val) vxge_vBIT(val, 0, 61)
+/*0x00a70*/    u64     prc_cfg6;
+#define        VXGE_HW_PRC_CFG6_FRM_PAD_EN     vxge_mBIT(0)
+#define        VXGE_HW_PRC_CFG6_QSIZE_ALIGNED_RXD      vxge_mBIT(2)
+#define        VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN       vxge_mBIT(5)
+#define        VXGE_HW_PRC_CFG6_L3_CPC_TRSFR_CODE_EN   vxge_mBIT(8)
+#define        VXGE_HW_PRC_CFG6_L4_CPC_TRSFR_CODE_EN   vxge_mBIT(9)
+#define VXGE_HW_PRC_CFG6_RXD_CRXDT(val) vxge_vBIT(val, 23, 9)
+#define VXGE_HW_PRC_CFG6_RXD_SPAT(val) vxge_vBIT(val, 36, 9)
+/*0x00a78*/    u64     prc_cfg7;
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE(val) vxge_vBIT(val, 6, 2)
+#define        VXGE_HW_PRC_CFG7_SMART_SCAT_EN  vxge_mBIT(11)
+#define        VXGE_HW_PRC_CFG7_RXD_NS_CHG_EN  vxge_mBIT(12)
+#define        VXGE_HW_PRC_CFG7_NO_HDR_SEPARATION      vxge_mBIT(14)
+#define VXGE_HW_PRC_CFG7_RXD_BUFF_SIZE_MASK(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_PRC_CFG7_BUFF_SIZE0_MASK(val) vxge_vBIT(val, 27, 5)
+/*0x00a80*/    u64     tim_dest_addr;
+#define VXGE_HW_TIM_DEST_ADDR_TIM_DEST_ADDR(val) vxge_vBIT(val, 0, 64)
+/*0x00a88*/    u64     prc_rxd_doorbell;
+#define VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val) vxge_vBIT(val, 48, 16)
+/*0x00a90*/    u64     rqa_prty_for_vp;
+#define VXGE_HW_RQA_PRTY_FOR_VP_RQA_PRTY_FOR_VP(val) vxge_vBIT(val, 59, 5)
+/*0x00a98*/    u64     rxdmem_size;
+#define VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(val) vxge_vBIT(val, 51, 13)
+/*0x00aa0*/    u64     frm_in_progress_cnt;
+#define        VXGE_HW_FRM_IN_PROGRESS_CNT_PRC_FRM_IN_PROGRESS_CNT(val) \
+                                                       vxge_vBIT(val, 59, 5)
+/*0x00aa8*/    u64     rx_multi_cast_stats;
+#define VXGE_HW_RX_MULTI_CAST_STATS_FRAME_DISCARD(val) vxge_vBIT(val, 48, 16)
+/*0x00ab0*/    u64     rx_frm_transferred;
+#define        VXGE_HW_RX_FRM_TRANSFERRED_RX_FRM_TRANSFERRED(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x00ab8*/    u64     rxd_returned;
+#define VXGE_HW_RXD_RETURNED_RXD_RETURNED(val) vxge_vBIT(val, 48, 16)
+       u8      unused00c00[0x00c00-0x00ac0];
+
+/*0x00c00*/    u64     kdfc_fifo_trpl_partition;
+#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_1(val) vxge_vBIT(val, 33, 15)
+#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_2(val) vxge_vBIT(val, 49, 15)
+/*0x00c08*/    u64     kdfc_fifo_trpl_ctrl;
+#define        VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE      vxge_mBIT(7)
+/*0x00c10*/    u64     kdfc_trpl_fifo_0_ctrl;
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(val) vxge_vBIT(val, 14, 2)
+#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_FLIP_EN   vxge_mBIT(22)
+#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN   vxge_mBIT(23)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
+#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_CTRL_STRUC        vxge_mBIT(28)
+#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_ADD_PAD   vxge_mBIT(29)
+#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_NO_SNOOP  vxge_mBIT(30)
+#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_RLX_ORD   vxge_mBIT(31)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
+/*0x00c18*/    u64     kdfc_trpl_fifo_1_ctrl;
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE(val) vxge_vBIT(val, 14, 2)
+#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_FLIP_EN   vxge_mBIT(22)
+#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SWAP_EN   vxge_mBIT(23)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
+#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_CTRL_STRUC        vxge_mBIT(28)
+#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_ADD_PAD   vxge_mBIT(29)
+#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_NO_SNOOP  vxge_mBIT(30)
+#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_RLX_ORD   vxge_mBIT(31)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
+/*0x00c20*/    u64     kdfc_trpl_fifo_2_ctrl;
+#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_FLIP_EN   vxge_mBIT(22)
+#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SWAP_EN   vxge_mBIT(23)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
+#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_CTRL_STRUC        vxge_mBIT(28)
+#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_ADD_PAD   vxge_mBIT(29)
+#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_NO_SNOOP  vxge_mBIT(30)
+#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_RLX_ORD   vxge_mBIT(31)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
+/*0x00c28*/    u64     kdfc_trpl_fifo_0_wb_address;
+#define VXGE_HW_KDFC_TRPL_FIFO_0_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x00c30*/    u64     kdfc_trpl_fifo_1_wb_address;
+#define VXGE_HW_KDFC_TRPL_FIFO_1_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x00c38*/    u64     kdfc_trpl_fifo_2_wb_address;
+#define VXGE_HW_KDFC_TRPL_FIFO_2_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x00c40*/    u64     kdfc_trpl_fifo_offset;
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR0(val) vxge_vBIT(val, 1, 15)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR1(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR2(val) vxge_vBIT(val, 33, 15)
+/*0x00c48*/    u64     kdfc_drbl_triplet_total;
+#define        VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_KDFC_MAX_SIZE(val) \
+                                                       vxge_vBIT(val, 17, 15)
+       u8      unused00c60[0x00c60-0x00c50];
+
+/*0x00c60*/    u64     usdc_drbl_ctrl;
+#define        VXGE_HW_USDC_DRBL_CTRL_FLIP_EN  vxge_mBIT(22)
+#define        VXGE_HW_USDC_DRBL_CTRL_SWAP_EN  vxge_mBIT(23)
+/*0x00c68*/    u64     usdc_vp_ready;
+#define        VXGE_HW_USDC_VP_READY_USDC_HTN_READY    vxge_mBIT(7)
+#define        VXGE_HW_USDC_VP_READY_USDC_SRQ_READY    vxge_mBIT(15)
+#define        VXGE_HW_USDC_VP_READY_USDC_CQRQ_READY   vxge_mBIT(23)
+/*0x00c70*/    u64     kdfc_status;
+#define        VXGE_HW_KDFC_STATUS_KDFC_WRR_0_READY    vxge_mBIT(0)
+#define        VXGE_HW_KDFC_STATUS_KDFC_WRR_1_READY    vxge_mBIT(1)
+#define        VXGE_HW_KDFC_STATUS_KDFC_WRR_2_READY    vxge_mBIT(2)
+       u8      unused00c80[0x00c80-0x00c78];
+
+/*0x00c80*/    u64     xmac_rpa_vcfg;
+#define        VXGE_HW_XMAC_RPA_VCFG_IPV4_TCP_INCL_PH  vxge_mBIT(3)
+#define        VXGE_HW_XMAC_RPA_VCFG_IPV6_TCP_INCL_PH  vxge_mBIT(7)
+#define        VXGE_HW_XMAC_RPA_VCFG_IPV4_UDP_INCL_PH  vxge_mBIT(11)
+#define        VXGE_HW_XMAC_RPA_VCFG_IPV6_UDP_INCL_PH  vxge_mBIT(15)
+#define        VXGE_HW_XMAC_RPA_VCFG_L4_INCL_CF        vxge_mBIT(19)
+#define        VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG    vxge_mBIT(23)
+/*0x00c88*/    u64     rxmac_vcfg0;
+#define VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(val) vxge_vBIT(val, 2, 14)
+#define        VXGE_HW_RXMAC_VCFG0_RTS_USE_MIN_LEN     vxge_mBIT(19)
+#define VXGE_HW_RXMAC_VCFG0_RTS_MIN_FRM_LEN(val) vxge_vBIT(val, 26, 14)
+#define        VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN   vxge_mBIT(43)
+#define        VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN   vxge_mBIT(47)
+#define        VXGE_HW_RXMAC_VCFG0_BCAST_EN    vxge_mBIT(51)
+#define        VXGE_HW_RXMAC_VCFG0_ALL_VID_EN  vxge_mBIT(55)
+/*0x00c90*/    u64     rxmac_vcfg1;
+#define VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(val) vxge_vBIT(val, 42, 2)
+#define        VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE    vxge_mBIT(47)
+#define        VXGE_HW_RXMAC_VCFG1_CONTRIB_L2_FLOW     vxge_mBIT(51)
+/*0x00c98*/    u64     rts_access_steer_ctrl;
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(val) vxge_vBIT(val, 1, 7)
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(val) vxge_vBIT(val, 8, 4)
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE    vxge_mBIT(15)
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_BEHAV_TBL_SEL     vxge_mBIT(23)
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL vxge_mBIT(27)
+#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS      vxge_mBIT(0)
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(val) vxge_vBIT(val, 40, 8)
+/*0x00ca0*/    u64     rts_access_steer_data0;
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DATA(val) vxge_vBIT(val, 0, 64)
+/*0x00ca8*/    u64     rts_access_steer_data1;
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DATA(val) vxge_vBIT(val, 0, 64)
+       u8      unused00d00[0x00d00-0x00cb0];
+
+/*0x00d00*/    u64     xmac_vsport_choice;
+#define VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER(val) vxge_vBIT(val, 3, 5)
+/*0x00d08*/    u64     xmac_stats_cfg;
+/*0x00d10*/    u64     xmac_stats_access_cmd;
+#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(val) vxge_vBIT(val, 6, 2)
+#define        VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE    vxge_mBIT(15)
+#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8)
+/*0x00d18*/    u64     xmac_stats_access_data;
+#define VXGE_HW_XMAC_STATS_ACCESS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64)
+/*0x00d20*/    u64     asic_ntwk_vp_ctrl;
+#define        VXGE_HW_ASIC_NTWK_VP_CTRL_REQ_TEST_NTWK vxge_mBIT(3)
+#define        VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_SHOW_PORT_INFO  vxge_mBIT(55)
+#define        VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_PORT_NUM        vxge_mBIT(63)
+       u8      unused00d30[0x00d30-0x00d28];
+
+/*0x00d30*/    u64     xgmac_vp_int_status;
+#define        VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT \
+                                                               vxge_mBIT(3)
+/*0x00d38*/    u64     xgmac_vp_int_mask;
+/*0x00d40*/    u64     asic_ntwk_vp_err_reg;
+#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT        vxge_mBIT(3)
+#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK vxge_mBIT(7)
+#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR \
+                                                               vxge_mBIT(11)
+#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR \
+                                                       vxge_mBIT(15)
+#define        VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT \
+                                                       vxge_mBIT(19)
+#define        VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK   vxge_mBIT(23)
+/*0x00d48*/    u64     asic_ntwk_vp_err_mask;
+/*0x00d50*/    u64     asic_ntwk_vp_err_alarm;
+       u8      unused00d80[0x00d80-0x00d58];
+
+/*0x00d80*/    u64     rtdma_bw_ctrl;
+#define        VXGE_HW_RTDMA_BW_CTRL_BW_CTRL_EN        vxge_mBIT(39)
+#define VXGE_HW_RTDMA_BW_CTRL_DESIRED_BW(val) vxge_vBIT(val, 46, 18)
+/*0x00d88*/    u64     rtdma_rd_optimization_ctrl;
+#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_GEN_INT_AFTER_ABORT  vxge_mBIT(3)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_MODE(val) vxge_vBIT(val, 6, 2)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_PATTERN(val) vxge_vBIT(val, 8, 8)
+#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE    vxge_mBIT(19)
+#define VXGE_HW_PCI_EXP_DEVCTL_READRQ   0x7000  /* Max_Read_Request_Size */
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val) \
+                                                       vxge_vBIT(val, 21, 3)
+#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK_EN    vxge_mBIT(28)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK(val) \
+                                                       vxge_vBIT(val, 29, 3)
+#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN      vxge_mBIT(35)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(val) \
+                                                       vxge_vBIT(val, 37, 3)
+#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_WAIT_FOR_SPACE   vxge_mBIT(43)
+#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_FILL_THRESH(val) \
+                                                       vxge_vBIT(val, 51, 5)
+#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY_EN     vxge_mBIT(59)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY(val) \
+                                                       vxge_vBIT(val, 61, 3)
+/*0x00d90*/    u64     pda_pcc_job_monitor;
+#define        VXGE_HW_PDA_PCC_JOB_MONITOR_PDA_PCC_JOB_STATUS  vxge_mBIT(7)
+/*0x00d98*/    u64     tx_protocol_assist_cfg;
+#define        VXGE_HW_TX_PROTOCOL_ASSIST_CFG_LSOV2_EN vxge_mBIT(6)
+#define        VXGE_HW_TX_PROTOCOL_ASSIST_CFG_IPV6_KEEP_SEARCHING      vxge_mBIT(7)
+       u8      unused01000[0x01000-0x00da0];
+
+/*0x01000*/    u64     tim_cfg1_int_num[4];
+#define VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(val) vxge_vBIT(val, 6, 26)
+#define        VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN       vxge_mBIT(35)
+#define        VXGE_HW_TIM_CFG1_INT_NUM_TXFRM_CNT_EN   vxge_mBIT(36)
+#define        VXGE_HW_TIM_CFG1_INT_NUM_TXD_CNT_EN     vxge_mBIT(37)
+#define        VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC       vxge_mBIT(38)
+#define        VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI       vxge_mBIT(39)
+#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(val) vxge_vBIT(val, 49, 7)
+#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(val) vxge_vBIT(val, 57, 7)
+/*0x01020*/    u64     tim_cfg2_int_num[4];
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(val) vxge_vBIT(val, 48, 16)
+/*0x01040*/    u64     tim_cfg3_int_num[4];
+#define        VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI       vxge_mBIT(0)
+#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(val) vxge_vBIT(val, 1, 4)
+#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(val) vxge_vBIT(val, 6, 26)
+#define VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(val) vxge_vBIT(val, 32, 6)
+#define VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(val) vxge_vBIT(val, 38, 26)
+/*0x01060*/    u64     tim_wrkld_clc;
+#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_PRD(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_DIV(val) vxge_vBIT(val, 35, 5)
+#define        VXGE_HW_TIM_WRKLD_CLC_CNT_FRM_BYTE      vxge_mBIT(40)
+#define VXGE_HW_TIM_WRKLD_CLC_CNT_RX_TX(val) vxge_vBIT(val, 41, 2)
+#define        VXGE_HW_TIM_WRKLD_CLC_CNT_LNK_EN        vxge_mBIT(43)
+#define VXGE_HW_TIM_WRKLD_CLC_HOST_UTIL(val) vxge_vBIT(val, 57, 7)
+/*0x01068*/    u64     tim_bitmap;
+#define VXGE_HW_TIM_BITMAP_MASK(val) vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_TIM_BITMAP_LLROOT_RXD_EN        vxge_mBIT(32)
+#define        VXGE_HW_TIM_BITMAP_LLROOT_TXD_EN        vxge_mBIT(33)
+/*0x01070*/    u64     tim_ring_assn;
+#define VXGE_HW_TIM_RING_ASSN_INT_NUM(val) vxge_vBIT(val, 6, 2)
+/*0x01078*/    u64     tim_remap;
+#define        VXGE_HW_TIM_REMAP_TX_EN vxge_mBIT(5)
+#define        VXGE_HW_TIM_REMAP_RX_EN vxge_mBIT(6)
+#define        VXGE_HW_TIM_REMAP_OFFLOAD_EN    vxge_mBIT(7)
+#define VXGE_HW_TIM_REMAP_TO_VPATH_NUM(val) vxge_vBIT(val, 11, 5)
+/*0x01080*/    u64     tim_vpath_map;
+#define VXGE_HW_TIM_VPATH_MAP_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
+/*0x01088*/    u64     tim_pci_cfg;
+#define        VXGE_HW_TIM_PCI_CFG_ADD_PAD     vxge_mBIT(7)
+#define        VXGE_HW_TIM_PCI_CFG_NO_SNOOP    vxge_mBIT(15)
+#define        VXGE_HW_TIM_PCI_CFG_RELAXED     vxge_mBIT(23)
+#define        VXGE_HW_TIM_PCI_CFG_CTL_STR     vxge_mBIT(31)
+       u8      unused01100[0x01100-0x01090];
+
+/*0x01100*/    u64     sgrp_assign;
+#define VXGE_HW_SGRP_ASSIGN_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 64)
+/*0x01108*/    u64     sgrp_aoa_and_result;
+#define        VXGE_HW_SGRP_AOA_AND_RESULT_PET_SGRP_AOA_AND_RESULT(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x01110*/    u64     rpe_pci_cfg;
+#define        VXGE_HW_RPE_PCI_CFG_PAD_LRO_DATA_ENABLE vxge_mBIT(7)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_LRO_HDR_ENABLE  vxge_mBIT(8)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_LRO_CQE_ENABLE  vxge_mBIT(9)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_NONLL_CQE_ENABLE        vxge_mBIT(10)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_BASE_LL_CQE_ENABLE      vxge_mBIT(11)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_LL_CQE_IDATA_ENABLE     vxge_mBIT(12)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_CQRQ_IR_ENABLE  vxge_mBIT(13)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_CQSQ_IR_ENABLE  vxge_mBIT(14)
+#define        VXGE_HW_RPE_PCI_CFG_PAD_CQRR_IR_ENABLE  vxge_mBIT(15)
+#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_DATA        vxge_mBIT(18)
+#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_NONLL_CQE   vxge_mBIT(19)
+#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_LL_CQE      vxge_mBIT(20)
+#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRQ_IR     vxge_mBIT(21)
+#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQSQ_IR     vxge_mBIT(22)
+#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRR_IR     vxge_mBIT(23)
+#define        VXGE_HW_RPE_PCI_CFG_RELAXED_DATA        vxge_mBIT(26)
+#define        VXGE_HW_RPE_PCI_CFG_RELAXED_NONLL_CQE   vxge_mBIT(27)
+#define        VXGE_HW_RPE_PCI_CFG_RELAXED_LL_CQE      vxge_mBIT(28)
+#define        VXGE_HW_RPE_PCI_CFG_RELAXED_CQRQ_IR     vxge_mBIT(29)
+#define        VXGE_HW_RPE_PCI_CFG_RELAXED_CQSQ_IR     vxge_mBIT(30)
+#define        VXGE_HW_RPE_PCI_CFG_RELAXED_CQRR_IR     vxge_mBIT(31)
+/*0x01118*/    u64     rpe_lro_cfg;
+#define        VXGE_HW_RPE_LRO_CFG_SUPPRESS_LRO_ETH_TRLR       vxge_mBIT(7)
+#define        VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_SNAP_SNAPJUMBO_MRG        vxge_mBIT(11)
+#define        VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_LLC_LLCJUMBO_MRG  vxge_mBIT(15)
+#define        VXGE_HW_RPE_LRO_CFG_INCL_ACK_CNT_IN_CQE vxge_mBIT(23)
+/*0x01120*/    u64     pe_mr2vp_ack_blk_limit;
+#define VXGE_HW_PE_MR2VP_ACK_BLK_LIMIT_BLK_LIMIT(val) vxge_vBIT(val, 32, 32)
+/*0x01128*/    u64     pe_mr2vp_rirr_lirr_blk_limit;
+#define        VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_RIRR_BLK_LIMIT(val) \
+                                                       vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_LIRR_BLK_LIMIT(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x01130*/    u64     txpe_pci_nce_cfg;
+#define VXGE_HW_TXPE_PCI_NCE_CFG_NCE_THRESH(val) vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_TXPE_PCI_NCE_CFG_PAD_TOWI_ENABLE        vxge_mBIT(55)
+#define        VXGE_HW_TXPE_PCI_NCE_CFG_NOSNOOP_TOWI   vxge_mBIT(63)
+       u8      unused01180[0x01180-0x01138];
+
+/*0x01180*/    u64     msg_qpad_en_cfg;
+#define        VXGE_HW_MSG_QPAD_EN_CFG_UMQ_BWR_READ    vxge_mBIT(3)
+#define        VXGE_HW_MSG_QPAD_EN_CFG_DMQ_BWR_READ    vxge_mBIT(7)
+#define        VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_READ vxge_mBIT(11)
+#define        VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_READ vxge_mBIT(15)
+#define        VXGE_HW_MSG_QPAD_EN_CFG_UMQ_MSG_WRITE   vxge_mBIT(19)
+#define        VXGE_HW_MSG_QPAD_EN_CFG_UMQDMQ_IR_WRITE vxge_mBIT(23)
+#define        VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_WRITE        vxge_mBIT(27)
+#define        VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_WRITE        vxge_mBIT(31)
+/*0x01188*/    u64     msg_pci_cfg;
+#define        VXGE_HW_MSG_PCI_CFG_GENDMA_NO_SNOOP     vxge_mBIT(3)
+#define        VXGE_HW_MSG_PCI_CFG_UMQDMQ_IR_NO_SNOOP  vxge_mBIT(7)
+#define        VXGE_HW_MSG_PCI_CFG_UMQ_NO_SNOOP        vxge_mBIT(11)
+#define        VXGE_HW_MSG_PCI_CFG_DMQ_NO_SNOOP        vxge_mBIT(15)
+/*0x01190*/    u64     umqdmq_ir_init;
+#define VXGE_HW_UMQDMQ_IR_INIT_HOST_WRITE_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x01198*/    u64     dmq_ir_int;
+#define        VXGE_HW_DMQ_IR_INT_IMMED_ENABLE vxge_mBIT(6)
+#define        VXGE_HW_DMQ_IR_INT_EVENT_ENABLE vxge_mBIT(7)
+#define VXGE_HW_DMQ_IR_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
+#define VXGE_HW_DMQ_IR_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
+/*0x011a0*/    u64     dmq_bwr_init_add;
+#define VXGE_HW_DMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64)
+/*0x011a8*/    u64     dmq_bwr_init_byte;
+#define VXGE_HW_DMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32)
+/*0x011b0*/    u64     dmq_ir;
+#define VXGE_HW_DMQ_IR_POLICY(val) vxge_vBIT(val, 0, 8)
+/*0x011b8*/    u64     umq_int;
+#define        VXGE_HW_UMQ_INT_IMMED_ENABLE    vxge_mBIT(6)
+#define        VXGE_HW_UMQ_INT_EVENT_ENABLE    vxge_mBIT(7)
+#define VXGE_HW_UMQ_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
+#define VXGE_HW_UMQ_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
+/*0x011c0*/    u64     umq_mr2vp_bwr_pfch_init;
+#define VXGE_HW_UMQ_MR2VP_BWR_PFCH_INIT_NUMBER(val) vxge_vBIT(val, 0, 8)
+/*0x011c8*/    u64     umq_bwr_pfch_ctrl;
+#define        VXGE_HW_UMQ_BWR_PFCH_CTRL_POLL_EN       vxge_mBIT(3)
+/*0x011d0*/    u64     umq_mr2vp_bwr_eol;
+#define VXGE_HW_UMQ_MR2VP_BWR_EOL_POLL_LATENCY(val) vxge_vBIT(val, 32, 32)
+/*0x011d8*/    u64     umq_bwr_init_add;
+#define VXGE_HW_UMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64)
+/*0x011e0*/    u64     umq_bwr_init_byte;
+#define VXGE_HW_UMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32)
+/*0x011e8*/    u64     gendma_int;
+#define        VXGE_HW_GENDMA_INT_IMMED_ENABLE vxge_mBIT(6)
+#define        VXGE_HW_GENDMA_INT_EVENT_ENABLE vxge_mBIT(7)
+#define VXGE_HW_GENDMA_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
+#define VXGE_HW_GENDMA_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
+/*0x011f0*/    u64     umqdmq_ir_init_notify;
+#define        VXGE_HW_UMQDMQ_IR_INIT_NOTIFY_PULSE     vxge_mBIT(3)
+/*0x011f8*/    u64     dmq_init_notify;
+#define        VXGE_HW_DMQ_INIT_NOTIFY_PULSE   vxge_mBIT(3)
+/*0x01200*/    u64     umq_init_notify;
+#define        VXGE_HW_UMQ_INIT_NOTIFY_PULSE   vxge_mBIT(3)
+       u8      unused01380[0x01380-0x01208];
+
+/*0x01380*/    u64     tpa_cfg;
+#define        VXGE_HW_TPA_CFG_IGNORE_FRAME_ERR        vxge_mBIT(3)
+#define        VXGE_HW_TPA_CFG_IPV6_STOP_SEARCHING     vxge_mBIT(7)
+#define        VXGE_HW_TPA_CFG_L4_PSHDR_PRESENT        vxge_mBIT(11)
+#define        VXGE_HW_TPA_CFG_SUPPORT_MOBILE_IPV6_HDRS        vxge_mBIT(15)
+       u8      unused01400[0x01400-0x01388];
+
+/*0x01400*/    u64     tx_vp_reset_discarded_frms;
+#define        VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_TX_VP_RESET_DISCARDED_FRMS(val) \
+                                                       vxge_vBIT(val, 48, 16)
+       u8      unused01480[0x01480-0x01408];
+
+/*0x01480*/    u64     fau_rpa_vcfg;
+#define        VXGE_HW_FAU_RPA_VCFG_L4_COMP_CSUM       vxge_mBIT(7)
+#define        VXGE_HW_FAU_RPA_VCFG_L3_INCL_CF vxge_mBIT(11)
+#define        VXGE_HW_FAU_RPA_VCFG_L3_COMP_CSUM       vxge_mBIT(15)
+       u8      unused014d0[0x014d0-0x01488];
+
+/*0x014d0*/    u64     dbg_stats_rx_mpa;
+#define VXGE_HW_DBG_STATS_RX_MPA_CRC_FAIL_FRMS(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_DBG_STATS_RX_MPA_MRK_FAIL_FRMS(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_DBG_STATS_RX_MPA_LEN_FAIL_FRMS(val) vxge_vBIT(val, 32, 16)
+/*0x014d8*/    u64     dbg_stats_rx_fau;
+#define VXGE_HW_DBG_STATS_RX_FAU_RX_WOL_FRMS(val) vxge_vBIT(val, 0, 16)
+#define        VXGE_HW_DBG_STATS_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val) \
+                                                       vxge_vBIT(val, 16, 16)
+#define        VXGE_HW_DBG_STATS_RX_FAU_RX_PERMITTED_FRMS(val) \
+                                                       vxge_vBIT(val, 32, 32)
+       u8      unused014f0[0x014f0-0x014e0];
+
+/*0x014f0*/    u64     fbmc_vp_rdy;
+#define        VXGE_HW_FBMC_VP_RDY_QUEUE_SPAV_FM       vxge_mBIT(0)
+       u8      unused01e00[0x01e00-0x014f8];
+
+/*0x01e00*/    u64     vpath_pcipif_int_status;
+#define \
+VXGE_HW_VPATH_PCIPIF_INT_STATUS_SRPCIM_MSG_TO_VPATH_SRPCIM_MSG_TO_VPATH_INT \
+                                                               vxge_mBIT(3)
+#define        VXGE_HW_VPATH_PCIPIF_INT_STATUS_VPATH_SPARE_R1_VPATH_SPARE_R1_INT \
+                                                               vxge_mBIT(7)
+/*0x01e08*/    u64     vpath_pcipif_int_mask;
+       u8      unused01e20[0x01e20-0x01e10];
+
+/*0x01e20*/    u64     srpcim_msg_to_vpath_reg;
+#define        VXGE_HW_SRPCIM_MSG_TO_VPATH_REG_SWIF_SRPCIM_TO_VPATH_RMSG_INT \
+                                                               vxge_mBIT(3)
+/*0x01e28*/    u64     srpcim_msg_to_vpath_mask;
+/*0x01e30*/    u64     srpcim_msg_to_vpath_alarm;
+       u8      unused01ea0[0x01ea0-0x01e38];
+
+/*0x01ea0*/    u64     vpath_to_srpcim_wmsg;
+#define VXGE_HW_VPATH_TO_SRPCIM_WMSG_VPATH_TO_SRPCIM_WMSG(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x01ea8*/    u64     vpath_to_srpcim_wmsg_trig;
+#define        VXGE_HW_VPATH_TO_SRPCIM_WMSG_TRIG_VPATH_TO_SRPCIM_WMSG_TRIG \
+                                                       vxge_mBIT(0)
+       u8      unused02000[0x02000-0x01eb0];
+
+/*0x02000*/    u64     vpath_general_int_status;
+#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT        vxge_mBIT(3)
+#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT        vxge_mBIT(7)
+#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT      vxge_mBIT(15)
+#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT       vxge_mBIT(19)
+/*0x02008*/    u64     vpath_general_int_mask;
+#define        VXGE_HW_VPATH_GENERAL_INT_MASK_PIC_INT  vxge_mBIT(3)
+#define        VXGE_HW_VPATH_GENERAL_INT_MASK_PCI_INT  vxge_mBIT(7)
+#define        VXGE_HW_VPATH_GENERAL_INT_MASK_WRDMA_INT        vxge_mBIT(15)
+#define        VXGE_HW_VPATH_GENERAL_INT_MASK_XMAC_INT vxge_mBIT(19)
+/*0x02010*/    u64     vpath_ppif_int_status;
+#define        VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT \
+                                                       vxge_mBIT(3)
+#define        VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT \
+                                                       vxge_mBIT(7)
+#define        VXGE_HW_VPATH_PPIF_INT_STATUS_PCI_CONFIG_ERRORS_PCI_CONFIG_INT \
+                                                       vxge_mBIT(11)
+#define \
+VXGE_HW_VPATH_PPIF_INT_STATUS_MRPCIM_TO_VPATH_ALARM_MRPCIM_TO_VPATH_ALARM_INT \
+                                                       vxge_mBIT(15)
+#define \
+VXGE_HW_VPATH_PPIF_INT_STATUS_SRPCIM_TO_VPATH_ALARM_SRPCIM_TO_VPATH_ALARM_INT \
+                                                       vxge_mBIT(19)
+/*0x02018*/    u64     vpath_ppif_int_mask;
+/*0x02020*/    u64     kdfcctl_errors_reg;
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR  vxge_mBIT(3)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR  vxge_mBIT(7)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR  vxge_mBIT(11)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON vxge_mBIT(15)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON vxge_mBIT(19)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON vxge_mBIT(23)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR        vxge_mBIT(31)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR        vxge_mBIT(35)
+#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_DMA_ERR        vxge_mBIT(39)
+/*0x02028*/    u64     kdfcctl_errors_mask;
+/*0x02030*/    u64     kdfcctl_errors_alarm;
+       u8      unused02040[0x02040-0x02038];
+
+/*0x02040*/    u64     general_errors_reg;
+#define        VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW vxge_mBIT(3)
+#define        VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW vxge_mBIT(7)
+#define        VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW vxge_mBIT(11)
+#define        VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR vxge_mBIT(15)
+#define        VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ      vxge_mBIT(19)
+#define        VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS   vxge_mBIT(27)
+#define        VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET vxge_mBIT(31)
+/*0x02048*/    u64     general_errors_mask;
+/*0x02050*/    u64     general_errors_alarm;
+/*0x02058*/    u64     pci_config_errors_reg;
+#define        VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_STATUS_ERR      vxge_mBIT(3)
+#define        VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_UNCOR_ERR       vxge_mBIT(7)
+#define        VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_COR_ERR vxge_mBIT(11)
+/*0x02060*/    u64     pci_config_errors_mask;
+/*0x02068*/    u64     pci_config_errors_alarm;
+/*0x02070*/    u64     mrpcim_to_vpath_alarm_reg;
+#define        VXGE_HW_MRPCIM_TO_VPATH_ALARM_REG_PPIF_MRPCIM_TO_VPATH_ALARM \
+                                                               vxge_mBIT(3)
+/*0x02078*/    u64     mrpcim_to_vpath_alarm_mask;
+/*0x02080*/    u64     mrpcim_to_vpath_alarm_alarm;
+/*0x02088*/    u64     srpcim_to_vpath_alarm_reg;
+#define        VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_PPIF_SRPCIM_TO_VPATH_ALARM(val) \
+                                                       vxge_vBIT(val, 0, 17)
+/*0x02090*/    u64     srpcim_to_vpath_alarm_mask;
+/*0x02098*/    u64     srpcim_to_vpath_alarm_alarm;
+       u8      unused02108[0x02108-0x020a0];
+
+/*0x02108*/    u64     kdfcctl_status;
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_PRES(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_PRES(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_PRES(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_OVRWR(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_OVRWR(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_OVRWR(val) vxge_vBIT(val, 40, 8)
+/*0x02110*/    u64     rsthdlr_status;
+#define        VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_RESET    vxge_mBIT(3)
+#define VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_VPIN(val) vxge_vBIT(val, 6, 2)
+/*0x02118*/    u64     fifo0_status;
+#define VXGE_HW_FIFO0_STATUS_DBLGEN_FIFO0_RDIDX(val) vxge_vBIT(val, 0, 12)
+/*0x02120*/    u64     fifo1_status;
+#define VXGE_HW_FIFO1_STATUS_DBLGEN_FIFO1_RDIDX(val) vxge_vBIT(val, 0, 12)
+/*0x02128*/    u64     fifo2_status;
+#define VXGE_HW_FIFO2_STATUS_DBLGEN_FIFO2_RDIDX(val) vxge_vBIT(val, 0, 12)
+       u8      unused02158[0x02158-0x02130];
+
+/*0x02158*/    u64     tgt_illegal_access;
+#define VXGE_HW_TGT_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7)
+       u8      unused02200[0x02200-0x02160];
+
+/*0x02200*/    u64     vpath_general_cfg1;
+#define VXGE_HW_VPATH_GENERAL_CFG1_TC_VALUE(val) vxge_vBIT(val, 1, 3)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_DATA_BYTE_SWAPEN     vxge_mBIT(7)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_DATA_FLIPEN  vxge_mBIT(11)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN      vxge_mBIT(15)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_CTL_FLIPEN   vxge_mBIT(23)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_SWAPEN     vxge_mBIT(51)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_FLIPEN     vxge_mBIT(55)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_SWAPEN     vxge_mBIT(59)
+#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_FLIPEN     vxge_mBIT(63)
+/*0x02208*/    u64     vpath_general_cfg2;
+#define VXGE_HW_VPATH_GENERAL_CFG2_SIZE_QUANTUM(val) vxge_vBIT(val, 1, 3)
+/*0x02210*/    u64     vpath_general_cfg3;
+#define        VXGE_HW_VPATH_GENERAL_CFG3_IGNORE_VPATH_RST_FOR_INTA    vxge_mBIT(3)
+       u8      unused02220[0x02220-0x02218];
+
+/*0x02220*/    u64     kdfcctl_cfg0;
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0  vxge_mBIT(1)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1  vxge_mBIT(2)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2  vxge_mBIT(3)
+#define        VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO0   vxge_mBIT(5)
+#define        VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO1   vxge_mBIT(6)
+#define        VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO2   vxge_mBIT(7)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO0      vxge_mBIT(9)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO1      vxge_mBIT(10)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO2      vxge_mBIT(11)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO0      vxge_mBIT(13)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO1      vxge_mBIT(14)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO2      vxge_mBIT(15)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO0      vxge_mBIT(17)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO1      vxge_mBIT(18)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO2      vxge_mBIT(19)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO0      vxge_mBIT(21)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO1      vxge_mBIT(22)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO2      vxge_mBIT(23)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO0      vxge_mBIT(25)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO1      vxge_mBIT(26)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO2      vxge_mBIT(27)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO0      vxge_mBIT(29)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO1      vxge_mBIT(30)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO2      vxge_mBIT(31)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO0      vxge_mBIT(33)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO1      vxge_mBIT(34)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO2      vxge_mBIT(35)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO0      vxge_mBIT(37)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO1      vxge_mBIT(38)
+#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO2      vxge_mBIT(39)
+
+       u8      unused02268[0x02268-0x02228];
+
+/*0x02268*/    u64     stats_cfg;
+#define VXGE_HW_STATS_CFG_START_HOST_ADDR(val) vxge_vBIT(val, 0, 57)
+/*0x02270*/    u64     interrupt_cfg0;
+#define VXGE_HW_INTERRUPT_CFG0_MSIX_FOR_RXTI(val) vxge_vBIT(val, 1, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI(val) vxge_vBIT(val, 9, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI(val) vxge_vBIT(val, 17, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP2_MSIX_FOR_TXTI(val) vxge_vBIT(val, 25, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP3_MSIX_FOR_TXTI(val) vxge_vBIT(val, 33, 7)
+       u8      unused02280[0x02280-0x02278];
+
+/*0x02280*/    u64     interrupt_cfg2;
+#define VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7)
+/*0x02288*/    u64     one_shot_vect0_en;
+#define        VXGE_HW_ONE_SHOT_VECT0_EN_ONE_SHOT_VECT0_EN     vxge_mBIT(3)
+/*0x02290*/    u64     one_shot_vect1_en;
+#define        VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN     vxge_mBIT(3)
+/*0x02298*/    u64     one_shot_vect2_en;
+#define        VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN     vxge_mBIT(3)
+/*0x022a0*/    u64     one_shot_vect3_en;
+#define        VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN     vxge_mBIT(3)
+       u8      unused022b0[0x022b0-0x022a8];
+
+/*0x022b0*/    u64     pci_config_access_cfg1;
+#define VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(val) vxge_vBIT(val, 0, 12)
+#define        VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0        vxge_mBIT(15)
+/*0x022b8*/    u64     pci_config_access_cfg2;
+#define        VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ      vxge_mBIT(0)
+/*0x022c0*/    u64     pci_config_access_status;
+#define        VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR     vxge_mBIT(0)
+#define VXGE_HW_PCI_CONFIG_ACCESS_STATUS_DATA(val) vxge_vBIT(val, 32, 32)
+       u8      unused02300[0x02300-0x022c8];
+
+/*0x02300*/    u64     vpath_debug_stats0;
+#define VXGE_HW_VPATH_DEBUG_STATS0_INI_NUM_MWR_SENT(val) vxge_vBIT(val, 0, 32)
+/*0x02308*/    u64     vpath_debug_stats1;
+#define VXGE_HW_VPATH_DEBUG_STATS1_INI_NUM_MRD_SENT(val) vxge_vBIT(val, 0, 32)
+/*0x02310*/    u64     vpath_debug_stats2;
+#define VXGE_HW_VPATH_DEBUG_STATS2_INI_NUM_CPL_RCVD(val) vxge_vBIT(val, 0, 32)
+/*0x02318*/    u64     vpath_debug_stats3;
+#define VXGE_HW_VPATH_DEBUG_STATS3_INI_NUM_MWR_BYTE_SENT(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x02320*/    u64     vpath_debug_stats4;
+#define VXGE_HW_VPATH_DEBUG_STATS4_INI_NUM_CPL_BYTE_RCVD(val) \
+                                                       vxge_vBIT(val, 0, 64)
+/*0x02328*/    u64     vpath_debug_stats5;
+#define VXGE_HW_VPATH_DEBUG_STATS5_WRCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32)
+/*0x02330*/    u64     vpath_debug_stats6;
+#define VXGE_HW_VPATH_DEBUG_STATS6_RDCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32)
+/*0x02338*/    u64     vpath_genstats_count01;
+#define        VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT1(val) \
+                                                       vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT0(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x02340*/    u64     vpath_genstats_count23;
+#define        VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT3(val) \
+                                                       vxge_vBIT(val, 0, 32)
+#define        VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT2(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x02348*/    u64     vpath_genstats_count4;
+#define        VXGE_HW_VPATH_GENSTATS_COUNT4_PPIF_VPATH_GENSTATS_COUNT4(val) \
+                                                       vxge_vBIT(val, 32, 32)
+/*0x02350*/    u64     vpath_genstats_count5;
+#define        VXGE_HW_VPATH_GENSTATS_COUNT5_PPIF_VPATH_GENSTATS_COUNT5(val) \
+                                                       vxge_vBIT(val, 32, 32)
+       u8      unused02648[0x02648-0x02358];
+} __packed;
+
+#define VXGE_HW_EEPROM_SIZE    (0x01 << 11)
+
+/* Capability lists */
+#define  VXGE_HW_PCI_EXP_LNKCAP_LNK_SPEED    0xf  /* Supported Link speeds */
+#define  VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH    0x3f0 /* Supported Link speeds. */
+#define  VXGE_HW_PCI_EXP_LNKCAP_LW_RES       0x0  /* Reserved. */
+
+#endif
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
new file mode 100644 (file)
index 0000000..7be0ae1
--- /dev/null
@@ -0,0 +1,2528 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-traffic.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                 Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#include <linux/etherdevice.h>
+
+#include "vxge-traffic.h"
+#include "vxge-config.h"
+#include "vxge-main.h"
+
+/*
+ * vxge_hw_vpath_intr_enable - Enable vpath interrupts.
+ * @vp: Virtual Path handle.
+ *
+ * Enable vpath interrupts. The function is to be executed the last in
+ * vpath initialization sequence.
+ *
+ * See also: vxge_hw_vpath_intr_disable()
+ */
+enum vxge_hw_status vxge_hw_vpath_intr_enable(struct __vxge_hw_vpath_handle *vp)
+{
+       u64 val64;
+
+       struct __vxge_hw_virtualpath *vpath;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+
+       vp_reg = vpath->vp_reg;
+
+       writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->general_errors_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->pci_config_errors_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->mrpcim_to_vpath_alarm_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->srpcim_to_vpath_alarm_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->vpath_ppif_int_status);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->srpcim_msg_to_vpath_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->vpath_pcipif_int_status);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->prc_alarm_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->wrdma_alarm_status);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->asic_ntwk_vp_err_reg);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->xgmac_vp_int_status);
+
+       val64 = readq(&vp_reg->vpath_general_int_status);
+
+       /* Mask unwanted interrupts */
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->vpath_pcipif_int_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->srpcim_msg_to_vpath_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->srpcim_to_vpath_alarm_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->mrpcim_to_vpath_alarm_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->pci_config_errors_mask);
+
+       /* Unmask the individual interrupts */
+
+       writeq((u32)vxge_bVALn((VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW|
+               VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW|
+               VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ|
+               VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR), 0, 32),
+               &vp_reg->general_errors_mask);
+
+       __vxge_hw_pio_mem_write32_upper(
+               (u32)vxge_bVALn((VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR|
+               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR|
+               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON|
+               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON|
+               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR|
+               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR), 0, 32),
+               &vp_reg->kdfcctl_errors_mask);
+
+       __vxge_hw_pio_mem_write32_upper(0, &vp_reg->vpath_ppif_int_mask);
+
+       __vxge_hw_pio_mem_write32_upper(
+               (u32)vxge_bVALn(VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP, 0, 32),
+               &vp_reg->prc_alarm_mask);
+
+       __vxge_hw_pio_mem_write32_upper(0, &vp_reg->wrdma_alarm_mask);
+       __vxge_hw_pio_mem_write32_upper(0, &vp_reg->xgmac_vp_int_mask);
+
+       if (vpath->hldev->first_vp_id != vpath->vp_id)
+               __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->asic_ntwk_vp_err_mask);
+       else
+               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn((
+               VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT |
+               VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK), 0, 32),
+               &vp_reg->asic_ntwk_vp_err_mask);
+
+       __vxge_hw_pio_mem_write32_upper(0,
+               &vp_reg->vpath_general_int_mask);
+exit:
+       return status;
+
+}
+
+/*
+ * vxge_hw_vpath_intr_disable - Disable vpath interrupts.
+ * @vp: Virtual Path handle.
+ *
+ * Disable vpath interrupts. The function is to be executed the last in
+ * vpath initialization sequence.
+ *
+ * See also: vxge_hw_vpath_intr_enable()
+ */
+enum vxge_hw_status vxge_hw_vpath_intr_disable(
+                       struct __vxge_hw_vpath_handle *vp)
+{
+       u64 val64;
+
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+
+       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+               goto exit;
+       }
+       vp_reg = vpath->vp_reg;
+
+       __vxge_hw_pio_mem_write32_upper(
+               (u32)VXGE_HW_INTR_MASK_ALL,
+               &vp_reg->vpath_general_int_mask);
+
+       val64 = VXGE_HW_TIM_CLR_INT_EN_VP(1 << (16 - vpath->vp_id));
+
+       writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->general_errors_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->pci_config_errors_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->mrpcim_to_vpath_alarm_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->srpcim_to_vpath_alarm_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->vpath_ppif_int_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->srpcim_msg_to_vpath_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->vpath_pcipif_int_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->wrdma_alarm_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->prc_alarm_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->xgmac_vp_int_mask);
+
+       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+                       &vp_reg->asic_ntwk_vp_err_mask);
+
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_channel_msix_mask - Mask MSIX Vector.
+ * @channeh: Channel for rx or tx handle
+ * @msix_id:  MSIX ID
+ *
+ * The function masks the msix interrupt for the given msix_id
+ *
+ * Returns: 0
+ */
+void vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channel, int msix_id)
+{
+
+       __vxge_hw_pio_mem_write32_upper(
+               (u32)vxge_bVALn(vxge_mBIT(channel->first_vp_id+(msix_id/4)),
+                       0, 32),
+               &channel->common_reg->set_msix_mask_vect[msix_id%4]);
+
+       return;
+}
+
+/**
+ * vxge_hw_channel_msix_unmask - Unmask the MSIX Vector.
+ * @channeh: Channel for rx or tx handle
+ * @msix_id:  MSI ID
+ *
+ * The function unmasks the msix interrupt for the given msix_id
+ *
+ * Returns: 0
+ */
+void
+vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channel, int msix_id)
+{
+
+       __vxge_hw_pio_mem_write32_upper(
+               (u32)vxge_bVALn(vxge_mBIT(channel->first_vp_id+(msix_id/4)),
+                       0, 32),
+               &channel->common_reg->clear_msix_mask_vect[msix_id%4]);
+
+       return;
+}
+
+/**
+ * vxge_hw_device_set_intr_type - Updates the configuration
+ *             with new interrupt type.
+ * @hldev: HW device handle.
+ * @intr_mode: New interrupt type
+ */
+u32 vxge_hw_device_set_intr_type(struct __vxge_hw_device *hldev, u32 intr_mode)
+{
+
+       if ((intr_mode != VXGE_HW_INTR_MODE_IRQLINE) &&
+          (intr_mode != VXGE_HW_INTR_MODE_MSIX) &&
+          (intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) &&
+          (intr_mode != VXGE_HW_INTR_MODE_DEF))
+               intr_mode = VXGE_HW_INTR_MODE_IRQLINE;
+
+       hldev->config.intr_mode = intr_mode;
+       return intr_mode;
+}
+
+/**
+ * vxge_hw_device_intr_enable - Enable interrupts.
+ * @hldev: HW device handle.
+ * @op: One of the enum vxge_hw_device_intr enumerated values specifying
+ *      the type(s) of interrupts to enable.
+ *
+ * Enable Titan interrupts. The function is to be executed the last in
+ * Titan initialization sequence.
+ *
+ * See also: vxge_hw_device_intr_disable()
+ */
+void vxge_hw_device_intr_enable(struct __vxge_hw_device *hldev)
+{
+       u32 i;
+       u64 val64;
+       u32 val32;
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
+                       continue;
+
+               vxge_hw_vpath_intr_enable(
+                       VXGE_HW_VIRTUAL_PATH_HANDLE(&hldev->virtual_paths[i]));
+       }
+
+       if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_IRQLINE) {
+               val64 = hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
+                       hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX];
+
+               if (val64 != 0) {
+                       writeq(val64, &hldev->common_reg->tim_int_status0);
+
+                       writeq(~val64, &hldev->common_reg->tim_int_mask0);
+               }
+
+               val32 = hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
+                       hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX];
+
+               if (val32 != 0) {
+                       __vxge_hw_pio_mem_write32_upper(val32,
+                                       &hldev->common_reg->tim_int_status1);
+
+                       __vxge_hw_pio_mem_write32_upper(~val32,
+                                       &hldev->common_reg->tim_int_mask1);
+               }
+       }
+
+       val64 = readq(&hldev->common_reg->titan_general_int_status);
+
+       vxge_hw_device_unmask_all(hldev);
+
+       return;
+}
+
+/**
+ * vxge_hw_device_intr_disable - Disable Titan interrupts.
+ * @hldev: HW device handle.
+ * @op: One of the enum vxge_hw_device_intr enumerated values specifying
+ *      the type(s) of interrupts to disable.
+ *
+ * Disable Titan interrupts.
+ *
+ * See also: vxge_hw_device_intr_enable()
+ */
+void vxge_hw_device_intr_disable(struct __vxge_hw_device *hldev)
+{
+       u32 i;
+
+       vxge_hw_device_mask_all(hldev);
+
+       /* mask all the tim interrupts */
+       writeq(VXGE_HW_INTR_MASK_ALL, &hldev->common_reg->tim_int_mask0);
+       __vxge_hw_pio_mem_write32_upper(VXGE_HW_DEFAULT_32,
+               &hldev->common_reg->tim_int_mask1);
+
+       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+               if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
+                       continue;
+
+               vxge_hw_vpath_intr_disable(
+                       VXGE_HW_VIRTUAL_PATH_HANDLE(&hldev->virtual_paths[i]));
+       }
+
+       return;
+}
+
+/**
+ * vxge_hw_device_mask_all - Mask all device interrupts.
+ * @hldev: HW device handle.
+ *
+ * Mask        all device interrupts.
+ *
+ * See also: vxge_hw_device_unmask_all()
+ */
+void vxge_hw_device_mask_all(struct __vxge_hw_device *hldev)
+{
+       u64 val64;
+
+       val64 = VXGE_HW_TITAN_MASK_ALL_INT_ALARM |
+               VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC;
+
+       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+                               &hldev->common_reg->titan_mask_all_int);
+
+       return;
+}
+
+/**
+ * vxge_hw_device_unmask_all - Unmask all device interrupts.
+ * @hldev: HW device handle.
+ *
+ * Unmask all device interrupts.
+ *
+ * See also: vxge_hw_device_mask_all()
+ */
+void vxge_hw_device_unmask_all(struct __vxge_hw_device *hldev)
+{
+       u64 val64 = 0;
+
+       if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_IRQLINE)
+               val64 =  VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC;
+
+       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+                       &hldev->common_reg->titan_mask_all_int);
+
+       return;
+}
+
+/**
+ * vxge_hw_device_flush_io - Flush io writes.
+ * @hldev: HW device handle.
+ *
+ * The function        performs a read operation to flush io writes.
+ *
+ * Returns: void
+ */
+void vxge_hw_device_flush_io(struct __vxge_hw_device *hldev)
+{
+       u32 val32;
+
+       val32 = readl(&hldev->common_reg->titan_general_int_status);
+}
+
+/**
+ * vxge_hw_device_begin_irq - Begin IRQ processing.
+ * @hldev: HW device handle.
+ * @skip_alarms: Do not clear the alarms
+ * @reason: "Reason" for the interrupt, the value of Titan's
+ *     general_int_status register.
+ *
+ * The function        performs two actions, It first checks whether (shared IRQ) the
+ * interrupt was raised        by the device. Next, it masks the device interrupts.
+ *
+ * Note:
+ * vxge_hw_device_begin_irq() does not flush MMIO writes through the
+ * bridge. Therefore, two back-to-back interrupts are potentially possible.
+ *
+ * Returns: 0, if the interrupt        is not "ours" (note that in this case the
+ * device remain enabled).
+ * Otherwise, vxge_hw_device_begin_irq() returns 64bit general adapter
+ * status.
+ */
+enum vxge_hw_status vxge_hw_device_begin_irq(struct __vxge_hw_device *hldev,
+                                            u32 skip_alarms, u64 *reason)
+{
+       u32 i;
+       u64 val64;
+       u64 adapter_status;
+       u64 vpath_mask;
+       enum vxge_hw_status ret = VXGE_HW_OK;
+
+       val64 = readq(&hldev->common_reg->titan_general_int_status);
+
+       if (unlikely(!val64)) {
+               /* not Titan interrupt  */
+               *reason = 0;
+               ret = VXGE_HW_ERR_WRONG_IRQ;
+               goto exit;
+       }
+
+       if (unlikely(val64 == VXGE_HW_ALL_FOXES)) {
+
+               adapter_status = readq(&hldev->common_reg->adapter_status);
+
+               if (adapter_status == VXGE_HW_ALL_FOXES) {
+
+                       __vxge_hw_device_handle_error(hldev,
+                               NULL_VPID, VXGE_HW_EVENT_SLOT_FREEZE);
+                       *reason = 0;
+                       ret = VXGE_HW_ERR_SLOT_FREEZE;
+                       goto exit;
+               }
+       }
+
+       hldev->stats.sw_dev_info_stats.total_intr_cnt++;
+
+       *reason = val64;
+
+       vpath_mask = hldev->vpaths_deployed >>
+                               (64 - VXGE_HW_MAX_VIRTUAL_PATHS);
+
+       if (val64 &
+           VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(vpath_mask)) {
+               hldev->stats.sw_dev_info_stats.traffic_intr_cnt++;
+
+               return VXGE_HW_OK;
+       }
+
+       hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
+
+       if (unlikely(val64 &
+                       VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT)) {
+
+               enum vxge_hw_status error_level = VXGE_HW_OK;
+
+               hldev->stats.sw_dev_err_stats.vpath_alarms++;
+
+               for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+                       if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
+                               continue;
+
+                       ret = __vxge_hw_vpath_alarm_process(
+                               &hldev->virtual_paths[i], skip_alarms);
+
+                       error_level = VXGE_HW_SET_LEVEL(ret, error_level);
+
+                       if (unlikely((ret == VXGE_HW_ERR_CRITICAL) ||
+                               (ret == VXGE_HW_ERR_SLOT_FREEZE)))
+                               break;
+               }
+
+               ret = error_level;
+       }
+exit:
+       return ret;
+}
+
+/*
+ * __vxge_hw_device_handle_link_up_ind
+ * @hldev: HW device handle.
+ *
+ * Link up indication handler. The function is invoked by HW when
+ * Titan indicates that the link is up for programmable amount of time.
+ */
+enum vxge_hw_status
+__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev)
+{
+       /*
+        * If the previous link state is not down, return.
+        */
+       if (hldev->link_state == VXGE_HW_LINK_UP)
+               goto exit;
+
+       hldev->link_state = VXGE_HW_LINK_UP;
+
+       /* notify driver */
+       if (hldev->uld_callbacks.link_up)
+               hldev->uld_callbacks.link_up(hldev);
+exit:
+       return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_handle_link_down_ind
+ * @hldev: HW device handle.
+ *
+ * Link down indication handler. The function is invoked by HW when
+ * Titan indicates that the link is down.
+ */
+enum vxge_hw_status
+__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev)
+{
+       /*
+        * If the previous link state is not down, return.
+        */
+       if (hldev->link_state == VXGE_HW_LINK_DOWN)
+               goto exit;
+
+       hldev->link_state = VXGE_HW_LINK_DOWN;
+
+       /* notify driver */
+       if (hldev->uld_callbacks.link_down)
+               hldev->uld_callbacks.link_down(hldev);
+exit:
+       return VXGE_HW_OK;
+}
+
+/**
+ * __vxge_hw_device_handle_error - Handle error
+ * @hldev: HW device
+ * @vp_id: Vpath Id
+ * @type: Error type. Please see enum vxge_hw_event{}
+ *
+ * Handle error.
+ */
+enum vxge_hw_status
+__vxge_hw_device_handle_error(
+               struct __vxge_hw_device *hldev,
+               u32 vp_id,
+               enum vxge_hw_event type)
+{
+       switch (type) {
+       case VXGE_HW_EVENT_UNKNOWN:
+               break;
+       case VXGE_HW_EVENT_RESET_START:
+       case VXGE_HW_EVENT_RESET_COMPLETE:
+       case VXGE_HW_EVENT_LINK_DOWN:
+       case VXGE_HW_EVENT_LINK_UP:
+               goto out;
+       case VXGE_HW_EVENT_ALARM_CLEARED:
+               goto out;
+       case VXGE_HW_EVENT_ECCERR:
+       case VXGE_HW_EVENT_MRPCIM_ECCERR:
+               goto out;
+       case VXGE_HW_EVENT_FIFO_ERR:
+       case VXGE_HW_EVENT_VPATH_ERR:
+       case VXGE_HW_EVENT_CRITICAL_ERR:
+       case VXGE_HW_EVENT_SERR:
+               break;
+       case VXGE_HW_EVENT_SRPCIM_SERR:
+       case VXGE_HW_EVENT_MRPCIM_SERR:
+               goto out;
+       case VXGE_HW_EVENT_SLOT_FREEZE:
+               break;
+       default:
+               vxge_assert(0);
+               goto out;
+       }
+
+       /* notify driver */
+       if (hldev->uld_callbacks.crit_err)
+               hldev->uld_callbacks.crit_err(
+                       (struct __vxge_hw_device *)hldev,
+                       type, vp_id);
+out:
+
+       return VXGE_HW_OK;
+}
+
+/**
+ * vxge_hw_device_clear_tx_rx - Acknowledge (that is, clear) the
+ * condition that has caused the Tx and RX interrupt.
+ * @hldev: HW device.
+ *
+ * Acknowledge (that is, clear) the condition that has caused
+ * the Tx and Rx interrupt.
+ * See also: vxge_hw_device_begin_irq(),
+ * vxge_hw_device_mask_tx_rx(), vxge_hw_device_unmask_tx_rx().
+ */
+void vxge_hw_device_clear_tx_rx(struct __vxge_hw_device *hldev)
+{
+
+       if ((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) ||
+          (hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) {
+               writeq((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
+                                hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX]),
+                               &hldev->common_reg->tim_int_status0);
+       }
+
+       if ((hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) ||
+          (hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) {
+               __vxge_hw_pio_mem_write32_upper(
+                               (hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
+                                hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX]),
+                               &hldev->common_reg->tim_int_status1);
+       }
+
+       return;
+}
+
+/*
+ * vxge_hw_channel_dtr_alloc - Allocate a dtr from the channel
+ * @channel: Channel
+ * @dtrh: Buffer to return the DTR pointer
+ *
+ * Allocates a dtr from the reserve array. If the reserve array is empty,
+ * it swaps the reserve and free arrays.
+ *
+ */
+enum vxge_hw_status
+vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh)
+{
+       void **tmp_arr;
+
+       if (channel->reserve_ptr - channel->reserve_top > 0) {
+_alloc_after_swap:
+               *dtrh = channel->reserve_arr[--channel->reserve_ptr];
+
+               return VXGE_HW_OK;
+       }
+
+       /* switch between empty and full arrays */
+
+       /* the idea behind such a design is that by having free and reserved
+        * arrays separated we basically separated irq and non-irq parts.
+        * i.e. no additional lock need to be done when we free a resource */
+
+       if (channel->length - channel->free_ptr > 0) {
+
+               tmp_arr = channel->reserve_arr;
+               channel->reserve_arr = channel->free_arr;
+               channel->free_arr = tmp_arr;
+               channel->reserve_ptr = channel->length;
+               channel->reserve_top = channel->free_ptr;
+               channel->free_ptr = channel->length;
+
+               channel->stats->reserve_free_swaps_cnt++;
+
+               goto _alloc_after_swap;
+       }
+
+       channel->stats->full_cnt++;
+
+       *dtrh = NULL;
+       return VXGE_HW_INF_OUT_OF_DESCRIPTORS;
+}
+
+/*
+ * vxge_hw_channel_dtr_post - Post a dtr to the channel
+ * @channelh: Channel
+ * @dtrh: DTR pointer
+ *
+ * Posts a dtr to work array.
+ *
+ */
+void vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh)
+{
+       vxge_assert(channel->work_arr[channel->post_index] == NULL);
+
+       channel->work_arr[channel->post_index++] = dtrh;
+
+       /* wrap-around */
+       if (channel->post_index == channel->length)
+               channel->post_index = 0;
+}
+
+/*
+ * vxge_hw_channel_dtr_try_complete - Returns next completed dtr
+ * @channel: Channel
+ * @dtr: Buffer to return the next completed DTR pointer
+ *
+ * Returns the next completed dtr with out removing it from work array
+ *
+ */
+void
+vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel, void **dtrh)
+{
+       vxge_assert(channel->compl_index < channel->length);
+
+       *dtrh = channel->work_arr[channel->compl_index];
+}
+
+/*
+ * vxge_hw_channel_dtr_complete - Removes next completed dtr from the work array
+ * @channel: Channel handle
+ *
+ * Removes the next completed dtr from work array
+ *
+ */
+void vxge_hw_channel_dtr_complete(struct __vxge_hw_channel *channel)
+{
+       channel->work_arr[channel->compl_index] = NULL;
+
+       /* wrap-around */
+       if (++channel->compl_index == channel->length)
+               channel->compl_index = 0;
+
+       channel->stats->total_compl_cnt++;
+}
+
+/*
+ * vxge_hw_channel_dtr_free - Frees a dtr
+ * @channel: Channel handle
+ * @dtr:  DTR pointer
+ *
+ * Returns the dtr to free array
+ *
+ */
+void vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh)
+{
+       channel->free_arr[--channel->free_ptr] = dtrh;
+}
+
+/*
+ * vxge_hw_channel_dtr_count
+ * @channel: Channel handle. Obtained via vxge_hw_channel_open().
+ *
+ * Retreive number of DTRs available. This function can not be called
+ * from data path. ring_initial_replenishi() is the only user.
+ */
+int vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel)
+{
+       return (channel->reserve_ptr - channel->reserve_top) +
+               (channel->length - channel->free_ptr);
+}
+
+/**
+ * vxge_hw_ring_rxd_reserve    - Reserve ring descriptor.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Reserved descriptor. On success HW fills this "out" parameter
+ * with a valid handle.
+ *
+ * Reserve Rx descriptor for the subsequent filling-in driver
+ * and posting on the corresponding channel (@channelh)
+ * via vxge_hw_ring_rxd_post().
+ *
+ * Returns: VXGE_HW_OK - success.
+ * VXGE_HW_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available.
+ *
+ */
+enum vxge_hw_status vxge_hw_ring_rxd_reserve(struct __vxge_hw_ring *ring,
+       void **rxdh)
+{
+       enum vxge_hw_status status;
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       status = vxge_hw_channel_dtr_alloc(channel, rxdh);
+
+       if (status == VXGE_HW_OK) {
+               struct vxge_hw_ring_rxd_1 *rxdp =
+                       (struct vxge_hw_ring_rxd_1 *)*rxdh;
+
+               rxdp->control_0 = rxdp->control_1 = 0;
+       }
+
+       return status;
+}
+
+/**
+ * vxge_hw_ring_rxd_free - Free descriptor.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor handle.
+ *
+ * Free        the reserved descriptor. This operation is "symmetrical" to
+ * vxge_hw_ring_rxd_reserve. The "free-ing" completes the descriptor's
+ * lifecycle.
+ *
+ * After free-ing (see vxge_hw_ring_rxd_free()) the descriptor again can
+ * be:
+ *
+ * - reserved (vxge_hw_ring_rxd_reserve);
+ *
+ * - posted    (vxge_hw_ring_rxd_post);
+ *
+ * - completed (vxge_hw_ring_rxd_next_completed);
+ *
+ * - and recycled again        (vxge_hw_ring_rxd_free).
+ *
+ * For alternative state transitions and more details please refer to
+ * the design doc.
+ *
+ */
+void vxge_hw_ring_rxd_free(struct __vxge_hw_ring *ring, void *rxdh)
+{
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       vxge_hw_channel_dtr_free(channel, rxdh);
+
+}
+
+/**
+ * vxge_hw_ring_rxd_pre_post - Prepare rxd and post
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor handle.
+ *
+ * This routine prepares a rxd and posts
+ */
+void vxge_hw_ring_rxd_pre_post(struct __vxge_hw_ring *ring, void *rxdh)
+{
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       vxge_hw_channel_dtr_post(channel, rxdh);
+}
+
+/**
+ * vxge_hw_ring_rxd_post_post - Process rxd after post.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor handle.
+ *
+ * Processes rxd after post
+ */
+void vxge_hw_ring_rxd_post_post(struct __vxge_hw_ring *ring, void *rxdh)
+{
+       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
+
+       if (ring->stats->common_stats.usage_cnt > 0)
+               ring->stats->common_stats.usage_cnt--;
+}
+
+/**
+ * vxge_hw_ring_rxd_post - Post descriptor on the ring.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor obtained via vxge_hw_ring_rxd_reserve().
+ *
+ * Post        descriptor on the ring.
+ * Prior to posting the        descriptor should be filled in accordance with
+ * Host/Titan interface specification for a given service (LL, etc.).
+ *
+ */
+void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring, void *rxdh)
+{
+       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       wmb();
+       rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
+
+       vxge_hw_channel_dtr_post(channel, rxdh);
+
+       if (ring->stats->common_stats.usage_cnt > 0)
+               ring->stats->common_stats.usage_cnt--;
+}
+
+/**
+ * vxge_hw_ring_rxd_post_post_wmb - Process rxd after post with memory barrier.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor handle.
+ *
+ * Processes rxd after post with memory barrier.
+ */
+void vxge_hw_ring_rxd_post_post_wmb(struct __vxge_hw_ring *ring, void *rxdh)
+{
+       struct __vxge_hw_channel *channel;
+
+       channel = &ring->channel;
+
+       wmb();
+       vxge_hw_ring_rxd_post_post(ring, rxdh);
+}
+
+/**
+ * vxge_hw_ring_rxd_next_completed - Get the _next_ completed descriptor.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor handle. Returned by HW.
+ * @t_code:    Transfer code, as per Titan User Guide,
+ *      Receive Descriptor Format. Returned by HW.
+ *
+ * Retrieve the        _next_ completed descriptor.
+ * HW uses ring callback (*vxge_hw_ring_callback_f) to notifiy
+ * driver of new completed descriptors. After that
+ * the driver can use vxge_hw_ring_rxd_next_completed to retrieve the rest
+ * completions (the very first completion is passed by HW via
+ * vxge_hw_ring_callback_f).
+ *
+ * Implementation-wise, the driver is free to call
+ * vxge_hw_ring_rxd_next_completed either immediately from inside the
+ * ring callback, or in a deferred fashion and separate (from HW)
+ * context.
+ *
+ * Non-zero @t_code means failure to fill-in receive buffer(s)
+ * of the descriptor.
+ * For instance, parity        error detected during the data transfer.
+ * In this case        Titan will complete the descriptor and indicate
+ * for the host        that the received data is not to be used.
+ * For details please refer to Titan User Guide.
+ *
+ * Returns: VXGE_HW_OK - success.
+ * VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors
+ * are currently available for processing.
+ *
+ * See also: vxge_hw_ring_callback_f{},
+ * vxge_hw_fifo_rxd_next_completed(), enum vxge_hw_status{}.
+ */
+enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
+       struct __vxge_hw_ring *ring, void **rxdh, u8 *t_code)
+{
+       struct __vxge_hw_channel *channel;
+       struct vxge_hw_ring_rxd_1 *rxdp;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       channel = &ring->channel;
+
+       vxge_hw_channel_dtr_try_complete(channel, rxdh);
+
+       rxdp = (struct vxge_hw_ring_rxd_1 *)*rxdh;
+       if (rxdp == NULL) {
+               status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
+               goto exit;
+       }
+
+       /* check whether it is not the end */
+       if (!(rxdp->control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER)) {
+
+               vxge_assert(((struct vxge_hw_ring_rxd_1 *)rxdp)->host_control !=
+                               0);
+
+               ++ring->cmpl_cnt;
+               vxge_hw_channel_dtr_complete(channel);
+
+               *t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(rxdp->control_0);
+
+               vxge_assert(*t_code != VXGE_HW_RING_RXD_T_CODE_UNUSED);
+
+               ring->stats->common_stats.usage_cnt++;
+               if (ring->stats->common_stats.usage_max <
+                               ring->stats->common_stats.usage_cnt)
+                       ring->stats->common_stats.usage_max =
+                               ring->stats->common_stats.usage_cnt;
+
+               status = VXGE_HW_OK;
+               goto exit;
+       }
+
+       /* reset it. since we don't want to return
+        * garbage to the driver */
+       *rxdh = NULL;
+       status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_ring_handle_tcode - Handle transfer code.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor handle.
+ * @t_code: One of the enumerated (and documented in the Titan user guide)
+ * "transfer codes".
+ *
+ * Handle descriptor's transfer code. The latter comes with each completed
+ * descriptor.
+ *
+ * Returns: one of the enum vxge_hw_status{} enumerated types.
+ * VXGE_HW_OK                  - for success.
+ * VXGE_HW_ERR_CRITICAL         - when encounters critical error.
+ */
+enum vxge_hw_status vxge_hw_ring_handle_tcode(
+       struct __vxge_hw_ring *ring, void *rxdh, u8 t_code)
+{
+       struct __vxge_hw_channel *channel;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       channel = &ring->channel;
+
+       /* If the t_code is not supported and if the
+        * t_code is other than 0x5 (unparseable packet
+        * such as unknown UPV6 header), Drop it !!!
+        */
+
+       if (t_code == 0 || t_code == 5) {
+               status = VXGE_HW_OK;
+               goto exit;
+       }
+
+       if (t_code > 0xF) {
+               status = VXGE_HW_ERR_INVALID_TCODE;
+               goto exit;
+       }
+
+       ring->stats->rxd_t_code_err_cnt[t_code]++;
+exit:
+       return status;
+}
+
+/**
+ * __vxge_hw_non_offload_db_post - Post non offload doorbell
+ *
+ * @fifo: fifohandle
+ * @txdl_ptr: The starting location of the TxDL in host memory
+ * @num_txds: The highest TxD in this TxDL (0 to 255 means 1 to 256)
+ * @no_snoop: No snoop flags
+ *
+ * This function posts a non-offload doorbell to doorbell FIFO
+ *
+ */
+static void __vxge_hw_non_offload_db_post(struct __vxge_hw_fifo *fifo,
+       u64 txdl_ptr, u32 num_txds, u32 no_snoop)
+{
+       struct __vxge_hw_channel *channel;
+
+       channel = &fifo->channel;
+
+       writeq(VXGE_HW_NODBW_TYPE(VXGE_HW_NODBW_TYPE_NODBW) |
+               VXGE_HW_NODBW_LAST_TXD_NUMBER(num_txds) |
+               VXGE_HW_NODBW_GET_NO_SNOOP(no_snoop),
+               &fifo->nofl_db->control_0);
+
+       wmb();
+
+       writeq(txdl_ptr, &fifo->nofl_db->txdl_ptr);
+       wmb();
+
+}
+
+/**
+ * vxge_hw_fifo_free_txdl_count_get - returns the number of txdls available in
+ * the fifo
+ * @fifoh: Handle to the fifo object used for non offload send
+ */
+u32 vxge_hw_fifo_free_txdl_count_get(struct __vxge_hw_fifo *fifoh)
+{
+       return vxge_hw_channel_dtr_count(&fifoh->channel);
+}
+
+/**
+ * vxge_hw_fifo_txdl_reserve - Reserve fifo descriptor.
+ * @fifoh: Handle to the fifo object used for non offload send
+ * @txdlh: Reserved descriptor. On success HW fills this "out" parameter
+ *        with a valid handle.
+ * @txdl_priv: Buffer to return the pointer to per txdl space
+ *
+ * Reserve a single TxDL (that is, fifo descriptor)
+ * for the subsequent filling-in by driver)
+ * and posting on the corresponding channel (@channelh)
+ * via vxge_hw_fifo_txdl_post().
+ *
+ * Note: it is the responsibility of driver to reserve multiple descriptors
+ * for lengthy (e.g., LSO) transmit operation. A single fifo descriptor
+ * carries up to configured number (fifo.max_frags) of contiguous buffers.
+ *
+ * Returns: VXGE_HW_OK - success;
+ * VXGE_HW_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available
+ *
+ */
+enum vxge_hw_status vxge_hw_fifo_txdl_reserve(
+       struct __vxge_hw_fifo *fifo,
+       void **txdlh, void **txdl_priv)
+{
+       struct __vxge_hw_channel *channel;
+       enum vxge_hw_status status;
+       int i;
+
+       channel = &fifo->channel;
+
+       status = vxge_hw_channel_dtr_alloc(channel, txdlh);
+
+       if (status == VXGE_HW_OK) {
+               struct vxge_hw_fifo_txd *txdp =
+                       (struct vxge_hw_fifo_txd *)*txdlh;
+               struct __vxge_hw_fifo_txdl_priv *priv;
+
+               priv = __vxge_hw_fifo_txdl_priv(fifo, txdp);
+
+               /* reset the TxDL's private */
+               priv->align_dma_offset = 0;
+               priv->align_vaddr_start = priv->align_vaddr;
+               priv->align_used_frags = 0;
+               priv->frags = 0;
+               priv->alloc_frags = fifo->config->max_frags;
+               priv->next_txdl_priv = NULL;
+
+               *txdl_priv = (void *)(size_t)txdp->host_control;
+
+               for (i = 0; i < fifo->config->max_frags; i++) {
+                       txdp = ((struct vxge_hw_fifo_txd *)*txdlh) + i;
+                       txdp->control_0 = txdp->control_1 = 0;
+               }
+       }
+
+       return status;
+}
+
+/**
+ * vxge_hw_fifo_txdl_buffer_set - Set transmit buffer pointer in the
+ * descriptor.
+ * @fifo: Handle to the fifo object used for non offload send
+ * @txdlh: Descriptor handle.
+ * @frag_idx: Index of the data buffer in the caller's scatter-gather list
+ *            (of buffers).
+ * @dma_pointer: DMA address of the data buffer referenced by @frag_idx.
+ * @size: Size of the data buffer (in bytes).
+ *
+ * This API is part of the preparation of the transmit descriptor for posting
+ * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include
+ * vxge_hw_fifo_txdl_mss_set() and vxge_hw_fifo_txdl_cksum_set_bits().
+ * All three APIs fill in the fields of the fifo descriptor,
+ * in accordance with the Titan specification.
+ *
+ */
+void vxge_hw_fifo_txdl_buffer_set(struct __vxge_hw_fifo *fifo,
+                                 void *txdlh, u32 frag_idx,
+                                 dma_addr_t dma_pointer, u32 size)
+{
+       struct __vxge_hw_fifo_txdl_priv *txdl_priv;
+       struct vxge_hw_fifo_txd *txdp, *txdp_last;
+       struct __vxge_hw_channel *channel;
+
+       channel = &fifo->channel;
+
+       txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdlh);
+       txdp = (struct vxge_hw_fifo_txd *)txdlh  +  txdl_priv->frags;
+
+       if (frag_idx != 0)
+               txdp->control_0 = txdp->control_1 = 0;
+       else {
+               txdp->control_0 |= VXGE_HW_FIFO_TXD_GATHER_CODE(
+                       VXGE_HW_FIFO_TXD_GATHER_CODE_FIRST);
+               txdp->control_1 |= fifo->interrupt_type;
+               txdp->control_1 |= VXGE_HW_FIFO_TXD_INT_NUMBER(
+                       fifo->tx_intr_num);
+               if (txdl_priv->frags) {
+                       txdp_last = (struct vxge_hw_fifo_txd *)txdlh  +
+                       (txdl_priv->frags - 1);
+                       txdp_last->control_0 |= VXGE_HW_FIFO_TXD_GATHER_CODE(
+                               VXGE_HW_FIFO_TXD_GATHER_CODE_LAST);
+               }
+       }
+
+       vxge_assert(frag_idx < txdl_priv->alloc_frags);
+
+       txdp->buffer_pointer = (u64)dma_pointer;
+       txdp->control_0 |= VXGE_HW_FIFO_TXD_BUFFER_SIZE(size);
+       fifo->stats->total_buffers++;
+       txdl_priv->frags++;
+}
+
+/**
+ * vxge_hw_fifo_txdl_post - Post descriptor on the fifo channel.
+ * @fifo: Handle to the fifo object used for non offload send
+ * @txdlh: Descriptor obtained via vxge_hw_fifo_txdl_reserve()
+ * @frags: Number of contiguous buffers that are part of a single
+ *         transmit operation.
+ *
+ * Post descriptor on the 'fifo' type channel for transmission.
+ * Prior to posting the descriptor should be filled in accordance with
+ * Host/Titan interface specification for a given service (LL, etc.).
+ *
+ */
+void vxge_hw_fifo_txdl_post(struct __vxge_hw_fifo *fifo, void *txdlh)
+{
+       struct __vxge_hw_fifo_txdl_priv *txdl_priv;
+       struct vxge_hw_fifo_txd *txdp_last;
+       struct vxge_hw_fifo_txd *txdp_first;
+       struct __vxge_hw_channel *channel;
+
+       channel = &fifo->channel;
+
+       txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdlh);
+       txdp_first = (struct vxge_hw_fifo_txd *)txdlh;
+
+       txdp_last = (struct vxge_hw_fifo_txd *)txdlh  +  (txdl_priv->frags - 1);
+       txdp_last->control_0 |=
+             VXGE_HW_FIFO_TXD_GATHER_CODE(VXGE_HW_FIFO_TXD_GATHER_CODE_LAST);
+       txdp_first->control_0 |= VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER;
+
+       vxge_hw_channel_dtr_post(&fifo->channel, txdlh);
+
+       __vxge_hw_non_offload_db_post(fifo,
+               (u64)(size_t)txdl_priv->dma_addr,
+               txdl_priv->frags - 1,
+               fifo->no_snoop_bits);
+
+       fifo->stats->total_posts++;
+       fifo->stats->common_stats.usage_cnt++;
+       if (fifo->stats->common_stats.usage_max <
+               fifo->stats->common_stats.usage_cnt)
+               fifo->stats->common_stats.usage_max =
+                       fifo->stats->common_stats.usage_cnt;
+}
+
+/**
+ * vxge_hw_fifo_txdl_next_completed - Retrieve next completed descriptor.
+ * @fifo: Handle to the fifo object used for non offload send
+ * @txdlh: Descriptor handle. Returned by HW.
+ * @t_code: Transfer code, as per Titan User Guide,
+ *          Transmit Descriptor Format.
+ *          Returned by HW.
+ *
+ * Retrieve the _next_ completed descriptor.
+ * HW uses channel callback (*vxge_hw_channel_callback_f) to notifiy
+ * driver of new completed descriptors. After that
+ * the driver can use vxge_hw_fifo_txdl_next_completed to retrieve the rest
+ * completions (the very first completion is passed by HW via
+ * vxge_hw_channel_callback_f).
+ *
+ * Implementation-wise, the driver is free to call
+ * vxge_hw_fifo_txdl_next_completed either immediately from inside the
+ * channel callback, or in a deferred fashion and separate (from HW)
+ * context.
+ *
+ * Non-zero @t_code means failure to process the descriptor.
+ * The failure could happen, for instance, when the link is
+ * down, in which case Titan completes the descriptor because it
+ * is not able to send the data out.
+ *
+ * For details please refer to Titan User Guide.
+ *
+ * Returns: VXGE_HW_OK - success.
+ * VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors
+ * are currently available for processing.
+ *
+ */
+enum vxge_hw_status vxge_hw_fifo_txdl_next_completed(
+       struct __vxge_hw_fifo *fifo, void **txdlh,
+       enum vxge_hw_fifo_tcode *t_code)
+{
+       struct __vxge_hw_channel *channel;
+       struct vxge_hw_fifo_txd *txdp;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       channel = &fifo->channel;
+
+       vxge_hw_channel_dtr_try_complete(channel, txdlh);
+
+       txdp = (struct vxge_hw_fifo_txd *)*txdlh;
+       if (txdp == NULL) {
+               status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
+               goto exit;
+       }
+
+       /* check whether host owns it */
+       if (!(txdp->control_0 & VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER)) {
+
+               vxge_assert(txdp->host_control != 0);
+
+               vxge_hw_channel_dtr_complete(channel);
+
+               *t_code = (u8)VXGE_HW_FIFO_TXD_T_CODE_GET(txdp->control_0);
+
+               if (fifo->stats->common_stats.usage_cnt > 0)
+                       fifo->stats->common_stats.usage_cnt--;
+
+               status = VXGE_HW_OK;
+               goto exit;
+       }
+
+       /* no more completions */
+       *txdlh = NULL;
+       status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_fifo_handle_tcode - Handle transfer code.
+ * @fifo: Handle to the fifo object used for non offload send
+ * @txdlh: Descriptor handle.
+ * @t_code: One of the enumerated (and documented in the Titan user guide)
+ *          "transfer codes".
+ *
+ * Handle descriptor's transfer code. The latter comes with each completed
+ * descriptor.
+ *
+ * Returns: one of the enum vxge_hw_status{} enumerated types.
+ * VXGE_HW_OK - for success.
+ * VXGE_HW_ERR_CRITICAL - when encounters critical error.
+ */
+enum vxge_hw_status vxge_hw_fifo_handle_tcode(struct __vxge_hw_fifo *fifo,
+                                             void *txdlh,
+                                             enum vxge_hw_fifo_tcode t_code)
+{
+       struct __vxge_hw_channel *channel;
+
+       enum vxge_hw_status status = VXGE_HW_OK;
+       channel = &fifo->channel;
+
+       if (((t_code & 0x7) < 0) || ((t_code & 0x7) > 0x4)) {
+               status = VXGE_HW_ERR_INVALID_TCODE;
+               goto exit;
+       }
+
+       fifo->stats->txd_t_code_err_cnt[t_code]++;
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_fifo_txdl_free - Free descriptor.
+ * @fifo: Handle to the fifo object used for non offload send
+ * @txdlh: Descriptor handle.
+ *
+ * Free the reserved descriptor. This operation is "symmetrical" to
+ * vxge_hw_fifo_txdl_reserve. The "free-ing" completes the descriptor's
+ * lifecycle.
+ *
+ * After free-ing (see vxge_hw_fifo_txdl_free()) the descriptor again can
+ * be:
+ *
+ * - reserved (vxge_hw_fifo_txdl_reserve);
+ *
+ * - posted (vxge_hw_fifo_txdl_post);
+ *
+ * - completed (vxge_hw_fifo_txdl_next_completed);
+ *
+ * - and recycled again (vxge_hw_fifo_txdl_free).
+ *
+ * For alternative state transitions and more details please refer to
+ * the design doc.
+ *
+ */
+void vxge_hw_fifo_txdl_free(struct __vxge_hw_fifo *fifo, void *txdlh)
+{
+       struct __vxge_hw_fifo_txdl_priv *txdl_priv;
+       u32 max_frags;
+       struct __vxge_hw_channel *channel;
+
+       channel = &fifo->channel;
+
+       txdl_priv = __vxge_hw_fifo_txdl_priv(fifo,
+                       (struct vxge_hw_fifo_txd *)txdlh);
+
+       max_frags = fifo->config->max_frags;
+
+       vxge_hw_channel_dtr_free(channel, txdlh);
+}
+
+/**
+ * vxge_hw_vpath_mac_addr_add - Add the mac address entry for this vpath
+ *               to MAC address table.
+ * @vp: Vpath handle.
+ * @macaddr: MAC address to be added for this vpath into the list
+ * @macaddr_mask: MAC address mask for macaddr
+ * @duplicate_mode: Duplicate MAC address add mode. Please see
+ *             enum vxge_hw_vpath_mac_addr_add_mode{}
+ *
+ * Adds the given mac address and mac address mask into the list for this
+ * vpath.
+ * see also: vxge_hw_vpath_mac_addr_delete, vxge_hw_vpath_mac_addr_get and
+ * vxge_hw_vpath_mac_addr_get_next
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_add(
+       struct __vxge_hw_vpath_handle *vp,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN],
+       enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode)
+{
+       u32 i;
+       u64 data1 = 0ULL;
+       u64 data2 = 0ULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       for (i = 0; i < ETH_ALEN; i++) {
+               data1 <<= 8;
+               data1 |= (u8)macaddr[i];
+
+               data2 <<= 8;
+               data2 |= (u8)macaddr_mask[i];
+       }
+
+       switch (duplicate_mode) {
+       case VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE:
+               i = 0;
+               break;
+       case VXGE_HW_VPATH_MAC_ADDR_DISCARD_DUPLICATE:
+               i = 1;
+               break;
+       case VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE:
+               i = 2;
+               break;
+       default:
+               i = 0;
+               break;
+       }
+
+       status = __vxge_hw_vpath_rts_table_set(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
+                       0,
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(data1),
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(data2)|
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MODE(i));
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_mac_addr_get - Get the first mac address entry for this vpath
+ *               from MAC address table.
+ * @vp: Vpath handle.
+ * @macaddr: First MAC address entry for this vpath in the list
+ * @macaddr_mask: MAC address mask for macaddr
+ *
+ * Returns the first mac address and mac address mask in the list for this
+ * vpath.
+ * see also: vxge_hw_vpath_mac_addr_get_next
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_get(
+       struct __vxge_hw_vpath_handle *vp,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN])
+{
+       u32 i;
+       u64 data1 = 0ULL;
+       u64 data2 = 0ULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_rts_table_get(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
+                       0, &data1, &data2);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1);
+
+       data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(data2);
+
+       for (i = ETH_ALEN; i > 0; i--) {
+               macaddr[i-1] = (u8)(data1 & 0xFF);
+               data1 >>= 8;
+
+               macaddr_mask[i-1] = (u8)(data2 & 0xFF);
+               data2 >>= 8;
+       }
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_mac_addr_get_next - Get the next mac address entry for this
+ * vpath
+ *               from MAC address table.
+ * @vp: Vpath handle.
+ * @macaddr: Next MAC address entry for this vpath in the list
+ * @macaddr_mask: MAC address mask for macaddr
+ *
+ * Returns the next mac address and mac address mask in the list for this
+ * vpath.
+ * see also: vxge_hw_vpath_mac_addr_get
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_get_next(
+       struct __vxge_hw_vpath_handle *vp,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN])
+{
+       u32 i;
+       u64 data1 = 0ULL;
+       u64 data2 = 0ULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_rts_table_get(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
+                       0, &data1, &data2);
+
+       if (status != VXGE_HW_OK)
+               goto exit;
+
+       data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1);
+
+       data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(data2);
+
+       for (i = ETH_ALEN; i > 0; i--) {
+               macaddr[i-1] = (u8)(data1 & 0xFF);
+               data1 >>= 8;
+
+               macaddr_mask[i-1] = (u8)(data2 & 0xFF);
+               data2 >>= 8;
+       }
+
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_mac_addr_delete - Delete the mac address entry for this vpath
+ *               to MAC address table.
+ * @vp: Vpath handle.
+ * @macaddr: MAC address to be added for this vpath into the list
+ * @macaddr_mask: MAC address mask for macaddr
+ *
+ * Delete the given mac address and mac address mask into the list for this
+ * vpath.
+ * see also: vxge_hw_vpath_mac_addr_add, vxge_hw_vpath_mac_addr_get and
+ * vxge_hw_vpath_mac_addr_get_next
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_delete(
+       struct __vxge_hw_vpath_handle *vp,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN])
+{
+       u32 i;
+       u64 data1 = 0ULL;
+       u64 data2 = 0ULL;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       for (i = 0; i < ETH_ALEN; i++) {
+               data1 <<= 8;
+               data1 |= (u8)macaddr[i];
+
+               data2 <<= 8;
+               data2 |= (u8)macaddr_mask[i];
+       }
+
+       status = __vxge_hw_vpath_rts_table_set(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
+                       0,
+                       VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(data1),
+                       VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(data2));
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_vid_add - Add the vlan id entry for this vpath
+ *               to vlan id table.
+ * @vp: Vpath handle.
+ * @vid: vlan id to be added for this vpath into the list
+ *
+ * Adds the given vlan id into the list for this  vpath.
+ * see also: vxge_hw_vpath_vid_delete, vxge_hw_vpath_vid_get and
+ * vxge_hw_vpath_vid_get_next
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_vid_add(struct __vxge_hw_vpath_handle *vp, u64 vid)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_rts_table_set(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID,
+                       0, VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(vid), 0);
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_vid_get - Get the first vid entry for this vpath
+ *               from vlan id table.
+ * @vp: Vpath handle.
+ * @vid: Buffer to return vlan id
+ *
+ * Returns the first vlan id in the list for this vpath.
+ * see also: vxge_hw_vpath_vid_get_next
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_vid_get(struct __vxge_hw_vpath_handle *vp, u64 *vid)
+{
+       u64 data;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_rts_table_get(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID,
+                       0, vid, &data);
+
+       *vid = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(*vid);
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_vid_get_next - Get the next vid entry for this vpath
+ *               from vlan id table.
+ * @vp: Vpath handle.
+ * @vid: Buffer to return vlan id
+ *
+ * Returns the next vlan id in the list for this vpath.
+ * see also: vxge_hw_vpath_vid_get
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_vid_get_next(struct __vxge_hw_vpath_handle *vp, u64 *vid)
+{
+       u64 data;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_rts_table_get(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID,
+                       0, vid, &data);
+
+       *vid = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(*vid);
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_vid_delete - Delete the vlan id entry for this vpath
+ *               to vlan id table.
+ * @vp: Vpath handle.
+ * @vid: vlan id to be added for this vpath into the list
+ *
+ * Adds the given vlan id into the list for this  vpath.
+ * see also: vxge_hw_vpath_vid_add, vxge_hw_vpath_vid_get and
+ * vxge_hw_vpath_vid_get_next
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_vid_delete(struct __vxge_hw_vpath_handle *vp, u64 vid)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_rts_table_set(vp,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY,
+                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID,
+                       0, VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(vid), 0);
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_promisc_enable - Enable promiscuous mode.
+ * @vp: Vpath handle.
+ *
+ * Enable promiscuous mode of Titan-e operation.
+ *
+ * See also: vxge_hw_vpath_promisc_disable().
+ */
+enum vxge_hw_status vxge_hw_vpath_promisc_enable(
+                       struct __vxge_hw_vpath_handle *vp)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+
+       /* Enable promiscous mode for function 0 only */
+       if (!(vpath->hldev->access_rights &
+               VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM))
+               return VXGE_HW_OK;
+
+       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
+
+       if (!(val64 & VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN)) {
+
+               val64 |= VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN |
+                        VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN |
+                        VXGE_HW_RXMAC_VCFG0_BCAST_EN |
+                        VXGE_HW_RXMAC_VCFG0_ALL_VID_EN;
+
+               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
+       }
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_promisc_disable - Disable promiscuous mode.
+ * @vp: Vpath handle.
+ *
+ * Disable promiscuous mode of Titan-e operation.
+ *
+ * See also: vxge_hw_vpath_promisc_enable().
+ */
+enum vxge_hw_status vxge_hw_vpath_promisc_disable(
+                       struct __vxge_hw_vpath_handle *vp)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+
+       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
+
+       if (val64 & VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN) {
+
+               val64 &= ~(VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN |
+                          VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN |
+                          VXGE_HW_RXMAC_VCFG0_ALL_VID_EN);
+
+               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
+       }
+exit:
+       return status;
+}
+
+/*
+ * vxge_hw_vpath_bcast_enable - Enable broadcast
+ * @vp: Vpath handle.
+ *
+ * Enable receiving broadcasts.
+ */
+enum vxge_hw_status vxge_hw_vpath_bcast_enable(
+                       struct __vxge_hw_vpath_handle *vp)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+
+       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
+
+       if (!(val64 & VXGE_HW_RXMAC_VCFG0_BCAST_EN)) {
+               val64 |= VXGE_HW_RXMAC_VCFG0_BCAST_EN;
+               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
+       }
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_mcast_enable - Enable multicast addresses.
+ * @vp: Vpath handle.
+ *
+ * Enable Titan-e multicast addresses.
+ * Returns: VXGE_HW_OK on success.
+ *
+ */
+enum vxge_hw_status vxge_hw_vpath_mcast_enable(
+                       struct __vxge_hw_vpath_handle *vp)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+
+       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
+
+       if (!(val64 & VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN)) {
+               val64 |= VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN;
+               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
+       }
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_mcast_disable - Disable  multicast addresses.
+ * @vp: Vpath handle.
+ *
+ * Disable Titan-e multicast addresses.
+ * Returns: VXGE_HW_OK - success.
+ * VXGE_HW_ERR_INVALID_HANDLE - Invalid handle
+ *
+ */
+enum vxge_hw_status
+vxge_hw_vpath_mcast_disable(struct __vxge_hw_vpath_handle *vp)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath;
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       vpath = vp->vpath;
+
+       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
+
+       if (val64 & VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN) {
+               val64 &= ~VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN;
+               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
+       }
+exit:
+       return status;
+}
+
+/*
+ * __vxge_hw_vpath_alarm_process - Process Alarms.
+ * @vpath: Virtual Path.
+ * @skip_alarms: Do not clear the alarms
+ *
+ * Process vpath alarms.
+ *
+ */
+enum vxge_hw_status __vxge_hw_vpath_alarm_process(
+                       struct __vxge_hw_virtualpath *vpath,
+                       u32 skip_alarms)
+{
+       u64 val64;
+       u64 alarm_status;
+       u64 pic_status;
+       struct __vxge_hw_device *hldev = NULL;
+       enum vxge_hw_event alarm_event = VXGE_HW_EVENT_UNKNOWN;
+       u64 mask64;
+       struct vxge_hw_vpath_stats_sw_info *sw_stats;
+       struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+       if (vpath == NULL) {
+               alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
+                       alarm_event);
+               goto out;
+       }
+
+       hldev = vpath->hldev;
+       vp_reg = vpath->vp_reg;
+       alarm_status = readq(&vp_reg->vpath_general_int_status);
+
+       if (alarm_status == VXGE_HW_ALL_FOXES) {
+               alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_SLOT_FREEZE,
+                       alarm_event);
+               goto out;
+       }
+
+       sw_stats = vpath->sw_stats;
+
+       if (alarm_status & ~(
+               VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT |
+               VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT |
+               VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT |
+               VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) {
+               sw_stats->error_stats.unknown_alarms++;
+
+               alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
+                       alarm_event);
+               goto out;
+       }
+
+       if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT) {
+
+               val64 = readq(&vp_reg->xgmac_vp_int_status);
+
+               if (val64 &
+               VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT) {
+
+                       val64 = readq(&vp_reg->asic_ntwk_vp_err_reg);
+
+                       if (((val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) &&
+                           (!(val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK))) ||
+                           ((val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR)
+                               && (!(val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR)
+                       ))) {
+                               sw_stats->error_stats.network_sustained_fault++;
+
+                               writeq(
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT,
+                                       &vp_reg->asic_ntwk_vp_err_mask);
+
+                               __vxge_hw_device_handle_link_down_ind(hldev);
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_LINK_DOWN, alarm_event);
+                       }
+
+                       if (((val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) &&
+                           (!(val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT))) ||
+                           ((val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR)
+                               && (!(val64 &
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR)
+                       ))) {
+
+                               sw_stats->error_stats.network_sustained_ok++;
+
+                               writeq(
+                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK,
+                                       &vp_reg->asic_ntwk_vp_err_mask);
+
+                               __vxge_hw_device_handle_link_up_ind(hldev);
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_LINK_UP, alarm_event);
+                       }
+
+                       writeq(VXGE_HW_INTR_MASK_ALL,
+                               &vp_reg->asic_ntwk_vp_err_reg);
+
+                       alarm_event = VXGE_HW_SET_LEVEL(
+                               VXGE_HW_EVENT_ALARM_CLEARED, alarm_event);
+
+                       if (skip_alarms)
+                               return VXGE_HW_OK;
+               }
+       }
+
+       if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT) {
+
+               pic_status = readq(&vp_reg->vpath_ppif_int_status);
+
+               if (pic_status &
+                   VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT) {
+
+                       val64 = readq(&vp_reg->general_errors_reg);
+                       mask64 = readq(&vp_reg->general_errors_mask);
+
+                       if ((val64 &
+                               VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET) &
+                               ~mask64) {
+                               sw_stats->error_stats.ini_serr_det++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_SERR, alarm_event);
+                       }
+
+                       if ((val64 &
+                           VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW) &
+                               ~mask64) {
+                               sw_stats->error_stats.dblgen_fifo0_overflow++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_FIFO_ERR, alarm_event);
+                       }
+
+                       if ((val64 &
+                           VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR) &
+                               ~mask64)
+                               sw_stats->error_stats.statsb_pif_chain_error++;
+
+                       if ((val64 &
+                          VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ) &
+                               ~mask64)
+                               sw_stats->error_stats.statsb_drop_timeout++;
+
+                       if ((val64 &
+                               VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS) &
+                               ~mask64)
+                               sw_stats->error_stats.target_illegal_access++;
+
+                       if (!skip_alarms) {
+                               writeq(VXGE_HW_INTR_MASK_ALL,
+                                       &vp_reg->general_errors_reg);
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_ALARM_CLEARED,
+                                       alarm_event);
+                       }
+               }
+
+               if (pic_status &
+                   VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT) {
+
+                       val64 = readq(&vp_reg->kdfcctl_errors_reg);
+                       mask64 = readq(&vp_reg->kdfcctl_errors_mask);
+
+                       if ((val64 &
+                           VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR) &
+                               ~mask64) {
+                               sw_stats->error_stats.kdfcctl_fifo0_overwrite++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_FIFO_ERR,
+                                       alarm_event);
+                       }
+
+                       if ((val64 &
+                           VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON) &
+                               ~mask64) {
+                               sw_stats->error_stats.kdfcctl_fifo0_poison++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_FIFO_ERR,
+                                       alarm_event);
+                       }
+
+                       if ((val64 &
+                           VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR) &
+                               ~mask64) {
+                               sw_stats->error_stats.kdfcctl_fifo0_dma_error++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_FIFO_ERR,
+                                       alarm_event);
+                       }
+
+                       if (!skip_alarms) {
+                               writeq(VXGE_HW_INTR_MASK_ALL,
+                                       &vp_reg->kdfcctl_errors_reg);
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_ALARM_CLEARED,
+                                       alarm_event);
+                       }
+               }
+
+       }
+
+       if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT) {
+
+               val64 = readq(&vp_reg->wrdma_alarm_status);
+
+               if (val64 & VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT) {
+
+                       val64 = readq(&vp_reg->prc_alarm_reg);
+                       mask64 = readq(&vp_reg->prc_alarm_mask);
+
+                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP)&
+                               ~mask64)
+                               sw_stats->error_stats.prc_ring_bumps++;
+
+                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR) &
+                               ~mask64) {
+                               sw_stats->error_stats.prc_rxdcm_sc_err++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_VPATH_ERR,
+                                       alarm_event);
+                       }
+
+                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT)
+                               & ~mask64) {
+                               sw_stats->error_stats.prc_rxdcm_sc_abort++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                               VXGE_HW_EVENT_VPATH_ERR,
+                                               alarm_event);
+                       }
+
+                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR)
+                                & ~mask64) {
+                               sw_stats->error_stats.prc_quanta_size_err++;
+
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                       VXGE_HW_EVENT_VPATH_ERR,
+                                       alarm_event);
+                       }
+
+                       if (!skip_alarms) {
+                               writeq(VXGE_HW_INTR_MASK_ALL,
+                                       &vp_reg->prc_alarm_reg);
+                               alarm_event = VXGE_HW_SET_LEVEL(
+                                               VXGE_HW_EVENT_ALARM_CLEARED,
+                                               alarm_event);
+                       }
+               }
+       }
+out:
+       hldev->stats.sw_dev_err_stats.vpath_alarms++;
+
+       if ((alarm_event == VXGE_HW_EVENT_ALARM_CLEARED) ||
+               (alarm_event == VXGE_HW_EVENT_UNKNOWN))
+               return VXGE_HW_OK;
+
+       __vxge_hw_device_handle_error(hldev, vpath->vp_id, alarm_event);
+
+       if (alarm_event == VXGE_HW_EVENT_SERR)
+               return VXGE_HW_ERR_CRITICAL;
+
+       return (alarm_event == VXGE_HW_EVENT_SLOT_FREEZE) ?
+               VXGE_HW_ERR_SLOT_FREEZE :
+               (alarm_event == VXGE_HW_EVENT_FIFO_ERR) ? VXGE_HW_ERR_FIFO :
+               VXGE_HW_ERR_VPATH;
+}
+
+/*
+ * vxge_hw_vpath_alarm_process - Process Alarms.
+ * @vpath: Virtual Path.
+ * @skip_alarms: Do not clear the alarms
+ *
+ * Process vpath alarms.
+ *
+ */
+enum vxge_hw_status vxge_hw_vpath_alarm_process(
+                       struct __vxge_hw_vpath_handle *vp,
+                       u32 skip_alarms)
+{
+       enum vxge_hw_status status = VXGE_HW_OK;
+
+       if (vp == NULL) {
+               status = VXGE_HW_ERR_INVALID_HANDLE;
+               goto exit;
+       }
+
+       status = __vxge_hw_vpath_alarm_process(vp->vpath, skip_alarms);
+exit:
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_msix_set - Associate MSIX vectors with TIM interrupts and
+ *                            alrms
+ * @vp: Virtual Path handle.
+ * @tim_msix_id: MSIX vectors associated with VXGE_HW_MAX_INTR_PER_VP number of
+ *             interrupts(Can be repeated). If fifo or ring are not enabled
+ *             the MSIX vector for that should be set to 0
+ * @alarm_msix_id: MSIX vector for alarm.
+ *
+ * This API will associate a given MSIX vector numbers with the four TIM
+ * interrupts and alarm interrupt.
+ */
+enum vxge_hw_status
+vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vp, int *tim_msix_id,
+                      int alarm_msix_id)
+{
+       u64 val64;
+       struct __vxge_hw_virtualpath *vpath = vp->vpath;
+       struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
+       u32 first_vp_id = vpath->hldev->first_vp_id;
+
+       val64 =  VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI(
+                 (first_vp_id * 4) + tim_msix_id[0]) |
+                VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI(
+                 (first_vp_id * 4) + tim_msix_id[1]) |
+                VXGE_HW_INTERRUPT_CFG0_GROUP2_MSIX_FOR_TXTI(
+                       (first_vp_id * 4) + tim_msix_id[2]);
+
+               val64 |= VXGE_HW_INTERRUPT_CFG0_GROUP3_MSIX_FOR_TXTI(
+                       (first_vp_id * 4) + tim_msix_id[3]);
+
+       writeq(val64, &vp_reg->interrupt_cfg0);
+
+       writeq(VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG(
+                       (first_vp_id * 4) + alarm_msix_id),
+                       &vp_reg->interrupt_cfg2);
+
+       if (vpath->hldev->config.intr_mode ==
+                                       VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) {
+               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(
+                               VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN,
+                               0, 32), &vp_reg->one_shot_vect1_en);
+       }
+
+       if (vpath->hldev->config.intr_mode ==
+               VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) {
+               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(
+                               VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN,
+                               0, 32), &vp_reg->one_shot_vect2_en);
+
+               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(
+                               VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN,
+                               0, 32), &vp_reg->one_shot_vect3_en);
+       }
+
+       return VXGE_HW_OK;
+}
+
+/**
+ * vxge_hw_vpath_msix_mask - Mask MSIX Vector.
+ * @vp: Virtual Path handle.
+ * @msix_id:  MSIX ID
+ *
+ * The function masks the msix interrupt for the given msix_id
+ *
+ * Returns: 0,
+ * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range
+ * status.
+ * See also:
+ */
+void
+vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vp, int msix_id)
+{
+       struct __vxge_hw_device *hldev = vp->vpath->hldev;
+       __vxge_hw_pio_mem_write32_upper(
+               (u32) vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
+                       (msix_id  / 4)), 0, 32),
+               &hldev->common_reg->set_msix_mask_vect[msix_id % 4]);
+
+       return;
+}
+
+/**
+ * vxge_hw_vpath_msix_clear - Clear MSIX Vector.
+ * @vp: Virtual Path handle.
+ * @msix_id:  MSI ID
+ *
+ * The function clears the msix interrupt for the given msix_id
+ *
+ * Returns: 0,
+ * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range
+ * status.
+ * See also:
+ */
+void
+vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id)
+{
+       struct __vxge_hw_device *hldev = vp->vpath->hldev;
+       if (hldev->config.intr_mode ==
+                       VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) {
+               __vxge_hw_pio_mem_write32_upper(
+                       (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
+                               (msix_id/4)), 0, 32),
+                               &hldev->common_reg->
+                                       clr_msix_one_shot_vec[msix_id%4]);
+       } else {
+               __vxge_hw_pio_mem_write32_upper(
+                       (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
+                               (msix_id/4)), 0, 32),
+                               &hldev->common_reg->
+                                       clear_msix_mask_vect[msix_id%4]);
+       }
+
+       return;
+}
+
+/**
+ * vxge_hw_vpath_msix_unmask - Unmask the MSIX Vector.
+ * @vp: Virtual Path handle.
+ * @msix_id:  MSI ID
+ *
+ * The function unmasks the msix interrupt for the given msix_id
+ *
+ * Returns: 0,
+ * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range
+ * status.
+ * See also:
+ */
+void
+vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vp, int msix_id)
+{
+       struct __vxge_hw_device *hldev = vp->vpath->hldev;
+       __vxge_hw_pio_mem_write32_upper(
+                       (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
+                       (msix_id/4)), 0, 32),
+                       &hldev->common_reg->clear_msix_mask_vect[msix_id%4]);
+
+       return;
+}
+
+/**
+ * vxge_hw_vpath_msix_mask_all - Mask all MSIX vectors for the vpath.
+ * @vp: Virtual Path handle.
+ *
+ * The function masks all msix interrupt for the given vpath
+ *
+ */
+void
+vxge_hw_vpath_msix_mask_all(struct __vxge_hw_vpath_handle *vp)
+{
+
+       __vxge_hw_pio_mem_write32_upper(
+               (u32)vxge_bVALn(vxge_mBIT(vp->vpath->vp_id), 0, 32),
+               &vp->vpath->hldev->common_reg->set_msix_mask_all_vect);
+
+       return;
+}
+
+/**
+ * vxge_hw_vpath_inta_mask_tx_rx - Mask Tx and Rx interrupts.
+ * @vp: Virtual Path handle.
+ *
+ * Mask Tx and Rx vpath interrupts.
+ *
+ * See also: vxge_hw_vpath_inta_mask_tx_rx()
+ */
+void vxge_hw_vpath_inta_mask_tx_rx(struct __vxge_hw_vpath_handle *vp)
+{
+       u64     tim_int_mask0[4] = {[0 ...3] = 0};
+       u32     tim_int_mask1[4] = {[0 ...3] = 0};
+       u64     val64;
+       struct __vxge_hw_device *hldev = vp->vpath->hldev;
+
+       VXGE_HW_DEVICE_TIM_INT_MASK_SET(tim_int_mask0,
+               tim_int_mask1, vp->vpath->vp_id);
+
+       val64 = readq(&hldev->common_reg->tim_int_mask0);
+
+       if ((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) ||
+               (tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) {
+               writeq((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
+                       tim_int_mask0[VXGE_HW_VPATH_INTR_RX] | val64),
+                       &hldev->common_reg->tim_int_mask0);
+       }
+
+       val64 = readl(&hldev->common_reg->tim_int_mask1);
+
+       if ((tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) ||
+               (tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) {
+               __vxge_hw_pio_mem_write32_upper(
+                       (tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
+                       tim_int_mask1[VXGE_HW_VPATH_INTR_RX] | val64),
+                       &hldev->common_reg->tim_int_mask1);
+       }
+
+       return;
+}
+
+/**
+ * vxge_hw_vpath_inta_unmask_tx_rx - Unmask Tx and Rx interrupts.
+ * @vp: Virtual Path handle.
+ *
+ * Unmask Tx and Rx vpath interrupts.
+ *
+ * See also: vxge_hw_vpath_inta_mask_tx_rx()
+ */
+void vxge_hw_vpath_inta_unmask_tx_rx(struct __vxge_hw_vpath_handle *vp)
+{
+       u64     tim_int_mask0[4] = {[0 ...3] = 0};
+       u32     tim_int_mask1[4] = {[0 ...3] = 0};
+       u64     val64;
+       struct __vxge_hw_device *hldev = vp->vpath->hldev;
+
+       VXGE_HW_DEVICE_TIM_INT_MASK_SET(tim_int_mask0,
+               tim_int_mask1, vp->vpath->vp_id);
+
+       val64 = readq(&hldev->common_reg->tim_int_mask0);
+
+       if ((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) ||
+          (tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) {
+               writeq((~(tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
+                       tim_int_mask0[VXGE_HW_VPATH_INTR_RX])) & val64,
+                       &hldev->common_reg->tim_int_mask0);
+       }
+
+       if ((tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) ||
+          (tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) {
+               __vxge_hw_pio_mem_write32_upper(
+                       (~(tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
+                         tim_int_mask1[VXGE_HW_VPATH_INTR_RX])) & val64,
+                       &hldev->common_reg->tim_int_mask1);
+       }
+
+       return;
+}
+
+/**
+ * vxge_hw_vpath_poll_rx - Poll Rx Virtual Path for completed
+ * descriptors and process the same.
+ * @ring: Handle to the ring object used for receive
+ *
+ * The function        polls the Rx for the completed  descriptors and calls
+ * the driver via supplied completion  callback.
+ *
+ * Returns: VXGE_HW_OK, if the polling is completed successful.
+ * VXGE_HW_COMPLETIONS_REMAIN: There are still more completed
+ * descriptors available which are yet to be processed.
+ *
+ * See also: vxge_hw_vpath_poll_rx()
+ */
+enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring)
+{
+       u8 t_code;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       void *first_rxdh;
+       u64 val64 = 0;
+       int new_count = 0;
+
+       ring->cmpl_cnt = 0;
+
+       status = vxge_hw_ring_rxd_next_completed(ring, &first_rxdh, &t_code);
+       if (status == VXGE_HW_OK)
+               ring->callback(ring, first_rxdh,
+                       t_code, ring->channel.userdata);
+
+       if (ring->cmpl_cnt != 0) {
+               ring->doorbell_cnt += ring->cmpl_cnt;
+               if (ring->doorbell_cnt >= ring->rxds_limit) {
+                       /*
+                        * Each RxD is of 4 qwords, update the number of
+                        * qwords replenished
+                        */
+                       new_count = (ring->doorbell_cnt * 4);
+
+                       /* For each block add 4 more qwords */
+                       ring->total_db_cnt += ring->doorbell_cnt;
+                       if (ring->total_db_cnt >= ring->rxds_per_block) {
+                               new_count += 4;
+                               /* Reset total count */
+                               ring->total_db_cnt %= ring->rxds_per_block;
+                       }
+                       writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(new_count),
+                               &ring->vp_reg->prc_rxd_doorbell);
+                       val64 =
+                         readl(&ring->common_reg->titan_general_int_status);
+                       ring->doorbell_cnt = 0;
+               }
+       }
+
+       return status;
+}
+
+/**
+ * vxge_hw_vpath_poll_tx - Poll Tx for completed descriptors and process
+ * the same.
+ * @fifo: Handle to the fifo object used for non offload send
+ *
+ * The function        polls the Tx for the completed  descriptors and calls
+ * the driver via supplied completion callback.
+ *
+ * Returns: VXGE_HW_OK, if the polling is completed successful.
+ * VXGE_HW_COMPLETIONS_REMAIN: There are still more completed
+ * descriptors available which are yet to be processed.
+ *
+ * See also: vxge_hw_vpath_poll_tx().
+ */
+enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo,
+                                       void **skb_ptr)
+{
+       enum vxge_hw_fifo_tcode t_code;
+       void *first_txdlh;
+       enum vxge_hw_status status = VXGE_HW_OK;
+       struct __vxge_hw_channel *channel;
+
+       channel = &fifo->channel;
+
+       status = vxge_hw_fifo_txdl_next_completed(fifo,
+                               &first_txdlh, &t_code);
+       if (status == VXGE_HW_OK)
+               if (fifo->callback(fifo, first_txdlh,
+                       t_code, channel->userdata, skb_ptr) != VXGE_HW_OK)
+                       status = VXGE_HW_COMPLETIONS_REMAIN;
+
+       return status;
+}
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
new file mode 100644 (file)
index 0000000..7567a11
--- /dev/null
@@ -0,0 +1,2409 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-traffic.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                 Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#ifndef VXGE_TRAFFIC_H
+#define VXGE_TRAFFIC_H
+
+#include "vxge-reg.h"
+#include "vxge-version.h"
+
+#define VXGE_HW_DTR_MAX_T_CODE         16
+#define VXGE_HW_ALL_FOXES              0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_INTR_MASK_ALL          0xFFFFFFFFFFFFFFFFULL
+#define        VXGE_HW_MAX_VIRTUAL_PATHS       17
+
+#define VXGE_HW_MAC_MAX_MAC_PORT_ID    2
+
+#define VXGE_HW_DEFAULT_32             0xffffffff
+/* frames sizes */
+#define VXGE_HW_HEADER_802_2_SIZE      3
+#define VXGE_HW_HEADER_SNAP_SIZE       5
+#define VXGE_HW_HEADER_VLAN_SIZE       4
+#define VXGE_HW_MAC_HEADER_MAX_SIZE \
+                       (ETH_HLEN + \
+                       VXGE_HW_HEADER_802_2_SIZE + \
+                       VXGE_HW_HEADER_VLAN_SIZE + \
+                       VXGE_HW_HEADER_SNAP_SIZE)
+
+#define VXGE_HW_TCPIP_HEADER_MAX_SIZE  (64 + 64)
+
+/* 32bit alignments */
+#define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN         2
+#define VXGE_HW_HEADER_802_2_SNAP_ALIGN                        2
+#define VXGE_HW_HEADER_802_2_ALIGN                     3
+#define VXGE_HW_HEADER_SNAP_ALIGN                      1
+
+#define VXGE_HW_L3_CKSUM_OK                            0xFFFF
+#define VXGE_HW_L4_CKSUM_OK                            0xFFFF
+
+/* Forward declarations */
+struct __vxge_hw_device;
+struct __vxge_hw_vpath_handle;
+struct vxge_hw_vp_config;
+struct __vxge_hw_virtualpath;
+struct __vxge_hw_channel;
+struct __vxge_hw_fifo;
+struct __vxge_hw_ring;
+struct vxge_hw_ring_attr;
+struct vxge_hw_mempool;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*VXGE_HW_STATUS_H*/
+
+#define VXGE_HW_EVENT_BASE                     0
+#define VXGE_LL_EVENT_BASE                     100
+
+/**
+ * enum vxge_hw_event- Enumerates slow-path HW events.
+ * @VXGE_HW_EVENT_UNKNOWN: Unknown (and invalid) event.
+ * @VXGE_HW_EVENT_SERR: Serious vpath hardware error event.
+ * @VXGE_HW_EVENT_ECCERR: vpath ECC error event.
+ * @VXGE_HW_EVENT_VPATH_ERR: Error local to the respective vpath
+ * @VXGE_HW_EVENT_FIFO_ERR: FIFO Doorbell fifo error.
+ * @VXGE_HW_EVENT_SRPCIM_SERR: srpcim hardware error event.
+ * @VXGE_HW_EVENT_MRPCIM_SERR: mrpcim hardware error event.
+ * @VXGE_HW_EVENT_MRPCIM_ECCERR: mrpcim ecc error event.
+ * @VXGE_HW_EVENT_RESET_START: Privileged entity is starting device reset
+ * @VXGE_HW_EVENT_RESET_COMPLETE: Device reset has been completed
+ * @VXGE_HW_EVENT_SLOT_FREEZE: Slot-freeze event. Driver tries to distinguish
+ * slot-freeze from the rest critical events (e.g. ECC) when it is
+ * impossible to PIO read "through" the bus, i.e. when getting all-foxes.
+ *
+ * enum vxge_hw_event enumerates slow-path HW eventis.
+ *
+ * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_up_f{},
+ * vxge_uld_link_down_f{}.
+ */
+enum vxge_hw_event {
+       VXGE_HW_EVENT_UNKNOWN           = 0,
+       /* HW events */
+       VXGE_HW_EVENT_RESET_START       = VXGE_HW_EVENT_BASE + 1,
+       VXGE_HW_EVENT_RESET_COMPLETE    = VXGE_HW_EVENT_BASE + 2,
+       VXGE_HW_EVENT_LINK_DOWN         = VXGE_HW_EVENT_BASE + 3,
+       VXGE_HW_EVENT_LINK_UP           = VXGE_HW_EVENT_BASE + 4,
+       VXGE_HW_EVENT_ALARM_CLEARED     = VXGE_HW_EVENT_BASE + 5,
+       VXGE_HW_EVENT_ECCERR            = VXGE_HW_EVENT_BASE + 6,
+       VXGE_HW_EVENT_MRPCIM_ECCERR     = VXGE_HW_EVENT_BASE + 7,
+       VXGE_HW_EVENT_FIFO_ERR          = VXGE_HW_EVENT_BASE + 8,
+       VXGE_HW_EVENT_VPATH_ERR         = VXGE_HW_EVENT_BASE + 9,
+       VXGE_HW_EVENT_CRITICAL_ERR      = VXGE_HW_EVENT_BASE + 10,
+       VXGE_HW_EVENT_SERR              = VXGE_HW_EVENT_BASE + 11,
+       VXGE_HW_EVENT_SRPCIM_SERR       = VXGE_HW_EVENT_BASE + 12,
+       VXGE_HW_EVENT_MRPCIM_SERR       = VXGE_HW_EVENT_BASE + 13,
+       VXGE_HW_EVENT_SLOT_FREEZE       = VXGE_HW_EVENT_BASE + 14,
+};
+
+#define VXGE_HW_SET_LEVEL(a, b) (((a) > (b)) ? (a) : (b))
+
+/*
+ * struct vxge_hw_mempool_dma - Represents DMA objects passed to the
+       caller.
+ */
+struct vxge_hw_mempool_dma {
+       dma_addr_t                      addr;
+       struct pci_dev *handle;
+       struct pci_dev *acc_handle;
+};
+
+/*
+ * vxge_hw_mempool_item_f  - Mempool item alloc/free callback
+ * @mempoolh: Memory pool handle.
+ * @memblock: Address of memory block
+ * @memblock_index: Index of memory block
+ * @item: Item that gets allocated or freed.
+ * @index: Item's index in the memory pool.
+ * @is_last: True, if this item is the last one in the pool; false - otherwise.
+ * userdata: Per-pool user context.
+ *
+ * Memory pool allocation/deallocation callback.
+ */
+
+/*
+ * struct vxge_hw_mempool - Memory pool.
+ */
+struct vxge_hw_mempool {
+
+       void (*item_func_alloc)(
+       struct vxge_hw_mempool *mempoolh,
+       u32                     memblock_index,
+       struct vxge_hw_mempool_dma      *dma_object,
+       u32                     index,
+       u32                     is_last);
+
+       void            *userdata;
+       void            **memblocks_arr;
+       void            **memblocks_priv_arr;
+       struct vxge_hw_mempool_dma      *memblocks_dma_arr;
+       struct __vxge_hw_device *devh;
+       u32                     memblock_size;
+       u32                     memblocks_max;
+       u32                     memblocks_allocated;
+       u32                     item_size;
+       u32                     items_max;
+       u32                     items_initial;
+       u32                     items_current;
+       u32                     items_per_memblock;
+       void            **items_arr;
+       u32                     items_priv_size;
+};
+
+#define        VXGE_HW_MAX_INTR_PER_VP                         4
+#define        VXGE_HW_VPATH_INTR_TX                           0
+#define        VXGE_HW_VPATH_INTR_RX                           1
+#define        VXGE_HW_VPATH_INTR_EINTA                        2
+#define        VXGE_HW_VPATH_INTR_BMAP                         3
+
+#define VXGE_HW_BLOCK_SIZE                             4096
+
+/**
+ * struct vxge_hw_tim_intr_config - Titan Tim interrupt configuration.
+ * @intr_enable: Set to 1, if interrupt is enabled.
+ * @btimer_val: Boundary Timer Initialization value in units of 272 ns.
+ * @timer_ac_en: Timer Automatic Cancel. 1 : Automatic Canceling Enable: when
+ *             asserted, other interrupt-generating entities will cancel the
+ *             scheduled timer interrupt.
+ * @timer_ci_en: Timer Continuous Interrupt. 1 : Continuous Interrupting Enable:
+ *             When asserted, an interrupt will be generated every time the
+ *             boundary timer expires, even if no traffic has been transmitted
+ *             on this interrupt.
+ * @timer_ri_en: Timer Consecutive (Re-) Interrupt 1 : Consecutive
+ *             (Re-) Interrupt Enable: When asserted, an interrupt will be
+ *             generated the next time the timer expires, even if no traffic has
+ *             been transmitted on this interrupt. (This will only happen once
+ *             each time that this value is written to the TIM.) This bit is
+ *             cleared by H/W at the end of the current-timer-interval when
+ *             the interrupt is triggered.
+ * @rtimer_val: Restriction Timer Initialization value in units of 272 ns.
+ * @util_sel: Utilization Selector. Selects which of the workload approximations
+ *             to use (e.g. legacy Tx utilization, Tx/Rx utilization, host
+ *             specified utilization etc.), selects one of
+ *             the 17 host configured values.
+ *             0-Virtual Path 0
+ *             1-Virtual Path 1
+ *             ...
+ *             16-Virtual Path 17
+ *             17-Legacy Tx network utilization, provided by TPA
+ *             18-Legacy Rx network utilization, provided by FAU
+ *             19-Average of legacy Rx and Tx utilization calculated from link
+ *                utilization values.
+ *             20-31-Invalid configurations
+ *             32-Host utilization for Virtual Path 0
+ *             33-Host utilization for Virtual Path 1
+ *             ...
+ *             48-Host utilization for Virtual Path 17
+ *             49-Legacy Tx network utilization, provided by TPA
+ *             50-Legacy Rx network utilization, provided by FAU
+ *             51-Average of legacy Rx and Tx utilization calculated from
+ *                link utilization values.
+ *             52-63-Invalid configurations
+ * @ltimer_val: Latency Timer Initialization Value in units of 272 ns.
+ * @txd_cnt_en: TxD Return Event Count Enable. This configuration bit when set
+ *             to 1 enables counting of TxD0 returns (signalled by PCC's),
+ *             towards utilization event count values.
+ * @urange_a: Defines the upper limit (in percent) for this utilization range
+ *             to be active. This range is considered active
+ *             if 0 = UTIL = URNG_A
+ *             and the UEC_A field (below) is non-zero.
+ * @uec_a: Utilization Event Count A. If this range is active, the adapter will
+ *             wait until UEC_A events have occurred on the interrupt before
+ *             generating an interrupt.
+ * @urange_b: Link utilization range B.
+ * @uec_b: Utilization Event Count B.
+ * @urange_c: Link utilization range C.
+ * @uec_c: Utilization Event Count C.
+ * @urange_d: Link utilization range D.
+ * @uec_d: Utilization Event Count D.
+ * Traffic Interrupt Controller Module interrupt configuration.
+ */
+struct vxge_hw_tim_intr_config {
+
+       u32                             intr_enable;
+#define VXGE_HW_TIM_INTR_ENABLE                                1
+#define VXGE_HW_TIM_INTR_DISABLE                               0
+#define VXGE_HW_TIM_INTR_DEFAULT                               0
+
+       u32                             btimer_val;
+#define VXGE_HW_MIN_TIM_BTIMER_VAL                             0
+#define VXGE_HW_MAX_TIM_BTIMER_VAL                             67108864
+#define VXGE_HW_USE_FLASH_DEFAULT                              0xffffffff
+
+       u32                             timer_ac_en;
+#define VXGE_HW_TIM_TIMER_AC_ENABLE                            1
+#define VXGE_HW_TIM_TIMER_AC_DISABLE                           0
+
+       u32                             timer_ci_en;
+#define VXGE_HW_TIM_TIMER_CI_ENABLE                            1
+#define VXGE_HW_TIM_TIMER_CI_DISABLE                           0
+
+       u32                             timer_ri_en;
+#define VXGE_HW_TIM_TIMER_RI_ENABLE                            1
+#define VXGE_HW_TIM_TIMER_RI_DISABLE                           0
+
+       u32                             rtimer_val;
+#define VXGE_HW_MIN_TIM_RTIMER_VAL                             0
+#define VXGE_HW_MAX_TIM_RTIMER_VAL                             67108864
+
+       u32                             util_sel;
+#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL                17
+#define VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL                18
+#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_RX_AVE_NET_UTIL         19
+#define VXGE_HW_TIM_UTIL_SEL_PER_VPATH                         63
+
+       u32                             ltimer_val;
+#define VXGE_HW_MIN_TIM_LTIMER_VAL                             0
+#define VXGE_HW_MAX_TIM_LTIMER_VAL                             67108864
+
+       /* Line utilization interrupts */
+       u32                             urange_a;
+#define VXGE_HW_MIN_TIM_URANGE_A                               0
+#define VXGE_HW_MAX_TIM_URANGE_A                               100
+
+       u32                             uec_a;
+#define VXGE_HW_MIN_TIM_UEC_A                                  0
+#define VXGE_HW_MAX_TIM_UEC_A                                  65535
+
+       u32                             urange_b;
+#define VXGE_HW_MIN_TIM_URANGE_B                               0
+#define VXGE_HW_MAX_TIM_URANGE_B                               100
+
+       u32                             uec_b;
+#define VXGE_HW_MIN_TIM_UEC_B                                  0
+#define VXGE_HW_MAX_TIM_UEC_B                                  65535
+
+       u32                             urange_c;
+#define VXGE_HW_MIN_TIM_URANGE_C                               0
+#define VXGE_HW_MAX_TIM_URANGE_C                               100
+
+       u32                             uec_c;
+#define VXGE_HW_MIN_TIM_UEC_C                                  0
+#define VXGE_HW_MAX_TIM_UEC_C                                  65535
+
+       u32                             uec_d;
+#define VXGE_HW_MIN_TIM_UEC_D                                  0
+#define VXGE_HW_MAX_TIM_UEC_D                                  65535
+};
+
+#define        VXGE_HW_STATS_OP_READ                                   0
+#define        VXGE_HW_STATS_OP_CLEAR_STAT                             1
+#define        VXGE_HW_STATS_OP_CLEAR_ALL_VPATH_STATS                  2
+#define        VXGE_HW_STATS_OP_CLEAR_ALL_STATS_OF_LOC                 2
+#define        VXGE_HW_STATS_OP_CLEAR_ALL_STATS                        3
+
+#define        VXGE_HW_STATS_LOC_AGGR                                  17
+#define VXGE_HW_STATS_AGGRn_OFFSET                             0x00720
+
+#define VXGE_HW_STATS_VPATH_TX_OFFSET                          0x0
+#define VXGE_HW_STATS_VPATH_RX_OFFSET                          0x00090
+
+#define        VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET        (0x001d0 >> 3)
+#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(bits) \
+                                               vxge_bVALn(bits, 0, 32)
+
+#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(bits) \
+                                               vxge_bVALn(bits, 32, 32)
+
+#define        VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET        (0x001d8 >> 3)
+#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(bits) \
+                                               vxge_bVALn(bits, 0, 32)
+
+#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(bits) \
+                                               vxge_bVALn(bits, 32, 32)
+
+/**
+ * struct vxge_hw_xmac_aggr_stats - Per-Aggregator XMAC Statistics
+ *
+ * @tx_frms: Count of data frames transmitted on this Aggregator on all
+ *             its Aggregation ports. Does not include LACPDUs or Marker PDUs.
+ *             However, does include frames discarded by the Distribution
+ *             function.
+ * @tx_data_octets: Count of data and padding octets of frames transmitted
+ *             on this Aggregator on all its Aggregation ports. Does not include
+ *             octets of LACPDUs or Marker PDUs. However, does include octets of
+ *             frames discarded by the Distribution function.
+ * @tx_mcast_frms: Count of data frames transmitted (to a group destination
+ *             address other than the broadcast address) on this Aggregator on
+ *             all its Aggregation ports. Does not include LACPDUs or Marker
+ *             PDUs. However, does include frames discarded by the Distribution
+ *             function.
+ * @tx_bcast_frms: Count of broadcast data frames transmitted on this Aggregator
+ *             on all its Aggregation ports. Does not include LACPDUs or Marker
+ *             PDUs. However, does include frames discarded by the Distribution
+ *             function.
+ * @tx_discarded_frms: Count of data frames to be transmitted on this Aggregator
+ *             that are discarded by the Distribution function. This occurs when
+ *             conversation are allocated to different ports and have to be
+ *             flushed on old ports
+ * @tx_errored_frms: Count of data frames transmitted on this Aggregator that
+ *             experience transmission errors on its Aggregation ports.
+ * @rx_frms: Count of data frames received on this Aggregator on all its
+ *             Aggregation ports. Does not include LACPDUs or Marker PDUs.
+ *             Also, does not include frames discarded by the Collection
+ *             function.
+ * @rx_data_octets: Count of data and padding octets of frames received on this
+ *             Aggregator on all its Aggregation ports. Does not include octets
+ *             of LACPDUs or Marker PDUs. Also, does not include
+ *             octets of frames
+ *             discarded by the Collection function.
+ * @rx_mcast_frms: Count of data frames received (from a group destination
+ *             address other than the broadcast address) on this Aggregator on
+ *             all its Aggregation ports. Does not include LACPDUs or Marker
+ *             PDUs. Also, does not include frames discarded by the Collection
+ *             function.
+ * @rx_bcast_frms: Count of broadcast data frames received on this Aggregator on
+ *             all its Aggregation ports. Does not include LACPDUs or Marker
+ *             PDUs. Also, does not include frames discarded by the Collection
+ *             function.
+ * @rx_discarded_frms: Count of data frames received on this Aggregator that are
+ *             discarded by the Collection function because the Collection
+ *             function was disabled on the port which the frames are received.
+ * @rx_errored_frms: Count of data frames received on this Aggregator that are
+ *             discarded by its Aggregation ports, or are discarded by the
+ *             Collection function of the Aggregator, or that are discarded by
+ *             the Aggregator due to detection of an illegal Slow Protocols PDU.
+ * @rx_unknown_slow_proto_frms: Count of data frames received on this Aggregator
+ *             that are discarded by its Aggregation ports due to detection of
+ *             an unknown Slow Protocols PDU.
+ *
+ * Per aggregator XMAC RX statistics.
+ */
+struct vxge_hw_xmac_aggr_stats {
+/*0x000*/              u64     tx_frms;
+/*0x008*/              u64     tx_data_octets;
+/*0x010*/              u64     tx_mcast_frms;
+/*0x018*/              u64     tx_bcast_frms;
+/*0x020*/              u64     tx_discarded_frms;
+/*0x028*/              u64     tx_errored_frms;
+/*0x030*/              u64     rx_frms;
+/*0x038*/              u64     rx_data_octets;
+/*0x040*/              u64     rx_mcast_frms;
+/*0x048*/              u64     rx_bcast_frms;
+/*0x050*/              u64     rx_discarded_frms;
+/*0x058*/              u64     rx_errored_frms;
+/*0x060*/              u64     rx_unknown_slow_proto_frms;
+} __packed;
+
+/**
+ * struct vxge_hw_xmac_port_stats - XMAC Port Statistics
+ *
+ * @tx_ttl_frms: Count of successfully transmitted MAC frames
+ * @tx_ttl_octets: Count of total octets of transmitted frames, not including
+ *            framing characters (i.e. less framing bits). To determine the
+ *            total octets of transmitted frames, including framing characters,
+ *            multiply PORTn_TX_TTL_FRMS by 8 and add it to this stat (unless
+ *            otherwise configured, this stat only counts frames that have
+ *            8 bytes of preamble for each frame). This stat can be configured
+ *            (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count everything
+ *            including the preamble octets.
+ * @tx_data_octets: Count of data and padding octets of successfully transmitted
+ *            frames.
+ * @tx_mcast_frms: Count of successfully transmitted frames to a group address
+ *            other than the broadcast address.
+ * @tx_bcast_frms: Count of successfully transmitted frames to the broadcast
+ *            group address.
+ * @tx_ucast_frms: Count of transmitted frames containing a unicast address.
+ *            Includes discarded frames that are not sent to the network.
+ * @tx_tagged_frms: Count of transmitted frames containing a VLAN tag.
+ * @tx_vld_ip: Count of transmitted IP datagrams that are passed to the network.
+ * @tx_vld_ip_octets: Count of total octets of transmitted IP datagrams that
+ *            are passed to the network.
+ * @tx_icmp: Count of transmitted ICMP messages. Includes messages not sent
+ *            due to problems within ICMP.
+ * @tx_tcp: Count of transmitted TCP segments. Does not include segments
+ *            containing retransmitted octets.
+ * @tx_rst_tcp: Count of transmitted TCP segments containing the RST flag.
+ * @tx_udp: Count of transmitted UDP datagrams.
+ * @tx_parse_error: Increments when the TPA is unable to parse a packet. This
+ *            generally occurs when a packet is corrupt somehow, including
+ *            packets that have IP version mismatches, invalid Layer 2 control
+ *            fields, etc. L3/L4 checksums are not offloaded, but the packet
+ *            is still be transmitted.
+ * @tx_unknown_protocol: Increments when the TPA encounters an unknown
+ *            protocol, such as a new IPv6 extension header, or an unsupported
+ *            Routing Type. The packet still has a checksum calculated but it
+ *            may be incorrect.
+ * @tx_pause_ctrl_frms: Count of MAC PAUSE control frames that are transmitted.
+ *            Since, the only control frames supported by this device are
+ *            PAUSE frames, this register is a count of all transmitted MAC
+ *            control frames.
+ * @tx_marker_pdu_frms: Count of Marker PDUs transmitted
+ * on this Aggregation port.
+ * @tx_lacpdu_frms: Count of LACPDUs transmitted on this Aggregation port.
+ * @tx_drop_ip: Count of transmitted IP datagrams that could not be passed to
+ *            the network. Increments because of:
+ *            1) An internal processing error
+ *            (such as an uncorrectable ECC error). 2) A frame parsing error
+ *            during IP checksum calculation.
+ * @tx_marker_resp_pdu_frms: Count of Marker Response PDUs transmitted on this
+ *            Aggregation port.
+ * @tx_xgmii_char2_match: Maintains a count of the number of transmitted XGMII
+ *            characters that match a pattern that is programmable through
+ *            register XMAC_STATS_TX_XGMII_CHAR_PORTn. By default, the pattern
+ *            is set to /T/ (i.e. the terminate character), thus the statistic
+ *            tracks the number of transmitted Terminate characters.
+ * @tx_xgmii_char1_match: Maintains a count of the number of transmitted XGMII
+ *            characters that match a pattern that is programmable through
+ *            register XMAC_STATS_TX_XGMII_CHAR_PORTn. By default, the pattern
+ *            is set to /S/ (i.e. the start character),
+ *            thus the statistic tracks
+ *            the number of transmitted Start characters.
+ * @tx_xgmii_column2_match: Maintains a count of the number of transmitted XGMII
+ *            columns that match a pattern that is programmable through register
+ *            XMAC_STATS_TX_XGMII_COLUMN2_PORTn. By default, the pattern is set
+ *            to 4 x /E/ (i.e. a column containing all error characters), thus
+ *            the statistic tracks the number of Error columns transmitted at
+ *            any time. If XMAC_STATS_TX_XGMII_BEHAV_COLUMN2_PORTn.NEAR_COL1 is
+ *            set to 1, then this stat increments when COLUMN2 is found within
+ *            'n' clocks after COLUMN1. Here, 'n' is defined by
+ *            XMAC_STATS_TX_XGMII_BEHAV_COLUMN2_PORTn.NUM_COL (if 'n' is set
+ *            to 0, then it means to search anywhere for COLUMN2).
+ * @tx_xgmii_column1_match: Maintains a count of the number of transmitted XGMII
+ *            columns that match a pattern that is programmable through register
+ *            XMAC_STATS_TX_XGMII_COLUMN1_PORTn. By default, the pattern is set
+ *            to 4 x /I/ (i.e. a column containing all idle characters),
+ *            thus the statistic tracks the number of transmitted Idle columns.
+ * @tx_any_err_frms: Count of transmitted frames containing any error that
+ *            prevents them from being passed to the network. Increments if
+ *            there is an ECC while reading the frame out of the transmit
+ *            buffer. Also increments if the transmit protocol assist (TPA)
+ *            block determines that the frame should not be sent.
+ * @tx_drop_frms: Count of frames that could not be sent for no other reason
+ *            than internal MAC processing. Increments once whenever the
+ *            transmit buffer is flushed (due to an ECC error on a memory
+ *            descriptor).
+ * @rx_ttl_frms: Count of total received MAC frames, including frames received
+ *            with frame-too-long, FCS, or length errors. This stat can be
+ *            configured (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count
+ *            everything, even "frames" as small one byte of preamble.
+ * @rx_vld_frms: Count of successfully received MAC frames. Does not include
+ *            frames received with frame-too-long, FCS, or length errors.
+ * @rx_offload_frms: Count of offloaded received frames that are passed to
+ *            the host.
+ * @rx_ttl_octets: Count of total octets of received frames, not including
+ *            framing characters (i.e. less framing bits). To determine the
+ *            total octets of received frames, including framing characters,
+ *            multiply PORTn_RX_TTL_FRMS by 8 and add it to this stat (unless
+ *            otherwise configured, this stat only counts frames that have 8
+ *            bytes of preamble for each frame). This stat can be configured
+ *            (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count everything,
+ *            even the preamble octets of "frames" as small one byte of preamble
+ * @rx_data_octets: Count of data and padding octets of successfully received
+ *            frames. Does not include frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_offload_octets: Count of total octets, not including framing
+ *            characters, of offloaded received frames that are passed
+ *            to the host.
+ * @rx_vld_mcast_frms: Count of successfully received MAC frames containing a
+ *           nonbroadcast group address. Does not include frames received
+ *            with frame-too-long, FCS, or length errors.
+ * @rx_vld_bcast_frms: Count of successfully received MAC frames containing
+ *            the broadcast group address. Does not include frames received
+ *            with frame-too-long, FCS, or length errors.
+ * @rx_accepted_ucast_frms: Count of successfully received frames containing
+ *            a unicast address. Only includes frames that are passed to
+ *            the system.
+ * @rx_accepted_nucast_frms: Count of successfully received frames containing
+ *            a non-unicast (broadcast or multicast) address. Only includes
+ *            frames that are passed to the system. Could include, for instance,
+ *            non-unicast frames that contain FCS errors if the MAC_ERROR_CFG
+ *            register is set to pass FCS-errored frames to the host.
+ * @rx_tagged_frms: Count of received frames containing a VLAN tag.
+ * @rx_long_frms: Count of received frames that are longer than RX_MAX_PYLD_LEN
+ *            + 18 bytes (+ 22 bytes if VLAN-tagged).
+ * @rx_usized_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) less than 64 octets, that are otherwise well-formed.
+ *            In other words, counts runts.
+ * @rx_osized_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) more than 1518 octets, that are otherwise
+ *            well-formed. Note: If register XMAC_STATS_GLOBAL_CFG.VLAN_HANDLING
+ *            is set to 1, then "more than 1518 octets" becomes "more than 1518
+ *            (1522 if VLAN-tagged) octets".
+ * @rx_frag_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) less than 64 octets that had bad FCS. In other
+ *            words, counts fragments.
+ * @rx_jabber_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) more than 1518 octets that had bad FCS. In other
+ *            words, counts jabbers. Note: If register
+ *            XMAC_STATS_GLOBAL_CFG.VLAN_HANDLING is set to 1, then "more than
+ *            1518 octets" becomes "more than 1518 (1522 if VLAN-tagged)
+ *            octets".
+ * @rx_ttl_64_frms: Count of total received MAC frames with length (including
+ *            FCS, but not framing bits) of exactly 64 octets. Includes frames
+ *            received with frame-too-long, FCS, or length errors.
+ * @rx_ttl_65_127_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 65 and 127
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_128_255_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 128 and 255
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_256_511_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 256 and 511
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_512_1023_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 512 and 1023
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_1024_1518_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 1024 and 1518
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_1519_4095_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 1519 and 4095
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_4096_8191_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 4096 and 8191
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_8192_max_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 8192 and
+ *            RX_MAX_PYLD_LEN+18 octets inclusive. Includes frames received
+ *            with frame-too-long, FCS, or length errors.
+ * @rx_ttl_gt_max_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) exceeding
+ *            RX_MAX_PYLD_LEN+18 (+22 bytes if VLAN-tagged) octets inclusive.
+ *            Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ip: Count of received IP datagrams. Includes errored IP datagrams.
+ * @rx_accepted_ip: Count of received IP datagrams that
+ *             are passed to the system.
+ * @rx_ip_octets: Count of number of octets in received IP datagrams. Includes
+ *            errored IP datagrams.
+ * @rx_err_ip:         Count of received IP datagrams containing errors. For example,
+ *            bad IP checksum.
+ * @rx_icmp: Count of received ICMP messages. Includes errored ICMP messages.
+ * @rx_tcp: Count of received TCP segments. Includes errored TCP segments.
+ *            Note: This stat contains a count of all received TCP segments,
+ *            regardless of whether or not they pertain to an established
+ *            connection.
+ * @rx_udp: Count of received UDP datagrams.
+ * @rx_err_tcp: Count of received TCP segments containing errors. For example,
+ *            bad TCP checksum.
+ * @rx_pause_count: Count of number of pause quanta that the MAC has been in
+ *            the paused state. Recall, one pause quantum equates to 512
+ *            bit times.
+ * @rx_pause_ctrl_frms: Count of received MAC PAUSE control frames.
+ * @rx_unsup_ctrl_frms: Count of received MAC control frames that do not
+ *            contain the PAUSE opcode. The sum of RX_PAUSE_CTRL_FRMS and
+ *            this register is a count of all received MAC control frames.
+ *            Note: This stat may be configured to count all layer 2 errors
+ *            (i.e. length errors and FCS errors).
+ * @rx_fcs_err_frms: Count of received MAC frames that do not pass FCS. Does
+ *            not include frames received with frame-too-long or
+ *            frame-too-short error.
+ * @rx_in_rng_len_err_frms: Count of received frames with a length/type field
+ *            value between 46 (42 for VLAN-tagged frames) and 1500 (also 1500
+ *            for VLAN-tagged frames), inclusive, that does not match the
+ *            number of data octets (including pad) received. Also contains
+ *            a count of received frames with a length/type field less than
+ *            46 (42 for VLAN-tagged frames) and the number of data octets
+ *            (including pad) received is greater than 46 (42 for VLAN-tagged
+ *            frames).
+ * @rx_out_rng_len_err_frms:  Count of received frames with length/type field
+ *            between 1501 and 1535 decimal, inclusive.
+ * @rx_drop_frms: Count of received frames that could not be passed to the host.
+ *            See PORTn_RX_L2_MGMT_DISCARD, PORTn_RX_RPA_DISCARD,
+ *            PORTn_RX_TRASH_DISCARD, PORTn_RX_RTS_DISCARD, PORTn_RX_RED_DISCARD
+ *            for a list of reasons. Because the RMAC drops one frame at a time,
+ *            this stat also indicates the number of drop events.
+ * @rx_discarded_frms: Count of received frames containing
+ *             any error that prevents
+ *            them from being passed to the system. See PORTn_RX_FCS_DISCARD,
+ *            PORTn_RX_LEN_DISCARD, and PORTn_RX_SWITCH_DISCARD for a list of
+ *            reasons.
+ * @rx_drop_ip: Count of received IP datagrams that could not be passed to the
+ *            host. See PORTn_RX_DROP_FRMS for a list of reasons.
+ * @rx_drop_udp: Count of received UDP datagrams that are not delivered to the
+ *            host. See PORTn_RX_DROP_FRMS for a list of reasons.
+ * @rx_marker_pdu_frms: Count of valid Marker PDUs received on this Aggregation
+ *            port.
+ * @rx_lacpdu_frms: Count of valid LACPDUs received on this Aggregation port.
+ * @rx_unknown_pdu_frms: Count of received frames (on this Aggregation port)
+ *            that carry the Slow Protocols EtherType, but contain an unknown
+ *            PDU. Or frames that contain the Slow Protocols group MAC address,
+ *            but do not carry the Slow Protocols EtherType.
+ * @rx_marker_resp_pdu_frms: Count of valid Marker Response PDUs received on
+ *            this Aggregation port.
+ * @rx_fcs_discard: Count of received frames that are discarded because the
+ *            FCS check failed.
+ * @rx_illegal_pdu_frms: Count of received frames (on this Aggregation port)
+ *            that carry the Slow Protocols EtherType, but contain a badly
+ *            formed PDU. Or frames that carry the Slow Protocols EtherType,
+ *            but contain an illegal value of Protocol Subtype.
+ * @rx_switch_discard: Count of received frames that are discarded by the
+ *            internal switch because they did not have an entry in the
+ *            Filtering Database. This includes frames that had an invalid
+ *            destination MAC address or VLAN ID. It also includes frames are
+ *            discarded because they did not satisfy the length requirements
+ *            of the target VPATH.
+ * @rx_len_discard: Count of received frames that are discarded because of an
+ *            invalid frame length (includes fragments, oversized frames and
+ *            mismatch between frame length and length/type field). This stat
+ *            can be configured
+ *            (see XMAC_STATS_GLOBAL_CFG.LEN_DISCARD_HANDLING).
+ * @rx_rpa_discard: Count of received frames that were discarded because the
+ *            receive protocol assist (RPA) discovered and error in the frame
+ *            or was unable to parse the frame.
+ * @rx_l2_mgmt_discard: Count of Layer 2 management frames (eg. pause frames,
+ *            Link Aggregation Control Protocol (LACP) frames, etc.) that are
+ *            discarded.
+ * @rx_rts_discard: Count of received frames that are discarded by the receive
+ *            traffic steering (RTS) logic. Includes those frame discarded
+ *            because the SSC response contradicted the switch table, because
+ *            the SSC timed out, or because the target queue could not fit the
+ *            frame.
+ * @rx_trash_discard: Count of received frames that are discarded because
+ *            receive traffic steering (RTS) steered the frame to the trash
+ *            queue.
+ * @rx_buff_full_discard: Count of received frames that are discarded because
+ *            internal buffers are full. Includes frames discarded because the
+ *            RTS logic is waiting for an SSC lookup that has no timeout bound.
+ *            Also, includes frames that are dropped because the MAC2FAU buffer
+ *            is nearly full -- this can happen if the external receive buffer
+ *            is full and the receive path is backing up.
+ * @rx_red_discard: Count of received frames that are discarded because of RED
+ *            (Random Early Discard).
+ * @rx_xgmii_ctrl_err_cnt: Maintains a count of unexpected or misplaced control
+ *            characters occuring between times of normal data transmission
+ *            (i.e. not included in RX_XGMII_DATA_ERR_CNT). This counter is
+ *            incremented when either -
+ *            1) The Reconciliation Sublayer (RS) is expecting one control
+ *               character and gets another (i.e. is expecting a Start
+ *               character, but gets another control character).
+ *            2) Start control character is not in lane 0
+ *            Only increments the count by one for each XGMII column.
+ * @rx_xgmii_data_err_cnt: Maintains a count of unexpected control characters
+ *            during normal data transmission. If the Reconciliation Sublayer
+ *            (RS) receives a control character, other than a terminate control
+ *            character, during receipt of data octets then this register is
+ *            incremented. Also increments if the start frame delimiter is not
+ *            found in the correct location. Only increments the count by one
+ *            for each XGMII column.
+ * @rx_xgmii_char1_match: Maintains a count of the number of XGMII characters
+ *            that match a pattern that is programmable through register
+ *            XMAC_STATS_RX_XGMII_CHAR_PORTn. By default, the pattern is set
+ *            to /E/ (i.e. the error character), thus the statistic tracks the
+ *            number of Error characters received at any time.
+ * @rx_xgmii_err_sym: Count of the number of symbol errors in the received
+ *            XGMII data (i.e. PHY indicates "Receive Error" on the XGMII).
+ *            Only includes symbol errors that are observed between the XGMII
+ *            Start Frame Delimiter and End Frame Delimiter, inclusive. And
+ *            only increments the count by one for each frame.
+ * @rx_xgmii_column1_match: Maintains a count of the number of XGMII columns
+ *            that match a pattern that is programmable through register
+ *            XMAC_STATS_RX_XGMII_COLUMN1_PORTn. By default, the pattern is set
+ *            to 4 x /E/ (i.e. a column containing all error characters), thus
+ *            the statistic tracks the number of Error columns received at any
+ *            time.
+ * @rx_xgmii_char2_match: Maintains a count of the number of XGMII characters
+ *            that match a pattern that is programmable through register
+ *            XMAC_STATS_RX_XGMII_CHAR_PORTn. By default, the pattern is set
+ *            to /E/ (i.e. the error character), thus the statistic tracks the
+ *            number of Error characters received at any time.
+ * @rx_local_fault: Maintains a count of the number of times that link
+ *            transitioned from "up" to "down" due to a local fault.
+ * @rx_xgmii_column2_match: Maintains a count of the number of XGMII columns
+ *            that match a pattern that is programmable through register
+ *            XMAC_STATS_RX_XGMII_COLUMN2_PORTn. By default, the pattern is set
+ *            to 4 x /E/ (i.e. a column containing all error characters), thus
+ *            the statistic tracks the number of Error columns received at any
+ *            time. If XMAC_STATS_RX_XGMII_BEHAV_COLUMN2_PORTn.NEAR_COL1 is set
+ *            to 1, then this stat increments when COLUMN2 is found within 'n'
+ *            clocks after COLUMN1. Here, 'n' is defined by
+ *            XMAC_STATS_RX_XGMII_BEHAV_COLUMN2_PORTn.NUM_COL (if 'n' is set to
+ *            0, then it means to search anywhere for COLUMN2).
+ * @rx_jettison: Count of received frames that are jettisoned because internal
+ *            buffers are full.
+ * @rx_remote_fault: Maintains a count of the number of times that link
+ *            transitioned from "up" to "down" due to a remote fault.
+ *
+ * XMAC Port Statistics.
+ */
+struct vxge_hw_xmac_port_stats {
+/*0x000*/              u64     tx_ttl_frms;
+/*0x008*/              u64     tx_ttl_octets;
+/*0x010*/              u64     tx_data_octets;
+/*0x018*/              u64     tx_mcast_frms;
+/*0x020*/              u64     tx_bcast_frms;
+/*0x028*/              u64     tx_ucast_frms;
+/*0x030*/              u64     tx_tagged_frms;
+/*0x038*/              u64     tx_vld_ip;
+/*0x040*/              u64     tx_vld_ip_octets;
+/*0x048*/              u64     tx_icmp;
+/*0x050*/              u64     tx_tcp;
+/*0x058*/              u64     tx_rst_tcp;
+/*0x060*/              u64     tx_udp;
+/*0x068*/              u32     tx_parse_error;
+/*0x06c*/              u32     tx_unknown_protocol;
+/*0x070*/              u64     tx_pause_ctrl_frms;
+/*0x078*/              u32     tx_marker_pdu_frms;
+/*0x07c*/              u32     tx_lacpdu_frms;
+/*0x080*/              u32     tx_drop_ip;
+/*0x084*/              u32     tx_marker_resp_pdu_frms;
+/*0x088*/              u32     tx_xgmii_char2_match;
+/*0x08c*/              u32     tx_xgmii_char1_match;
+/*0x090*/              u32     tx_xgmii_column2_match;
+/*0x094*/              u32     tx_xgmii_column1_match;
+/*0x098*/              u32     unused1;
+/*0x09c*/              u16     tx_any_err_frms;
+/*0x09e*/              u16     tx_drop_frms;
+/*0x0a0*/              u64     rx_ttl_frms;
+/*0x0a8*/              u64     rx_vld_frms;
+/*0x0b0*/              u64     rx_offload_frms;
+/*0x0b8*/              u64     rx_ttl_octets;
+/*0x0c0*/              u64     rx_data_octets;
+/*0x0c8*/              u64     rx_offload_octets;
+/*0x0d0*/              u64     rx_vld_mcast_frms;
+/*0x0d8*/              u64     rx_vld_bcast_frms;
+/*0x0e0*/              u64     rx_accepted_ucast_frms;
+/*0x0e8*/              u64     rx_accepted_nucast_frms;
+/*0x0f0*/              u64     rx_tagged_frms;
+/*0x0f8*/              u64     rx_long_frms;
+/*0x100*/              u64     rx_usized_frms;
+/*0x108*/              u64     rx_osized_frms;
+/*0x110*/              u64     rx_frag_frms;
+/*0x118*/              u64     rx_jabber_frms;
+/*0x120*/              u64     rx_ttl_64_frms;
+/*0x128*/              u64     rx_ttl_65_127_frms;
+/*0x130*/              u64     rx_ttl_128_255_frms;
+/*0x138*/              u64     rx_ttl_256_511_frms;
+/*0x140*/              u64     rx_ttl_512_1023_frms;
+/*0x148*/              u64     rx_ttl_1024_1518_frms;
+/*0x150*/              u64     rx_ttl_1519_4095_frms;
+/*0x158*/              u64     rx_ttl_4096_8191_frms;
+/*0x160*/              u64     rx_ttl_8192_max_frms;
+/*0x168*/              u64     rx_ttl_gt_max_frms;
+/*0x170*/              u64     rx_ip;
+/*0x178*/              u64     rx_accepted_ip;
+/*0x180*/              u64     rx_ip_octets;
+/*0x188*/              u64     rx_err_ip;
+/*0x190*/              u64     rx_icmp;
+/*0x198*/              u64     rx_tcp;
+/*0x1a0*/              u64     rx_udp;
+/*0x1a8*/              u64     rx_err_tcp;
+/*0x1b0*/              u64     rx_pause_count;
+/*0x1b8*/              u64     rx_pause_ctrl_frms;
+/*0x1c0*/              u64     rx_unsup_ctrl_frms;
+/*0x1c8*/              u64     rx_fcs_err_frms;
+/*0x1d0*/              u64     rx_in_rng_len_err_frms;
+/*0x1d8*/              u64     rx_out_rng_len_err_frms;
+/*0x1e0*/              u64     rx_drop_frms;
+/*0x1e8*/              u64     rx_discarded_frms;
+/*0x1f0*/              u64     rx_drop_ip;
+/*0x1f8*/              u64     rx_drop_udp;
+/*0x200*/              u32     rx_marker_pdu_frms;
+/*0x204*/              u32     rx_lacpdu_frms;
+/*0x208*/              u32     rx_unknown_pdu_frms;
+/*0x20c*/              u32     rx_marker_resp_pdu_frms;
+/*0x210*/              u32     rx_fcs_discard;
+/*0x214*/              u32     rx_illegal_pdu_frms;
+/*0x218*/              u32     rx_switch_discard;
+/*0x21c*/              u32     rx_len_discard;
+/*0x220*/              u32     rx_rpa_discard;
+/*0x224*/              u32     rx_l2_mgmt_discard;
+/*0x228*/              u32     rx_rts_discard;
+/*0x22c*/              u32     rx_trash_discard;
+/*0x230*/              u32     rx_buff_full_discard;
+/*0x234*/              u32     rx_red_discard;
+/*0x238*/              u32     rx_xgmii_ctrl_err_cnt;
+/*0x23c*/              u32     rx_xgmii_data_err_cnt;
+/*0x240*/              u32     rx_xgmii_char1_match;
+/*0x244*/              u32     rx_xgmii_err_sym;
+/*0x248*/              u32     rx_xgmii_column1_match;
+/*0x24c*/              u32     rx_xgmii_char2_match;
+/*0x250*/              u32     rx_local_fault;
+/*0x254*/              u32     rx_xgmii_column2_match;
+/*0x258*/              u32     rx_jettison;
+/*0x25c*/              u32     rx_remote_fault;
+} __packed;
+
+/**
+ * struct vxge_hw_xmac_vpath_tx_stats - XMAC Vpath Tx Statistics
+ *
+ * @tx_ttl_eth_frms: Count of successfully transmitted MAC frames.
+ * @tx_ttl_eth_octets: Count of total octets of transmitted frames,
+ *             not including framing characters (i.e. less framing bits).
+ *             To determine the total octets of transmitted frames, including
+ *             framing characters, multiply TX_TTL_ETH_FRMS by 8 and add it to
+ *             this stat (the device always prepends 8 bytes of preamble for
+ *             each frame)
+ * @tx_data_octets: Count of data and padding octets of successfully transmitted
+ *             frames.
+ * @tx_mcast_frms: Count of successfully transmitted frames to a group address
+ *             other than the broadcast address.
+ * @tx_bcast_frms: Count of successfully transmitted frames to the broadcast
+ *             group address.
+ * @tx_ucast_frms: Count of transmitted frames containing a unicast address.
+ *             Includes discarded frames that are not sent to the network.
+ * @tx_tagged_frms: Count of transmitted frames containing a VLAN tag.
+ * @tx_vld_ip: Count of transmitted IP datagrams that are passed to the network.
+ * @tx_vld_ip_octets: Count of total octets of transmitted IP datagrams that
+ *            are passed to the network.
+ * @tx_icmp: Count of transmitted ICMP messages. Includes messages not sent due
+ *            to problems within ICMP.
+ * @tx_tcp: Count of transmitted TCP segments. Does not include segments
+ *            containing retransmitted octets.
+ * @tx_rst_tcp: Count of transmitted TCP segments containing the RST flag.
+ * @tx_udp: Count of transmitted UDP datagrams.
+ * @tx_unknown_protocol: Increments when the TPA encounters an unknown protocol,
+ *            such as a new IPv6 extension header, or an unsupported Routing
+ *            Type. The packet still has a checksum calculated but it may be
+ *            incorrect.
+ * @tx_lost_ip: Count of transmitted IP datagrams that could not be passed
+ *            to the network. Increments because of: 1) An internal processing
+ *            error (such as an uncorrectable ECC error). 2) A frame parsing
+ *            error during IP checksum calculation.
+ * @tx_parse_error: Increments when the TPA is unable to parse a packet. This
+ *            generally occurs when a packet is corrupt somehow, including
+ *            packets that have IP version mismatches, invalid Layer 2 control
+ *            fields, etc. L3/L4 checksums are not offloaded, but the packet
+ *            is still be transmitted.
+ * @tx_tcp_offload: For frames belonging to offloaded sessions only, a count
+ *            of transmitted TCP segments. Does not include segments containing
+ *            retransmitted octets.
+ * @tx_retx_tcp_offload: For frames belonging to offloaded sessions only, the
+ *            total number of segments retransmitted. Retransmitted segments
+ *            that are sourced by the host are counted by the host.
+ * @tx_lost_ip_offload: For frames belonging to offloaded sessions only, a count
+ *            of transmitted IP datagrams that could not be passed to the
+ *            network.
+ *
+ * XMAC Vpath TX Statistics.
+ */
+struct vxge_hw_xmac_vpath_tx_stats {
+       u64     tx_ttl_eth_frms;
+       u64     tx_ttl_eth_octets;
+       u64     tx_data_octets;
+       u64     tx_mcast_frms;
+       u64     tx_bcast_frms;
+       u64     tx_ucast_frms;
+       u64     tx_tagged_frms;
+       u64     tx_vld_ip;
+       u64     tx_vld_ip_octets;
+       u64     tx_icmp;
+       u64     tx_tcp;
+       u64     tx_rst_tcp;
+       u64     tx_udp;
+       u32     tx_unknown_protocol;
+       u32     tx_lost_ip;
+       u32     unused1;
+       u32     tx_parse_error;
+       u64     tx_tcp_offload;
+       u64     tx_retx_tcp_offload;
+       u64     tx_lost_ip_offload;
+} __packed;
+
+/**
+ * struct vxge_hw_xmac_vpath_rx_stats - XMAC Vpath RX Statistics
+ *
+ * @rx_ttl_eth_frms: Count of successfully received MAC frames.
+ * @rx_vld_frms: Count of successfully received MAC frames. Does not include
+ *            frames received with frame-too-long, FCS, or length errors.
+ * @rx_offload_frms: Count of offloaded received frames that are passed to
+ *            the host.
+ * @rx_ttl_eth_octets: Count of total octets of received frames, not including
+ *            framing characters (i.e. less framing bits). Only counts octets
+ *            of frames that are at least 14 bytes (18 bytes for VLAN-tagged)
+ *            before FCS. To determine the total octets of received frames,
+ *            including framing characters, multiply RX_TTL_ETH_FRMS by 8 and
+ *            add it to this stat (the stat RX_TTL_ETH_FRMS only counts frames
+ *            that have the required 8 bytes of preamble).
+ * @rx_data_octets: Count of data and padding octets of successfully received
+ *            frames. Does not include frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_offload_octets: Count of total octets, not including framing characters,
+ *            of offloaded received frames that are passed to the host.
+ * @rx_vld_mcast_frms: Count of successfully received MAC frames containing a
+ *            nonbroadcast group address. Does not include frames received with
+ *            frame-too-long, FCS, or length errors.
+ * @rx_vld_bcast_frms: Count of successfully received MAC frames containing the
+ *            broadcast group address. Does not include frames received with
+ *            frame-too-long, FCS, or length errors.
+ * @rx_accepted_ucast_frms: Count of successfully received frames containing
+ *            a unicast address. Only includes frames that are passed to the
+ *            system.
+ * @rx_accepted_nucast_frms: Count of successfully received frames containing
+ *            a non-unicast (broadcast or multicast) address. Only includes
+ *            frames that are passed to the system. Could include, for instance,
+ *            non-unicast frames that contain FCS errors if the MAC_ERROR_CFG
+ *            register is set to pass FCS-errored frames to the host.
+ * @rx_tagged_frms: Count of received frames containing a VLAN tag.
+ * @rx_long_frms: Count of received frames that are longer than RX_MAX_PYLD_LEN
+ *            + 18 bytes (+ 22 bytes if VLAN-tagged).
+ * @rx_usized_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) less than 64 octets, that are otherwise well-formed.
+ *            In other words, counts runts.
+ * @rx_osized_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) more than 1518 octets, that are otherwise
+ *            well-formed.
+ * @rx_frag_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) less than 64 octets that had bad FCS.
+ *            In other words, counts fragments.
+ * @rx_jabber_frms: Count of received frames of length (including FCS, but not
+ *            framing bits) more than 1518 octets that had bad FCS. In other
+ *            words, counts jabbers.
+ * @rx_ttl_64_frms: Count of total received MAC frames with length (including
+ *            FCS, but not framing bits) of exactly 64 octets. Includes frames
+ *            received with frame-too-long, FCS, or length errors.
+ * @rx_ttl_65_127_frms: Count of total received MAC frames
+ *             with length (including
+ *            FCS, but not framing bits) of between 65 and 127 octets inclusive.
+ *            Includes frames received with frame-too-long, FCS,
+ *            or length errors.
+ * @rx_ttl_128_255_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits)
+ *            of between 128 and 255 octets
+ *            inclusive. Includes frames received with frame-too-long, FCS,
+ *            or length errors.
+ * @rx_ttl_256_511_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits)
+ *            of between 256 and 511 octets
+ *            inclusive. Includes frames received with frame-too-long, FCS, or
+ *            length errors.
+ * @rx_ttl_512_1023_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 512 and 1023
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_1024_1518_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 1024 and 1518
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_1519_4095_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 1519 and 4095
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_4096_8191_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 4096 and 8191
+ *            octets inclusive. Includes frames received with frame-too-long,
+ *            FCS, or length errors.
+ * @rx_ttl_8192_max_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) of between 8192 and
+ *            RX_MAX_PYLD_LEN+18 octets inclusive. Includes frames received
+ *            with frame-too-long, FCS, or length errors.
+ * @rx_ttl_gt_max_frms: Count of total received MAC frames with length
+ *            (including FCS, but not framing bits) exceeding RX_MAX_PYLD_LEN+18
+ *            (+22 bytes if VLAN-tagged) octets inclusive. Includes frames
+ *            received with frame-too-long, FCS, or length errors.
+ * @rx_ip: Count of received IP datagrams. Includes errored IP datagrams.
+ * @rx_accepted_ip: Count of received IP datagrams that
+ *             are passed to the system.
+ * @rx_ip_octets: Count of number of octets in received IP datagrams.
+ *            Includes errored IP datagrams.
+ * @rx_err_ip: Count of received IP datagrams containing errors. For example,
+ *            bad IP checksum.
+ * @rx_icmp: Count of received ICMP messages. Includes errored ICMP messages.
+ * @rx_tcp: Count of received TCP segments. Includes errored TCP segments.
+ *             Note: This stat contains a count of all received TCP segments,
+ *             regardless of whether or not they pertain to an established
+ *             connection.
+ * @rx_udp: Count of received UDP datagrams.
+ * @rx_err_tcp: Count of received TCP segments containing errors. For example,
+ *             bad TCP checksum.
+ * @rx_lost_frms: Count of received frames that could not be passed to the host.
+ *             See RX_QUEUE_FULL_DISCARD and RX_RED_DISCARD
+ *             for a list of reasons.
+ * @rx_lost_ip: Count of received IP datagrams that could not be passed to
+ *             the host. See RX_LOST_FRMS for a list of reasons.
+ * @rx_lost_ip_offload: For frames belonging to offloaded sessions only, a count
+ *             of received IP datagrams that could not be passed to the host.
+ *             See RX_LOST_FRMS for a list of reasons.
+ * @rx_various_discard: Count of received frames that are discarded because
+ *             the target receive queue is full.
+ * @rx_sleep_discard: Count of received frames that are discarded because the
+ *            target VPATH is asleep (a Wake-on-LAN magic packet can be used
+ *            to awaken the VPATH).
+ * @rx_red_discard: Count of received frames that are discarded because of RED
+ *            (Random Early Discard).
+ * @rx_queue_full_discard: Count of received frames that are discarded because
+ *             the target receive queue is full.
+ * @rx_mpa_ok_frms: Count of received frames that pass the MPA checks.
+ *
+ * XMAC Vpath RX Statistics.
+ */
+struct vxge_hw_xmac_vpath_rx_stats {
+       u64     rx_ttl_eth_frms;
+       u64     rx_vld_frms;
+       u64     rx_offload_frms;
+       u64     rx_ttl_eth_octets;
+       u64     rx_data_octets;
+       u64     rx_offload_octets;
+       u64     rx_vld_mcast_frms;
+       u64     rx_vld_bcast_frms;
+       u64     rx_accepted_ucast_frms;
+       u64     rx_accepted_nucast_frms;
+       u64     rx_tagged_frms;
+       u64     rx_long_frms;
+       u64     rx_usized_frms;
+       u64     rx_osized_frms;
+       u64     rx_frag_frms;
+       u64     rx_jabber_frms;
+       u64     rx_ttl_64_frms;
+       u64     rx_ttl_65_127_frms;
+       u64     rx_ttl_128_255_frms;
+       u64     rx_ttl_256_511_frms;
+       u64     rx_ttl_512_1023_frms;
+       u64     rx_ttl_1024_1518_frms;
+       u64     rx_ttl_1519_4095_frms;
+       u64     rx_ttl_4096_8191_frms;
+       u64     rx_ttl_8192_max_frms;
+       u64     rx_ttl_gt_max_frms;
+       u64     rx_ip;
+       u64     rx_accepted_ip;
+       u64     rx_ip_octets;
+       u64     rx_err_ip;
+       u64     rx_icmp;
+       u64     rx_tcp;
+       u64     rx_udp;
+       u64     rx_err_tcp;
+       u64     rx_lost_frms;
+       u64     rx_lost_ip;
+       u64     rx_lost_ip_offload;
+       u16     rx_various_discard;
+       u16     rx_sleep_discard;
+       u16     rx_red_discard;
+       u16     rx_queue_full_discard;
+       u64     rx_mpa_ok_frms;
+} __packed;
+
+/**
+ * struct vxge_hw_xmac_stats - XMAC Statistics
+ *
+ * @aggr_stats: Statistics on aggregate port(port 0, port 1)
+ * @port_stats: Staticstics on ports(wire 0, wire 1, lag)
+ * @vpath_tx_stats: Per vpath XMAC TX stats
+ * @vpath_rx_stats: Per vpath XMAC RX stats
+ *
+ * XMAC Statistics.
+ */
+struct vxge_hw_xmac_stats {
+       struct vxge_hw_xmac_aggr_stats
+                               aggr_stats[VXGE_HW_MAC_MAX_MAC_PORT_ID];
+       struct vxge_hw_xmac_port_stats
+                               port_stats[VXGE_HW_MAC_MAX_MAC_PORT_ID+1];
+       struct vxge_hw_xmac_vpath_tx_stats
+                               vpath_tx_stats[VXGE_HW_MAX_VIRTUAL_PATHS];
+       struct vxge_hw_xmac_vpath_rx_stats
+                               vpath_rx_stats[VXGE_HW_MAX_VIRTUAL_PATHS];
+};
+
+/**
+ * struct vxge_hw_vpath_stats_hw_info - Titan vpath hardware statistics.
+ * @ini_num_mwr_sent: The number of PCI memory writes initiated by the PIC block
+ *             for the given VPATH
+ * @ini_num_mrd_sent: The number of PCI memory reads initiated by the PIC block
+ * @ini_num_cpl_rcvd: The number of PCI read completions received by the
+ *             PIC block
+ * @ini_num_mwr_byte_sent: The number of PCI memory write bytes sent by the PIC
+ *             block to the host
+ * @ini_num_cpl_byte_rcvd: The number of PCI read completion bytes received by
+ *             the PIC block
+ * @wrcrdtarb_xoff: TBD
+ * @rdcrdtarb_xoff: TBD
+ * @vpath_genstats_count0: TBD
+ * @vpath_genstats_count1: TBD
+ * @vpath_genstats_count2: TBD
+ * @vpath_genstats_count3: TBD
+ * @vpath_genstats_count4: TBD
+ * @vpath_gennstats_count5: TBD
+ * @tx_stats: Transmit stats
+ * @rx_stats: Receive stats
+ * @prog_event_vnum1: Programmable statistic. Increments when internal logic
+ *             detects a certain event. See register
+ *             XMAC_STATS_CFG.EVENT_VNUM1_CFG for more information.
+ * @prog_event_vnum0: Programmable statistic. Increments when internal logic
+ *             detects a certain event. See register
+ *             XMAC_STATS_CFG.EVENT_VNUM0_CFG for more information.
+ * @prog_event_vnum3: Programmable statistic. Increments when internal logic
+ *             detects a certain event. See register
+ *             XMAC_STATS_CFG.EVENT_VNUM3_CFG for more information.
+ * @prog_event_vnum2: Programmable statistic. Increments when internal logic
+ *             detects a certain event. See register
+ *             XMAC_STATS_CFG.EVENT_VNUM2_CFG for more information.
+ * @rx_multi_cast_frame_discard: TBD
+ * @rx_frm_transferred: TBD
+ * @rxd_returned: TBD
+ * @rx_mpa_len_fail_frms: Count of received frames
+ *             that fail the MPA length check
+ * @rx_mpa_mrk_fail_frms: Count of received frames
+ *             that fail the MPA marker check
+ * @rx_mpa_crc_fail_frms: Count of received frames that fail the MPA CRC check
+ * @rx_permitted_frms: Count of frames that pass through the FAU and on to the
+ *             frame buffer (and subsequently to the host).
+ * @rx_vp_reset_discarded_frms: Count of receive frames that are discarded
+ *             because the VPATH is in reset
+ * @rx_wol_frms: Count of received "magic packet" frames. Stat increments
+ *             whenever the received frame matches the VPATH's Wake-on-LAN
+ *             signature(s) CRC.
+ * @tx_vp_reset_discarded_frms: Count of transmit frames that are discarded
+ *             because the VPATH is in reset. Includes frames that are discarded
+ *             because the current VPIN does not match that VPIN of the frame
+ *
+ * Titan vpath hardware statistics.
+ */
+struct vxge_hw_vpath_stats_hw_info {
+/*0x000*/      u32 ini_num_mwr_sent;
+/*0x004*/      u32 unused1;
+/*0x008*/      u32 ini_num_mrd_sent;
+/*0x00c*/      u32 unused2;
+/*0x010*/      u32 ini_num_cpl_rcvd;
+/*0x014*/      u32 unused3;
+/*0x018*/      u64 ini_num_mwr_byte_sent;
+/*0x020*/      u64 ini_num_cpl_byte_rcvd;
+/*0x028*/      u32 wrcrdtarb_xoff;
+/*0x02c*/      u32 unused4;
+/*0x030*/      u32 rdcrdtarb_xoff;
+/*0x034*/      u32 unused5;
+/*0x038*/      u32 vpath_genstats_count0;
+/*0x03c*/      u32 vpath_genstats_count1;
+/*0x040*/      u32 vpath_genstats_count2;
+/*0x044*/      u32 vpath_genstats_count3;
+/*0x048*/      u32 vpath_genstats_count4;
+/*0x04c*/      u32 unused6;
+/*0x050*/      u32 vpath_genstats_count5;
+/*0x054*/      u32 unused7;
+/*0x058*/      struct vxge_hw_xmac_vpath_tx_stats tx_stats;
+/*0x0e8*/      struct vxge_hw_xmac_vpath_rx_stats rx_stats;
+/*0x220*/      u64 unused9;
+/*0x228*/      u32 prog_event_vnum1;
+/*0x22c*/      u32 prog_event_vnum0;
+/*0x230*/      u32 prog_event_vnum3;
+/*0x234*/      u32 prog_event_vnum2;
+/*0x238*/      u16 rx_multi_cast_frame_discard;
+/*0x23a*/      u8 unused10[6];
+/*0x240*/      u32 rx_frm_transferred;
+/*0x244*/      u32 unused11;
+/*0x248*/      u16 rxd_returned;
+/*0x24a*/      u8 unused12[6];
+/*0x252*/      u16 rx_mpa_len_fail_frms;
+/*0x254*/      u16 rx_mpa_mrk_fail_frms;
+/*0x256*/      u16 rx_mpa_crc_fail_frms;
+/*0x258*/      u16 rx_permitted_frms;
+/*0x25c*/      u64 rx_vp_reset_discarded_frms;
+/*0x25e*/      u64 rx_wol_frms;
+/*0x260*/      u64 tx_vp_reset_discarded_frms;
+} __packed;
+
+
+/**
+ * struct vxge_hw_device_stats_mrpcim_info - Titan mrpcim hardware statistics.
+ * @pic.ini_rd_drop     0x0000          4       Number of DMA reads initiated
+ *  by the adapter that were discarded because the VPATH is out of service
+ * @pic.ini_wr_drop    0x0004  4       Number of DMA writes initiated by the
+ *  adapter that were discared because the VPATH is out of service
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane0]    0x0008  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane1]    0x0010  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane2]    0x0018  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane3]    0x0020  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane4]    0x0028  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane5]    0x0030  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane6]    0x0038  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane7]    0x0040  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane8]    0x0048  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane9]    0x0050  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane10]   0x0058  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane11]   0x0060  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane12]   0x0068  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane13]   0x0070  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane14]   0x0078  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane15]   0x0080  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_ph_crdt_depleted[vplane16]   0x0088  4       Number of times
+ *  the posted header credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane0]    0x0090  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane1]    0x0098  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane2]    0x00a0  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane3]    0x00a8  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane4]    0x00b0  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane5]    0x00b8  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane6]    0x00c0  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane7]    0x00c8  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane8]    0x00d0  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane9]    0x00d8  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane10]   0x00e0  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane11]   0x00e8  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane12]   0x00f0  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane13]   0x00f8  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane14]   0x0100  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane15]   0x0108  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.wrcrdtarb_pd_crdt_depleted[vplane16]   0x0110  4       Number of times
+ *  the posted data credits for upstream PCI writes were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane0]   0x0118  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane1]   0x0120  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane2]   0x0128  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane3]   0x0130  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane4]   0x0138  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane5]   0x0140  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane6]   0x0148  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane7]   0x0150  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane8]   0x0158  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane9]   0x0160  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane10]  0x0168  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane11]  0x0170  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane12]  0x0178  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane13]  0x0180  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane14]  0x0188  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane15]  0x0190  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.rdcrdtarb_nph_crdt_depleted[vplane16]  0x0198  4       Number of times
+ *  the non-posted header credits for upstream PCI reads were depleted
+ * @pic.ini_rd_vpin_drop       0x01a0  4       Number of DMA reads initiated by
+ *  the adapter that were discarded because the VPATH instance number does
+ *  not match
+ * @pic.ini_wr_vpin_drop       0x01a4  4       Number of DMA writes initiated
+ *  by the adapter that were discarded because the VPATH instance number
+ *  does not match
+ * @pic.genstats_count0        0x01a8  4       Configurable statistic #1. Refer
+ *  to the GENSTATS0_CFG for information on configuring this statistic
+ * @pic.genstats_count1        0x01ac  4       Configurable statistic #2. Refer
+ *  to the GENSTATS1_CFG for information on configuring this statistic
+ * @pic.genstats_count2        0x01b0  4       Configurable statistic #3. Refer
+ *  to the GENSTATS2_CFG for information on configuring this statistic
+ * @pic.genstats_count3        0x01b4  4       Configurable statistic #4. Refer
+ *  to the GENSTATS3_CFG for information on configuring this statistic
+ * @pic.genstats_count4        0x01b8  4       Configurable statistic #5. Refer
+ *  to the GENSTATS4_CFG for information on configuring this statistic
+ * @pic.genstats_count5        0x01c0  4       Configurable statistic #6. Refer
+ *  to the GENSTATS5_CFG for information on configuring this statistic
+ * @pci.rstdrop_cpl    0x01c8  4
+ * @pci.rstdrop_msg    0x01cc  4
+ * @pci.rstdrop_client1        0x01d0  4
+ * @pci.rstdrop_client0        0x01d4  4
+ * @pci.rstdrop_client2        0x01d8  4
+ * @pci.depl_cplh[vplane0]     0x01e2  2       Number of times completion
+ *  header credits were depleted
+ * @pci.depl_nph[vplane0]      0x01e4  2       Number of times non posted
+ *  header credits were depleted
+ * @pci.depl_ph[vplane0]       0x01e6  2       Number of times the posted
+ *  header credits were depleted
+ * @pci.depl_cplh[vplane1]     0x01ea  2
+ * @pci.depl_nph[vplane1]      0x01ec  2
+ * @pci.depl_ph[vplane1]       0x01ee  2
+ * @pci.depl_cplh[vplane2]     0x01f2  2
+ * @pci.depl_nph[vplane2]      0x01f4  2
+ * @pci.depl_ph[vplane2]       0x01f6  2
+ * @pci.depl_cplh[vplane3]     0x01fa  2
+ * @pci.depl_nph[vplane3]      0x01fc  2
+ * @pci.depl_ph[vplane3]       0x01fe  2
+ * @pci.depl_cplh[vplane4]     0x0202  2
+ * @pci.depl_nph[vplane4]      0x0204  2
+ * @pci.depl_ph[vplane4]       0x0206  2
+ * @pci.depl_cplh[vplane5]     0x020a  2
+ * @pci.depl_nph[vplane5]      0x020c  2
+ * @pci.depl_ph[vplane5]       0x020e  2
+ * @pci.depl_cplh[vplane6]     0x0212  2
+ * @pci.depl_nph[vplane6]      0x0214  2
+ * @pci.depl_ph[vplane6]       0x0216  2
+ * @pci.depl_cplh[vplane7]     0x021a  2
+ * @pci.depl_nph[vplane7]      0x021c  2
+ * @pci.depl_ph[vplane7]       0x021e  2
+ * @pci.depl_cplh[vplane8]     0x0222  2
+ * @pci.depl_nph[vplane8]      0x0224  2
+ * @pci.depl_ph[vplane8]       0x0226  2
+ * @pci.depl_cplh[vplane9]     0x022a  2
+ * @pci.depl_nph[vplane9]      0x022c  2
+ * @pci.depl_ph[vplane9]       0x022e  2
+ * @pci.depl_cplh[vplane10]    0x0232  2
+ * @pci.depl_nph[vplane10]     0x0234  2
+ * @pci.depl_ph[vplane10]      0x0236  2
+ * @pci.depl_cplh[vplane11]    0x023a  2
+ * @pci.depl_nph[vplane11]     0x023c  2
+ * @pci.depl_ph[vplane11]      0x023e  2
+ * @pci.depl_cplh[vplane12]    0x0242  2
+ * @pci.depl_nph[vplane12]     0x0244  2
+ * @pci.depl_ph[vplane12]      0x0246  2
+ * @pci.depl_cplh[vplane13]    0x024a  2
+ * @pci.depl_nph[vplane13]     0x024c  2
+ * @pci.depl_ph[vplane13]      0x024e  2
+ * @pci.depl_cplh[vplane14]    0x0252  2
+ * @pci.depl_nph[vplane14]     0x0254  2
+ * @pci.depl_ph[vplane14]      0x0256  2
+ * @pci.depl_cplh[vplane15]    0x025a  2
+ * @pci.depl_nph[vplane15]     0x025c  2
+ * @pci.depl_ph[vplane15]      0x025e  2
+ * @pci.depl_cplh[vplane16]    0x0262  2
+ * @pci.depl_nph[vplane16]     0x0264  2
+ * @pci.depl_ph[vplane16]      0x0266  2
+ * @pci.depl_cpld[vplane0]     0x026a  2       Number of times completion data
+ *  credits were depleted
+ * @pci.depl_npd[vplane0]      0x026c  2       Number of times non posted data
+ *  credits were depleted
+ * @pci.depl_pd[vplane0]       0x026e  2       Number of times the posted data
+ *  credits were depleted
+ * @pci.depl_cpld[vplane1]     0x0272  2
+ * @pci.depl_npd[vplane1]      0x0274  2
+ * @pci.depl_pd[vplane1]       0x0276  2
+ * @pci.depl_cpld[vplane2]     0x027a  2
+ * @pci.depl_npd[vplane2]      0x027c  2
+ * @pci.depl_pd[vplane2]       0x027e  2
+ * @pci.depl_cpld[vplane3]     0x0282  2
+ * @pci.depl_npd[vplane3]      0x0284  2
+ * @pci.depl_pd[vplane3]       0x0286  2
+ * @pci.depl_cpld[vplane4]     0x028a  2
+ * @pci.depl_npd[vplane4]      0x028c  2
+ * @pci.depl_pd[vplane4]       0x028e  2
+ * @pci.depl_cpld[vplane5]     0x0292  2
+ * @pci.depl_npd[vplane5]      0x0294  2
+ * @pci.depl_pd[vplane5]       0x0296  2
+ * @pci.depl_cpld[vplane6]     0x029a  2
+ * @pci.depl_npd[vplane6]      0x029c  2
+ * @pci.depl_pd[vplane6]       0x029e  2
+ * @pci.depl_cpld[vplane7]     0x02a2  2
+ * @pci.depl_npd[vplane7]      0x02a4  2
+ * @pci.depl_pd[vplane7]       0x02a6  2
+ * @pci.depl_cpld[vplane8]     0x02aa  2
+ * @pci.depl_npd[vplane8]      0x02ac  2
+ * @pci.depl_pd[vplane8]       0x02ae  2
+ * @pci.depl_cpld[vplane9]     0x02b2  2
+ * @pci.depl_npd[vplane9]      0x02b4  2
+ * @pci.depl_pd[vplane9]       0x02b6  2
+ * @pci.depl_cpld[vplane10]    0x02ba  2
+ * @pci.depl_npd[vplane10]     0x02bc  2
+ * @pci.depl_pd[vplane10]      0x02be  2
+ * @pci.depl_cpld[vplane11]    0x02c2  2
+ * @pci.depl_npd[vplane11]     0x02c4  2
+ * @pci.depl_pd[vplane11]      0x02c6  2
+ * @pci.depl_cpld[vplane12]    0x02ca  2
+ * @pci.depl_npd[vplane12]     0x02cc  2
+ * @pci.depl_pd[vplane12]      0x02ce  2
+ * @pci.depl_cpld[vplane13]    0x02d2  2
+ * @pci.depl_npd[vplane13]     0x02d4  2
+ * @pci.depl_pd[vplane13]      0x02d6  2
+ * @pci.depl_cpld[vplane14]    0x02da  2
+ * @pci.depl_npd[vplane14]     0x02dc  2
+ * @pci.depl_pd[vplane14]      0x02de  2
+ * @pci.depl_cpld[vplane15]    0x02e2  2
+ * @pci.depl_npd[vplane15]     0x02e4  2
+ * @pci.depl_pd[vplane15]      0x02e6  2
+ * @pci.depl_cpld[vplane16]    0x02ea  2
+ * @pci.depl_npd[vplane16]     0x02ec  2
+ * @pci.depl_pd[vplane16]      0x02ee  2
+ * @xgmac_port[3];
+ * @xgmac_aggr[2];
+ * @xgmac.global_prog_event_gnum0      0x0ae0  8       Programmable statistic.
+ *  Increments when internal logic detects a certain event. See register
+ *  XMAC_STATS_GLOBAL_CFG.EVENT_GNUM0_CFG for more information.
+ * @xgmac.global_prog_event_gnum1      0x0ae8  8       Programmable statistic.
+ *  Increments when internal logic detects a certain event. See register
+ *  XMAC_STATS_GLOBAL_CFG.EVENT_GNUM1_CFG for more information.
+ * @xgmac.orp_lro_events       0x0af8  8
+ * @xgmac.orp_bs_events        0x0b00  8
+ * @xgmac.orp_iwarp_events     0x0b08  8
+ * @xgmac.tx_permitted_frms    0x0b14  4
+ * @xgmac.port2_tx_any_frms    0x0b1d  1
+ * @xgmac.port1_tx_any_frms    0x0b1e  1
+ * @xgmac.port0_tx_any_frms    0x0b1f  1
+ * @xgmac.port2_rx_any_frms    0x0b25  1
+ * @xgmac.port1_rx_any_frms    0x0b26  1
+ * @xgmac.port0_rx_any_frms    0x0b27  1
+ *
+ * Titan mrpcim hardware statistics.
+ */
+struct vxge_hw_device_stats_mrpcim_info {
+/*0x0000*/     u32     pic_ini_rd_drop;
+/*0x0004*/     u32     pic_ini_wr_drop;
+/*0x0008*/     struct {
+       /*0x0000*/      u32     pic_wrcrdtarb_ph_crdt_depleted;
+       /*0x0004*/      u32     unused1;
+               } pic_wrcrdtarb_ph_crdt_depleted_vplane[17];
+/*0x0090*/     struct {
+       /*0x0000*/      u32     pic_wrcrdtarb_pd_crdt_depleted;
+       /*0x0004*/      u32     unused2;
+               } pic_wrcrdtarb_pd_crdt_depleted_vplane[17];
+/*0x0118*/     struct {
+       /*0x0000*/      u32     pic_rdcrdtarb_nph_crdt_depleted;
+       /*0x0004*/      u32     unused3;
+               } pic_rdcrdtarb_nph_crdt_depleted_vplane[17];
+/*0x01a0*/     u32     pic_ini_rd_vpin_drop;
+/*0x01a4*/     u32     pic_ini_wr_vpin_drop;
+/*0x01a8*/     u32     pic_genstats_count0;
+/*0x01ac*/     u32     pic_genstats_count1;
+/*0x01b0*/     u32     pic_genstats_count2;
+/*0x01b4*/     u32     pic_genstats_count3;
+/*0x01b8*/     u32     pic_genstats_count4;
+/*0x01bc*/     u32     unused4;
+/*0x01c0*/     u32     pic_genstats_count5;
+/*0x01c4*/     u32     unused5;
+/*0x01c8*/     u32     pci_rstdrop_cpl;
+/*0x01cc*/     u32     pci_rstdrop_msg;
+/*0x01d0*/     u32     pci_rstdrop_client1;
+/*0x01d4*/     u32     pci_rstdrop_client0;
+/*0x01d8*/     u32     pci_rstdrop_client2;
+/*0x01dc*/     u32     unused6;
+/*0x01e0*/     struct {
+       /*0x0000*/      u16     unused7;
+       /*0x0002*/      u16     pci_depl_cplh;
+       /*0x0004*/      u16     pci_depl_nph;
+       /*0x0006*/      u16     pci_depl_ph;
+               } pci_depl_h_vplane[17];
+/*0x0268*/     struct {
+       /*0x0000*/      u16     unused8;
+       /*0x0002*/      u16     pci_depl_cpld;
+       /*0x0004*/      u16     pci_depl_npd;
+       /*0x0006*/      u16     pci_depl_pd;
+               } pci_depl_d_vplane[17];
+/*0x02f0*/     struct vxge_hw_xmac_port_stats xgmac_port[3];
+/*0x0a10*/     struct vxge_hw_xmac_aggr_stats xgmac_aggr[2];
+/*0x0ae0*/     u64     xgmac_global_prog_event_gnum0;
+/*0x0ae8*/     u64     xgmac_global_prog_event_gnum1;
+/*0x0af0*/     u64     unused7;
+/*0x0af8*/     u64     unused8;
+/*0x0b00*/     u64     unused9;
+/*0x0b08*/     u64     unused10;
+/*0x0b10*/     u32     unused11;
+/*0x0b14*/     u32     xgmac_tx_permitted_frms;
+/*0x0b18*/     u32     unused12;
+/*0x0b1c*/     u8      unused13;
+/*0x0b1d*/     u8      xgmac_port2_tx_any_frms;
+/*0x0b1e*/     u8      xgmac_port1_tx_any_frms;
+/*0x0b1f*/     u8      xgmac_port0_tx_any_frms;
+/*0x0b20*/     u32     unused14;
+/*0x0b24*/     u8      unused15;
+/*0x0b25*/     u8      xgmac_port2_rx_any_frms;
+/*0x0b26*/     u8      xgmac_port1_rx_any_frms;
+/*0x0b27*/     u8      xgmac_port0_rx_any_frms;
+} __packed;
+
+/**
+ * struct vxge_hw_device_stats_hw_info - Titan hardware statistics.
+ * @vpath_info: VPath statistics
+ * @vpath_info_sav: Vpath statistics saved
+ *
+ * Titan hardware statistics.
+ */
+struct vxge_hw_device_stats_hw_info {
+       struct vxge_hw_vpath_stats_hw_info
+               *vpath_info[VXGE_HW_MAX_VIRTUAL_PATHS];
+       struct vxge_hw_vpath_stats_hw_info
+               vpath_info_sav[VXGE_HW_MAX_VIRTUAL_PATHS];
+};
+
+/**
+ * struct vxge_hw_vpath_stats_sw_common_info - HW common
+ * statistics for queues.
+ * @full_cnt: Number of times the queue was full
+ * @usage_cnt: usage count.
+ * @usage_max: Maximum usage
+ * @reserve_free_swaps_cnt: Reserve/free swap counter. Internal usage.
+ * @total_compl_cnt: Total descriptor completion count.
+ *
+ * Hw queue counters
+ * See also: struct vxge_hw_vpath_stats_sw_fifo_info{},
+ * struct vxge_hw_vpath_stats_sw_ring_info{},
+ */
+struct vxge_hw_vpath_stats_sw_common_info {
+       u32     full_cnt;
+       u32     usage_cnt;
+       u32     usage_max;
+       u32     reserve_free_swaps_cnt;
+       u32 total_compl_cnt;
+};
+
+/**
+ * struct vxge_hw_vpath_stats_sw_fifo_info - HW fifo statistics
+ * @common_stats: Common counters for all queues
+ * @total_posts: Total number of postings on the queue.
+ * @total_buffers: Total number of buffers posted.
+ * @txd_t_code_err_cnt: Array of transmit transfer codes. The position
+ * (index) in this array reflects the transfer code type, for instance
+ * 0xA - "loss of link".
+ * Value txd_t_code_err_cnt[i] reflects the
+ * number of times the corresponding transfer code was encountered.
+ *
+ * HW fifo counters
+ * See also: struct vxge_hw_vpath_stats_sw_common_info{},
+ * struct vxge_hw_vpath_stats_sw_ring_info{},
+ */
+struct vxge_hw_vpath_stats_sw_fifo_info {
+       struct vxge_hw_vpath_stats_sw_common_info common_stats;
+       u32 total_posts;
+       u32 total_buffers;
+       u32 txd_t_code_err_cnt[VXGE_HW_DTR_MAX_T_CODE];
+};
+
+/**
+ * struct vxge_hw_vpath_stats_sw_ring_info - HW ring statistics
+ * @common_stats: Common counters for all queues
+ * @rxd_t_code_err_cnt: Array of receive transfer codes. The position
+ *             (index) in this array reflects the transfer code type,
+ *             for instance
+ *             0x7 - for "invalid receive buffer size", or 0x8 - for ECC.
+ *             Value rxd_t_code_err_cnt[i] reflects the
+ *             number of times the corresponding transfer code was encountered.
+ *
+ * HW ring counters
+ * See also: struct vxge_hw_vpath_stats_sw_common_info{},
+ * struct vxge_hw_vpath_stats_sw_fifo_info{},
+ */
+struct vxge_hw_vpath_stats_sw_ring_info {
+       struct vxge_hw_vpath_stats_sw_common_info common_stats;
+       u32 rxd_t_code_err_cnt[VXGE_HW_DTR_MAX_T_CODE];
+
+};
+
+/**
+ * struct vxge_hw_vpath_stats_sw_err - HW vpath error statistics
+ * @unknown_alarms:
+ * @network_sustained_fault:
+ * @network_sustained_ok:
+ * @kdfcctl_fifo0_overwrite:
+ * @kdfcctl_fifo0_poison:
+ * @kdfcctl_fifo0_dma_error:
+ * @dblgen_fifo0_overflow:
+ * @statsb_pif_chain_error:
+ * @statsb_drop_timeout:
+ * @target_illegal_access:
+ * @ini_serr_det:
+ * @prc_ring_bumps:
+ * @prc_rxdcm_sc_err:
+ * @prc_rxdcm_sc_abort:
+ * @prc_quanta_size_err:
+ *
+ * HW vpath error statistics
+ */
+struct vxge_hw_vpath_stats_sw_err {
+       u32     unknown_alarms;
+       u32     network_sustained_fault;
+       u32     network_sustained_ok;
+       u32     kdfcctl_fifo0_overwrite;
+       u32     kdfcctl_fifo0_poison;
+       u32     kdfcctl_fifo0_dma_error;
+       u32     dblgen_fifo0_overflow;
+       u32     statsb_pif_chain_error;
+       u32     statsb_drop_timeout;
+       u32     target_illegal_access;
+       u32     ini_serr_det;
+       u32     prc_ring_bumps;
+       u32     prc_rxdcm_sc_err;
+       u32     prc_rxdcm_sc_abort;
+       u32     prc_quanta_size_err;
+};
+
+/**
+ * struct vxge_hw_vpath_stats_sw_info - HW vpath sw statistics
+ * @soft_reset_cnt: Number of times soft reset is done on this vpath.
+ * @error_stats: error counters for the vpath
+ * @ring_stats: counters for ring belonging to the vpath
+ * @fifo_stats: counters for fifo belonging to the vpath
+ *
+ * HW vpath sw statistics
+ * See also: struct vxge_hw_device_info{} }.
+ */
+struct vxge_hw_vpath_stats_sw_info {
+       u32    soft_reset_cnt;
+       struct vxge_hw_vpath_stats_sw_err       error_stats;
+       struct vxge_hw_vpath_stats_sw_ring_info ring_stats;
+       struct vxge_hw_vpath_stats_sw_fifo_info fifo_stats;
+};
+
+/**
+ * struct vxge_hw_device_stats_sw_info - HW own per-device statistics.
+ *
+ * @not_traffic_intr_cnt: Number of times the host was interrupted
+ *                        without new completions.
+ *                        "Non-traffic interrupt counter".
+ * @traffic_intr_cnt: Number of traffic interrupts for the device.
+ * @total_intr_cnt: Total number of traffic interrupts for the device.
+ *                  @total_intr_cnt == @traffic_intr_cnt +
+ *                              @not_traffic_intr_cnt
+ * @soft_reset_cnt: Number of times soft reset is done on this device.
+ * @vpath_info: please see struct vxge_hw_vpath_stats_sw_info{}
+ * HW per-device statistics.
+ */
+struct vxge_hw_device_stats_sw_info {
+       u32     not_traffic_intr_cnt;
+       u32     traffic_intr_cnt;
+       u32     total_intr_cnt;
+       u32     soft_reset_cnt;
+       struct vxge_hw_vpath_stats_sw_info
+               vpath_info[VXGE_HW_MAX_VIRTUAL_PATHS];
+};
+
+/**
+ * struct vxge_hw_device_stats_sw_err - HW device error statistics.
+ * @vpath_alarms: Number of vpath alarms
+ *
+ * HW Device error stats
+ */
+struct vxge_hw_device_stats_sw_err {
+       u32     vpath_alarms;
+};
+
+/**
+ * struct vxge_hw_device_stats - Contains HW per-device statistics,
+ * including hw.
+ * @devh: HW device handle.
+ * @dma_addr: DMA addres of the %hw_info. Given to device to fill-in the stats.
+ * @hw_info_dmah: DMA handle used to map hw statistics onto the device memory
+ *                space.
+ * @hw_info_dma_acch: One more DMA handle used subsequently to free the
+ *                    DMA object. Note that this and the previous handle have
+ *                    physical meaning for Solaris; on Windows and Linux the
+ *                    corresponding value will be simply pointer to PCI device.
+ *
+ * @hw_dev_info_stats: Titan statistics maintained by the hardware.
+ * @sw_dev_info_stats: HW's "soft" device informational statistics, e.g. number
+ *                     of completions per interrupt.
+ * @sw_dev_err_stats: HW's "soft" device error statistics.
+ *
+ * Structure-container of HW per-device statistics. Note that per-channel
+ * statistics are kept in separate structures under HW's fifo and ring
+ * channels.
+ */
+struct vxge_hw_device_stats {
+       /* handles */
+       struct __vxge_hw_device *devh;
+
+       /* HW device hardware statistics */
+       struct vxge_hw_device_stats_hw_info     hw_dev_info_stats;
+
+       /* HW device "soft" stats */
+       struct vxge_hw_device_stats_sw_err   sw_dev_err_stats;
+       struct vxge_hw_device_stats_sw_info  sw_dev_info_stats;
+
+};
+
+enum vxge_hw_status vxge_hw_device_hw_stats_enable(
+                       struct __vxge_hw_device *devh);
+
+enum vxge_hw_status vxge_hw_device_stats_get(
+                       struct __vxge_hw_device *devh,
+                       struct vxge_hw_device_stats_hw_info *hw_stats);
+
+enum vxge_hw_status vxge_hw_driver_stats_get(
+                       struct __vxge_hw_device *devh,
+                       struct vxge_hw_device_stats_sw_info *sw_stats);
+
+enum vxge_hw_status vxge_hw_mrpcim_stats_enable(struct __vxge_hw_device *devh);
+
+enum vxge_hw_status vxge_hw_mrpcim_stats_disable(struct __vxge_hw_device *devh);
+
+enum vxge_hw_status
+vxge_hw_mrpcim_stats_access(
+       struct __vxge_hw_device *devh,
+       u32 operation,
+       u32 location,
+       u32 offset,
+       u64 *stat);
+
+enum vxge_hw_status
+vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *devh, u32 port,
+                                  struct vxge_hw_xmac_aggr_stats *aggr_stats);
+
+enum vxge_hw_status
+vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *devh, u32 port,
+                                  struct vxge_hw_xmac_port_stats *port_stats);
+
+enum vxge_hw_status
+vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *devh,
+                             struct vxge_hw_xmac_stats *xmac_stats);
+
+/**
+ * enum enum vxge_hw_mgmt_reg_type - Register types.
+ *
+ * @vxge_hw_mgmt_reg_type_legacy: Legacy registers
+ * @vxge_hw_mgmt_reg_type_toc: TOC Registers
+ * @vxge_hw_mgmt_reg_type_common: Common Registers
+ * @vxge_hw_mgmt_reg_type_mrpcim: mrpcim registers
+ * @vxge_hw_mgmt_reg_type_srpcim: srpcim registers
+ * @vxge_hw_mgmt_reg_type_vpmgmt: vpath management registers
+ * @vxge_hw_mgmt_reg_type_vpath: vpath registers
+ *
+ * Register type enumaration
+ */
+enum vxge_hw_mgmt_reg_type {
+       vxge_hw_mgmt_reg_type_legacy = 0,
+       vxge_hw_mgmt_reg_type_toc = 1,
+       vxge_hw_mgmt_reg_type_common = 2,
+       vxge_hw_mgmt_reg_type_mrpcim = 3,
+       vxge_hw_mgmt_reg_type_srpcim = 4,
+       vxge_hw_mgmt_reg_type_vpmgmt = 5,
+       vxge_hw_mgmt_reg_type_vpath = 6
+};
+
+enum vxge_hw_status
+vxge_hw_mgmt_reg_read(struct __vxge_hw_device *devh,
+                     enum vxge_hw_mgmt_reg_type type,
+                     u32 index,
+                     u32 offset,
+                     u64 *value);
+
+enum vxge_hw_status
+vxge_hw_mgmt_reg_write(struct __vxge_hw_device *devh,
+                     enum vxge_hw_mgmt_reg_type type,
+                     u32 index,
+                     u32 offset,
+                     u64 value);
+
+/**
+ * enum enum vxge_hw_rxd_state - Descriptor (RXD) state.
+ * @VXGE_HW_RXD_STATE_NONE: Invalid state.
+ * @VXGE_HW_RXD_STATE_AVAIL: Descriptor is available for reservation.
+ * @VXGE_HW_RXD_STATE_POSTED: Descriptor is posted for processing by the
+ * device.
+ * @VXGE_HW_RXD_STATE_FREED: Descriptor is free and can be reused for
+ * filling-in and posting later.
+ *
+ * Titan/HW descriptor states.
+ *
+ */
+enum vxge_hw_rxd_state {
+       VXGE_HW_RXD_STATE_NONE          = 0,
+       VXGE_HW_RXD_STATE_AVAIL         = 1,
+       VXGE_HW_RXD_STATE_POSTED        = 2,
+       VXGE_HW_RXD_STATE_FREED         = 3
+};
+
+/**
+ * struct vxge_hw_ring_rxd_info - Extended information associated with a
+ * completed ring descriptor.
+ * @syn_flag: SYN flag
+ * @is_icmp: Is ICMP
+ * @fast_path_eligible: Fast Path Eligible flag
+ * @l3_cksum: in L3 checksum is valid
+ * @l3_cksum: Result of IP checksum check (by Titan hardware).
+ *            This field containing VXGE_HW_L3_CKSUM_OK would mean that
+ *            the checksum is correct, otherwise - the datagram is
+ *            corrupted.
+ * @l4_cksum: in L4 checksum is valid
+ * @l4_cksum: Result of TCP/UDP checksum check (by Titan hardware).
+ *            This field containing VXGE_HW_L4_CKSUM_OK would mean that
+ *            the checksum is correct. Otherwise - the packet is
+ *            corrupted.
+ * @frame: Zero or more of enum vxge_hw_frame_type flags.
+ *             See enum vxge_hw_frame_type{}.
+ * @proto: zero or more of enum vxge_hw_frame_proto flags.  Reporting bits for
+ *            various higher-layer protocols, including (but note restricted to)
+ *            TCP and UDP. See enum vxge_hw_frame_proto{}.
+ * @is_vlan: If vlan tag is valid
+ * @vlan: VLAN tag extracted from the received frame.
+ * @rth_bucket: RTH bucket
+ * @rth_it_hit: Set, If RTH hash value calculated by the Titan hardware
+ *             has a matching entry in the Indirection table.
+ * @rth_spdm_hit: Set, If RTH hash value calculated by the Titan hardware
+ *             has a matching entry in the Socket Pair Direct Match table.
+ * @rth_hash_type: RTH hash code of the function used to calculate the hash.
+ * @rth_value: Receive Traffic Hashing(RTH) hash value. Produced by Titan
+ *             hardware if RTH is enabled.
+ */
+struct vxge_hw_ring_rxd_info {
+       u32     syn_flag;
+       u32     is_icmp;
+       u32     fast_path_eligible;
+       u32     l3_cksum_valid;
+       u32     l3_cksum;
+       u32     l4_cksum_valid;
+       u32     l4_cksum;
+       u32     frame;
+       u32     proto;
+       u32     is_vlan;
+       u32     vlan;
+       u32     rth_bucket;
+       u32     rth_it_hit;
+       u32     rth_spdm_hit;
+       u32     rth_hash_type;
+       u32     rth_value;
+};
+
+/**
+ * enum enum vxge_hw_ring_hash_type - RTH hash types
+ * @VXGE_HW_RING_HASH_TYPE_NONE: No Hash
+ * @VXGE_HW_RING_HASH_TYPE_TCP_IPV4: TCP IPv4
+ * @VXGE_HW_RING_HASH_TYPE_UDP_IPV4: UDP IPv4
+ * @VXGE_HW_RING_HASH_TYPE_IPV4: IPv4
+ * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6: TCP IPv6
+ * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6: UDP IPv6
+ * @VXGE_HW_RING_HASH_TYPE_IPV6: IPv6
+ * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX: TCP IPv6 extension
+ * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX: UDP IPv6 extension
+ * @VXGE_HW_RING_HASH_TYPE_IPV6_EX: IPv6 extension
+ *
+ * RTH hash types
+ */
+enum vxge_hw_ring_hash_type {
+       VXGE_HW_RING_HASH_TYPE_NONE                     = 0x0,
+       VXGE_HW_RING_HASH_TYPE_TCP_IPV4         = 0x1,
+       VXGE_HW_RING_HASH_TYPE_UDP_IPV4         = 0x2,
+       VXGE_HW_RING_HASH_TYPE_IPV4                     = 0x3,
+       VXGE_HW_RING_HASH_TYPE_TCP_IPV6         = 0x4,
+       VXGE_HW_RING_HASH_TYPE_UDP_IPV6         = 0x5,
+       VXGE_HW_RING_HASH_TYPE_IPV6                     = 0x6,
+       VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX      = 0x7,
+       VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX      = 0x8,
+       VXGE_HW_RING_HASH_TYPE_IPV6_EX          = 0x9
+};
+
+enum vxge_hw_status vxge_hw_ring_rxd_reserve(
+       struct __vxge_hw_ring *ring_handle,
+       void **rxdh);
+
+void
+vxge_hw_ring_rxd_pre_post(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh);
+
+void
+vxge_hw_ring_rxd_post_post(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh);
+
+enum vxge_hw_status
+vxge_hw_ring_replenish(struct __vxge_hw_ring *ring_handle, u16 min_flag);
+
+void
+vxge_hw_ring_rxd_post_post_wmb(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh);
+
+void vxge_hw_ring_rxd_post(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh);
+
+enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
+       struct __vxge_hw_ring *ring_handle,
+       void **rxdh,
+       u8 *t_code);
+
+enum vxge_hw_status vxge_hw_ring_handle_tcode(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh,
+       u8 t_code);
+
+void vxge_hw_ring_rxd_free(
+       struct __vxge_hw_ring *ring_handle,
+       void *rxdh);
+
+/**
+ * enum enum vxge_hw_frame_proto - Higher-layer ethernet protocols.
+ * @VXGE_HW_FRAME_PROTO_VLAN_TAGGED: VLAN.
+ * @VXGE_HW_FRAME_PROTO_IPV4: IPv4.
+ * @VXGE_HW_FRAME_PROTO_IPV6: IPv6.
+ * @VXGE_HW_FRAME_PROTO_IP_FRAG: IP fragmented.
+ * @VXGE_HW_FRAME_PROTO_TCP: TCP.
+ * @VXGE_HW_FRAME_PROTO_UDP: UDP.
+ * @VXGE_HW_FRAME_PROTO_TCP_OR_UDP: TCP or UDP.
+ *
+ * Higher layer ethernet protocols and options.
+ */
+enum vxge_hw_frame_proto {
+       VXGE_HW_FRAME_PROTO_VLAN_TAGGED = 0x80,
+       VXGE_HW_FRAME_PROTO_IPV4                = 0x10,
+       VXGE_HW_FRAME_PROTO_IPV6                = 0x08,
+       VXGE_HW_FRAME_PROTO_IP_FRAG             = 0x04,
+       VXGE_HW_FRAME_PROTO_TCP                 = 0x02,
+       VXGE_HW_FRAME_PROTO_UDP                 = 0x01,
+       VXGE_HW_FRAME_PROTO_TCP_OR_UDP  = (VXGE_HW_FRAME_PROTO_TCP | \
+                                                  VXGE_HW_FRAME_PROTO_UDP)
+};
+
+/**
+ * enum enum vxge_hw_fifo_gather_code - Gather codes used in fifo TxD
+ * @VXGE_HW_FIFO_GATHER_CODE_FIRST: First TxDL
+ * @VXGE_HW_FIFO_GATHER_CODE_MIDDLE: Middle TxDL
+ * @VXGE_HW_FIFO_GATHER_CODE_LAST: Last TxDL
+ * @VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST: First and Last TxDL.
+ *
+ * These gather codes are used to indicate the position of a TxD in a TxD list
+ */
+enum vxge_hw_fifo_gather_code {
+       VXGE_HW_FIFO_GATHER_CODE_FIRST          = 0x2,
+       VXGE_HW_FIFO_GATHER_CODE_MIDDLE         = 0x0,
+       VXGE_HW_FIFO_GATHER_CODE_LAST           = 0x1,
+       VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST     = 0x3
+};
+
+/**
+ * enum enum vxge_hw_fifo_tcode - tcodes used in fifo
+ * @VXGE_HW_FIFO_T_CODE_OK: Transfer OK
+ * @VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT: PCI read transaction (either TxD or
+ *             frame data) returned with corrupt data.
+ * @VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL:PCI read transaction was returned
+ *             with no data.
+ * @VXGE_HW_FIFO_T_CODE_INVALID_MSS: The host attempted to send either a
+ *             frame or LSO MSS that was too long (>9800B).
+ * @VXGE_HW_FIFO_T_CODE_LSO_ERROR: Error detected during TCP/UDP Large Send
+       *              Offload operation, due to improper header template,
+       *              unsupported protocol, etc.
+ * @VXGE_HW_FIFO_T_CODE_UNUSED: Unused
+ * @VXGE_HW_FIFO_T_CODE_MULTI_ERROR: Set to 1 by the adapter if multiple
+ *             data buffer transfer errors are encountered (see below).
+ *             Otherwise it is set to 0.
+ *
+ * These tcodes are returned in various API for TxD status
+ */
+enum vxge_hw_fifo_tcode {
+       VXGE_HW_FIFO_T_CODE_OK                  = 0x0,
+       VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT    = 0x1,
+       VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL       = 0x2,
+       VXGE_HW_FIFO_T_CODE_INVALID_MSS         = 0x3,
+       VXGE_HW_FIFO_T_CODE_LSO_ERROR           = 0x4,
+       VXGE_HW_FIFO_T_CODE_UNUSED              = 0x7,
+       VXGE_HW_FIFO_T_CODE_MULTI_ERROR         = 0x8
+};
+
+enum vxge_hw_status vxge_hw_fifo_txdl_reserve(
+       struct __vxge_hw_fifo *fifoh,
+       void **txdlh,
+       void **txdl_priv);
+
+void vxge_hw_fifo_txdl_buffer_set(
+                       struct __vxge_hw_fifo *fifo_handle,
+                       void *txdlh,
+                       u32 frag_idx,
+                       dma_addr_t dma_pointer,
+                       u32 size);
+
+void vxge_hw_fifo_txdl_post(
+                       struct __vxge_hw_fifo *fifo_handle,
+                       void *txdlh);
+
+u32 vxge_hw_fifo_free_txdl_count_get(
+                       struct __vxge_hw_fifo *fifo_handle);
+
+enum vxge_hw_status vxge_hw_fifo_txdl_next_completed(
+       struct __vxge_hw_fifo *fifoh,
+       void **txdlh,
+       enum vxge_hw_fifo_tcode *t_code);
+
+enum vxge_hw_status vxge_hw_fifo_handle_tcode(
+       struct __vxge_hw_fifo *fifoh,
+       void *txdlh,
+       enum vxge_hw_fifo_tcode t_code);
+
+void vxge_hw_fifo_txdl_free(
+       struct __vxge_hw_fifo *fifoh,
+       void *txdlh);
+
+/*
+ * Device
+ */
+
+#define VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET (VXGE_HW_BLOCK_SIZE-8)
+#define VXGE_HW_RING_MEMBLOCK_IDX_OFFSET               (VXGE_HW_BLOCK_SIZE-16)
+#define VXGE_HW_RING_MIN_BUFF_ALLOCATION               64
+
+/*
+ * struct __vxge_hw_ring_rxd_priv - Receive descriptor HW-private data.
+ * @dma_addr: DMA (mapped) address of _this_ descriptor.
+ * @dma_handle: DMA handle used to map the descriptor onto device.
+ * @dma_offset: Descriptor's offset in the memory block. HW allocates
+ *              descriptors in memory blocks of %VXGE_HW_BLOCK_SIZE
+ *              bytes. Each memblock is contiguous DMA-able memory. Each
+ *              memblock contains 1 or more 4KB RxD blocks visible to the
+ *              Titan hardware.
+ * @dma_object: DMA address and handle of the memory block that contains
+ *              the descriptor. This member is used only in the "checked"
+ *              version of the HW (to enforce certain assertions);
+ *              otherwise it gets compiled out.
+ * @allocated: True if the descriptor is reserved, 0 otherwise. Internal usage.
+ *
+ * Per-receive decsriptor HW-private data. HW uses the space to keep DMA
+ * information associated with the descriptor. Note that driver can ask HW
+ * to allocate additional per-descriptor space for its own (driver-specific)
+ * purposes.
+ */
+struct __vxge_hw_ring_rxd_priv {
+       dma_addr_t      dma_addr;
+       struct pci_dev *dma_handle;
+       ptrdiff_t       dma_offset;
+#ifdef VXGE_DEBUG_ASSERT
+       struct vxge_hw_mempool_dma      *dma_object;
+#endif
+};
+
+/* ========================= RING PRIVATE API ============================= */
+u64
+__vxge_hw_ring_first_block_address_get(
+       struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status
+__vxge_hw_ring_create(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       struct vxge_hw_ring_attr *attr);
+
+enum vxge_hw_status
+__vxge_hw_ring_abort(
+       struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status
+__vxge_hw_ring_reset(
+       struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status
+__vxge_hw_ring_delete(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+/* ========================= FIFO PRIVATE API ============================= */
+
+struct vxge_hw_fifo_attr;
+
+enum vxge_hw_status
+__vxge_hw_fifo_create(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       struct vxge_hw_fifo_attr *attr);
+
+enum vxge_hw_status
+__vxge_hw_fifo_abort(
+       struct __vxge_hw_fifo *fifoh);
+
+enum vxge_hw_status
+__vxge_hw_fifo_reset(
+       struct __vxge_hw_fifo *ringh);
+
+enum vxge_hw_status
+__vxge_hw_fifo_delete(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+struct vxge_hw_mempool_cbs {
+       void (*item_func_alloc)(
+                       struct vxge_hw_mempool *mempoolh,
+                       u32                     memblock_index,
+                       struct vxge_hw_mempool_dma      *dma_object,
+                       u32                     index,
+                       u32                     is_last);
+};
+
+void
+__vxge_hw_mempool_destroy(
+       struct vxge_hw_mempool *mempool);
+
+#define VXGE_HW_VIRTUAL_PATH_HANDLE(vpath)                             \
+               ((struct __vxge_hw_vpath_handle *)(vpath)->vpath_handles.next)
+
+enum vxge_hw_status
+__vxge_hw_vpath_rts_table_get(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u32                     action,
+       u32                     rts_table,
+       u32                     offset,
+       u64                     *data1,
+       u64                     *data2);
+
+enum vxge_hw_status
+__vxge_hw_vpath_rts_table_set(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u32                     action,
+       u32                     rts_table,
+       u32                     offset,
+       u64                     data1,
+       u64                     data2);
+
+enum vxge_hw_status
+__vxge_hw_vpath_reset(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_sw_reset(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_enable(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+void
+__vxge_hw_vpath_prc_configure(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_kdfc_configure(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_mac_configure(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_tim_configure(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_initialize(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vp_initialize(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id,
+       struct vxge_hw_vp_config        *config);
+
+void
+__vxge_hw_vp_terminate(
+       struct __vxge_hw_device *devh,
+       u32                     vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_alarm_process(
+       struct __vxge_hw_virtualpath    *vpath,
+       u32                     skip_alarms);
+
+void vxge_hw_device_intr_enable(
+       struct __vxge_hw_device *devh);
+
+u32 vxge_hw_device_set_intr_type(struct __vxge_hw_device *devh, u32 intr_mode);
+
+void vxge_hw_device_intr_disable(
+       struct __vxge_hw_device *devh);
+
+void vxge_hw_device_mask_all(
+       struct __vxge_hw_device *devh);
+
+void vxge_hw_device_unmask_all(
+       struct __vxge_hw_device *devh);
+
+enum vxge_hw_status vxge_hw_device_begin_irq(
+       struct __vxge_hw_device *devh,
+       u32 skip_alarms,
+       u64 *reason);
+
+void vxge_hw_device_clear_tx_rx(
+       struct __vxge_hw_device *devh);
+
+/*
+ *  Virtual Paths
+ */
+
+u32 vxge_hw_vpath_id(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_vpath_mac_addr_add_mode {
+       VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE = 0,
+       VXGE_HW_VPATH_MAC_ADDR_DISCARD_DUPLICATE = 1,
+       VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE = 2
+};
+
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_add(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN],
+       enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode);
+
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_get(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN]);
+
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_get_next(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN]);
+
+enum vxge_hw_status
+vxge_hw_vpath_mac_addr_delete(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u8 (macaddr)[ETH_ALEN],
+       u8 (macaddr_mask)[ETH_ALEN]);
+
+enum vxge_hw_status
+vxge_hw_vpath_vid_add(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     vid);
+
+enum vxge_hw_status
+vxge_hw_vpath_vid_get(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     *vid);
+
+enum vxge_hw_status
+vxge_hw_vpath_vid_get_next(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     *vid);
+
+enum vxge_hw_status
+vxge_hw_vpath_vid_delete(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     vid);
+
+enum vxge_hw_status
+vxge_hw_vpath_etype_add(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     etype);
+
+enum vxge_hw_status
+vxge_hw_vpath_etype_get(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     *etype);
+
+enum vxge_hw_status
+vxge_hw_vpath_etype_get_next(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     *etype);
+
+enum vxge_hw_status
+vxge_hw_vpath_etype_delete(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u64                     etype);
+
+enum vxge_hw_status vxge_hw_vpath_promisc_enable(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status vxge_hw_vpath_promisc_disable(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status vxge_hw_vpath_bcast_enable(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status vxge_hw_vpath_mcast_enable(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status vxge_hw_vpath_mcast_disable(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status vxge_hw_vpath_poll_rx(
+       struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status vxge_hw_vpath_poll_tx(
+       struct __vxge_hw_fifo *fifoh,
+       void **skb_ptr);
+
+enum vxge_hw_status vxge_hw_vpath_alarm_process(
+       struct __vxge_hw_vpath_handle *vpath_handle,
+       u32 skip_alarms);
+
+enum vxge_hw_status
+vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vpath_handle,
+                      int *tim_msix_id, int alarm_msix_id);
+
+void
+vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vpath_handle,
+                       int msix_id);
+
+void vxge_hw_device_flush_io(struct __vxge_hw_device *devh);
+
+void
+vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vpath_handle,
+                        int msix_id);
+
+void
+vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vpath_handle,
+                         int msix_id);
+
+void
+vxge_hw_vpath_msix_mask_all(struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status vxge_hw_vpath_intr_enable(
+                               struct __vxge_hw_vpath_handle *vpath_handle);
+
+enum vxge_hw_status vxge_hw_vpath_intr_disable(
+                               struct __vxge_hw_vpath_handle *vpath_handle);
+
+void vxge_hw_vpath_inta_mask_tx_rx(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+void vxge_hw_vpath_inta_unmask_tx_rx(
+       struct __vxge_hw_vpath_handle *vpath_handle);
+
+void
+vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channelh, int msix_id);
+
+void
+vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channelh, int msix_id);
+
+enum vxge_hw_status
+vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh);
+
+void
+vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh);
+
+void
+vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel,
+                                void **dtrh);
+
+void
+vxge_hw_channel_dtr_complete(struct __vxge_hw_channel *channel);
+
+void
+vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh);
+
+int
+vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel);
+
+/* ========================== PRIVATE API ================================= */
+
+enum vxge_hw_status
+__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_device_handle_error(
+               struct __vxge_hw_device *hldev,
+               u32 vp_id,
+               enum vxge_hw_event type);
+
+#endif
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
new file mode 100644 (file)
index 0000000..7da02c5
--- /dev/null
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ *
+ * vxge-version.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                 Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#ifndef VXGE_VERSION_H
+
+#define VXGE_VERSION_H
+
+#define VXGE_VERSION_MAJOR     "2"
+#define VXGE_VERSION_MINOR     "0"
+#define VXGE_VERSION_FIX       "1"
+#define VXGE_VERSION_BUILD     "17129"
+#define VXGE_VERSION_FOR       "k"
+#endif
index 00945f7c1e9b07f7c3c0db54bf0d6db698825ece..25c9ef6a18155383bad5538f4912d7e660bb187a 100644 (file)
@@ -69,7 +69,7 @@ MODULE_LICENSE("GPL");
 #endif
 
 /*
- * Modules parameters and associated varaibles
+ * Modules parameters and associated variables
  */
 static int fst_txq_low = FST_LOW_WATER_MARK;
 static int fst_txq_high = FST_HIGH_WATER_MARK;
index 7e80aba8a148dbb821e6096181378f3768f4455a..f21a6171c691940b8f9d7788da1153766ba3ec74 100644 (file)
@@ -2752,7 +2752,6 @@ static const struct net_device_ops airo_netdev_ops = {
        .ndo_set_mac_address    = airo_set_mac_address,
        .ndo_do_ioctl           = airo_ioctl,
        .ndo_change_mtu         = airo_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 };
 
@@ -2765,7 +2764,6 @@ static const struct net_device_ops mpi_netdev_ops = {
        .ndo_set_mac_address    = airo_set_mac_address,
        .ndo_do_ioctl           = airo_ioctl,
        .ndo_change_mtu         = airo_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 };
 
@@ -4494,7 +4492,6 @@ static int setup_proc_entry( struct net_device *dev,
                goto fail;
        apriv->proc_entry->uid = proc_uid;
        apriv->proc_entry->gid = proc_gid;
-       apriv->proc_entry->owner = THIS_MODULE;
 
        /* Setup the StatsDelta */
        entry = proc_create_data("StatsDelta",
index 115b704875027fc794079b1a3ac856b8c4641ecb..f4e963ba768bd49537186d0c3b2112e0b9213ff3 100644 (file)
@@ -2362,7 +2362,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
                       i * sizeof(struct ipw2100_status));
 
 #ifdef IPW2100_DEBUG_C3
-       /* Halt the fimrware so we can get a good image */
+       /* Halt the firmware so we can get a good image */
        write_register(priv->net_dev, IPW_REG_RESET_REG,
                       IPW_AUX_HOST_RESET_REG_STOP_MASTER);
        j = 5;
index b3449948a25a92ca8ac3afe17d099530249f0601..e17a4593e1f5f1d3c82fa5830b51d7c9bf78628a 100644 (file)
@@ -8844,7 +8844,7 @@ static int ipw_wx_set_mode(struct net_device *dev,
 #endif                         /* CONFIG_IPW2200_MONITOR */
 
        /* Free the existing firmware and reset the fw_loaded
-        * flag so ipw_load() will bring in the new firmawre */
+        * flag so ipw_load() will bring in the new firmware */
        free_firmware();
 
        priv->ieee->iw_mode = wrqu->mode;
@@ -11593,7 +11593,6 @@ static const struct net_device_ops ipw_netdev_ops = {
        .ndo_set_mac_address    = ipw_net_set_mac_address,
        .ndo_start_xmit         = ieee80211_xmit,
        .ndo_change_mtu         = ieee80211_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 };
 
index 663dc83be501d22c742759feadbf3d9ce8570a79..3889158b359c964d5cdda212bdf0f35ca16af3f2 100644 (file)
@@ -1337,7 +1337,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 
        /* api_ver should match the api version forming part of the
         * firmware filename ... but we don't check for that and only rely
-        * on the API version read from firware header from here on forward */
+        * on the API version read from firmware header from here on forward */
 
        if (api_ver < api_min || api_ver > api_max) {
                IWL_ERR(priv, "Driver unable to support your firmware API. "
index a71b08ca7c7116f096bf9e097048058055f454c3..9d5f97dd7c738508afb731ac1b6ac0fe7fbbe928 100644 (file)
@@ -2562,7 +2562,7 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
 
        /* api_ver should match the api version forming part of the
         * firmware filename ... but we don't check for that and only rely
-        * on the API version read from firware header from here on forward */
+        * on the API version read from firmware header from here on forward */
 
        if (api_ver < api_min || api_ver > api_max) {
                IWL_ERR(priv, "Driver unable to support your firmware API. "
index 639dd02d3d31d72e74ca916a772aa7406875612b..8c3605cdc64c090de61dd4fdd98e3cb23b9c4d6a 100644 (file)
@@ -1649,7 +1649,7 @@ static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
 
 /**
  *  @brief This function executes next command in command
- *  pending queue. It will put fimware back to PS mode
+ *  pending queue. It will put firmware back to PS mode
  *  if applicable.
  *
  *  @param priv     A pointer to struct lbs_private structure
index 166ed95846017c0463f5ab65a78acc8e5048aa49..e26d7b3ceab51cee23198ab5fc5c7fa60406ed59 100644 (file)
@@ -803,7 +803,6 @@ static const struct net_device_ops islpci_netdev_ops = {
        .ndo_tx_timeout         = islpci_eth_tx_timeout,
        .ndo_set_mac_address    = prism54_set_mac_address,
        .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 };
 
index 9b244c96b221bbc3c96006112681d1157e4d42d6..5fabd9c0f07a791483b01728e599b14a4a38ad3b 100644 (file)
@@ -1725,7 +1725,6 @@ static const struct net_device_ops zd1201_netdev_ops = {
        .ndo_set_multicast_list = zd1201_set_multicast,
        .ndo_set_mac_address    = zd1201_set_mac_address,
        .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 };
 
index cd17092b82bd4bbfa93e760e994046861d8f9902..41c5dfd853586704d0ac75fee8b23068466fa9d8 100644 (file)
@@ -446,6 +446,7 @@ struct of_modalias_table {
 };
 static struct of_modalias_table of_modalias_table[] = {
        { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" },
+       { "mmc-spi-slot", "mmc_spi" },
 };
 
 /**
index c3ea5fa7d05a6db4079bebb99ecc865b89eefca5..2c9aa49e43cdf1a879214ac281bf705b84015f25 100644 (file)
@@ -574,7 +574,7 @@ int __init buffer_sync_init(void)
                return 0;
 }
 
-void __exit buffer_sync_cleanup(void)
+void buffer_sync_cleanup(void)
 {
        free_cpumask_var(marked_cpus);
 }
index 7931133526c48dd57438e9bfb2cda2ef6e784824..9ca21098b146c73e54e0facbf101e657e21ddaa0 100644 (file)
@@ -81,7 +81,7 @@ static int __init asp_init_chip(struct parisc_device *dev)
        asp.hpa = ASP_INTERRUPT_ADDR;
 
        printk(KERN_INFO "%s version %d at 0x%lx found.\n", 
-               asp.name, asp.version, dev->hpa.start);
+               asp.name, asp.version, (unsigned long)dev->hpa.start);
 
        /* the IRQ ASP should use */
        ret = -EBUSY;
index cd4dd7ed2c06b60fd471319fc6ef78fca8a91184..5d610cbcfe80cf294a676c38a18bce5dbdd9af4b 100644 (file)
@@ -406,8 +406,6 @@ resource_found:
        }
        ioc->avg_search[ioc->avg_idx++] = cr_start;
        ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1;
-#endif
-#ifdef CCIO_COLLECT_STATS
        ioc->used_pages += pages_needed;
 #endif
        /* 
@@ -453,10 +451,10 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
                unsigned long mask = ~(~0UL >> pages_mapped);
                CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8);
 #else
-               CCIO_FREE_MAPPINGS(ioc, res_idx, 0xff, 8);
+               CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffUL, 8);
 #endif
        } else if(pages_mapped <= 16) {
-               CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffff, 16);
+               CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffffUL, 16);
        } else if(pages_mapped <= 32) {
                CCIO_FREE_MAPPINGS(ioc, res_idx, ~(unsigned int)0, 32);
 #ifdef __LP64__
@@ -1028,8 +1026,10 @@ static int ccio_proc_info(struct seq_file *m, void *p)
 
        while (ioc != NULL) {
                unsigned int total_pages = ioc->res_size << 3;
+#ifdef CCIO_COLLECT_STATS
                unsigned long avg = 0, min, max;
                int j;
+#endif
 
                len += seq_printf(m, "%s\n", ioc->name);
                
@@ -1060,8 +1060,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
                avg /= CCIO_SEARCH_SAMPLE;
                len += seq_printf(m, "  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
                                  min, avg, max);
-#endif
-#ifdef CCIO_COLLECT_STATS
+
                len += seq_printf(m, "pci_map_single(): %8ld calls  %8ld pages (avg %d/1000)\n",
                                  ioc->msingle_calls, ioc->msingle_pages,
                                  (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
@@ -1400,7 +1399,7 @@ ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr)
        result = insert_resource(&iomem_resource, res);
        if (result < 0) {
                printk(KERN_ERR "%s() failed to claim CCIO bus address space (%08lx,%08lx)\n", 
-                       __func__, res->start, res->end);
+                       __func__, (unsigned long)res->start, (unsigned long)res->end);
        }
 }
 
@@ -1551,7 +1550,8 @@ static int __init ccio_probe(struct parisc_device *dev)
 
        ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn";
 
-       printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa.start);
+       printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name,
+               (unsigned long)dev->hpa.start);
 
        for (i = 0; i < ioc_count; i++) {
                ioc_p = &(*ioc_p)->next;
index bb5a1c9597cb50d814c927ed2a1447ac03495f49..52ae0b1d470ccd24ee39a32fd04d29ac86722d44 100644 (file)
@@ -819,7 +819,9 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name)
 
                result = ccio_request_resource(dino_dev->hba.dev, &res[i]);
                if (result < 0) {
-                       printk(KERN_ERR "%s: failed to claim PCI Bus address space %d (0x%lx-0x%lx)!\n", name, i, res[i].start, res[i].end);
+                       printk(KERN_ERR "%s: failed to claim PCI Bus address "
+                              "space %d (0x%lx-0x%lx)!\n", name, i,
+                              (unsigned long)res[i].start, (unsigned long)res[i].end);
                        return result;
                }
        }
@@ -899,7 +901,8 @@ static int __init dino_common_init(struct parisc_device *dev,
        if (request_resource(&ioport_resource, res) < 0) {
                printk(KERN_ERR "%s: request I/O Port region failed "
                       "0x%lx/%lx (hpa 0x%p)\n",
-                      name, res->start, res->end, dino_dev->hba.base_addr);
+                      name, (unsigned long)res->start, (unsigned long)res->end,
+                      dino_dev->hba.base_addr);
                return 1;
        }
 
index 7891db50c483bc6e6def22133ae78e17cc97da50..f415fdd9a88599296a9c5195854c25192b8fbc0b 100644 (file)
@@ -314,7 +314,7 @@ static int __init eisa_probe(struct parisc_device *dev)
        char *name = is_mongoose(dev) ? "Mongoose" : "Wax";
 
        printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n", 
-               name, dev->hpa.start);
+               name, (unsigned long)dev->hpa.start);
 
        eisa_dev.hba.dev = dev;
        eisa_dev.hba.iommu = ccio_get_iommu(dev);
index 6d8aae003f6c19c9fd733766b897d082ccb7a657..c709ecc2b7f71626622f9c6f834b4c2160e374b0 100644 (file)
@@ -98,7 +98,7 @@ static int configure_memory(const unsigned char *buf,
                        res->start = mem_parent->start + get_24(buf+len+2);
                        res->end = res->start + get_16(buf+len+5)*1024;
                        res->flags = IORESOURCE_MEM;
-                       printk("memory %lx-%lx ", res->start, res->end);
+                       printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
                        result = request_resource(mem_parent, res);
                        if (result < 0) {
                                printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
@@ -188,7 +188,7 @@ static int configure_port(const unsigned char *buf, struct resource *io_parent,
                        res->start = get_16(buf+len+1);
                        res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
                        res->flags = IORESOURCE_IO;
-                       printk("ioports %lx-%lx ", res->start, res->end);
+                       printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
                        result = request_resource(io_parent, res);
                        if (result < 0) {
                                printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
index 501aaf1f253f28c4af811d747d1d0461f790133d..73348c4047e98d249a9a576b87f2e8d44edaf623 100644 (file)
@@ -714,7 +714,7 @@ static void iosapic_set_affinity_irq(unsigned int irq,
        if (dest_cpu < 0)
                return;
 
-       irq_desc[irq].affinity = cpumask_of_cpu(dest_cpu);
+       cpumask_copy(irq_desc[irq].affinity, cpumask_of(dest_cpu));
        vi->txn_addr = txn_affinity_addr(irq, dest_cpu);
 
        spin_lock_irqsave(&iosapic_lock, flags);
index 454b6532e40998cce76aa3eeb7ed8fdaa901748a..9581d3619450d609ca69e305d4fcad7148f9ab93 100644 (file)
@@ -3,7 +3,7 @@
  *
  *      (c) Copyright 2000 Red Hat Software
  *      (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
- *      (c) Copyright 2001-2005 Helge Deller <deller@gmx.de>
+ *      (c) Copyright 2001-2009 Helge Deller <deller@gmx.de>
  *      (c) Copyright 2001 Randolph Chung <tausq@debian.org>
  *
  *      This program is free software; you can redistribute it and/or modify
@@ -243,13 +243,11 @@ static int __init led_create_procfs(void)
 
        proc_pdc_root = proc_mkdir("pdc", 0);
        if (!proc_pdc_root) return -1;
-       proc_pdc_root->owner = THIS_MODULE;
        ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
        if (!ent) return -1;
        ent->data = (void *)LED_NOLCD; /* LED */
        ent->read_proc = led_proc_read;
        ent->write_proc = led_proc_write;
-       ent->owner = THIS_MODULE;
 
        if (led_type == LED_HASLCD)
        {
@@ -258,7 +256,6 @@ static int __init led_create_procfs(void)
                ent->data = (void *)LED_HASLCD; /* LCD */
                ent->read_proc = led_proc_read;
                ent->write_proc = led_proc_write;
-               ent->owner = THIS_MODULE;
        }
 
        return 0;
@@ -463,9 +460,20 @@ static void led_work_func (struct work_struct *unused)
        if (likely(led_lanrxtx))  currentleds |= led_get_net_activity();
        if (likely(led_diskio))   currentleds |= led_get_diskio_activity();
 
-       /* blink all LEDs twice a second if we got an Oops (HPMC) */
-       if (unlikely(oops_in_progress)) 
-               currentleds = (count_HZ<=(HZ/2)) ? 0 : 0xff;
+       /* blink LEDs if we got an Oops (HPMC) */
+       if (unlikely(oops_in_progress)) {
+               if (boot_cpu_data.cpu_type >= pcxl2) {
+                       /* newer machines don't have loadavg. LEDs, so we
+                        * let all LEDs blink twice per second instead */
+                       currentleds = (count_HZ <= (HZ/2)) ? 0 : 0xff;
+               } else {
+                       /* old machines: blink loadavg. LEDs twice per second */
+                       if (count_HZ <= (HZ/2))
+                               currentleds &= ~(LED4|LED5|LED6|LED7);
+                       else
+                               currentleds |= (LED4|LED5|LED6|LED7);
+               }
+       }
 
        if (currentleds != lastleds)
        {
@@ -511,7 +519,7 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf)
        
        /* Cancel the work item and delete the queue */
        if (led_wq) {
-               cancel_rearming_delayed_workqueue(led_wq, &led_task);
+               cancel_delayed_work_sync(&led_task);
                destroy_workqueue(led_wq);
                led_wq = NULL;
        }
@@ -630,7 +638,7 @@ int lcd_print( const char *str )
        
        /* temporarily disable the led work task */
        if (led_wq)
-               cancel_rearming_delayed_workqueue(led_wq, &led_task);
+               cancel_delayed_work_sync(&led_task);
 
        /* copy display string to buffer for procfs */
        strlcpy(lcd_text, str, sizeof(lcd_text));
index 032db815b0f9784f6835548d68333edc4c376022..f3492110b1ad31bb8f895f2c2e6bde361221148c 100644 (file)
@@ -30,6 +30,7 @@ enum parport_pc_pci_cards {
        titan_210l,
        netmos_9xx5_combo,
        netmos_9855,
+       netmos_9855_2p,
        avlab_1s1p,
        avlab_1s2p,
        avlab_2s1p,
@@ -62,7 +63,7 @@ struct parport_pc_pci {
                                struct parport_pc_pci *card, int failed);
 };
 
-static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma)
+static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par, int autoirq, int autodma)
 {
        /* the rule described below doesn't hold for this device */
        if (dev->device == PCI_DEVICE_ID_NETMOS_9835 &&
@@ -74,9 +75,17 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc
         * and serial ports.  The form is 0x00PS, where <P> is the number of
         * parallel ports and <S> is the number of serial ports.
         */
-       card->numports = (dev->subsystem_device & 0xf0) >> 4;
-       if (card->numports > ARRAY_SIZE(card->addr))
-               card->numports = ARRAY_SIZE(card->addr);
+       par->numports = (dev->subsystem_device & 0xf0) >> 4;
+       if (par->numports > ARRAY_SIZE(par->addr))
+               par->numports = ARRAY_SIZE(par->addr);
+       /*
+        * This function is currently only called for cards with up to
+        * one parallel port.
+        * Parallel port BAR is either before or after serial ports BARS;
+        * hence, lo should be either 0 or equal to the number of serial ports.
+        */
+       if (par->addr[0].lo != 0)
+               par->addr[0].lo = dev->subsystem_device & 0xf;
        return 0;
 }
 
@@ -84,7 +93,8 @@ static struct parport_pc_pci cards[] __devinitdata = {
        /* titan_110l */                { 1, { { 3, -1 }, } },
        /* titan_210l */                { 1, { { 3, -1 }, } },
        /* netmos_9xx5_combo */         { 1, { { 2, -1 }, }, netmos_parallel_init },
-       /* netmos_9855 */               { 1, { { 2, -1 }, }, netmos_parallel_init },
+       /* netmos_9855 */               { 1, { { 0, -1 }, }, netmos_parallel_init },
+       /* netmos_9855_2p */            { 2, { { 0, -1 }, { 2, -1 }, } },
        /* avlab_1s1p     */            { 1, { { 1, 2}, } },
        /* avlab_1s2p     */            { 2, { { 1, 2}, { 3, 4 },} },
        /* avlab_2s1p     */            { 1, { { 2, 3}, } },
@@ -109,6 +119,10 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
+         0x1000, 0x0020, 0, 0, netmos_9855_2p },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
+         0x1000, 0x0022, 0, 0, netmos_9855_2p },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
        /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
@@ -192,6 +206,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
                .uart_offset    = 8,
        },
        [netmos_9855] = {
+               .flags          = FL_BASE2 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [netmos_9855_2p] = {
                .flags          = FL_BASE4 | FL_BASE_BARS,
                .num_ports      = 1,
                .base_baud      = 115200,
index 2a4501dd251503ddb6d5fefd78737b4c97425452..fdc864f9cf233d5134803593640f49c3ed0b1ccf 100644 (file)
@@ -59,3 +59,13 @@ config HT_IRQ
           This allows native hypertransport devices to use interrupts.
 
           If unsure say Y.
+
+config PCI_IOV
+       bool "PCI IOV support"
+       depends on PCI
+       help
+         I/O Virtualization is a PCI feature supported by some devices
+         which allows them to create virtual devices which share their
+         physical resources.
+
+         If unsure, say N.
index 3d07ce24f6a8a2eae8b44bdbaf11dcaf536a2fed..ba6af162fd39a259663c53c0269cf98f380499cc 100644 (file)
@@ -29,6 +29,8 @@ obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
 
 obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
 
+obj-$(CONFIG_PCI_IOV) += iov.o
+
 #
 # Some architectures use the generic PCI setup functions
 #
index 52b54f053be092e4c589b03d1dd03c6be9deacb6..68f91a25259563c6bb7250d8ea3acfd636ad0b29 100644 (file)
@@ -133,7 +133,7 @@ int pci_bus_add_child(struct pci_bus *bus)
  *
  * Call hotplug for each new devices.
  */
-void pci_bus_add_devices(struct pci_bus *bus)
+void pci_bus_add_devices(const struct pci_bus *bus)
 {
        struct pci_dev *dev;
        struct pci_bus *child;
@@ -184,8 +184,10 @@ void pci_enable_bridges(struct pci_bus *bus)
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                if (dev->subordinate) {
-                       retval = pci_enable_device(dev);
-                       pci_set_master(dev);
+                       if (atomic_read(&dev->enable_cnt) == 0) {
+                               retval = pci_enable_device(dev);
+                               pci_set_master(dev);
+                       }
                        pci_enable_bridges(dev->subordinate);
                }
        }
index 1c1141801060ea1c791e6c788a225e29921c752d..fbc63d5e459fd4182f35f5beffc9bee1a875c8d8 100644 (file)
@@ -30,9 +30,8 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
+#include <linux/acpi.h>
 #include <linux/pci-acpi.h>
-#include <acpi/acpi.h>
-#include <acpi/acpi_bus.h>
 
 #define MY_NAME        "acpi_pcihp"
 
@@ -333,19 +332,14 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
 {
        acpi_status status = AE_NOT_FOUND;
        acpi_handle handle, phandle;
-       struct pci_bus *pbus = bus;
-       struct pci_dev *pdev;
-
-       do {
-               pdev = pbus->self;
-               if (!pdev) {
-                       handle = acpi_get_pci_rootbridge_handle(
-                               pci_domain_nr(pbus), pbus->number);
+       struct pci_bus *pbus;
+
+       handle = NULL;
+       for (pbus = bus; pbus; pbus = pbus->parent) {
+               handle = acpi_pci_get_bridge_handle(pbus);
+               if (handle)
                        break;
-               }
-               handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
-               pbus = pbus->parent;
-       } while (!handle);
+       }
 
        /*
         * _HPP settings apply to all child buses, until another _HPP is
@@ -378,12 +372,10 @@ EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware);
  *
  * Attempt to take hotplug control from firmware.
  */
-int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
+int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
 {
        acpi_status status;
        acpi_handle chandle, handle;
-       struct pci_dev *pdev = dev;
-       struct pci_bus *parent;
        struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
        flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
@@ -408,33 +400,25 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
                acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
                dbg("Trying to get hotplug control for %s\n",
                                (char *)string.pointer);
-               status = pci_osc_control_set(handle, flags);
+               status = acpi_pci_osc_control_set(handle, flags);
                if (ACPI_SUCCESS(status))
                        goto got_one;
                kfree(string.pointer);
                string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL };
        }
 
-       pdev = dev;
-       handle = DEVICE_ACPI_HANDLE(&dev->dev);
-       while (!handle) {
+       handle = DEVICE_ACPI_HANDLE(&pdev->dev);
+       if (!handle) {
                /*
                 * This hotplug controller was not listed in the ACPI name
                 * space at all. Try to get acpi handle of parent pci bus.
                 */
-               if (!pdev || !pdev->bus->parent)
-                       break;
-               parent = pdev->bus->parent;
-               dbg("Could not find %s in acpi namespace, trying parent\n",
-                   pci_name(pdev));
-               if (!parent->self)
-                       /* Parent must be a host bridge */
-                       handle = acpi_get_pci_rootbridge_handle(
-                                       pci_domain_nr(parent),
-                                       parent->number);
-               else
-                       handle = DEVICE_ACPI_HANDLE(&(parent->self->dev));
-               pdev = parent->self;
+               struct pci_bus *pbus;
+               for (pbus = pdev->bus; pbus; pbus = pbus->parent) {
+                       handle = acpi_pci_get_bridge_handle(pbus);
+                       if (handle)
+                               break;
+               }
        }
 
        while (handle) {
@@ -453,13 +437,13 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
        }
 
        dbg("Cannot get control of hotplug hardware for pci %s\n",
-           pci_name(dev));
+           pci_name(pdev));
 
        kfree(string.pointer);
        return -ENODEV;
 got_one:
-       dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev),
-                       (char *)string.pointer);
+       dbg("Gained control for hotplug HW for pci %s (%s)\n",
+           pci_name(pdev), (char *)string.pointer);
        kfree(string.pointer);
        return 0;
 }
index d8649e12729863f67f406b86af873b89bc58062f..6151389fd90304d1b02b364150432d8d3e17bb34 100644 (file)
-/*
- * Fake PCI Hot Plug Controller Driver
+/* Works like the fakephp driver used to, except a little better.
  *
- * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2003 IBM Corp.
- * Copyright (C) 2003 Rolf Eike Beer <eike-kernel@sf-tec.de>
+ * - It's possible to remove devices with subordinate busses.
+ * - New PCI devices that appear via any method, not just a fakephp triggered
+ *   rescan, will be noticed.
+ * - Devices that are removed via any method, not just a fakephp triggered
+ *   removal, will also be noticed.
  *
- * Based on ideas and code from:
- *     Vladimir Kondratiev <vladimir.kondratiev@intel.com>
- *     Rolf Eike Beer <eike-kernel@sf-tec.de>
+ * Uses nothing from the pci-hotplug subsystem.
  *
- * 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, version 2 of the License.
- *
- * Send feedback to <greg@kroah.com>
  */
 
-/*
- *
- * This driver will "emulate" removing PCI devices from the system.  If
- * the "power" file is written to with "0" then the specified PCI device
- * will be completely removed from the kernel.
- *
- * WARNING, this does NOT turn off the power to the PCI device.  This is
- * a "logical" removal, not a physical or electrical removal.
- *
- * Use this module at your own risk, you have been warned!
- *
- * Enabling PCI devices is left as an exercise for the reader...
- *
- */
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci_hotplug.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
 #include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/device.h>
 #include "../pci.h"
 
-#if !defined(MODULE)
-       #define MY_NAME "fakephp"
-#else
-       #define MY_NAME THIS_MODULE->name
-#endif
-
-#define dbg(format, arg...)                                    \
-       do {                                                    \
-               if (debug)                                      \
-                       printk(KERN_DEBUG "%s: " format,        \
-                               MY_NAME , ## arg);              \
-       } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-
-#define DRIVER_AUTHOR  "Greg Kroah-Hartman <greg@kroah.com>"
-#define DRIVER_DESC    "Fake PCI Hot Plug Controller Driver"
-
-struct dummy_slot {
-       struct list_head node;
-       struct hotplug_slot *slot;
-       struct pci_dev *dev;
-       struct work_struct remove_work;
-       unsigned long removed;
+struct legacy_slot {
+       struct kobject          kobj;
+       struct pci_dev          *dev;
+       struct list_head        list;
 };
 
-static int debug;
-static int dup_slots;
-static LIST_HEAD(slot_list);
-static struct workqueue_struct *dummyphp_wq;
-
-static void pci_rescan_worker(struct work_struct *work);
-static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
-
-static int enable_slot (struct hotplug_slot *slot);
-static int disable_slot (struct hotplug_slot *slot);
+static LIST_HEAD(legacy_list);
 
-static struct hotplug_slot_ops dummy_hotplug_slot_ops = {
-       .owner                  = THIS_MODULE,
-       .enable_slot            = enable_slot,
-       .disable_slot           = disable_slot,
-};
-
-static void dummy_release(struct hotplug_slot *slot)
+static ssize_t legacy_show(struct kobject *kobj, struct attribute *attr,
+                          char *buf)
 {
-       struct dummy_slot *dslot = slot->private;
-
-       list_del(&dslot->node);
-       kfree(dslot->slot->info);
-       kfree(dslot->slot);
-       pci_dev_put(dslot->dev);
-       kfree(dslot);
+       struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
+       strcpy(buf, "1\n");
+       return 2;
 }
 
-#define SLOT_NAME_SIZE 8
-
-static int add_slot(struct pci_dev *dev)
+static void remove_callback(void *data)
 {
-       struct dummy_slot *dslot;
-       struct hotplug_slot *slot;
-       char name[SLOT_NAME_SIZE];
-       int retval = -ENOMEM;
-       static int count = 1;
-
-       slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
-       if (!slot)
-               goto error;
-
-       slot->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
-       if (!slot->info)
-               goto error_slot;
-
-       slot->info->power_status = 1;
-       slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
-       slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
-
-       dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
-       if (!dslot)
-               goto error_info;
-
-       if (dup_slots)
-               snprintf(name, SLOT_NAME_SIZE, "fake");
-       else
-               snprintf(name, SLOT_NAME_SIZE, "fake%d", count++);
-       dbg("slot->name = %s\n", name);
-       slot->ops = &dummy_hotplug_slot_ops;
-       slot->release = &dummy_release;
-       slot->private = dslot;
-
-       retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn), name);
-       if (retval) {
-               err("pci_hp_register failed with error %d\n", retval);
-               goto error_dslot;
-       }
-
-       dbg("slot->name = %s\n", hotplug_slot_name(slot));
-       dslot->slot = slot;
-       dslot->dev = pci_dev_get(dev);
-       list_add (&dslot->node, &slot_list);
-       return retval;
-
-error_dslot:
-       kfree(dslot);
-error_info:
-       kfree(slot->info);
-error_slot:
-       kfree(slot);
-error:
-       return retval;
+       pci_remove_bus_device((struct pci_dev *)data);
 }
 
-static int __init pci_scan_buses(void)
+static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr,
+                           const char *buf, size_t len)
 {
-       struct pci_dev *dev = NULL;
-       int lastslot = 0;
+       struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
+       unsigned long val;
 
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               if (PCI_FUNC(dev->devfn) > 0 &&
-                               lastslot == PCI_SLOT(dev->devfn))
-                       continue;
-               lastslot = PCI_SLOT(dev->devfn);
-               add_slot(dev);
-       }
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
 
-       return 0;
+       if (val)
+               pci_rescan_bus(slot->dev->bus);
+       else
+               sysfs_schedule_callback(&slot->dev->dev.kobj, remove_callback,
+                                       slot->dev, THIS_MODULE);
+       return len;
 }
 
-static void remove_slot(struct dummy_slot *dslot)
-{
-       int retval;
-
-       dbg("removing slot %s\n", hotplug_slot_name(dslot->slot));
-       retval = pci_hp_deregister(dslot->slot);
-       if (retval)
-               err("Problem unregistering a slot %s\n",
-                       hotplug_slot_name(dslot->slot));
-}
+static struct attribute *legacy_attrs[] = {
+       &(struct attribute){ .name = "power", .mode = 0644 },
+       NULL,
+};
 
-/* called from the single-threaded workqueue handler to remove a slot */
-static void remove_slot_worker(struct work_struct *work)
+static void legacy_release(struct kobject *kobj)
 {
-       struct dummy_slot *dslot =
-               container_of(work, struct dummy_slot, remove_work);
-       remove_slot(dslot);
-}
+       struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj);
 
-/**
- * pci_rescan_slot - Rescan slot
- * @temp: Device template. Should be set: bus and devfn.
- *
- * Tries hard not to re-enable already existing devices;
- * also handles scanning of subfunctions.
- */
-static int pci_rescan_slot(struct pci_dev *temp)
-{
-       struct pci_bus *bus = temp->bus;
-       struct pci_dev *dev;
-       int func;
-       u8 hdr_type;
-       int count = 0;
-
-       if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
-               temp->hdr_type = hdr_type & 0x7f;
-               if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
-                       pci_dev_put(dev);
-               else {
-                       dev = pci_scan_single_device(bus, temp->devfn);
-                       if (dev) {
-                               dbg("New device on %s function %x:%x\n",
-                                       bus->name, temp->devfn >> 3,
-                                       temp->devfn & 7);
-                               count++;
-                       }
-               }
-               /* multifunction device? */
-               if (!(hdr_type & 0x80))
-                       return count;
-
-               /* continue scanning for other functions */
-               for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) {
-                       if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
-                               continue;
-                       temp->hdr_type = hdr_type & 0x7f;
-
-                       if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
-                               pci_dev_put(dev);
-                       else {
-                               dev = pci_scan_single_device(bus, temp->devfn);
-                               if (dev) {
-                                       dbg("New device on %s function %x:%x\n",
-                                               bus->name, temp->devfn >> 3,
-                                               temp->devfn & 7);
-                                       count++;
-                               }
-                       }
-               }
-       }
-
-       return count;
+       pci_dev_put(slot->dev);
+       kfree(slot);
 }
 
+static struct kobj_type legacy_ktype = {
+       .sysfs_ops = &(struct sysfs_ops){
+               .store = legacy_store, .show = legacy_show
+       },
+       .release = &legacy_release,
+       .default_attrs = legacy_attrs,
+};
 
-/**
- * pci_rescan_bus - Rescan PCI bus
- * @bus: the PCI bus to rescan
- *
- * Call pci_rescan_slot for each possible function of the bus.
- */
-static void pci_rescan_bus(const struct pci_bus *bus)
+static int legacy_add_slot(struct pci_dev *pdev)
 {
-       unsigned int devfn;
-       struct pci_dev *dev;
-       int retval;
-       int found = 0;
-       dev = alloc_pci_dev();
-       if (!dev)
-               return;
+       struct legacy_slot *slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 
-       dev->bus = (struct pci_bus*)bus;
-       dev->sysdata = bus->sysdata;
-       for (devfn = 0; devfn < 0x100; devfn += 8) {
-               dev->devfn = devfn;
-               found += pci_rescan_slot(dev);
-       }
-
-       if (found) {
-               pci_bus_assign_resources(bus);
-               list_for_each_entry(dev, &bus->devices, bus_list) {
-                       /* Skip already-added devices */
-                       if (dev->is_added)
-                                       continue;
-                       retval = pci_bus_add_device(dev);
-                       if (retval)
-                               dev_err(&dev->dev,
-                                       "Error adding device, continuing\n");
-                       else
-                               add_slot(dev);
-               }
-               pci_bus_add_devices(bus);
-       }
-       kfree(dev);
-}
+       if (!slot)
+               return -ENOMEM;
 
-/* recursively scan all buses */
-static void pci_rescan_buses(const struct list_head *list)
-{
-       const struct list_head *l;
-       list_for_each(l,list) {
-               const struct pci_bus *b = pci_bus_b(l);
-               pci_rescan_bus(b);
-               pci_rescan_buses(&b->children);
+       if (kobject_init_and_add(&slot->kobj, &legacy_ktype,
+                                &pci_slots_kset->kobj, "%s",
+                                dev_name(&pdev->dev))) {
+               dev_warn(&pdev->dev, "Failed to created legacy fake slot\n");
+               return -EINVAL;
        }
-}
+       slot->dev = pci_dev_get(pdev);
 
-/* initiate rescan of all pci buses */
-static inline void pci_rescan(void) {
-       pci_rescan_buses(&pci_root_buses);
-}
-
-/* called from the single-threaded workqueue handler to rescan all pci buses */
-static void pci_rescan_worker(struct work_struct *work)
-{
-       pci_rescan();
-}
+       list_add(&slot->list, &legacy_list);
 
-static int enable_slot(struct hotplug_slot *hotplug_slot)
-{
-       /* mis-use enable_slot for rescanning of the pci bus */
-       cancel_work_sync(&pci_rescan_work);
-       queue_work(dummyphp_wq, &pci_rescan_work);
        return 0;
 }
 
-static int disable_slot(struct hotplug_slot *slot)
+static int legacy_notify(struct notifier_block *nb,
+                        unsigned long action, void *data)
 {
-       struct dummy_slot *dslot;
-       struct pci_dev *dev;
-       int func;
-
-       if (!slot)
-               return -ENODEV;
-       dslot = slot->private;
-
-       dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(slot));
+       struct pci_dev *pdev = to_pci_dev(data);
 
-       for (func = 7; func >= 0; func--) {
-               dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func);
-               if (!dev)
-                       continue;
+       if (action == BUS_NOTIFY_ADD_DEVICE) {
+               legacy_add_slot(pdev);
+       } else if (action == BUS_NOTIFY_DEL_DEVICE) {
+               struct legacy_slot *slot;
 
-               if (test_and_set_bit(0, &dslot->removed)) {
-                       dbg("Slot already scheduled for removal\n");
-                       pci_dev_put(dev);
-                       return -ENODEV;
-               }
+               list_for_each_entry(slot, &legacy_list, list)
+                       if (slot->dev == pdev)
+                               goto found;
 
-               /* remove the device from the pci core */
-               pci_remove_bus_device(dev);
-
-               /* queue work item to blow away this sysfs entry and other
-                * parts.
-                */
-               INIT_WORK(&dslot->remove_work, remove_slot_worker);
-               queue_work(dummyphp_wq, &dslot->remove_work);
-
-               pci_dev_put(dev);
+               dev_warn(&pdev->dev, "Missing legacy fake slot?");
+               return -ENODEV;
+found:
+               kobject_del(&slot->kobj);
+               list_del(&slot->list);
+               kobject_put(&slot->kobj);
        }
+
        return 0;
 }
 
-static void cleanup_slots (void)
-{
-       struct list_head *tmp;
-       struct list_head *next;
-       struct dummy_slot *dslot;
-
-       destroy_workqueue(dummyphp_wq);
-       list_for_each_safe (tmp, next, &slot_list) {
-               dslot = list_entry (tmp, struct dummy_slot, node);
-               remove_slot(dslot);
-       }
-       
-}
+static struct notifier_block legacy_notifier = {
+       .notifier_call = legacy_notify
+};
 
-static int __init dummyphp_init(void)
+static int __init init_legacy(void)
 {
-       info(DRIVER_DESC "\n");
+       struct pci_dev *pdev = NULL;
 
-       dummyphp_wq = create_singlethread_workqueue(MY_NAME);
-       if (!dummyphp_wq)
-               return -ENOMEM;
+       /* Add existing devices */
+       while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)))
+               legacy_add_slot(pdev);
 
-       return pci_scan_buses();
+       /* Be alerted of any new ones */
+       bus_register_notifier(&pci_bus_type, &legacy_notifier);
+       return 0;
 }
+module_init(init_legacy);
 
-
-static void __exit dummyphp_exit(void)
+static void __exit remove_legacy(void)
 {
-       cleanup_slots();
+       struct legacy_slot *slot, *tmp;
+
+       bus_unregister_notifier(&pci_bus_type, &legacy_notifier);
+
+       list_for_each_entry_safe(slot, tmp, &legacy_list, list) {
+               list_del(&slot->list);
+               kobject_del(&slot->kobj);
+               kobject_put(&slot->kobj);
+       }
 }
+module_exit(remove_legacy);
 
-module_init(dummyphp_init);
-module_exit(dummyphp_exit);
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Trent Piepho <xyzzy@speakeasy.org>");
+MODULE_DESCRIPTION("Legacy version of the fakephp interface");
 MODULE_LICENSE("GPL");
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-module_param(dup_slots, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(dup_slots, "Force duplicate slot names for debugging");
index 39ae37589fda7f6106d845148d1175b4a927b1df..0a368547e6339d41ed7a80c08c9c6509d4d57007 100644 (file)
@@ -46,10 +46,10 @@ extern int pciehp_force;
 extern struct workqueue_struct *pciehp_wq;
 
 #define dbg(format, arg...)                                            \
-       do {                                                            \
-               if (pciehp_debug)                                       \
-                       printk("%s: " format, MY_NAME , ## arg);        \
-       } while (0)
+do {                                                                   \
+       if (pciehp_debug)                                               \
+               printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg);     \
+} while (0)
 #define err(format, arg...)                                            \
        printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
 #define info(format, arg...)                                           \
@@ -60,7 +60,7 @@ extern struct workqueue_struct *pciehp_wq;
 #define ctrl_dbg(ctrl, format, arg...)                                 \
        do {                                                            \
                if (pciehp_debug)                                       \
-                       dev_printk(, &ctrl->pcie->device,               \
+                       dev_printk(KERN_DEBUG, &ctrl->pcie->device,     \
                                        format, ## arg);                \
        } while (0)
 #define ctrl_err(ctrl, format, arg...)                                 \
@@ -108,10 +108,11 @@ struct controller {
        u32 slot_cap;
        u8 cap_base;
        struct timer_list poll_timer;
-       int cmd_busy;
+       unsigned int cmd_busy:1;
        unsigned int no_cmd_complete:1;
        unsigned int link_active_reporting:1;
        unsigned int notification_enabled:1;
+       unsigned int power_fault_detected;
 };
 
 #define INT_BUTTON_IGNORE              0
index 438d795f9fe31f1299e4612695db65ff36a4476d..96048010e7d9064f2f6b0a2d007ab056bfb8e94a 100644 (file)
@@ -67,37 +67,27 @@ static int __init parse_detect_mode(void)
        return PCIEHP_DETECT_DEFAULT;
 }
 
-static struct pcie_port_service_id __initdata port_pci_ids[] = {
-       {
-               .vendor = PCI_ANY_ID,
-               .device = PCI_ANY_ID,
-               .port_type = PCIE_ANY_PORT,
-               .service_type = PCIE_PORT_SERVICE_HP,
-               .driver_data =  0,
-        }, { /* end: all zeroes */ }
-};
-
 static int __initdata dup_slot_id;
 static int __initdata acpi_slot_detected;
 static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots);
 
 /* Dummy driver for dumplicate name detection */
-static int __init dummy_probe(struct pcie_device *dev,
-                             const struct pcie_port_service_id *id)
+static int __init dummy_probe(struct pcie_device *dev)
 {
        int pos;
        u32 slot_cap;
        struct slot *slot, *tmp;
        struct pci_dev *pdev = dev->port;
        struct pci_bus *pbus = pdev->subordinate;
-       if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL)))
-               return -ENOMEM;
        /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
        if (pciehp_get_hp_hw_control_from_firmware(pdev))
                return -ENODEV;
        if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP)))
                return -ENODEV;
        pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap);
+       slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+       if (!slot)
+               return -ENOMEM;
        slot->number = slot_cap >> 19;
        list_for_each_entry(tmp, &dummy_slots, slot_list) {
                if (tmp->number == slot->number)
@@ -111,7 +101,8 @@ static int __init dummy_probe(struct pcie_device *dev,
 
 static struct pcie_port_service_driver __initdata dummy_driver = {
         .name           = "pciehp_dummy",
-        .id_table       = port_pci_ids,
+       .port_type      = PCIE_ANY_PORT,
+       .service        = PCIE_PORT_SERVICE_HP,
         .probe          = dummy_probe,
 };
 
index 681e3912b821a4dce3f5ee11844b73cf6e8b316d..fb254b2454de7345ff4c0e3a73f43e2531e67b8a 100644 (file)
@@ -401,7 +401,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
        return 0;
 }
 
-static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id)
+static int pciehp_probe(struct pcie_device *dev)
 {
        int rc;
        struct controller *ctrl;
@@ -475,7 +475,7 @@ static void pciehp_remove (struct pcie_device *dev)
 }
 
 #ifdef CONFIG_PM
-static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
+static int pciehp_suspend (struct pcie_device *dev)
 {
        dev_info(&dev->device, "%s ENTRY\n", __func__);
        return 0;
@@ -503,20 +503,12 @@ static int pciehp_resume (struct pcie_device *dev)
        }
        return 0;
 }
-#endif
-
-static struct pcie_port_service_id port_pci_ids[] = { {
-       .vendor = PCI_ANY_ID,
-       .device = PCI_ANY_ID,
-       .port_type = PCIE_ANY_PORT,
-       .service_type = PCIE_PORT_SERVICE_HP,
-       .driver_data =  0,
-       }, { /* end: all zeroes */ }
-};
+#endif /* PM */
 
 static struct pcie_port_service_driver hpdriver_portdrv = {
        .name           = PCIE_MODULE_NAME,
-       .id_table       = &port_pci_ids[0],
+       .port_type      = PCIE_ANY_PORT,
+       .service        = PCIE_PORT_SERVICE_HP,
 
        .probe          = pciehp_probe,
        .remove         = pciehp_remove,
index 7a16c6897bb92698abc8edfb9af1d909f235453d..07bd321511463653ebe0005ebdf000efd083fe4c 100644 (file)
@@ -548,23 +548,21 @@ static int hpc_power_on_slot(struct slot * slot)
 
        slot_cmd = POWER_ON;
        cmd_mask = PCI_EXP_SLTCTL_PCC;
-       /* Enable detection that we turned off at slot power-off time */
        if (!pciehp_poll_mode) {
-               slot_cmd |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                            PCI_EXP_SLTCTL_PDCE);
-               cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                            PCI_EXP_SLTCTL_PDCE);
+               /* Enable power fault detection turned off at power off time */
+               slot_cmd |= PCI_EXP_SLTCTL_PFDE;
+               cmd_mask |= PCI_EXP_SLTCTL_PFDE;
        }
 
        retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
-
        if (retval) {
                ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd);
-               return -1;
+               return retval;
        }
        ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
                 __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
 
+       ctrl->power_fault_detected = 0;
        return retval;
 }
 
@@ -621,18 +619,10 @@ static int hpc_power_off_slot(struct slot * slot)
 
        slot_cmd = POWER_OFF;
        cmd_mask = PCI_EXP_SLTCTL_PCC;
-       /*
-        * If we get MRL or presence detect interrupts now, the isr
-        * will notice the sticky power-fault bit too and issue power
-        * indicator change commands. This will lead to an endless loop
-        * of command completions, since the power-fault bit remains on
-        * till the slot is powered on again.
-        */
        if (!pciehp_poll_mode) {
-               slot_cmd &= ~(PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                             PCI_EXP_SLTCTL_PDCE);
-               cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
-                            PCI_EXP_SLTCTL_PDCE);
+               /* Disable power fault detection */
+               slot_cmd &= ~PCI_EXP_SLTCTL_PFDE;
+               cmd_mask |= PCI_EXP_SLTCTL_PFDE;
        }
 
        retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
@@ -672,10 +662,11 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
                             PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
                             PCI_EXP_SLTSTA_CC);
+               detected &= ~intr_loc;
                intr_loc |= detected;
                if (!intr_loc)
                        return IRQ_NONE;
-               if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, detected)) {
+               if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, intr_loc)) {
                        ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n",
                                 __func__);
                        return IRQ_NONE;
@@ -709,9 +700,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                pciehp_handle_presence_change(p_slot);
 
        /* Check Power Fault Detected */
-       if (intr_loc & PCI_EXP_SLTSTA_PFD)
+       if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
+               ctrl->power_fault_detected = 1;
                pciehp_handle_power_fault(p_slot);
-
+       }
        return IRQ_HANDLED;
 }
 
index 6aba0b6cf2e0769fa25787e55e84beccbf9a0a21..974e924ca96d57d06fd5e689b97e1faaf6d9ae44 100644 (file)
@@ -48,10 +48,10 @@ extern int shpchp_debug;
 extern struct workqueue_struct *shpchp_wq;
 
 #define dbg(format, arg...)                                            \
-       do {                                                            \
-               if (shpchp_debug)                                       \
-                       printk("%s: " format, MY_NAME , ## arg);        \
-       } while (0)
+do {                                                                   \
+       if (shpchp_debug)                                               \
+               printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg);     \
+} while (0)
 #define err(format, arg...)                                            \
        printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
 #define info(format, arg...)                                           \
@@ -62,7 +62,7 @@ extern struct workqueue_struct *shpchp_wq;
 #define ctrl_dbg(ctrl, format, arg...)                                 \
        do {                                                            \
                if (shpchp_debug)                                       \
-                       dev_printk(, &ctrl->pci_dev->dev,               \
+                       dev_printk(KERN_DEBUG, &ctrl->pci_dev->dev,     \
                                        format, ## arg);                \
        } while (0)
 #define ctrl_err(ctrl, format, arg...)                                 \
index 138f161becc0758ef36121896b71f17ecc769c8c..aa315e52529bf60e0c72bd85142cf695c5c5c232 100644 (file)
@@ -137,7 +137,7 @@ int __ref shpchp_configure_device(struct slot *p_slot)
                                                        busnr))
                                        break;
                        }
-                       if (busnr >= end) {
+                       if (busnr > end) {
                                ctrl_err(ctrl,
                                         "No free bus for hot-added bridge\n");
                                pci_dev_put(dev);
index 49402c399232c2cd3d69c7050bc2cee0605cc59d..23e56a564e05056a208ac41d98828d32987865b7 100644 (file)
@@ -164,7 +164,8 @@ static inline void context_clear_entry(struct context_entry *context)
  * 1: writable
  * 2-6: reserved
  * 7: super page
- * 8-11: available
+ * 8-10: available
+ * 11: snoop behavior
  * 12-63: Host physcial address
  */
 struct dma_pte {
@@ -186,6 +187,11 @@ static inline void dma_set_pte_writable(struct dma_pte *pte)
        pte->val |= DMA_PTE_WRITE;
 }
 
+static inline void dma_set_pte_snp(struct dma_pte *pte)
+{
+       pte->val |= DMA_PTE_SNP;
+}
+
 static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
 {
        pte->val = (pte->val & ~3) | (prot & 3);
@@ -231,6 +237,7 @@ struct dmar_domain {
        int             flags;          /* flags to find out type of domain */
 
        int             iommu_coherency;/* indicate coherency of iommu access */
+       int             iommu_snooping; /* indicate snooping control feature*/
        int             iommu_count;    /* reference count of iommu */
        spinlock_t      iommu_lock;     /* protect iommu set in domain */
        u64             max_addr;       /* maximum mapped address */
@@ -421,7 +428,6 @@ static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
        return g_iommus[iommu_id];
 }
 
-/* "Coherency" capability may be different across iommus */
 static void domain_update_iommu_coherency(struct dmar_domain *domain)
 {
        int i;
@@ -438,6 +444,29 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
        }
 }
 
+static void domain_update_iommu_snooping(struct dmar_domain *domain)
+{
+       int i;
+
+       domain->iommu_snooping = 1;
+
+       i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
+       for (; i < g_num_of_iommus; ) {
+               if (!ecap_sc_support(g_iommus[i]->ecap)) {
+                       domain->iommu_snooping = 0;
+                       break;
+               }
+               i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
+       }
+}
+
+/* Some capabilities may be different across iommus */
+static void domain_update_iommu_cap(struct dmar_domain *domain)
+{
+       domain_update_iommu_coherency(domain);
+       domain_update_iommu_snooping(domain);
+}
+
 static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn)
 {
        struct dmar_drhd_unit *drhd = NULL;
@@ -689,15 +718,17 @@ static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
 static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
 {
        int addr_width = agaw_to_width(domain->agaw);
+       int npages;
 
        start &= (((u64)1) << addr_width) - 1;
        end &= (((u64)1) << addr_width) - 1;
        /* in case it's partial page */
        start = PAGE_ALIGN(start);
        end &= PAGE_MASK;
+       npages = (end - start) / VTD_PAGE_SIZE;
 
        /* we don't need lock here, nobody else touches the iova range */
-       while (start < end) {
+       while (npages--) {
                dma_pte_clear_one(domain, start);
                start += VTD_PAGE_SIZE;
        }
@@ -1241,6 +1272,11 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        else
                domain->iommu_coherency = 0;
 
+       if (ecap_sc_support(iommu->ecap))
+               domain->iommu_snooping = 1;
+       else
+               domain->iommu_snooping = 0;
+
        domain->iommu_count = 1;
 
        /* always allocate the top pgd */
@@ -1369,7 +1405,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
        spin_lock_irqsave(&domain->iommu_lock, flags);
        if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
                domain->iommu_count++;
-               domain_update_iommu_coherency(domain);
+               domain_update_iommu_cap(domain);
        }
        spin_unlock_irqrestore(&domain->iommu_lock, flags);
        return 0;
@@ -1469,6 +1505,8 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
                BUG_ON(dma_pte_addr(pte));
                dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT);
                dma_set_pte_prot(pte, prot);
+               if (prot & DMA_PTE_SNP)
+                       dma_set_pte_snp(pte);
                domain_flush_cache(domain, pte, sizeof(*pte));
                start_pfn++;
                index++;
@@ -1782,7 +1820,7 @@ static inline void iommu_prepare_isa(void)
        ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
 
        if (ret)
-               printk("IOMMU: Failed to create 0-64M identity map, "
+               printk(KERN_ERR "IOMMU: Failed to create 0-64M identity map, "
                        "floppy might not work\n");
 
 }
@@ -2119,7 +2157,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
 error:
        if (iova)
                __free_iova(&domain->iovad, iova);
-       printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
+       printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
                pci_name(pdev), size, (unsigned long long)paddr, dir);
        return 0;
 }
@@ -2218,7 +2256,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
        start_addr = iova->pfn_lo << PAGE_SHIFT;
        size = aligned_size((u64)dev_addr, size);
 
-       pr_debug("Device %s unmapping: %lx@%llx\n",
+       pr_debug("Device %s unmapping: %zx@%llx\n",
                pci_name(pdev), size, (unsigned long long)start_addr);
 
        /*  clear the whole page */
@@ -2282,8 +2320,6 @@ static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
        free_pages((unsigned long)vaddr, order);
 }
 
-#define SG_ENT_VIRT_ADDRESS(sg)        (sg_virt((sg)))
-
 static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
                           int nelems, enum dma_data_direction dir,
                           struct dma_attrs *attrs)
@@ -2294,7 +2330,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
        unsigned long start_addr;
        struct iova *iova;
        size_t size = 0;
-       void *addr;
+       phys_addr_t addr;
        struct scatterlist *sg;
        struct intel_iommu *iommu;
 
@@ -2310,7 +2346,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
        if (!iova)
                return;
        for_each_sg(sglist, sg, nelems, i) {
-               addr = SG_ENT_VIRT_ADDRESS(sg);
+               addr = page_to_phys(sg_page(sg)) + sg->offset;
                size += aligned_size((u64)addr, sg->length);
        }
 
@@ -2337,7 +2373,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,
 
        for_each_sg(sglist, sg, nelems, i) {
                BUG_ON(!sg_page(sg));
-               sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg));
+               sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
                sg->dma_length = sg->length;
        }
        return nelems;
@@ -2346,7 +2382,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,
 static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
                        enum dma_data_direction dir, struct dma_attrs *attrs)
 {
-       void *addr;
+       phys_addr_t addr;
        int i;
        struct pci_dev *pdev = to_pci_dev(hwdev);
        struct dmar_domain *domain;
@@ -2370,8 +2406,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
        iommu = domain_get_iommu(domain);
 
        for_each_sg(sglist, sg, nelems, i) {
-               addr = SG_ENT_VIRT_ADDRESS(sg);
-               addr = (void *)virt_to_phys(addr);
+               addr = page_to_phys(sg_page(sg)) + sg->offset;
                size += aligned_size((u64)addr, sg->length);
        }
 
@@ -2394,8 +2429,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
        start_addr = iova->pfn_lo << PAGE_SHIFT;
        offset = 0;
        for_each_sg(sglist, sg, nelems, i) {
-               addr = SG_ENT_VIRT_ADDRESS(sg);
-               addr = (void *)virt_to_phys(addr);
+               addr = page_to_phys(sg_page(sg)) + sg->offset;
                size = aligned_size((u64)addr, sg->length);
                ret = domain_page_mapping(domain, start_addr + offset,
                        ((u64)addr) & PAGE_MASK,
@@ -2628,6 +2662,33 @@ static int vm_domain_add_dev_info(struct dmar_domain *domain,
        return 0;
 }
 
+static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
+                                          struct pci_dev *pdev)
+{
+       struct pci_dev *tmp, *parent;
+
+       if (!iommu || !pdev)
+               return;
+
+       /* dependent device detach */
+       tmp = pci_find_upstream_pcie_bridge(pdev);
+       /* Secondary interface's bus number and devfn 0 */
+       if (tmp) {
+               parent = pdev->bus->self;
+               while (parent != tmp) {
+                       iommu_detach_dev(iommu, parent->bus->number,
+                               parent->devfn);
+                       parent = parent->bus->self;
+               }
+               if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
+                       iommu_detach_dev(iommu,
+                               tmp->subordinate->number, 0);
+               else /* this is a legacy PCI bridge */
+                       iommu_detach_dev(iommu,
+                               tmp->bus->number, tmp->devfn);
+       }
+}
+
 static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
                                          struct pci_dev *pdev)
 {
@@ -2653,6 +2714,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
                        spin_unlock_irqrestore(&device_domain_lock, flags);
 
                        iommu_detach_dev(iommu, info->bus, info->devfn);
+                       iommu_detach_dependent_devices(iommu, pdev);
                        free_devinfo_mem(info);
 
                        spin_lock_irqsave(&device_domain_lock, flags);
@@ -2676,7 +2738,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
                spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
                clear_bit(iommu->seq_id, &domain->iommu_bmp);
                domain->iommu_count--;
-               domain_update_iommu_coherency(domain);
+               domain_update_iommu_cap(domain);
                spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
        }
 
@@ -2702,15 +2764,16 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
 
                iommu = device_to_iommu(info->bus, info->devfn);
                iommu_detach_dev(iommu, info->bus, info->devfn);
+               iommu_detach_dependent_devices(iommu, info->dev);
 
                /* clear this iommu in iommu_bmp, update iommu count
-                * and coherency
+                * and capabilities
                 */
                spin_lock_irqsave(&domain->iommu_lock, flags2);
                if (test_and_clear_bit(iommu->seq_id,
                                       &domain->iommu_bmp)) {
                        domain->iommu_count--;
-                       domain_update_iommu_coherency(domain);
+                       domain_update_iommu_cap(domain);
                }
                spin_unlock_irqrestore(&domain->iommu_lock, flags2);
 
@@ -2933,6 +2996,8 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
                prot |= DMA_PTE_READ;
        if (iommu_prot & IOMMU_WRITE)
                prot |= DMA_PTE_WRITE;
+       if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
+               prot |= DMA_PTE_SNP;
 
        max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size);
        if (dmar_domain->max_addr < max_addr) {
@@ -2986,6 +3051,17 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
        return phys;
 }
 
+static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
+                                     unsigned long cap)
+{
+       struct dmar_domain *dmar_domain = domain->priv;
+
+       if (cap == IOMMU_CAP_CACHE_COHERENCY)
+               return dmar_domain->iommu_snooping;
+
+       return 0;
+}
+
 static struct iommu_ops intel_iommu_ops = {
        .domain_init    = intel_iommu_domain_init,
        .domain_destroy = intel_iommu_domain_destroy,
@@ -2994,6 +3070,7 @@ static struct iommu_ops intel_iommu_ops = {
        .map            = intel_iommu_map_range,
        .unmap          = intel_iommu_unmap_range,
        .iova_to_phys   = intel_iommu_iova_to_phys,
+       .domain_has_cap = intel_iommu_domain_has_cap,
 };
 
 static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
new file mode 100644 (file)
index 0000000..7227efc
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ * drivers/pci/iov.c
+ *
+ * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
+ *
+ * PCI Express I/O Virtualization (IOV) support.
+ *   Single Root IOV 1.0
+ */
+
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include "pci.h"
+
+#define VIRTFN_ID_LEN  16
+
+static inline u8 virtfn_bus(struct pci_dev *dev, int id)
+{
+       return dev->bus->number + ((dev->devfn + dev->sriov->offset +
+                                   dev->sriov->stride * id) >> 8);
+}
+
+static inline u8 virtfn_devfn(struct pci_dev *dev, int id)
+{
+       return (dev->devfn + dev->sriov->offset +
+               dev->sriov->stride * id) & 0xff;
+}
+
+static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
+{
+       int rc;
+       struct pci_bus *child;
+
+       if (bus->number == busnr)
+               return bus;
+
+       child = pci_find_bus(pci_domain_nr(bus), busnr);
+       if (child)
+               return child;
+
+       child = pci_add_new_bus(bus, NULL, busnr);
+       if (!child)
+               return NULL;
+
+       child->subordinate = busnr;
+       child->dev.parent = bus->bridge;
+       rc = pci_bus_add_child(child);
+       if (rc) {
+               pci_remove_bus(child);
+               return NULL;
+       }
+
+       return child;
+}
+
+static void virtfn_remove_bus(struct pci_bus *bus, int busnr)
+{
+       struct pci_bus *child;
+
+       if (bus->number == busnr)
+               return;
+
+       child = pci_find_bus(pci_domain_nr(bus), busnr);
+       BUG_ON(!child);
+
+       if (list_empty(&child->devices))
+               pci_remove_bus(child);
+}
+
+static int virtfn_add(struct pci_dev *dev, int id, int reset)
+{
+       int i;
+       int rc;
+       u64 size;
+       char buf[VIRTFN_ID_LEN];
+       struct pci_dev *virtfn;
+       struct resource *res;
+       struct pci_sriov *iov = dev->sriov;
+
+       virtfn = alloc_pci_dev();
+       if (!virtfn)
+               return -ENOMEM;
+
+       mutex_lock(&iov->dev->sriov->lock);
+       virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
+       if (!virtfn->bus) {
+               kfree(virtfn);
+               mutex_unlock(&iov->dev->sriov->lock);
+               return -ENOMEM;
+       }
+       virtfn->devfn = virtfn_devfn(dev, id);
+       virtfn->vendor = dev->vendor;
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
+       pci_setup_device(virtfn);
+       virtfn->dev.parent = dev->dev.parent;
+
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               if (!res->parent)
+                       continue;
+               virtfn->resource[i].name = pci_name(virtfn);
+               virtfn->resource[i].flags = res->flags;
+               size = resource_size(res);
+               do_div(size, iov->total);
+               virtfn->resource[i].start = res->start + size * id;
+               virtfn->resource[i].end = virtfn->resource[i].start + size - 1;
+               rc = request_resource(res, &virtfn->resource[i]);
+               BUG_ON(rc);
+       }
+
+       if (reset)
+               pci_execute_reset_function(virtfn);
+
+       pci_device_add(virtfn, virtfn->bus);
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       virtfn->physfn = pci_dev_get(dev);
+       virtfn->is_virtfn = 1;
+
+       rc = pci_bus_add_device(virtfn);
+       if (rc)
+               goto failed1;
+       sprintf(buf, "virtfn%u", id);
+       rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
+       if (rc)
+               goto failed1;
+       rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
+       if (rc)
+               goto failed2;
+
+       kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
+
+       return 0;
+
+failed2:
+       sysfs_remove_link(&dev->dev.kobj, buf);
+failed1:
+       pci_dev_put(dev);
+       mutex_lock(&iov->dev->sriov->lock);
+       pci_remove_bus_device(virtfn);
+       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       return rc;
+}
+
+static void virtfn_remove(struct pci_dev *dev, int id, int reset)
+{
+       char buf[VIRTFN_ID_LEN];
+       struct pci_bus *bus;
+       struct pci_dev *virtfn;
+       struct pci_sriov *iov = dev->sriov;
+
+       bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id));
+       if (!bus)
+               return;
+
+       virtfn = pci_get_slot(bus, virtfn_devfn(dev, id));
+       if (!virtfn)
+               return;
+
+       pci_dev_put(virtfn);
+
+       if (reset) {
+               device_release_driver(&virtfn->dev);
+               pci_execute_reset_function(virtfn);
+       }
+
+       sprintf(buf, "virtfn%u", id);
+       sysfs_remove_link(&dev->dev.kobj, buf);
+       sysfs_remove_link(&virtfn->dev.kobj, "physfn");
+
+       mutex_lock(&iov->dev->sriov->lock);
+       pci_remove_bus_device(virtfn);
+       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       pci_dev_put(dev);
+}
+
+static int sriov_migration(struct pci_dev *dev)
+{
+       u16 status;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!iov->nr_virtfn)
+               return 0;
+
+       if (!(iov->cap & PCI_SRIOV_CAP_VFM))
+               return 0;
+
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status);
+       if (!(status & PCI_SRIOV_STATUS_VFM))
+               return 0;
+
+       schedule_work(&iov->mtask);
+
+       return 1;
+}
+
+static void sriov_migration_task(struct work_struct *work)
+{
+       int i;
+       u8 state;
+       u16 status;
+       struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask);
+
+       for (i = iov->initial; i < iov->nr_virtfn; i++) {
+               state = readb(iov->mstate + i);
+               if (state == PCI_SRIOV_VFM_MI) {
+                       writeb(PCI_SRIOV_VFM_AV, iov->mstate + i);
+                       state = readb(iov->mstate + i);
+                       if (state == PCI_SRIOV_VFM_AV)
+                               virtfn_add(iov->self, i, 1);
+               } else if (state == PCI_SRIOV_VFM_MO) {
+                       virtfn_remove(iov->self, i, 1);
+                       writeb(PCI_SRIOV_VFM_UA, iov->mstate + i);
+                       state = readb(iov->mstate + i);
+                       if (state == PCI_SRIOV_VFM_AV)
+                               virtfn_add(iov->self, i, 0);
+               }
+       }
+
+       pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status);
+       status &= ~PCI_SRIOV_STATUS_VFM;
+       pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status);
+}
+
+static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn)
+{
+       int bir;
+       u32 table;
+       resource_size_t pa;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (nr_virtfn <= iov->initial)
+               return 0;
+
+       pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table);
+       bir = PCI_SRIOV_VFM_BIR(table);
+       if (bir > PCI_STD_RESOURCE_END)
+               return -EIO;
+
+       table = PCI_SRIOV_VFM_OFFSET(table);
+       if (table + nr_virtfn > pci_resource_len(dev, bir))
+               return -EIO;
+
+       pa = pci_resource_start(dev, bir) + table;
+       iov->mstate = ioremap(pa, nr_virtfn);
+       if (!iov->mstate)
+               return -ENOMEM;
+
+       INIT_WORK(&iov->mtask, sriov_migration_task);
+
+       iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR;
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+
+       return 0;
+}
+
+static void sriov_disable_migration(struct pci_dev *dev)
+{
+       struct pci_sriov *iov = dev->sriov;
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+
+       cancel_work_sync(&iov->mtask);
+       iounmap(iov->mstate);
+}
+
+static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
+{
+       int rc;
+       int i, j;
+       int nres;
+       u16 offset, stride, initial;
+       struct resource *res;
+       struct pci_dev *pdev;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!nr_virtfn)
+               return 0;
+
+       if (iov->nr_virtfn)
+               return -EINVAL;
+
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial);
+       if (initial > iov->total ||
+           (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total)))
+               return -EIO;
+
+       if (nr_virtfn < 0 || nr_virtfn > iov->total ||
+           (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
+               return -EINVAL;
+
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset);
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride);
+       if (!offset || (nr_virtfn > 1 && !stride))
+               return -EIO;
+
+       nres = 0;
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               if (res->parent)
+                       nres++;
+       }
+       if (nres != iov->nres) {
+               dev_err(&dev->dev, "not enough MMIO resources for SR-IOV\n");
+               return -ENOMEM;
+       }
+
+       iov->offset = offset;
+       iov->stride = stride;
+
+       if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->subordinate) {
+               dev_err(&dev->dev, "SR-IOV: bus number out of range\n");
+               return -ENOMEM;
+       }
+
+       if (iov->link != dev->devfn) {
+               pdev = pci_get_slot(dev->bus, iov->link);
+               if (!pdev)
+                       return -ENODEV;
+
+               pci_dev_put(pdev);
+
+               if (!pdev->is_physfn)
+                       return -ENODEV;
+
+               rc = sysfs_create_link(&dev->dev.kobj,
+                                       &pdev->dev.kobj, "dep_link");
+               if (rc)
+                       return rc;
+       }
+
+       iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       msleep(100);
+       pci_unblock_user_cfg_access(dev);
+
+       iov->initial = initial;
+       if (nr_virtfn < initial)
+               initial = nr_virtfn;
+
+       for (i = 0; i < initial; i++) {
+               rc = virtfn_add(dev, i, 0);
+               if (rc)
+                       goto failed;
+       }
+
+       if (iov->cap & PCI_SRIOV_CAP_VFM) {
+               rc = sriov_enable_migration(dev, nr_virtfn);
+               if (rc)
+                       goto failed;
+       }
+
+       kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
+       iov->nr_virtfn = nr_virtfn;
+
+       return 0;
+
+failed:
+       for (j = 0; j < i; j++)
+               virtfn_remove(dev, j, 0);
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       ssleep(1);
+       pci_unblock_user_cfg_access(dev);
+
+       if (iov->link != dev->devfn)
+               sysfs_remove_link(&dev->dev.kobj, "dep_link");
+
+       return rc;
+}
+
+static void sriov_disable(struct pci_dev *dev)
+{
+       int i;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!iov->nr_virtfn)
+               return;
+
+       if (iov->cap & PCI_SRIOV_CAP_VFM)
+               sriov_disable_migration(dev);
+
+       for (i = 0; i < iov->nr_virtfn; i++)
+               virtfn_remove(dev, i, 0);
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       ssleep(1);
+       pci_unblock_user_cfg_access(dev);
+
+       if (iov->link != dev->devfn)
+               sysfs_remove_link(&dev->dev.kobj, "dep_link");
+
+       iov->nr_virtfn = 0;
+}
+
+static int sriov_init(struct pci_dev *dev, int pos)
+{
+       int i;
+       int rc;
+       int nres;
+       u32 pgsz;
+       u16 ctrl, total, offset, stride;
+       struct pci_sriov *iov;
+       struct resource *res;
+       struct pci_dev *pdev;
+
+       if (dev->pcie_type != PCI_EXP_TYPE_RC_END &&
+           dev->pcie_type != PCI_EXP_TYPE_ENDPOINT)
+               return -ENODEV;
+
+       pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
+       if (ctrl & PCI_SRIOV_CTRL_VFE) {
+               pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
+               ssleep(1);
+       }
+
+       pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
+       if (!total)
+               return 0;
+
+       ctrl = 0;
+       list_for_each_entry(pdev, &dev->bus->devices, bus_list)
+               if (pdev->is_physfn)
+                       goto found;
+
+       pdev = NULL;
+       if (pci_ari_enabled(dev->bus))
+               ctrl |= PCI_SRIOV_CTRL_ARI;
+
+found:
+       pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
+       pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total);
+       pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
+       pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
+       if (!offset || (total > 1 && !stride))
+               return -EIO;
+
+       pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz);
+       i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0;
+       pgsz &= ~((1 << i) - 1);
+       if (!pgsz)
+               return -EIO;
+
+       pgsz &= ~(pgsz - 1);
+       pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
+
+       nres = 0;
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               i += __pci_read_base(dev, pci_bar_unknown, res,
+                                    pos + PCI_SRIOV_BAR + i * 4);
+               if (!res->flags)
+                       continue;
+               if (resource_size(res) & (PAGE_SIZE - 1)) {
+                       rc = -EIO;
+                       goto failed;
+               }
+               res->end = res->start + resource_size(res) * total - 1;
+               nres++;
+       }
+
+       iov = kzalloc(sizeof(*iov), GFP_KERNEL);
+       if (!iov) {
+               rc = -ENOMEM;
+               goto failed;
+       }
+
+       iov->pos = pos;
+       iov->nres = nres;
+       iov->ctrl = ctrl;
+       iov->total = total;
+       iov->offset = offset;
+       iov->stride = stride;
+       iov->pgsz = pgsz;
+       iov->self = dev;
+       pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
+       pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
+
+       if (pdev)
+               iov->dev = pci_dev_get(pdev);
+       else {
+               iov->dev = dev;
+               mutex_init(&iov->lock);
+       }
+
+       dev->sriov = iov;
+       dev->is_physfn = 1;
+
+       return 0;
+
+failed:
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               res->flags = 0;
+       }
+
+       return rc;
+}
+
+static void sriov_release(struct pci_dev *dev)
+{
+       BUG_ON(dev->sriov->nr_virtfn);
+
+       if (dev == dev->sriov->dev)
+               mutex_destroy(&dev->sriov->lock);
+       else
+               pci_dev_put(dev->sriov->dev);
+
+       kfree(dev->sriov);
+       dev->sriov = NULL;
+}
+
+static void sriov_restore_state(struct pci_dev *dev)
+{
+       int i;
+       u16 ctrl;
+       struct pci_sriov *iov = dev->sriov;
+
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl);
+       if (ctrl & PCI_SRIOV_CTRL_VFE)
+               return;
+
+       for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++)
+               pci_update_resource(dev, i);
+
+       pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->nr_virtfn);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       if (iov->ctrl & PCI_SRIOV_CTRL_VFE)
+               msleep(100);
+}
+
+/**
+ * pci_iov_init - initialize the IOV capability
+ * @dev: the PCI device
+ *
+ * Returns 0 on success, or negative on failure.
+ */
+int pci_iov_init(struct pci_dev *dev)
+{
+       int pos;
+
+       if (!dev->is_pcie)
+               return -ENODEV;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+       if (pos)
+               return sriov_init(dev, pos);
+
+       return -ENODEV;
+}
+
+/**
+ * pci_iov_release - release resources used by the IOV capability
+ * @dev: the PCI device
+ */
+void pci_iov_release(struct pci_dev *dev)
+{
+       if (dev->is_physfn)
+               sriov_release(dev);
+}
+
+/**
+ * pci_iov_resource_bar - get position of the SR-IOV BAR
+ * @dev: the PCI device
+ * @resno: the resource number
+ * @type: the BAR type to be filled in
+ *
+ * Returns position of the BAR encapsulated in the SR-IOV capability.
+ */
+int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+                        enum pci_bar_type *type)
+{
+       if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
+               return 0;
+
+       BUG_ON(!dev->is_physfn);
+
+       *type = pci_bar_unknown;
+
+       return dev->sriov->pos + PCI_SRIOV_BAR +
+               4 * (resno - PCI_IOV_RESOURCES);
+}
+
+/**
+ * pci_restore_iov_state - restore the state of the IOV capability
+ * @dev: the PCI device
+ */
+void pci_restore_iov_state(struct pci_dev *dev)
+{
+       if (dev->is_physfn)
+               sriov_restore_state(dev);
+}
+
+/**
+ * pci_iov_bus_range - find bus range used by Virtual Function
+ * @bus: the PCI bus
+ *
+ * Returns max number of buses (exclude current one) used by Virtual
+ * Functions.
+ */
+int pci_iov_bus_range(struct pci_bus *bus)
+{
+       int max = 0;
+       u8 busnr;
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               if (!dev->is_physfn)
+                       continue;
+               busnr = virtfn_bus(dev, dev->sriov->total - 1);
+               if (busnr > max)
+                       max = busnr;
+       }
+
+       return max ? max - bus->number : 0;
+}
+
+/**
+ * pci_enable_sriov - enable the SR-IOV capability
+ * @dev: the PCI device
+ *
+ * Returns 0 on success, or negative on failure.
+ */
+int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+       might_sleep();
+
+       if (!dev->is_physfn)
+               return -ENODEV;
+
+       return sriov_enable(dev, nr_virtfn);
+}
+EXPORT_SYMBOL_GPL(pci_enable_sriov);
+
+/**
+ * pci_disable_sriov - disable the SR-IOV capability
+ * @dev: the PCI device
+ */
+void pci_disable_sriov(struct pci_dev *dev)
+{
+       might_sleep();
+
+       if (!dev->is_physfn)
+               return;
+
+       sriov_disable(dev);
+}
+EXPORT_SYMBOL_GPL(pci_disable_sriov);
+
+/**
+ * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration
+ * @dev: the PCI device
+ *
+ * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not.
+ *
+ * Physical Function driver is responsible to register IRQ handler using
+ * VF Migration Interrupt Message Number, and call this function when the
+ * interrupt is generated by the hardware.
+ */
+irqreturn_t pci_sriov_migration(struct pci_dev *dev)
+{
+       if (!dev->is_physfn)
+               return IRQ_NONE;
+
+       return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE;
+}
+EXPORT_SYMBOL_GPL(pci_sriov_migration);
index baba2eb5367df54bcc947333beda7e56332f3785..6f2e6295e773d657eb76af3bbb39d53e917ce415 100644 (file)
@@ -27,48 +27,53 @@ static int pci_msi_enable = 1;
 
 /* Arch hooks */
 
-int __attribute__ ((weak))
-arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
+#ifndef arch_msi_check_device
+int arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
 {
        return 0;
 }
+#endif
 
-int __attribute__ ((weak))
-arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
-{
-       return 0;
-}
-
-int __attribute__ ((weak))
-arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+#ifndef arch_setup_msi_irqs
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
        struct msi_desc *entry;
        int ret;
 
+       /*
+        * If an architecture wants to support multiple MSI, it needs to
+        * override arch_setup_msi_irqs()
+        */
+       if (type == PCI_CAP_ID_MSI && nvec > 1)
+               return 1;
+
        list_for_each_entry(entry, &dev->msi_list, list) {
                ret = arch_setup_msi_irq(dev, entry);
-               if (ret)
+               if (ret < 0)
                        return ret;
+               if (ret > 0)
+                       return -ENOSPC;
        }
 
        return 0;
 }
+#endif
 
-void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
-{
-       return;
-}
-
-void __attribute__ ((weak))
-arch_teardown_msi_irqs(struct pci_dev *dev)
+#ifndef arch_teardown_msi_irqs
+void arch_teardown_msi_irqs(struct pci_dev *dev)
 {
        struct msi_desc *entry;
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               if (entry->irq != 0)
-                       arch_teardown_msi_irq(entry->irq);
+               int i, nvec;
+               if (entry->irq == 0)
+                       continue;
+               nvec = 1 << entry->msi_attrib.multiple;
+               for (i = 0; i < nvec; i++)
+                       arch_teardown_msi_irq(entry->irq + i);
        }
 }
+#endif
 
 static void __msi_set_enable(struct pci_dev *dev, int pos, int enable)
 {
@@ -111,27 +116,14 @@ static inline __attribute_const__ u32 msi_mask(unsigned x)
        return (1 << (1 << x)) - 1;
 }
 
-static void msix_flush_writes(struct irq_desc *desc)
+static inline __attribute_const__ u32 msi_capable_mask(u16 control)
 {
-       struct msi_desc *entry;
+       return msi_mask((control >> 1) & 7);
+}
 
-       entry = get_irq_desc_msi(desc);
-       BUG_ON(!entry || !entry->dev);
-       switch (entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-               /* nothing to do */
-               break;
-       case PCI_CAP_ID_MSIX:
-       {
-               int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
-               readl(entry->mask_base + offset);
-               break;
-       }
-       default:
-               BUG();
-               break;
-       }
+static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
+{
+       return msi_mask((control >> 4) & 7);
 }
 
 /*
@@ -143,49 +135,71 @@ static void msix_flush_writes(struct irq_desc *desc)
  * Returns 1 if it succeeded in masking the interrupt and 0 if the device
  * doesn't support MSI masking.
  */
-static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag)
+static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
 {
-       struct msi_desc *entry;
+       u32 mask_bits = desc->masked;
 
-       entry = get_irq_desc_msi(desc);
-       BUG_ON(!entry || !entry->dev);
-       switch (entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-               if (entry->msi_attrib.maskbit) {
-                       int pos;
-                       u32 mask_bits;
-
-                       pos = (long)entry->mask_base;
-                       pci_read_config_dword(entry->dev, pos, &mask_bits);
-                       mask_bits &= ~(mask);
-                       mask_bits |= flag & mask;
-                       pci_write_config_dword(entry->dev, pos, mask_bits);
-               } else {
-                       return 0;
-               }
-               break;
-       case PCI_CAP_ID_MSIX:
-       {
-               int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
-               writel(flag, entry->mask_base + offset);
-               readl(entry->mask_base + offset);
-               break;
-       }
-       default:
-               BUG();
-               break;
+       if (!desc->msi_attrib.maskbit)
+               return;
+
+       mask_bits &= ~mask;
+       mask_bits |= flag;
+       pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits);
+       desc->masked = mask_bits;
+}
+
+/*
+ * This internal function does not flush PCI writes to the device.
+ * All users must ensure that they read from the device before either
+ * assuming that the device state is up to date, or returning out of this
+ * file.  This saves a few milliseconds when initialising devices with lots
+ * of MSI-X interrupts.
+ */
+static void msix_mask_irq(struct msi_desc *desc, u32 flag)
+{
+       u32 mask_bits = desc->masked;
+       unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+                                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
+       mask_bits &= ~1;
+       mask_bits |= flag;
+       writel(mask_bits, desc->mask_base + offset);
+       desc->masked = mask_bits;
+}
+
+static void msi_set_mask_bit(unsigned irq, u32 flag)
+{
+       struct msi_desc *desc = get_irq_msi(irq);
+
+       if (desc->msi_attrib.is_msix) {
+               msix_mask_irq(desc, flag);
+               readl(desc->mask_base);         /* Flush write to device */
+       } else {
+               unsigned offset = irq - desc->dev->irq;
+               msi_mask_irq(desc, 1 << offset, flag << offset);
        }
-       entry->msi_attrib.masked = !!flag;
-       return 1;
+}
+
+void mask_msi_irq(unsigned int irq)
+{
+       msi_set_mask_bit(irq, 1);
+}
+
+void unmask_msi_irq(unsigned int irq)
+{
+       msi_set_mask_bit(irq, 0);
 }
 
 void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 {
        struct msi_desc *entry = get_irq_desc_msi(desc);
-       switch(entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-       {
+       if (entry->msi_attrib.is_msix) {
+               void __iomem *base = entry->mask_base +
+                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+               msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+               msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+               msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
+       } else {
                struct pci_dev *dev = entry->dev;
                int pos = entry->msi_attrib.pos;
                u16 data;
@@ -201,21 +215,6 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
                        pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
                }
                msg->data = data;
-               break;
-       }
-       case PCI_CAP_ID_MSIX:
-       {
-               void __iomem *base;
-               base = entry->mask_base +
-                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
-
-               msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-               msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-               msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
-               break;
-       }
-       default:
-               BUG();
        }
 }
 
@@ -229,11 +228,25 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 {
        struct msi_desc *entry = get_irq_desc_msi(desc);
-       switch (entry->msi_attrib.type) {
-       case PCI_CAP_ID_MSI:
-       {
+       if (entry->msi_attrib.is_msix) {
+               void __iomem *base;
+               base = entry->mask_base +
+                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+               writel(msg->address_lo,
+                       base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+               writel(msg->address_hi,
+                       base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+               writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
+       } else {
                struct pci_dev *dev = entry->dev;
                int pos = entry->msi_attrib.pos;
+               u16 msgctl;
+
+               pci_read_config_word(dev, msi_control_reg(pos), &msgctl);
+               msgctl &= ~PCI_MSI_FLAGS_QSIZE;
+               msgctl |= entry->msi_attrib.multiple << 4;
+               pci_write_config_word(dev, msi_control_reg(pos), msgctl);
 
                pci_write_config_dword(dev, msi_lower_address_reg(pos),
                                        msg->address_lo);
@@ -246,23 +259,6 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
                        pci_write_config_word(dev, msi_data_reg(pos, 0),
                                                msg->data);
                }
-               break;
-       }
-       case PCI_CAP_ID_MSIX:
-       {
-               void __iomem *base;
-               base = entry->mask_base +
-                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
-
-               writel(msg->address_lo,
-                       base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-               writel(msg->address_hi,
-                       base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-               writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
-               break;
-       }
-       default:
-               BUG();
        }
        entry->msg = *msg;
 }
@@ -274,37 +270,18 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
        write_msi_msg_desc(desc, msg);
 }
 
-void mask_msi_irq(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       msi_set_mask_bits(desc, 1, 1);
-       msix_flush_writes(desc);
-}
-
-void unmask_msi_irq(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       msi_set_mask_bits(desc, 1, 0);
-       msix_flush_writes(desc);
-}
-
 static int msi_free_irqs(struct pci_dev* dev);
 
-static struct msi_desc* alloc_msi_entry(void)
+static struct msi_desc *alloc_msi_entry(struct pci_dev *dev)
 {
-       struct msi_desc *entry;
-
-       entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL);
-       if (!entry)
+       struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
                return NULL;
 
-       INIT_LIST_HEAD(&entry->list);
-       entry->irq = 0;
-       entry->dev = NULL;
+       INIT_LIST_HEAD(&desc->list);
+       desc->dev = dev;
 
-       return entry;
+       return desc;
 }
 
 static void pci_intx_for_msi(struct pci_dev *dev, int enable)
@@ -328,15 +305,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
        pci_intx_for_msi(dev, 0);
        msi_set_enable(dev, 0);
        write_msi_msg(dev->irq, &entry->msg);
-       if (entry->msi_attrib.maskbit) {
-               struct irq_desc *desc = irq_to_desc(dev->irq);
-               msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask,
-                                 entry->msi_attrib.masked);
-       }
 
        pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+       msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
        control &= ~PCI_MSI_FLAGS_QSIZE;
-       control |= PCI_MSI_FLAGS_ENABLE;
+       control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
        pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
 }
 
@@ -354,9 +327,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
        msix_set_enable(dev, 0);
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               struct irq_desc *desc = irq_to_desc(entry->irq);
                write_msi_msg(entry->irq, &entry->msg);
-               msi_set_mask_bits(desc, 1, entry->msi_attrib.masked);
+               msix_mask_irq(entry, entry->masked);
        }
 
        BUG_ON(list_empty(&dev->msi_list));
@@ -378,52 +350,48 @@ EXPORT_SYMBOL_GPL(pci_restore_msi_state);
 /**
  * msi_capability_init - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
+ * @nvec: number of interrupts to allocate
  *
- * Setup the MSI capability structure of device function with a single
- * MSI irq, regardless of device function is capable of handling
- * multiple messages. A return of zero indicates the successful setup
- * of an entry zero with the new MSI irq or non-zero for otherwise.
- **/
-static int msi_capability_init(struct pci_dev *dev)
+ * Setup the MSI capability structure of the device with the requested
+ * number of interrupts.  A return value of zero indicates the successful
+ * setup of an entry with the new MSI irq.  A negative return value indicates
+ * an error, and a positive return value indicates the number of interrupts
+ * which could have been allocated.
+ */
+static int msi_capability_init(struct pci_dev *dev, int nvec)
 {
        struct msi_desc *entry;
        int pos, ret;
        u16 control;
+       unsigned mask;
 
        msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
 
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
        pci_read_config_word(dev, msi_control_reg(pos), &control);
        /* MSI Entry Initialization */
-       entry = alloc_msi_entry();
+       entry = alloc_msi_entry(dev);
        if (!entry)
                return -ENOMEM;
 
-       entry->msi_attrib.type = PCI_CAP_ID_MSI;
+       entry->msi_attrib.is_msix = 0;
        entry->msi_attrib.is_64 = is_64bit_address(control);
        entry->msi_attrib.entry_nr = 0;
        entry->msi_attrib.maskbit = is_mask_bit_support(control);
-       entry->msi_attrib.masked = 1;
        entry->msi_attrib.default_irq = dev->irq;       /* Save IOAPIC IRQ */
        entry->msi_attrib.pos = pos;
-       entry->dev = dev;
-       if (entry->msi_attrib.maskbit) {
-               unsigned int base, maskbits, temp;
-
-               base = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
-               entry->mask_base = (void __iomem *)(long)base;
-
-               /* All MSIs are unmasked by default, Mask them all */
-               pci_read_config_dword(dev, base, &maskbits);
-               temp = msi_mask((control & PCI_MSI_FLAGS_QMASK) >> 1);
-               maskbits |= temp;
-               pci_write_config_dword(dev, base, maskbits);
-               entry->msi_attrib.maskbits_mask = temp;
-       }
+
+       entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
+       /* All MSIs are unmasked by default, Mask them all */
+       if (entry->msi_attrib.maskbit)
+               pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
+       mask = msi_capable_mask(control);
+       msi_mask_irq(entry, mask, mask);
+
        list_add_tail(&entry->list, &dev->msi_list);
 
        /* Configure MSI capability structure */
-       ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI);
+       ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
        if (ret) {
                msi_free_irqs(dev);
                return ret;
@@ -476,26 +444,28 @@ static int msix_capability_init(struct pci_dev *dev,
 
        /* MSI-X Table Initialization */
        for (i = 0; i < nvec; i++) {
-               entry = alloc_msi_entry();
+               entry = alloc_msi_entry(dev);
                if (!entry)
                        break;
 
                j = entries[i].entry;
-               entry->msi_attrib.type = PCI_CAP_ID_MSIX;
+               entry->msi_attrib.is_msix = 1;
                entry->msi_attrib.is_64 = 1;
                entry->msi_attrib.entry_nr = j;
-               entry->msi_attrib.maskbit = 1;
-               entry->msi_attrib.masked = 1;
                entry->msi_attrib.default_irq = dev->irq;
                entry->msi_attrib.pos = pos;
-               entry->dev = dev;
                entry->mask_base = base;
+               entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE +
+                                       PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+               msix_mask_irq(entry, 1);
 
                list_add_tail(&entry->list, &dev->msi_list);
        }
 
        ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
-       if (ret) {
+       if (ret < 0) {
+               /* If we had some success report the number of irqs
+                * we succeeded in setting up. */
                int avail = 0;
                list_for_each_entry(entry, &dev->msi_list, list) {
                        if (entry->irq != 0) {
@@ -503,14 +473,13 @@ static int msix_capability_init(struct pci_dev *dev,
                        }
                }
 
-               msi_free_irqs(dev);
+               if (avail != 0)
+                       ret = avail;
+       }
 
-               /* If we had some success report the number of irqs
-                * we succeeded in setting up.
-                */
-               if (avail == 0)
-                       avail = ret;
-               return avail;
+       if (ret) {
+               msi_free_irqs(dev);
+               return ret;
        }
 
        i = 0;
@@ -575,39 +544,54 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type)
 }
 
 /**
- * pci_enable_msi - configure device's MSI capability structure
- * @dev: pointer to the pci_dev data structure of MSI device function
+ * pci_enable_msi_block - configure device's MSI capability structure
+ * @dev: device to configure
+ * @nvec: number of interrupts to configure
  *
- * Setup the MSI capability structure of device function with
- * a single MSI irq upon its software driver call to request for
- * MSI mode enabled on its hardware device function. A return of zero
- * indicates the successful setup of an entry zero with the new MSI
- * irq or non-zero for otherwise.
- **/
-int pci_enable_msi(struct pci_dev* dev)
+ * Allocate IRQs for a device with the MSI capability.
+ * This function returns a negative errno if an error occurs.  If it
+ * is unable to allocate the number of interrupts requested, it returns
+ * the number of interrupts it might be able to allocate.  If it successfully
+ * allocates at least the number of interrupts requested, it returns 0 and
+ * updates the @dev's irq member to the lowest new interrupt number; the
+ * other interrupt numbers allocated to this device are consecutive.
+ */
+int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
 {
-       int status;
+       int status, pos, maxvec;
+       u16 msgctl;
 
-       status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
+       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+       if (!pos)
+               return -EINVAL;
+       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+       maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
+       if (nvec > maxvec)
+               return maxvec;
+
+       status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI);
        if (status)
                return status;
 
        WARN_ON(!!dev->msi_enabled);
 
-       /* Check whether driver already requested for MSI-X irqs */
+       /* Check whether driver already requested MSI-X irqs */
        if (dev->msix_enabled) {
                dev_info(&dev->dev, "can't enable MSI "
                         "(MSI-X already enabled)\n");
                return -EINVAL;
        }
-       status = msi_capability_init(dev);
+
+       status = msi_capability_init(dev, nvec);
        return status;
 }
-EXPORT_SYMBOL(pci_enable_msi);
+EXPORT_SYMBOL(pci_enable_msi_block);
 
-void pci_msi_shutdown(struct pci_devdev)
+void pci_msi_shutdown(struct pci_dev *dev)
 {
-       struct msi_desc *entry;
+       struct msi_desc *desc;
+       u32 mask;
+       u16 ctrl;
 
        if (!pci_msi_enable || !dev || !dev->msi_enabled)
                return;
@@ -617,19 +601,15 @@ void pci_msi_shutdown(struct pci_dev* dev)
        dev->msi_enabled = 0;
 
        BUG_ON(list_empty(&dev->msi_list));
-       entry = list_entry(dev->msi_list.next, struct msi_desc, list);
-       /* Return the the pci reset with msi irqs unmasked */
-       if (entry->msi_attrib.maskbit) {
-               u32 mask = entry->msi_attrib.maskbits_mask;
-               struct irq_desc *desc = irq_to_desc(dev->irq);
-               msi_set_mask_bits(desc, mask, ~mask);
-       }
-       if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
-               return;
+       desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
+       pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl);
+       mask = msi_capable_mask(ctrl);
+       msi_mask_irq(desc, mask, ~mask);
 
        /* Restore dev->irq to its default pin-assertion irq */
-       dev->irq = entry->msi_attrib.default_irq;
+       dev->irq = desc->msi_attrib.default_irq;
 }
+
 void pci_disable_msi(struct pci_dev* dev)
 {
        struct msi_desc *entry;
@@ -640,7 +620,7 @@ void pci_disable_msi(struct pci_dev* dev)
        pci_msi_shutdown(dev);
 
        entry = list_entry(dev->msi_list.next, struct msi_desc, list);
-       if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
+       if (entry->msi_attrib.is_msix)
                return;
 
        msi_free_irqs(dev);
@@ -652,14 +632,18 @@ static int msi_free_irqs(struct pci_dev* dev)
        struct msi_desc *entry, *tmp;
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               if (entry->irq)
-                       BUG_ON(irq_has_action(entry->irq));
+               int i, nvec;
+               if (!entry->irq)
+                       continue;
+               nvec = 1 << entry->msi_attrib.multiple;
+               for (i = 0; i < nvec; i++)
+                       BUG_ON(irq_has_action(entry->irq + i));
        }
 
        arch_teardown_msi_irqs(dev);
 
        list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
-               if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) {
+               if (entry->msi_attrib.is_msix) {
                        writel(1, entry->mask_base + entry->msi_attrib.entry_nr
                                  * PCI_MSIX_ENTRY_SIZE
                                  + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
@@ -674,6 +658,23 @@ static int msi_free_irqs(struct pci_dev* dev)
        return 0;
 }
 
+/**
+ * pci_msix_table_size - return the number of device's MSI-X table entries
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ */
+int pci_msix_table_size(struct pci_dev *dev)
+{
+       int pos;
+       u16 control;
+
+       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+       if (!pos)
+               return 0;
+
+       pci_read_config_word(dev, msi_control_reg(pos), &control);
+       return multi_msix_capable(control);
+}
+
 /**
  * pci_enable_msix - configure device's MSI-X capability structure
  * @dev: pointer to the pci_dev data structure of MSI-X device function
@@ -691,9 +692,8 @@ static int msi_free_irqs(struct pci_dev* dev)
  **/
 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 {
-       int status, pos, nr_entries;
+       int status, nr_entries;
        int i, j;
-       u16 control;
 
        if (!entries)
                return -EINVAL;
@@ -702,9 +702,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
        if (status)
                return status;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       pci_read_config_word(dev, msi_control_reg(pos), &control);
-       nr_entries = multi_msix_capable(control);
+       nr_entries = pci_msix_table_size(dev);
        if (nvec > nr_entries)
                return -EINVAL;
 
index 3898f523714453a9a3f6481df2e74b56c863d157..71f4df2ef65499d84481441be24015f3b0c17398 100644 (file)
 #define msi_mask_bits_reg(base, is64bit) \
        ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
 #define msi_disable(control)           control &= ~PCI_MSI_FLAGS_ENABLE
-#define multi_msi_capable(control) \
-       (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
-#define multi_msi_enable(control, num) \
-       control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
 #define is_64bit_address(control)      (!!(control & PCI_MSI_FLAGS_64BIT))
 #define is_mask_bit_support(control)   (!!(control & PCI_MSI_FLAGS_MASKBIT))
-#define msi_enable(control, num) multi_msi_enable(control, num); \
-       control |= PCI_MSI_FLAGS_ENABLE
 
 #define msix_table_offset_reg(base)    (base + 0x04)
 #define msix_pba_offset_reg(base)      (base + 0x08)
index deea8a187eb86f6b81d423c2fae4e4859937764a..fac5eddcefd2a2ee1100471de5c627654cd76814 100644 (file)
 #include <linux/pci-acpi.h>
 #include "pci.h"
 
-struct acpi_osc_data {
-       acpi_handle handle;
-       u32 support_set;
-       u32 control_set;
-       u32 control_query;
-       int is_queried;
-       struct list_head sibiling;
-};
-static LIST_HEAD(acpi_osc_data_list);
-
-struct acpi_osc_args {
-       u32 capbuf[3];
-};
-
-static DEFINE_MUTEX(pci_acpi_lock);
-
-static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle)
-{
-       struct acpi_osc_data *data;
-
-       list_for_each_entry(data, &acpi_osc_data_list, sibiling) {
-               if (data->handle == handle)
-                       return data;
-       }
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return NULL;
-       INIT_LIST_HEAD(&data->sibiling);
-       data->handle = handle;
-       list_add_tail(&data->sibiling, &acpi_osc_data_list);
-       return data;
-}
-
-static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40,
-                         0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
-
-static acpi_status acpi_run_osc(acpi_handle handle,
-                               struct acpi_osc_args *osc_args, u32 *retval)
-{
-       acpi_status status;
-       struct acpi_object_list input;
-       union acpi_object in_params[4];
-       struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
-       union acpi_object *out_obj;
-       u32 errors, flags = osc_args->capbuf[OSC_QUERY_TYPE];
-
-       /* Setting up input parameters */
-       input.count = 4;
-       input.pointer = in_params;
-       in_params[0].type               = ACPI_TYPE_BUFFER;
-       in_params[0].buffer.length      = 16;
-       in_params[0].buffer.pointer     = OSC_UUID;
-       in_params[1].type               = ACPI_TYPE_INTEGER;
-       in_params[1].integer.value      = 1;
-       in_params[2].type               = ACPI_TYPE_INTEGER;
-       in_params[2].integer.value      = 3;
-       in_params[3].type               = ACPI_TYPE_BUFFER;
-       in_params[3].buffer.length      = 12;
-       in_params[3].buffer.pointer     = (u8 *)osc_args->capbuf;
-
-       status = acpi_evaluate_object(handle, "_OSC", &input, &output);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       if (!output.length)
-               return AE_NULL_OBJECT;
-
-       out_obj = output.pointer;
-       if (out_obj->type != ACPI_TYPE_BUFFER) {
-               printk(KERN_DEBUG "Evaluate _OSC returns wrong type\n");
-               status = AE_TYPE;
-               goto out_kfree;
-       }
-       /* Need to ignore the bit0 in result code */
-       errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
-       if (errors) {
-               if (errors & OSC_REQUEST_ERROR)
-                       printk(KERN_DEBUG "_OSC request fails\n"); 
-               if (errors & OSC_INVALID_UUID_ERROR)
-                       printk(KERN_DEBUG "_OSC invalid UUID\n"); 
-               if (errors & OSC_INVALID_REVISION_ERROR)
-                       printk(KERN_DEBUG "_OSC invalid revision\n"); 
-               if (errors & OSC_CAPABILITIES_MASK_ERROR) {
-                       if (flags & OSC_QUERY_ENABLE)
-                               goto out_success;
-                       printk(KERN_DEBUG "_OSC FW not grant req. control\n");
-                       status = AE_SUPPORT;
-                       goto out_kfree;
-               }
-               status = AE_ERROR;
-               goto out_kfree;
-       }
-out_success:
-       *retval = *((u32 *)(out_obj->buffer.pointer + 8));
-       status = AE_OK;
-
-out_kfree:
-       kfree(output.pointer);
-       return status;
-}
-
-static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data)
-{
-       acpi_status status;
-       u32 support_set, result;
-       struct acpi_osc_args osc_args;
-
-       /* do _OSC query for all possible controls */
-       support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS);
-       osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-       osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set;
-       osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
-
-       status = acpi_run_osc(osc_data->handle, &osc_args, &result);
-       if (ACPI_SUCCESS(status)) {
-               osc_data->support_set = support_set;
-               osc_data->control_query = result;
-               osc_data->is_queried = 1;
-       }
-
-       return status;
-}
-
-/*
- * pci_acpi_osc_support: Invoke _OSC indicating support for the given feature
- * @flags: Bitmask of flags to support
- *
- * See the ACPI spec for the definition of the flags
- */
-int pci_acpi_osc_support(acpi_handle handle, u32 flags)
-{
-       acpi_status status;
-       acpi_handle tmp;
-       struct acpi_osc_data *osc_data;
-       int rc = 0;
-
-       status = acpi_get_handle(handle, "_OSC", &tmp);
-       if (ACPI_FAILURE(status))
-               return -ENOTTY;
-
-       mutex_lock(&pci_acpi_lock);
-       osc_data = acpi_get_osc_data(handle);
-       if (!osc_data) {
-               printk(KERN_ERR "acpi osc data array is full\n");
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       __acpi_query_osc(flags, osc_data);
-out:
-       mutex_unlock(&pci_acpi_lock);
-       return rc;
-}
-
-/**
- * pci_osc_control_set - commit requested control to Firmware
- * @handle: acpi_handle for the target ACPI object
- * @flags: driver's requested control bits
- *
- * Attempt to take control from Firmware on requested control bits.
- **/
-acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
-{
-       acpi_status status;
-       u32 control_req, control_set, result;
-       acpi_handle tmp;
-       struct acpi_osc_data *osc_data;
-       struct acpi_osc_args osc_args;
-
-       status = acpi_get_handle(handle, "_OSC", &tmp);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       mutex_lock(&pci_acpi_lock);
-       osc_data = acpi_get_osc_data(handle);
-       if (!osc_data) {
-               printk(KERN_ERR "acpi osc data array is full\n");
-               status = AE_ERROR;
-               goto out;
-       }
-
-       control_req = (flags & OSC_CONTROL_MASKS);
-       if (!control_req) {
-               status = AE_TYPE;
-               goto out;
-       }
-
-       /* No need to evaluate _OSC if the control was already granted. */
-       if ((osc_data->control_set & control_req) == control_req)
-               goto out;
-
-       if (!osc_data->is_queried) {
-               status = __acpi_query_osc(osc_data->support_set, osc_data);
-               if (ACPI_FAILURE(status))
-                       goto out;
-       }
-
-       if ((osc_data->control_query & control_req) != control_req) {
-               status = AE_SUPPORT;
-               goto out;
-       }
-
-       control_set = osc_data->control_set | control_req;
-       osc_args.capbuf[OSC_QUERY_TYPE] = 0;
-       osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set;
-       osc_args.capbuf[OSC_CONTROL_TYPE] = control_set;
-       status = acpi_run_osc(handle, &osc_args, &result);
-       if (ACPI_SUCCESS(status))
-               osc_data->control_set = result;
-out:
-       mutex_unlock(&pci_acpi_lock);
-       return status;
-}
-EXPORT_SYMBOL(pci_osc_control_set);
-
 /*
  * _SxD returns the D-state with the highest power
  * (lowest D-state number) supported in the S-state "x".
index 93eac14235854c648e6e895c51f063b8af68e152..c0cbbb5a245e6167e3292e4765ff59aa06bc533b 100644 (file)
@@ -99,6 +99,52 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
 }
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
+/**
+ * store_remove_id - remove a PCI device ID from this driver
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Removes a dynamic pci device ID to this driver.
+ */
+static ssize_t
+store_remove_id(struct device_driver *driver, const char *buf, size_t count)
+{
+       struct pci_dynid *dynid, *n;
+       struct pci_driver *pdrv = to_pci_driver(driver);
+       __u32 vendor, device, subvendor = PCI_ANY_ID,
+               subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
+       int fields = 0;
+       int retval = -ENODEV;
+
+       fields = sscanf(buf, "%x %x %x %x %x %x",
+                       &vendor, &device, &subvendor, &subdevice,
+                       &class, &class_mask);
+       if (fields < 2)
+               return -EINVAL;
+
+       spin_lock(&pdrv->dynids.lock);
+       list_for_each_entry_safe(dynid, n, &pdrv->dynids.list, node) {
+               struct pci_device_id *id = &dynid->id;
+               if ((id->vendor == vendor) &&
+                   (id->device == device) &&
+                   (subvendor == PCI_ANY_ID || id->subvendor == subvendor) &&
+                   (subdevice == PCI_ANY_ID || id->subdevice == subdevice) &&
+                   !((id->class ^ class) & class_mask)) {
+                       list_del(&dynid->node);
+                       kfree(dynid);
+                       retval = 0;
+                       break;
+               }
+       }
+       spin_unlock(&pdrv->dynids.lock);
+
+       if (retval)
+               return retval;
+       return count;
+}
+static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
+
 static void
 pci_free_dynids(struct pci_driver *drv)
 {
@@ -125,6 +171,20 @@ static void pci_remove_newid_file(struct pci_driver *drv)
 {
        driver_remove_file(&drv->driver, &driver_attr_new_id);
 }
+
+static int
+pci_create_removeid_file(struct pci_driver *drv)
+{
+       int error = 0;
+       if (drv->probe != NULL)
+               error = driver_create_file(&drv->driver,&driver_attr_remove_id);
+       return error;
+}
+
+static void pci_remove_removeid_file(struct pci_driver *drv)
+{
+       driver_remove_file(&drv->driver, &driver_attr_remove_id);
+}
 #else /* !CONFIG_HOTPLUG */
 static inline void pci_free_dynids(struct pci_driver *drv) {}
 static inline int pci_create_newid_file(struct pci_driver *drv)
@@ -132,6 +192,11 @@ static inline int pci_create_newid_file(struct pci_driver *drv)
        return 0;
 }
 static inline void pci_remove_newid_file(struct pci_driver *drv) {}
+static inline int pci_create_removeid_file(struct pci_driver *drv)
+{
+       return 0;
+}
+static inline void pci_remove_removeid_file(struct pci_driver *drv) {}
 #endif
 
 /**
@@ -352,53 +417,60 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
 {
        struct pci_dev * pci_dev = to_pci_dev(dev);
        struct pci_driver * drv = pci_dev->driver;
-       int i = 0;
+
+       pci_dev->state_saved = false;
 
        if (drv && drv->suspend) {
                pci_power_t prev = pci_dev->current_state;
+               int error;
 
-               pci_dev->state_saved = false;
-
-               i = drv->suspend(pci_dev, state);
-               suspend_report_result(drv->suspend, i);
-               if (i)
-                       return i;
-
-               if (pci_dev->state_saved)
-                       goto Fixup;
+               error = drv->suspend(pci_dev, state);
+               suspend_report_result(drv->suspend, error);
+               if (error)
+                       return error;
 
-               if (pci_dev->current_state != PCI_D0
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
                    && pci_dev->current_state != PCI_UNKNOWN) {
                        WARN_ONCE(pci_dev->current_state != prev,
                                "PCI PM: Device state not saved by %pF\n",
                                drv->suspend);
-                       goto Fixup;
                }
        }
 
-       pci_save_state(pci_dev);
-       /*
-        * This is for compatibility with existing code with legacy PM support.
-        */
-       pci_pm_set_unknown_state(pci_dev);
-
- Fixup:
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
-       return i;
+       return 0;
 }
 
 static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
 {
        struct pci_dev * pci_dev = to_pci_dev(dev);
        struct pci_driver * drv = pci_dev->driver;
-       int i = 0;
 
        if (drv && drv->suspend_late) {
-               i = drv->suspend_late(pci_dev, state);
-               suspend_report_result(drv->suspend_late, i);
+               pci_power_t prev = pci_dev->current_state;
+               int error;
+
+               error = drv->suspend_late(pci_dev, state);
+               suspend_report_result(drv->suspend_late, error);
+               if (error)
+                       return error;
+
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
+                   && pci_dev->current_state != PCI_UNKNOWN) {
+                       WARN_ONCE(pci_dev->current_state != prev,
+                               "PCI PM: Device state not saved by %pF\n",
+                               drv->suspend_late);
+                       return 0;
+               }
        }
-       return i;
+
+       if (!pci_dev->state_saved)
+               pci_save_state(pci_dev);
+
+       pci_pm_set_unknown_state(pci_dev);
+
+       return 0;
 }
 
 static int pci_legacy_resume_early(struct device *dev)
@@ -423,6 +495,23 @@ static int pci_legacy_resume(struct device *dev)
 
 /* Auxiliary functions used by the new power management framework */
 
+/**
+ * pci_restore_standard_config - restore standard config registers of PCI device
+ * @pci_dev: PCI device to handle
+ */
+static int pci_restore_standard_config(struct pci_dev *pci_dev)
+{
+       pci_update_current_state(pci_dev, PCI_UNKNOWN);
+
+       if (pci_dev->current_state != PCI_D0) {
+               int error = pci_set_power_state(pci_dev, PCI_D0);
+               if (error)
+                       return error;
+       }
+
+       return pci_dev->state_saved ? pci_restore_state(pci_dev) : 0;
+}
+
 static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
 {
        pci_restore_standard_config(pci_dev);
@@ -443,7 +532,6 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev)
        /* Disable non-bridge devices without PM support */
        if (!pci_is_bridge(pci_dev))
                pci_disable_enabled_device(pci_dev);
-       pci_save_state(pci_dev);
 }
 
 static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
@@ -493,13 +581,13 @@ static int pci_pm_suspend(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_SUSPEND);
 
+       pci_dev->state_saved = false;
+
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                goto Fixup;
        }
 
-       pci_dev->state_saved = false;
-
        if (pm->suspend) {
                pci_power_t prev = pci_dev->current_state;
                int error;
@@ -509,24 +597,14 @@ static int pci_pm_suspend(struct device *dev)
                if (error)
                        return error;
 
-               if (pci_dev->state_saved)
-                       goto Fixup;
-
-               if (pci_dev->current_state != PCI_D0
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
                    && pci_dev->current_state != PCI_UNKNOWN) {
                        WARN_ONCE(pci_dev->current_state != prev,
                                "PCI PM: State of device not saved by %pF\n",
                                pm->suspend);
-                       goto Fixup;
                }
        }
 
-       if (!pci_dev->state_saved) {
-               pci_save_state(pci_dev);
-               if (!pci_is_bridge(pci_dev))
-                       pci_prepare_to_sleep(pci_dev);
-       }
-
  Fixup:
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
@@ -536,21 +614,43 @@ static int pci_pm_suspend(struct device *dev)
 static int pci_pm_suspend_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct device_driver *drv = dev->driver;
-       int error = 0;
+       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
 
-       if (drv && drv->pm && drv->pm->suspend_noirq) {
-               error = drv->pm->suspend_noirq(dev);
-               suspend_report_result(drv->pm->suspend_noirq, error);
+       if (!pm) {
+               pci_save_state(pci_dev);
+               return 0;
        }
 
-       if (!error)
-               pci_pm_set_unknown_state(pci_dev);
+       if (pm->suspend_noirq) {
+               pci_power_t prev = pci_dev->current_state;
+               int error;
 
-       return error;
+               error = pm->suspend_noirq(dev);
+               suspend_report_result(pm->suspend_noirq, error);
+               if (error)
+                       return error;
+
+               if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
+                   && pci_dev->current_state != PCI_UNKNOWN) {
+                       WARN_ONCE(pci_dev->current_state != prev,
+                               "PCI PM: State of device not saved by %pF\n",
+                               pm->suspend_noirq);
+                       return 0;
+               }
+       }
+
+       if (!pci_dev->state_saved) {
+               pci_save_state(pci_dev);
+               if (!pci_is_bridge(pci_dev))
+                       pci_prepare_to_sleep(pci_dev);
+       }
+
+       pci_pm_set_unknown_state(pci_dev);
+
+       return 0;
 }
 
 static int pci_pm_resume_noirq(struct device *dev)
@@ -617,13 +717,13 @@ static int pci_pm_freeze(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_FREEZE);
 
+       pci_dev->state_saved = false;
+
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                return 0;
        }
 
-       pci_dev->state_saved = false;
-
        if (pm->freeze) {
                int error;
 
@@ -633,9 +733,6 @@ static int pci_pm_freeze(struct device *dev)
                        return error;
        }
 
-       if (!pci_dev->state_saved)
-               pci_save_state(pci_dev);
-
        return 0;
 }
 
@@ -643,20 +740,25 @@ static int pci_pm_freeze_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
-       int error = 0;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_FREEZE);
 
        if (drv && drv->pm && drv->pm->freeze_noirq) {
+               int error;
+
                error = drv->pm->freeze_noirq(dev);
                suspend_report_result(drv->pm->freeze_noirq, error);
+               if (error)
+                       return error;
        }
 
-       if (!error)
-               pci_pm_set_unknown_state(pci_dev);
+       if (!pci_dev->state_saved)
+               pci_save_state(pci_dev);
 
-       return error;
+       pci_pm_set_unknown_state(pci_dev);
+
+       return 0;
 }
 
 static int pci_pm_thaw_noirq(struct device *dev)
@@ -699,46 +801,56 @@ static int pci_pm_poweroff(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int error = 0;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_HIBERNATE);
 
+       pci_dev->state_saved = false;
+
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                goto Fixup;
        }
 
-       pci_dev->state_saved = false;
-
        if (pm->poweroff) {
+               int error;
+
                error = pm->poweroff(dev);
                suspend_report_result(pm->poweroff, error);
+               if (error)
+                       return error;
        }
 
-       if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
-               pci_prepare_to_sleep(pci_dev);
-
  Fixup:
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
-       return error;
+       return 0;
 }
 
 static int pci_pm_poweroff_noirq(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
-       int error = 0;
 
        if (pci_has_legacy_pm_support(to_pci_dev(dev)))
                return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
 
-       if (drv && drv->pm && drv->pm->poweroff_noirq) {
+       if (!drv || !drv->pm)
+               return 0;
+
+       if (drv->pm->poweroff_noirq) {
+               int error;
+
                error = drv->pm->poweroff_noirq(dev);
                suspend_report_result(drv->pm->poweroff_noirq, error);
+               if (error)
+                       return error;
        }
 
-       return error;
+       if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
+               pci_prepare_to_sleep(pci_dev);
+
+       return 0;
 }
 
 static int pci_pm_restore_noirq(struct device *dev)
@@ -852,13 +964,23 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
        /* register with core */
        error = driver_register(&drv->driver);
        if (error)
-               return error;
+               goto out;
 
        error = pci_create_newid_file(drv);
        if (error)
-               driver_unregister(&drv->driver);
+               goto out_newid;
 
+       error = pci_create_removeid_file(drv);
+       if (error)
+               goto out_removeid;
+out:
        return error;
+
+out_removeid:
+       pci_remove_newid_file(drv);
+out_newid:
+       driver_unregister(&drv->driver);
+       goto out;
 }
 
 /**
@@ -874,6 +996,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
+       pci_remove_removeid_file(drv);
        pci_remove_newid_file(drv);
        driver_unregister(&drv->driver);
        pci_free_dynids(drv);
@@ -973,6 +1096,7 @@ struct bus_type pci_bus_type = {
        .remove         = pci_device_remove,
        .shutdown       = pci_device_shutdown,
        .dev_attrs      = pci_dev_attrs,
+       .bus_attrs      = pci_bus_attrs,
        .pm             = PCI_PM_OPS_PTR,
 };
 
index dfc4e0ddf241b57a93c8e94d3f81a583a772074c..e9a8706a640182de0da0257cf2d82b590245eaf5 100644 (file)
@@ -219,6 +219,83 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+#ifdef CONFIG_HOTPLUG
+static DEFINE_MUTEX(pci_remove_rescan_mutex);
+static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
+                               size_t count)
+{
+       unsigned long val;
+       struct pci_bus *b = NULL;
+
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
+
+       if (val) {
+               mutex_lock(&pci_remove_rescan_mutex);
+               while ((b = pci_find_next_bus(b)) != NULL)
+                       pci_rescan_bus(b);
+               mutex_unlock(&pci_remove_rescan_mutex);
+       }
+       return count;
+}
+
+struct bus_attribute pci_bus_attrs[] = {
+       __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
+       __ATTR_NULL
+};
+
+static ssize_t
+dev_rescan_store(struct device *dev, struct device_attribute *attr,
+                const char *buf, size_t count)
+{
+       unsigned long val;
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
+
+       if (val) {
+               mutex_lock(&pci_remove_rescan_mutex);
+               pci_rescan_bus(pdev->bus);
+               mutex_unlock(&pci_remove_rescan_mutex);
+       }
+       return count;
+}
+
+static void remove_callback(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       mutex_lock(&pci_remove_rescan_mutex);
+       pci_remove_bus_device(pdev);
+       mutex_unlock(&pci_remove_rescan_mutex);
+}
+
+static ssize_t
+remove_store(struct device *dev, struct device_attribute *dummy,
+            const char *buf, size_t count)
+{
+       int ret = 0;
+       unsigned long val;
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
+
+       if (pci_is_root_bus(pdev->bus))
+               return -EBUSY;
+
+       /* An attribute cannot be unregistered by one of its own methods,
+        * so we have to use this roundabout approach.
+        */
+       if (val)
+               ret = device_schedule_callback(dev, remove_callback);
+       if (ret)
+               count = ret;
+       return count;
+}
+#endif
+
 struct device_attribute pci_dev_attrs[] = {
        __ATTR_RO(resource),
        __ATTR_RO(vendor),
@@ -237,9 +314,24 @@ struct device_attribute pci_dev_attrs[] = {
        __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
                broken_parity_status_show,broken_parity_status_store),
        __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
+#ifdef CONFIG_HOTPLUG
+       __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store),
+       __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store),
+#endif
        __ATTR_NULL,
 };
 
+static ssize_t
+boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return sprintf(buf, "%u\n",
+               !!(pdev->resource[PCI_ROM_RESOURCE].flags &
+                  IORESOURCE_ROM_SHADOW));
+}
+struct device_attribute vga_attr = __ATTR_RO(boot_vga);
+
 static ssize_t
 pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
                char *buf, loff_t off, size_t count)
@@ -492,6 +584,19 @@ pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr,
         return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
 }
 
+/**
+ * pci_adjust_legacy_attr - adjustment of legacy file attributes
+ * @b: bus to create files under
+ * @mmap_type: I/O port or memory
+ *
+ * Stub implementation. Can be overridden by arch if necessary.
+ */
+void __weak
+pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type)
+{
+       return;
+}
+
 /**
  * pci_create_legacy_files - create legacy I/O port and memory files
  * @b: bus to create files under
@@ -518,6 +623,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        b->legacy_io->read = pci_read_legacy_io;
        b->legacy_io->write = pci_write_legacy_io;
        b->legacy_io->mmap = pci_mmap_legacy_io;
+       pci_adjust_legacy_attr(b, pci_mmap_io);
        error = device_create_bin_file(&b->dev, b->legacy_io);
        if (error)
                goto legacy_io_err;
@@ -528,6 +634,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        b->legacy_mem->size = 1024*1024;
        b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
        b->legacy_mem->mmap = pci_mmap_legacy_mem;
+       pci_adjust_legacy_attr(b, pci_mmap_mem);
        error = device_create_bin_file(&b->dev, b->legacy_mem);
        if (error)
                goto legacy_mem_err;
@@ -719,8 +826,8 @@ static int pci_create_resource_files(struct pci_dev *pdev)
        return 0;
 }
 #else /* !HAVE_PCI_MMAP */
-static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
-static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
+int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
+void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
 #endif /* HAVE_PCI_MMAP */
 
 /**
@@ -884,18 +991,27 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
                pdev->rom_attr = attr;
        }
 
+       if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+               retval = device_create_file(&pdev->dev, &vga_attr);
+               if (retval)
+                       goto err_rom_file;
+       }
+
        /* add platform-specific attributes */
        retval = pcibios_add_platform_entries(pdev);
        if (retval)
-               goto err_rom_file;
+               goto err_vga_file;
 
        /* add sysfs entries for various capabilities */
        retval = pci_create_capabilities_sysfs(pdev);
        if (retval)
-               goto err_rom_file;
+               goto err_vga_file;
 
        return 0;
 
+err_vga_file:
+       if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+               device_remove_file(&pdev->dev, &vga_attr);
 err_rom_file:
        if (rom_size) {
                sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
index 6d6120007af4ed01d5fdc39331bff59349b1ed00..445fb6f7ea3fa01dc79beabc6d5685c48fa064fe 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
 #include <asm/dma.h>   /* isa_dma_bridge_buggy */
+#include <linux/device.h>
+#include <asm/setup.h>
 #include "pci.h"
 
 unsigned int pci_pm_d3_delay = PCI_PM_D3_WAIT;
@@ -426,7 +428,6 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
  *                           given PCI device
  * @dev: PCI device to handle.
  * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
- * @wait: If 'true', wait for the device to change its power state
  *
  * RETURN VALUE:
  * -EINVAL if the requested state is invalid.
@@ -435,12 +436,15 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
  * 0 if device already is in the requested state.
  * 0 if device's power state has been successfully changed.
  */
-static int
-pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
+static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
        u16 pmcsr;
        bool need_restore = false;
 
+       /* Check if we're already there */
+       if (dev->current_state == state)
+               return 0;
+
        if (!dev->pm_cap)
                return -EIO;
 
@@ -451,10 +455,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
         * Can enter D0 from any state, but if we can only go deeper 
         * to sleep if we're already in a low power state
         */
-       if (dev->current_state == state) {
-               /* we're already there */
-               return 0;
-       } else if (state != PCI_D0 && dev->current_state <= PCI_D3cold
+       if (state != PCI_D0 && dev->current_state <= PCI_D3cold
            && dev->current_state > state) {
                dev_err(&dev->dev, "invalid power transition "
                        "(from state %d to %d)\n", dev->current_state, state);
@@ -481,10 +482,8 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
                break;
        case PCI_UNKNOWN: /* Boot-up */
                if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
-                && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) {
+                && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
                        need_restore = true;
-                       wait = true;
-               }
                /* Fall-through: force to D0 */
        default:
                pmcsr = 0;
@@ -494,9 +493,6 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
        /* enter specified state */
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 
-       if (!wait)
-               return 0;
-
        /* Mandatory power management transition delays */
        /* see PCI PM 1.1 5.6.1 table 18 */
        if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
@@ -521,7 +517,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
        if (need_restore)
                pci_restore_bars(dev);
 
-       if (wait && dev->bus->self)
+       if (dev->bus->self)
                pcie_aspm_pm_state_change(dev->bus->self);
 
        return 0;
@@ -545,12 +541,59 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
        }
 }
 
+/**
+ * pci_platform_power_transition - Use platform to change device power state
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ */
+static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       int error;
+
+       if (platform_pci_power_manageable(dev)) {
+               error = platform_pci_set_power_state(dev, state);
+               if (!error)
+                       pci_update_current_state(dev, state);
+       } else {
+               error = -ENODEV;
+               /* Fall back to PCI_D0 if native PM is not supported */
+               pci_update_current_state(dev, PCI_D0);
+       }
+
+       return error;
+}
+
+/**
+ * __pci_start_power_transition - Start power transition of a PCI device
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ */
+static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       if (state == PCI_D0)
+               pci_platform_power_transition(dev, PCI_D0);
+}
+
+/**
+ * __pci_complete_power_transition - Complete power transition of a PCI device
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ *
+ * This function should not be called directly by device drivers.
+ */
+int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       return state > PCI_D0 ?
+                       pci_platform_power_transition(dev, state) : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(__pci_complete_power_transition);
+
 /**
  * pci_set_power_state - Set the power state of a PCI device
  * @dev: PCI device to handle.
  * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
  *
- * Transition a device to a new power state, using the platform formware and/or
+ * Transition a device to a new power state, using the platform firmware and/or
  * the device's PCI PM registers.
  *
  * RETURN VALUE:
@@ -577,30 +620,21 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                 */
                return 0;
 
-       if (state == PCI_D0 && platform_pci_power_manageable(dev)) {
-               /*
-                * Allow the platform to change the state, for example via ACPI
-                * _PR0, _PS0 and some such, but do not trust it.
-                */
-               int ret = platform_pci_set_power_state(dev, PCI_D0);
-               if (!ret)
-                       pci_update_current_state(dev, PCI_D0);
-       }
+       /* Check if we're already there */
+       if (dev->current_state == state)
+               return 0;
+
+       __pci_start_power_transition(dev, state);
+
        /* This device is quirked not to be put into D3, so
           don't put it in D3 */
        if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
                return 0;
 
-       error = pci_raw_set_power_state(dev, state, true);
+       error = pci_raw_set_power_state(dev, state);
 
-       if (state > PCI_D0 && platform_pci_power_manageable(dev)) {
-               /* Allow the platform to finalize the transition */
-               int ret = platform_pci_set_power_state(dev, state);
-               if (!ret) {
-                       pci_update_current_state(dev, state);
-                       error = 0;
-               }
-       }
+       if (!__pci_complete_power_transition(dev, state))
+               error = 0;
 
        return error;
 }
@@ -645,6 +679,8 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 
 EXPORT_SYMBOL(pci_choose_state);
 
+#define PCI_EXP_SAVE_REGS      7
+
 static int pci_save_pcie_state(struct pci_dev *dev)
 {
        int pos, i = 0;
@@ -657,7 +693,7 @@ static int pci_save_pcie_state(struct pci_dev *dev)
 
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
        if (!save_state) {
-               dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
+               dev_err(&dev->dev, "buffer not found in %s\n", __func__);
                return -ENOMEM;
        }
        cap = (u16 *)&save_state->data[0];
@@ -666,6 +702,9 @@ static int pci_save_pcie_state(struct pci_dev *dev)
        pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
        pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
        pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
+       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
+       pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
+       pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
 
        return 0;
 }
@@ -686,6 +725,9 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
        pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
        pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
        pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
+       pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
+       pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
+       pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
 }
 
 
@@ -700,7 +742,7 @@ static int pci_save_pcix_state(struct pci_dev *dev)
 
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
        if (!save_state) {
-               dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
+               dev_err(&dev->dev, "buffer not found in %s\n", __func__);
                return -ENOMEM;
        }
 
@@ -773,6 +815,7 @@ pci_restore_state(struct pci_dev *dev)
        }
        pci_restore_pcix_state(dev);
        pci_restore_msi_state(dev);
+       pci_restore_iov_state(dev);
 
        return 0;
 }
@@ -1231,7 +1274,7 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
        if (target_state == PCI_POWER_ERROR)
                return -EIO;
 
-       pci_enable_wake(dev, target_state, true);
+       pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
 
        error = pci_set_power_state(dev, target_state);
 
@@ -1369,7 +1412,8 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
 {
        int error;
 
-       error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP, 4 * sizeof(u16));
+       error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP,
+                                       PCI_EXP_SAVE_REGS * sizeof(u16));
        if (error)
                dev_err(&dev->dev,
                        "unable to preallocate PCI Express save buffer\n");
@@ -1380,50 +1424,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
                        "unable to preallocate PCI-X save buffer\n");
 }
 
-/**
- * pci_restore_standard_config - restore standard config registers of PCI device
- * @dev: PCI device to handle
- *
- * This function assumes that the device's configuration space is accessible.
- * If the device needs to be powered up, the function will wait for it to
- * change the state.
- */
-int pci_restore_standard_config(struct pci_dev *dev)
-{
-       pci_power_t prev_state;
-       int error;
-
-       pci_update_current_state(dev, PCI_D0);
-
-       prev_state = dev->current_state;
-       if (prev_state == PCI_D0)
-               goto Restore;
-
-       error = pci_raw_set_power_state(dev, PCI_D0, false);
-       if (error)
-               return error;
-
-       /*
-        * This assumes that we won't get a bus in B2 or B3 from the BIOS, but
-        * we've made this assumption forever and it appears to be universally
-        * satisfied.
-        */
-       switch(prev_state) {
-       case PCI_D3cold:
-       case PCI_D3hot:
-               mdelay(pci_pm_d3_delay);
-               break;
-       case PCI_D2:
-               udelay(PCI_PM_D2_DELAY);
-               break;
-       }
-
-       pci_update_current_state(dev, PCI_D0);
-
- Restore:
-       return dev->state_saved ? pci_restore_state(dev) : 0;
-}
-
 /**
  * pci_enable_ari - enable ARI forwarding if hardware support it
  * @dev: the PCI device
@@ -1484,7 +1484,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
        if (!pin)
                return -1;
 
-       while (dev->bus->self) {
+       while (dev->bus->parent) {
                pin = pci_swizzle_interrupt_pin(dev, pin);
                dev = dev->bus->self;
        }
@@ -1504,7 +1504,7 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
 {
        u8 pin = *pinp;
 
-       while (dev->bus->self) {
+       while (dev->bus->parent) {
                pin = pci_swizzle_interrupt_pin(dev, pin);
                dev = dev->bus->self;
        }
@@ -2028,18 +2028,24 @@ static int __pcie_flr(struct pci_dev *dev, int probe)
        pci_block_user_cfg_access(dev);
 
        /* Wait for Transaction Pending bit clean */
+       pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
+       if (!(status & PCI_EXP_DEVSTA_TRPND))
+               goto transaction_done;
+
        msleep(100);
        pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
-       if (status & PCI_EXP_DEVSTA_TRPND) {
-               dev_info(&dev->dev, "Busy after 100ms while trying to reset; "
+       if (!(status & PCI_EXP_DEVSTA_TRPND))
+               goto transaction_done;
+
+       dev_info(&dev->dev, "Busy after 100ms while trying to reset; "
                        "sleeping for 1 second\n");
-               ssleep(1);
-               pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
-               if (status & PCI_EXP_DEVSTA_TRPND)
-                       dev_info(&dev->dev, "Still busy after 1s; "
+       ssleep(1);
+       pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
+       if (status & PCI_EXP_DEVSTA_TRPND)
+               dev_info(&dev->dev, "Still busy after 1s; "
                                "proceeding with reset anyway\n");
-       }
 
+transaction_done:
        pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL,
                                PCI_EXP_DEVCTL_BCR_FLR);
        mdelay(100);
@@ -2066,18 +2072,24 @@ static int __pci_af_flr(struct pci_dev *dev, int probe)
        pci_block_user_cfg_access(dev);
 
        /* Wait for Transaction Pending bit clean */
+       pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
+       if (!(status & PCI_AF_STATUS_TP))
+               goto transaction_done;
+
        msleep(100);
        pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
-       if (status & PCI_AF_STATUS_TP) {
-               dev_info(&dev->dev, "Busy after 100ms while trying to"
-                               " reset; sleeping for 1 second\n");
-               ssleep(1);
-               pci_read_config_byte(dev,
-                               cappos + PCI_AF_STATUS, &status);
-               if (status & PCI_AF_STATUS_TP)
-                       dev_info(&dev->dev, "Still busy after 1s; "
-                                       "proceeding with reset anyway\n");
-       }
+       if (!(status & PCI_AF_STATUS_TP))
+               goto transaction_done;
+
+       dev_info(&dev->dev, "Busy after 100ms while trying to"
+                       " reset; sleeping for 1 second\n");
+       ssleep(1);
+       pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
+       if (status & PCI_AF_STATUS_TP)
+               dev_info(&dev->dev, "Still busy after 1s; "
+                               "proceeding with reset anyway\n");
+
+transaction_done:
        pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
        mdelay(100);
 
@@ -2346,18 +2358,140 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
  */
 int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
 {
+       int reg;
+
        if (resno < PCI_ROM_RESOURCE) {
                *type = pci_bar_unknown;
                return PCI_BASE_ADDRESS_0 + 4 * resno;
        } else if (resno == PCI_ROM_RESOURCE) {
                *type = pci_bar_mem32;
                return dev->rom_base_reg;
+       } else if (resno < PCI_BRIDGE_RESOURCES) {
+               /* device specific resource */
+               reg = pci_iov_resource_bar(dev, resno, type);
+               if (reg)
+                       return reg;
        }
 
        dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno);
        return 0;
 }
 
+#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
+static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
+spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * pci_specified_resource_alignment - get resource alignment specified by user.
+ * @dev: the PCI device to get
+ *
+ * RETURNS: Resource alignment if it is specified.
+ *          Zero if it is not specified.
+ */
+resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
+{
+       int seg, bus, slot, func, align_order, count;
+       resource_size_t align = 0;
+       char *p;
+
+       spin_lock(&resource_alignment_lock);
+       p = resource_alignment_param;
+       while (*p) {
+               count = 0;
+               if (sscanf(p, "%d%n", &align_order, &count) == 1 &&
+                                                       p[count] == '@') {
+                       p += count + 1;
+               } else {
+                       align_order = -1;
+               }
+               if (sscanf(p, "%x:%x:%x.%x%n",
+                       &seg, &bus, &slot, &func, &count) != 4) {
+                       seg = 0;
+                       if (sscanf(p, "%x:%x.%x%n",
+                                       &bus, &slot, &func, &count) != 3) {
+                               /* Invalid format */
+                               printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
+                                       p);
+                               break;
+                       }
+               }
+               p += count;
+               if (seg == pci_domain_nr(dev->bus) &&
+                       bus == dev->bus->number &&
+                       slot == PCI_SLOT(dev->devfn) &&
+                       func == PCI_FUNC(dev->devfn)) {
+                       if (align_order == -1) {
+                               align = PAGE_SIZE;
+                       } else {
+                               align = 1 << align_order;
+                       }
+                       /* Found */
+                       break;
+               }
+               if (*p != ';' && *p != ',') {
+                       /* End of param or invalid format */
+                       break;
+               }
+               p++;
+       }
+       spin_unlock(&resource_alignment_lock);
+       return align;
+}
+
+/**
+ * pci_is_reassigndev - check if specified PCI is target device to reassign
+ * @dev: the PCI device to check
+ *
+ * RETURNS: non-zero for PCI device is a target device to reassign,
+ *          or zero is not.
+ */
+int pci_is_reassigndev(struct pci_dev *dev)
+{
+       return (pci_specified_resource_alignment(dev) != 0);
+}
+
+ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
+{
+       if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
+               count = RESOURCE_ALIGNMENT_PARAM_SIZE - 1;
+       spin_lock(&resource_alignment_lock);
+       strncpy(resource_alignment_param, buf, count);
+       resource_alignment_param[count] = '\0';
+       spin_unlock(&resource_alignment_lock);
+       return count;
+}
+
+ssize_t pci_get_resource_alignment_param(char *buf, size_t size)
+{
+       size_t count;
+       spin_lock(&resource_alignment_lock);
+       count = snprintf(buf, size, "%s", resource_alignment_param);
+       spin_unlock(&resource_alignment_lock);
+       return count;
+}
+
+static ssize_t pci_resource_alignment_show(struct bus_type *bus, char *buf)
+{
+       return pci_get_resource_alignment_param(buf, PAGE_SIZE);
+}
+
+static ssize_t pci_resource_alignment_store(struct bus_type *bus,
+                                       const char *buf, size_t count)
+{
+       return pci_set_resource_alignment_param(buf, count);
+}
+
+BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show,
+                                       pci_resource_alignment_store);
+
+static int __init pci_resource_alignment_sysfs_init(void)
+{
+       return bus_create_file(&pci_bus_type,
+                                       &bus_attr_resource_alignment);
+}
+
+late_initcall(pci_resource_alignment_sysfs_init);
+
 static void __devinit pci_no_domains(void)
 {
 #ifdef CONFIG_PCI_DOMAINS
@@ -2406,6 +2540,9 @@ static int __init pci_setup(char *str)
                                pci_cardbus_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "cbmemsize=", 10)) {
                                pci_cardbus_mem_size = memparse(str + 10, &str);
+                       } else if (!strncmp(str, "resource_alignment=", 19)) {
+                               pci_set_resource_alignment_param(str + 19,
+                                                       strlen(str + 19));
                        } else {
                                printk(KERN_ERR "PCI: Unknown option `%s'\n",
                                                str);
index 07c0aa5275e6edf33ab1914761d6acb3113f1741..d03f6b99f292cbe36e619ad1c599aadd75bb39dd 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef DRIVERS_PCI_H
 #define DRIVERS_PCI_H
 
+#include <linux/workqueue.h>
+
 #define PCI_CFG_SPACE_SIZE     256
 #define PCI_CFG_SPACE_EXP_SIZE 4096
 
@@ -49,7 +51,6 @@ extern void pci_disable_enabled_device(struct pci_dev *dev);
 extern void pci_pm_init(struct pci_dev *dev);
 extern void platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
-extern int pci_restore_standard_config(struct pci_dev *dev);
 
 static inline bool pci_is_bridge(struct pci_dev *pci_dev)
 {
@@ -136,6 +137,12 @@ extern int pcie_mch_quirk;
 extern struct device_attribute pci_dev_attrs[];
 extern struct device_attribute dev_attr_cpuaffinity;
 extern struct device_attribute dev_attr_cpulistaffinity;
+#ifdef CONFIG_HOTPLUG
+extern struct bus_attribute pci_bus_attrs[];
+#else
+#define pci_bus_attrs  NULL
+#endif
+
 
 /**
  * pci_match_one_device - Tell if a PCI device structure has a matching
@@ -178,6 +185,7 @@ enum pci_bar_type {
        pci_bar_mem64,          /* A 64-bit memory BAR */
 };
 
+extern int pci_setup_device(struct pci_dev *dev);
 extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                                struct resource *res, unsigned int reg);
 extern int pci_resource_bar(struct pci_dev *dev, int resno,
@@ -195,4 +203,60 @@ static inline int pci_ari_enabled(struct pci_bus *bus)
        return bus->self && bus->self->ari_enabled;
 }
 
+#ifdef CONFIG_PCI_QUIRKS
+extern int pci_is_reassigndev(struct pci_dev *dev);
+resource_size_t pci_specified_resource_alignment(struct pci_dev *dev);
+extern void pci_disable_bridge_window(struct pci_dev *dev);
+#endif
+
+/* Single Root I/O Virtualization */
+struct pci_sriov {
+       int pos;                /* capability position */
+       int nres;               /* number of resources */
+       u32 cap;                /* SR-IOV Capabilities */
+       u16 ctrl;               /* SR-IOV Control */
+       u16 total;              /* total VFs associated with the PF */
+       u16 initial;            /* initial VFs associated with the PF */
+       u16 nr_virtfn;          /* number of VFs available */
+       u16 offset;             /* first VF Routing ID offset */
+       u16 stride;             /* following VF stride */
+       u32 pgsz;               /* page size for BAR alignment */
+       u8 link;                /* Function Dependency Link */
+       struct pci_dev *dev;    /* lowest numbered PF */
+       struct pci_dev *self;   /* this PF */
+       struct mutex lock;      /* lock for VF bus */
+       struct work_struct mtask; /* VF Migration task */
+       u8 __iomem *mstate;     /* VF Migration State Array */
+};
+
+#ifdef CONFIG_PCI_IOV
+extern int pci_iov_init(struct pci_dev *dev);
+extern void pci_iov_release(struct pci_dev *dev);
+extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+                               enum pci_bar_type *type);
+extern void pci_restore_iov_state(struct pci_dev *dev);
+extern int pci_iov_bus_range(struct pci_bus *bus);
+#else
+static inline int pci_iov_init(struct pci_dev *dev)
+{
+       return -ENODEV;
+}
+static inline void pci_iov_release(struct pci_dev *dev)
+
+{
+}
+static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+                                      enum pci_bar_type *type)
+{
+       return 0;
+}
+static inline void pci_restore_iov_state(struct pci_dev *dev)
+{
+}
+static inline int pci_iov_bus_range(struct pci_bus *bus)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI_IOV */
+
 #endif /* DRIVERS_PCI_H */
index e390707661dde323e8beafc4bf96e651a843dd06..32ade5af927e21c11e008be87ae7380c64a1932a 100644 (file)
@@ -38,30 +38,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static int __devinit aer_probe (struct pcie_device *dev,
-       const struct pcie_port_service_id *id );
+static int __devinit aer_probe (struct pcie_device *dev);
 static void aer_remove(struct pcie_device *dev);
-static int aer_suspend(struct pcie_device *dev, pm_message_t state)
-{return 0;}
-static int aer_resume(struct pcie_device *dev) {return 0;}
 static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
        enum pci_channel_state error);
 static void aer_error_resume(struct pci_dev *dev);
 static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
 
-/*
- * PCI Express bus's AER Root service driver data structure
- */
-static struct pcie_port_service_id aer_id[] = {
-       {
-       .vendor         = PCI_ANY_ID,
-       .device         = PCI_ANY_ID,
-       .port_type      = PCIE_RC_PORT,
-       .service_type   = PCIE_PORT_SERVICE_AER,
-       },
-       { /* end: all zeroes */ }
-};
-
 static struct pci_error_handlers aer_error_handlers = {
        .error_detected = aer_error_detected,
        .resume = aer_error_resume,
@@ -69,14 +52,12 @@ static struct pci_error_handlers aer_error_handlers = {
 
 static struct pcie_port_service_driver aerdriver = {
        .name           = "aer",
-       .id_table       = &aer_id[0],
+       .port_type      = PCIE_ANY_PORT,
+       .service        = PCIE_PORT_SERVICE_AER,
 
        .probe          = aer_probe,
        .remove         = aer_remove,
 
-       .suspend        = aer_suspend,
-       .resume         = aer_resume,
-
        .err_handler    = &aer_error_handlers,
 
        .reset_link     = aer_root_reset,
@@ -207,8 +188,7 @@ static void aer_remove(struct pcie_device *dev)
  *
  * Invoked when PCI Express bus loads AER service driver.
  **/
-static int __devinit aer_probe (struct pcie_device *dev,
-                               const struct pcie_port_service_id *id )
+static int __devinit aer_probe (struct pcie_device *dev)
 {
        int status;
        struct aer_rpc *rpc;
index ebce26c37049ad5ccc0483da56d3df682f865414..8edb2f300e8f85cc91c31ad8f6c208b6363cb118 100644 (file)
@@ -38,7 +38,7 @@ int aer_osc_setup(struct pcie_device *pciedev)
 
        handle = acpi_find_root_bridge_handle(pdev);
        if (handle) {
-               status = pci_osc_control_set(handle,
+               status = acpi_pci_osc_control_set(handle,
                                        OSC_PCI_EXPRESS_AER_CONTROL |
                                        OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
        }
index 38257500738223486758e337cb49d7184ddcef5a..307452f30035562cea6f290fb0fa1bac34679893 100644 (file)
@@ -351,21 +351,21 @@ static int find_aer_service_iter(struct device *device, void *data)
 {
        struct device_driver *driver;
        struct pcie_port_service_driver *service_driver;
-       struct pcie_device *pcie_dev;
        struct find_aer_service_data *result;
 
        result = (struct find_aer_service_data *) data;
 
        if (device->bus == &pcie_port_bus_type) {
-               pcie_dev = to_pcie_device(device);
-               if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT)
+               struct pcie_port_data *port_data;
+
+               port_data = pci_get_drvdata(to_pcie_device(device)->port);
+               if (port_data->port_type == PCIE_SW_DOWNSTREAM_PORT)
                        result->is_downstream = 1;
 
                driver = device->driver;
                if (driver) {
                        service_driver = to_service_driver(driver);
-                       if (service_driver->id_table->service_type ==
-                                       PCIE_PORT_SERVICE_AER) {
+                       if (service_driver->service == PCIE_PORT_SERVICE_AER) {
                                result->aer_driver = service_driver;
                                return 1;
                        }
index 2529f3f2ea5a246ad3134307eb0e50d4c73d00a6..17ad53868f9f1566b0628061a4359cb15d1ae472 100644 (file)
 #define PCIE_CAPABILITIES_REG          0x2
 #define PCIE_SLOT_CAPABILITIES_REG     0x14
 #define PCIE_PORT_DEVICE_MAXSERVICES   4
+#define PCIE_PORT_MSI_VECTOR_MASK      0x1f
+/*
+ * According to the PCI Express Base Specification 2.0, the indices of the MSI-X
+ * table entires used by port services must not exceed 31
+ */
+#define PCIE_PORT_MAX_MSIX_ENTRIES     32
 
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
-struct pcie_port_device_ext {
-       int interrupt_mode;     /* [0:INTx | 1:MSI | 2:MSI-X] */
-};
-
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_probe(struct pci_dev *dev);
 extern int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
-extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state);
-extern int pcie_port_device_resume(struct pci_dev *dev);
+extern int pcie_port_device_suspend(struct device *dev);
+extern int pcie_port_device_resume(struct device *dev);
 #endif
 extern void pcie_port_device_remove(struct pci_dev *dev);
 extern int __must_check pcie_port_bus_register(void);
index eec89b767f9f828d3389ef2584ad5fd103388869..ef3a4eeaebb45077005f4948b458e3b241ba1f38 100644 (file)
@@ -26,20 +26,22 @@ EXPORT_SYMBOL_GPL(pcie_port_bus_type);
 static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct pcie_device *pciedev;
+       struct pcie_port_data *port_data;
        struct pcie_port_service_driver *driver;
 
        if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type)
                return 0;
-       
+
        pciedev = to_pcie_device(dev);
        driver = to_service_driver(drv);
-       if (   (driver->id_table->vendor != PCI_ANY_ID && 
-               driver->id_table->vendor != pciedev->id.vendor) ||
-              (driver->id_table->device != PCI_ANY_ID &&
-               driver->id_table->device != pciedev->id.device) ||      
-              (driver->id_table->port_type != PCIE_ANY_PORT &&
-               driver->id_table->port_type != pciedev->id.port_type) ||
-               driver->id_table->service_type != pciedev->id.service_type )
+
+       if (driver->service != pciedev->service)
+               return 0;
+
+       port_data = pci_get_drvdata(pciedev->port);
+
+       if (driver->port_type != PCIE_ANY_PORT
+            && driver->port_type != port_data->port_type)
                return 0;
 
        return 1;
index 8b3f8c18032f3a295c5af3ab7ab09ca0e11b2fc4..e39982503863e4a1539d4f1f968a9dbf47bc3242 100644 (file)
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
 
+#include "../pci.h"
 #include "portdrv.h"
 
-extern int pcie_mch_quirk;     /* MSI-quirk Indicator */
-
 /**
  * release_pcie_device - free PCI Express port service device structure
  * @dev: Port service device to release
@@ -31,26 +30,150 @@ static void release_pcie_device(struct device *dev)
        kfree(to_pcie_device(dev));                     
 }
 
-static int is_msi_quirked(struct pci_dev *dev)
+/**
+ * pcie_port_msix_add_entry - add entry to given array of MSI-X entries
+ * @entries: Array of MSI-X entries
+ * @new_entry: Index of the entry to add to the array
+ * @nr_entries: Number of entries aleady in the array
+ *
+ * Return value: Position of the added entry in the array
+ */
+static int pcie_port_msix_add_entry(
+       struct msix_entry *entries, int new_entry, int nr_entries)
 {
-       int port_type, quirk = 0;
+       int j;
+
+       for (j = 0; j < nr_entries; j++)
+               if (entries[j].entry == new_entry)
+                       return j;
+
+       entries[j].entry = new_entry;
+       return j;
+}
+
+/**
+ * pcie_port_enable_msix - try to set up MSI-X as interrupt mode for given port
+ * @dev: PCI Express port to handle
+ * @vectors: Array of interrupt vectors to populate
+ * @mask: Bitmask of port capabilities returned by get_port_device_capability()
+ *
+ * Return value: 0 on success, error code on failure
+ */
+static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
+{
+       struct msix_entry *msix_entries;
+       int idx[PCIE_PORT_DEVICE_MAXSERVICES];
+       int nr_entries, status, pos, i, nvec;
        u16 reg16;
+       u32 reg32;
 
-       pci_read_config_word(dev, 
-               pci_find_capability(dev, PCI_CAP_ID_EXP) + 
-               PCIE_CAPABILITIES_REG, &reg16);
-       port_type = (reg16 >> 4) & PORT_TYPE_MASK;
-       switch(port_type) {
-       case PCIE_RC_PORT:
-               if (pcie_mch_quirk == 1)
-                       quirk = 1;
-               break;
-       case PCIE_SW_UPSTREAM_PORT:
-       case PCIE_SW_DOWNSTREAM_PORT:
-       default:
-               break;  
+       nr_entries = pci_msix_table_size(dev);
+       if (!nr_entries)
+               return -EINVAL;
+       if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES)
+               nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES;
+
+       msix_entries = kzalloc(sizeof(*msix_entries) * nr_entries, GFP_KERNEL);
+       if (!msix_entries)
+               return -ENOMEM;
+
+       /*
+        * Allocate as many entries as the port wants, so that we can check
+        * which of them will be useful.  Moreover, if nr_entries is correctly
+        * equal to the number of entries this port actually uses, we'll happily
+        * go through without any tricks.
+        */
+       for (i = 0; i < nr_entries; i++)
+               msix_entries[i].entry = i;
+
+       status = pci_enable_msix(dev, msix_entries, nr_entries);
+       if (status)
+               goto Exit;
+
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               idx[i] = -1;
+       status = -EIO;
+       nvec = 0;
+
+       if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
+               int entry;
+
+               /*
+                * The code below follows the PCI Express Base Specification 2.0
+                * stating in Section 6.1.6 that "PME and Hot-Plug Event
+                * interrupts (when both are implemented) always share the same
+                * MSI or MSI-X vector, as indicated by the Interrupt Message
+                * Number field in the PCI Express Capabilities register", where
+                * according to Section 7.8.2 of the specification "For MSI-X,
+                * the value in this field indicates which MSI-X Table entry is
+                * used to generate the interrupt message."
+                */
+               pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+               pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg16);
+               entry = (reg16 >> 9) & PCIE_PORT_MSI_VECTOR_MASK;
+               if (entry >= nr_entries)
+                       goto Error;
+
+               i = pcie_port_msix_add_entry(msix_entries, entry, nvec);
+               if (i == nvec)
+                       nvec++;
+
+               idx[PCIE_PORT_SERVICE_PME_SHIFT] = i;
+               idx[PCIE_PORT_SERVICE_HP_SHIFT] = i;
+       }
+
+       if (mask & PCIE_PORT_SERVICE_AER) {
+               int entry;
+
+               /*
+                * The code below follows Section 7.10.10 of the PCI Express
+                * Base Specification 2.0 stating that bits 31-27 of the Root
+                * Error Status Register contain a value indicating which of the
+                * MSI/MSI-X vectors assigned to the port is going to be used
+                * for AER, where "For MSI-X, the value in this register
+                * indicates which MSI-X Table entry is used to generate the
+                * interrupt message."
+                */
+               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
+               entry = reg32 >> 27;
+               if (entry >= nr_entries)
+                       goto Error;
+
+               i = pcie_port_msix_add_entry(msix_entries, entry, nvec);
+               if (i == nvec)
+                       nvec++;
+
+               idx[PCIE_PORT_SERVICE_AER_SHIFT] = i;
        }
-       return quirk;
+
+       /*
+        * If nvec is equal to the allocated number of entries, we can just use
+        * what we have.  Otherwise, the port has some extra entries not for the
+        * services we know and we need to work around that.
+        */
+       if (nvec == nr_entries) {
+               status = 0;
+       } else {
+               /* Drop the temporary MSI-X setup */
+               pci_disable_msix(dev);
+
+               /* Now allocate the MSI-X vectors for real */
+               status = pci_enable_msix(dev, msix_entries, nvec);
+               if (status)
+                       goto Exit;
+       }
+
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               vectors[i] = idx[i] >= 0 ? msix_entries[idx[i]].vector : -1;
+
+ Exit:
+       kfree(msix_entries);
+       return status;
+
+ Error:
+       pci_disable_msix(dev);
+       goto Exit;
 }
 
 /**
@@ -64,47 +187,32 @@ static int is_msi_quirked(struct pci_dev *dev)
  */
 static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
 {
-       int i, pos, nvec, status = -EINVAL;
-       int interrupt_mode = PCIE_PORT_INTx_MODE;
+       struct pcie_port_data *port_data = pci_get_drvdata(dev);
+       int irq, interrupt_mode = PCIE_PORT_NO_IRQ;
+       int i;
 
-       /* Set INTx as default */
-       for (i = 0, nvec = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
-               if (mask & (1 << i)) 
-                       nvec++;
-               vectors[i] = dev->irq;
-       }
-       
        /* Check MSI quirk */
-       if (is_msi_quirked(dev))
-               return interrupt_mode;
-
-       /* Select MSI-X over MSI if supported */                
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] = 
-                       {{0, 0}, {0, 1}, {0, 2}, {0, 3}};
-               status = pci_enable_msix(dev, msix_entries, nvec);
-               if (!status) {
-                       int j = 0;
-
-                       interrupt_mode = PCIE_PORT_MSIX_MODE;
-                       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
-                               if (mask & (1 << i)) 
-                                       vectors[i] = msix_entries[j++].vector;
-                       }
-               }
-       } 
-       if (status) {
-               pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-               if (pos) {
-                       status = pci_enable_msi(dev);
-                       if (!status) {
-                               interrupt_mode = PCIE_PORT_MSI_MODE;
-                               for (i = 0;i < PCIE_PORT_DEVICE_MAXSERVICES;i++)
-                                       vectors[i] = dev->irq;
-                       }
-               }
-       } 
+       if (port_data->port_type == PCIE_RC_PORT && pcie_mch_quirk)
+               goto Fallback;
+
+       /* Try to use MSI-X if supported */
+       if (!pcie_port_enable_msix(dev, vectors, mask))
+               return PCIE_PORT_MSIX_MODE;
+
+       /* We're not going to use MSI-X, so try MSI and fall back to INTx */
+       if (!pci_enable_msi(dev))
+               interrupt_mode = PCIE_PORT_MSI_MODE;
+
+ Fallback:
+       if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin)
+               interrupt_mode = PCIE_PORT_INTx_MODE;
+
+       irq = interrupt_mode != PCIE_PORT_NO_IRQ ? dev->irq : -1;
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               vectors[i] = irq;
+
+       vectors[PCIE_PORT_SERVICE_VC_SHIFT] = -1;
+
        return interrupt_mode;
 }
 
@@ -132,13 +240,11 @@ static int get_port_device_capability(struct pci_dev *dev)
                        pos + PCIE_SLOT_CAPABILITIES_REG, &reg32);
                if (reg32 & SLOT_HP_CAPABLE_MASK)
                        services |= PCIE_PORT_SERVICE_HP;
-       } 
-       /* PME Capable - root port capability */
-       if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT)
-               services |= PCIE_PORT_SERVICE_PME;
-
+       }
+       /* AER capable */
        if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
                services |= PCIE_PORT_SERVICE_AER;
+       /* VC support */
        if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
                services |= PCIE_PORT_SERVICE_VC;
 
@@ -152,20 +258,17 @@ static int get_port_device_capability(struct pci_dev *dev)
  * @port_type: Type of the port
  * @service_type: Type of service to associate with the service device
  * @irq: Interrupt vector to associate with the service device
- * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
  */
 static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, 
-       int port_type, int service_type, int irq, int irq_mode)
+       int service_type, int irq)
 {
+       struct pcie_port_data *port_data = pci_get_drvdata(parent);
        struct device *device;
+       int port_type = port_data->port_type;
 
        dev->port = parent;
-       dev->interrupt_mode = irq_mode;
        dev->irq = irq;
-       dev->id.vendor = parent->vendor;
-       dev->id.device = parent->device;
-       dev->id.port_type = port_type;
-       dev->id.service_type = (1 << service_type);
+       dev->service = service_type;
 
        /* Initialize generic device interface */
        device = &dev->device;
@@ -185,10 +288,9 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
  * @port_type: Type of the port
  * @service_type: Type of service to associate with the service device
  * @irq: Interrupt vector to associate with the service device
- * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
  */
 static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
-       int port_type, int service_type, int irq, int irq_mode)
+       int service_type, int irq)
 {
        struct pcie_device *device;
 
@@ -196,7 +298,7 @@ static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
        if (!device)
                return NULL;
 
-       pcie_device_init(parent, device, port_type, service_type, irq,irq_mode);
+       pcie_device_init(parent, device, service_type, irq);
        return device;
 }
 
@@ -230,63 +332,90 @@ int pcie_port_device_probe(struct pci_dev *dev)
  */
 int pcie_port_device_register(struct pci_dev *dev)
 {
-       struct pcie_port_device_ext *p_ext;
-       int status, type, capabilities, irq_mode, i;
+       struct pcie_port_data *port_data;
+       int status, capabilities, irq_mode, i, nr_serv;
        int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
        u16 reg16;
 
-       /* Allocate port device extension */
-       if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL)))
+       port_data = kzalloc(sizeof(*port_data), GFP_KERNEL);
+       if (!port_data)
                return -ENOMEM;
-
-       pci_set_drvdata(dev, p_ext);
+       pci_set_drvdata(dev, port_data);
 
        /* Get port type */
        pci_read_config_word(dev,
                pci_find_capability(dev, PCI_CAP_ID_EXP) +
                PCIE_CAPABILITIES_REG, &reg16);
-       type = (reg16 >> 4) & PORT_TYPE_MASK;
+       port_data->port_type = (reg16 >> 4) & PORT_TYPE_MASK;
 
-       /* Now get port services */
        capabilities = get_port_device_capability(dev);
+       /* Root ports are capable of generating PME too */
+       if (port_data->port_type == PCIE_RC_PORT)
+               capabilities |= PCIE_PORT_SERVICE_PME;
+
        irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
-       p_ext->interrupt_mode = irq_mode;
+       if (irq_mode == PCIE_PORT_NO_IRQ) {
+               /*
+                * Don't use service devices that require interrupts if there is
+                * no way to generate them.
+                */
+               if (!(capabilities & PCIE_PORT_SERVICE_VC)) {
+                       status = -ENODEV;
+                       goto Error;
+               }
+               capabilities = PCIE_PORT_SERVICE_VC;
+       }
+       port_data->port_irq_mode = irq_mode;
+
+       status = pci_enable_device(dev);
+       if (status)
+               goto Error;
+       pci_set_master(dev);
 
        /* Allocate child services if any */
-       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
+       for (i = 0, nr_serv = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
                struct pcie_device *child;
+               int service = 1 << i;
+
+               if (!(capabilities & service))
+                       continue;
 
-               if (capabilities & (1 << i)) {
-                       child = alloc_pcie_device(
-                               dev,            /* parent */
-                               type,           /* port type */
-                               i,              /* service type */
-                               vectors[i],     /* irq */
-                               irq_mode        /* interrupt mode */);
-                       if (child) {
-                               status = device_register(&child->device);
-                               if (status) {
-                                       kfree(child);
-                                       continue;
-                               }
-                               get_device(&child->device);
-                       }
+               child = alloc_pcie_device(dev, service, vectors[i]);
+               if (!child)
+                       continue;
+
+               status = device_register(&child->device);
+               if (status) {
+                       kfree(child);
+                       continue;
                }
+
+               get_device(&child->device);
+               nr_serv++;
+       }
+       if (!nr_serv) {
+               pci_disable_device(dev);
+               status = -ENODEV;
+               goto Error;
        }
+
        return 0;
+
+ Error:
+       kfree(port_data);
+       return status;
 }
 
 #ifdef CONFIG_PM
 static int suspend_iter(struct device *dev, void *data)
 {
        struct pcie_port_service_driver *service_driver;
-       pm_message_t state = * (pm_message_t *) data;
 
        if ((dev->bus == &pcie_port_bus_type) &&
            (dev->driver)) {
                service_driver = to_service_driver(dev->driver);
                if (service_driver->suspend)
-                       service_driver->suspend(to_pcie_device(dev), state);
+                       service_driver->suspend(to_pcie_device(dev));
        }
        return 0;
 }
@@ -294,11 +423,10 @@ static int suspend_iter(struct device *dev, void *data)
 /**
  * pcie_port_device_suspend - suspend port services associated with a PCIe port
  * @dev: PCI Express port to handle
- * @state: Representation of system power management transition in progress
  */
-int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
+int pcie_port_device_suspend(struct device *dev)
 {
-       return device_for_each_child(&dev->dev, &state, suspend_iter);
+       return device_for_each_child(dev, NULL, suspend_iter);
 }
 
 static int resume_iter(struct device *dev, void *data)
@@ -318,24 +446,17 @@ static int resume_iter(struct device *dev, void *data)
  * pcie_port_device_suspend - resume port services associated with a PCIe port
  * @dev: PCI Express port to handle
  */
-int pcie_port_device_resume(struct pci_dev *dev)
+int pcie_port_device_resume(struct device *dev)
 {
-       return device_for_each_child(&dev->dev, NULL, resume_iter);
+       return device_for_each_child(dev, NULL, resume_iter);
 }
-#endif
+#endif /* PM */
 
 static int remove_iter(struct device *dev, void *data)
 {
-       struct pcie_port_service_driver *service_driver;
-
        if (dev->bus == &pcie_port_bus_type) {
-               if (dev->driver) {
-                       service_driver = to_service_driver(dev->driver);
-                       if (service_driver->remove)
-                               service_driver->remove(to_pcie_device(dev));
-               }
-               *(unsigned long*)data = (unsigned long)dev;
-               return 1;
+               put_device(dev);
+               device_unregister(dev);
        }
        return 0;
 }
@@ -349,25 +470,21 @@ static int remove_iter(struct device *dev, void *data)
  */
 void pcie_port_device_remove(struct pci_dev *dev)
 {
-       struct device *device;
-       unsigned long device_addr;
-       int interrupt_mode = PCIE_PORT_INTx_MODE;
-       int status;
+       struct pcie_port_data *port_data = pci_get_drvdata(dev);
 
-       do {
-               status = device_for_each_child(&dev->dev, &device_addr, remove_iter);
-               if (status) {
-                       device = (struct device*)device_addr;
-                       interrupt_mode = (to_pcie_device(device))->interrupt_mode;
-                       put_device(device);
-                       device_unregister(device);
-               }
-       } while (status);
-       /* Switch to INTx by default if MSI enabled */
-       if (interrupt_mode == PCIE_PORT_MSIX_MODE)
+       device_for_each_child(&dev->dev, NULL, remove_iter);
+       pci_disable_device(dev);
+
+       switch (port_data->port_irq_mode) {
+       case PCIE_PORT_MSIX_MODE:
                pci_disable_msix(dev);
-       else if (interrupt_mode == PCIE_PORT_MSI_MODE)
+               break;
+       case PCIE_PORT_MSI_MODE:
                pci_disable_msi(dev);
+               break;
+       }
+
+       kfree(port_data);
 }
 
 /**
@@ -392,7 +509,7 @@ static int pcie_port_probe_service(struct device *dev)
                return -ENODEV;
 
        pciedev = to_pcie_device(dev);
-       status = driver->probe(pciedev, driver->id_table);
+       status = driver->probe(pciedev);
        if (!status) {
                dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n",
                        driver->name);
index 5ea566e20b375410ed2cc5b19d30d8eec8992fd8..b924e2463f85e0dd7f8f8e313071e9340b579048 100644 (file)
@@ -32,11 +32,6 @@ MODULE_LICENSE("GPL");
 /* global data */
 static const char device_name[] = "pcieport-driver";
 
-static int pcie_portdrv_save_config(struct pci_dev *dev)
-{
-       return pci_save_state(dev);
-}
-
 static int pcie_portdrv_restore_config(struct pci_dev *dev)
 {
        int retval;
@@ -49,21 +44,21 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
 }
 
 #ifdef CONFIG_PM
-static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
-{
-       return pcie_port_device_suspend(dev, state);
+static struct dev_pm_ops pcie_portdrv_pm_ops = {
+       .suspend        = pcie_port_device_suspend,
+       .resume         = pcie_port_device_resume,
+       .freeze         = pcie_port_device_suspend,
+       .thaw           = pcie_port_device_resume,
+       .poweroff       = pcie_port_device_suspend,
+       .restore        = pcie_port_device_resume,
+};
 
-}
+#define PCIE_PORTDRV_PM_OPS    (&pcie_portdrv_pm_ops)
 
-static int pcie_portdrv_resume(struct pci_dev *dev)
-{
-       pci_set_master(dev);
-       return pcie_port_device_resume(dev);
-}
-#else
-#define pcie_portdrv_suspend NULL
-#define pcie_portdrv_resume NULL
-#endif
+#else /* !PM */
+
+#define PCIE_PORTDRV_PM_OPS    NULL
+#endif /* !PM */
 
 /*
  * pcie_portdrv_probe - Probe PCI-Express port devices
@@ -82,20 +77,15 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
        if (status)
                return status;
 
-       if (pci_enable_device(dev) < 0) 
-               return -ENODEV;
-       
-       pci_set_master(dev);
         if (!dev->irq && dev->pin) {
                dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; "
                         "check vendor BIOS\n", dev->vendor, dev->device);
        }
-       if (pcie_port_device_register(dev)) {
-               pci_disable_device(dev);
-               return -ENOMEM;
-       }
+       status = pcie_port_device_register(dev);
+       if (status)
+               return status;
 
-       pcie_portdrv_save_config(dev);
+       pci_save_state(dev);
 
        return 0;
 }
@@ -104,7 +94,6 @@ static void pcie_portdrv_remove (struct pci_dev *dev)
 {
        pcie_port_device_remove(dev);
        pci_disable_device(dev);
-       kfree(pci_get_drvdata(dev));
 }
 
 static int error_detected_iter(struct device *device, void *data)
@@ -278,10 +267,9 @@ static struct pci_driver pcie_portdriver = {
        .probe          = pcie_portdrv_probe,
        .remove         = pcie_portdrv_remove,
 
-       .suspend        = pcie_portdrv_suspend,
-       .resume         = pcie_portdrv_resume,
-
        .err_handler    = &pcie_portdrv_err_handler,
+
+       .driver.pm      = PCIE_PORTDRV_PM_OPS,
 };
 
 static int __init pcie_portdrv_init(void)
index 55ec44a27e89e65e8d01c750ebca0f76bcf4e152..e2f3dd098cfa16c710814dcffbb1f294f7197b0c 100644 (file)
@@ -287,7 +287,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
        struct resource *res;
        int i;
 
-       if (!dev)               /* It's a host bus, nothing to read */
+       if (!child->parent)     /* It's a host bus, nothing to read */
                return;
 
        if (dev->transparent) {
@@ -511,21 +511,21 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 
                /*
                 * If we already got to this bus through a different bridge,
-                * ignore it.  This can happen with the i450NX chipset.
+                * don't re-add it. This can happen with the i450NX chipset.
+                *
+                * However, we continue to descend down the hierarchy and
+                * scan remaining child buses.
                 */
-               if (pci_find_bus(pci_domain_nr(bus), busnr)) {
-                       dev_info(&dev->dev, "bus %04x:%02x already known\n",
-                                pci_domain_nr(bus), busnr);
-                       goto out;
+               child = pci_find_bus(pci_domain_nr(bus), busnr);
+               if (!child) {
+                       child = pci_add_new_bus(bus, dev, busnr);
+                       if (!child)
+                               goto out;
+                       child->primary = buses & 0xFF;
+                       child->subordinate = (buses >> 16) & 0xFF;
+                       child->bridge_ctl = bctl;
                }
 
-               child = pci_add_new_bus(bus, dev, busnr);
-               if (!child)
-                       goto out;
-               child->primary = buses & 0xFF;
-               child->subordinate = (buses >> 16) & 0xFF;
-               child->bridge_ctl = bctl;
-
                cmax = pci_scan_child_bus(child);
                if (cmax > max)
                        max = cmax;
@@ -674,6 +674,19 @@ static void pci_read_irq(struct pci_dev *dev)
        dev->irq = irq;
 }
 
+static void set_pcie_port_type(struct pci_dev *pdev)
+{
+       int pos;
+       u16 reg16;
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       if (!pos)
+               return;
+       pdev->is_pcie = 1;
+       pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
+       pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
 #define LEGACY_IO_RESOURCE     (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
 
 /**
@@ -683,12 +696,33 @@ static void pci_read_irq(struct pci_dev *dev)
  * Initialize the device structure with information about the device's 
  * vendor,class,memory and IO-space addresses,IRQ lines etc.
  * Called at initialisation of the PCI subsystem and by CardBus services.
- * Returns 0 on success and -1 if unknown type of device (not normal, bridge
- * or CardBus).
+ * Returns 0 on success and negative if unknown type of device (not normal,
+ * bridge or CardBus).
  */
-static int pci_setup_device(struct pci_dev * dev)
+int pci_setup_device(struct pci_dev *dev)
 {
        u32 class;
+       u8 hdr_type;
+       struct pci_slot *slot;
+
+       if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
+               return -EIO;
+
+       dev->sysdata = dev->bus->sysdata;
+       dev->dev.parent = dev->bus->bridge;
+       dev->dev.bus = &pci_bus_type;
+       dev->hdr_type = hdr_type & 0x7f;
+       dev->multifunction = !!(hdr_type & 0x80);
+       dev->error_state = pci_channel_io_normal;
+       set_pcie_port_type(dev);
+
+       list_for_each_entry(slot, &dev->bus->slots, list)
+               if (PCI_SLOT(dev->devfn) == slot->number)
+                       dev->slot = slot;
+
+       /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
+          set this higher, assuming the system even supports it.  */
+       dev->dma_mask = 0xffffffff;
 
        dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
                     dev->bus->number, PCI_SLOT(dev->devfn),
@@ -703,12 +737,14 @@ static int pci_setup_device(struct pci_dev * dev)
        dev_dbg(&dev->dev, "found [%04x:%04x] class %06x header type %02x\n",
                 dev->vendor, dev->device, class, dev->hdr_type);
 
+       /* need to have dev->class ready */
+       dev->cfg_size = pci_cfg_space_size(dev);
+
        /* "Unknown power state" */
        dev->current_state = PCI_UNKNOWN;
 
        /* Early fixups, before probing the BARs */
        pci_fixup_device(pci_fixup_early, dev);
-       class = dev->class >> 8;
 
        switch (dev->hdr_type) {                    /* header type */
        case PCI_HEADER_TYPE_NORMAL:                /* standard header */
@@ -770,7 +806,7 @@ static int pci_setup_device(struct pci_dev * dev)
        default:                                    /* unknown header */
                dev_err(&dev->dev, "unknown header type %02x, "
                        "ignoring device\n", dev->hdr_type);
-               return -1;
+               return -EIO;
 
        bad:
                dev_err(&dev->dev, "ignoring class %02x (doesn't match header "
@@ -785,6 +821,7 @@ static int pci_setup_device(struct pci_dev * dev)
 static void pci_release_capabilities(struct pci_dev *dev)
 {
        pci_vpd_release(dev);
+       pci_iov_release(dev);
 }
 
 /**
@@ -803,19 +840,6 @@ static void pci_release_dev(struct device *dev)
        kfree(pci_dev);
 }
 
-static void set_pcie_port_type(struct pci_dev *pdev)
-{
-       int pos;
-       u16 reg16;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
-       if (!pos)
-               return;
-       pdev->is_pcie = 1;
-       pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
-       pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
-}
-
 /**
  * pci_cfg_space_size - get the configuration space size of the PCI device.
  * @dev: PCI device
@@ -847,6 +871,11 @@ int pci_cfg_space_size(struct pci_dev *dev)
 {
        int pos;
        u32 status;
+       u16 class;
+
+       class = dev->class >> 8;
+       if (class == PCI_CLASS_BRIDGE_HOST)
+               return pci_cfg_space_size_ext(dev);
 
        pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
        if (!pos) {
@@ -891,9 +920,7 @@ EXPORT_SYMBOL(alloc_pci_dev);
 static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
 {
        struct pci_dev *dev;
-       struct pci_slot *slot;
        u32 l;
-       u8 hdr_type;
        int delay = 1;
 
        if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
@@ -920,34 +947,16 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
                }
        }
 
-       if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
-               return NULL;
-
        dev = alloc_pci_dev();
        if (!dev)
                return NULL;
 
        dev->bus = bus;
-       dev->sysdata = bus->sysdata;
-       dev->dev.parent = bus->bridge;
-       dev->dev.bus = &pci_bus_type;
        dev->devfn = devfn;
-       dev->hdr_type = hdr_type & 0x7f;
-       dev->multifunction = !!(hdr_type & 0x80);
        dev->vendor = l & 0xffff;
        dev->device = (l >> 16) & 0xffff;
-       dev->cfg_size = pci_cfg_space_size(dev);
-       dev->error_state = pci_channel_io_normal;
-       set_pcie_port_type(dev);
-
-       list_for_each_entry(slot, &bus->slots, list)
-               if (PCI_SLOT(devfn) == slot->number)
-                       dev->slot = slot;
 
-       /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
-          set this higher, assuming the system even supports it.  */
-       dev->dma_mask = 0xffffffff;
-       if (pci_setup_device(dev) < 0) {
+       if (pci_setup_device(dev)) {
                kfree(dev);
                return NULL;
        }
@@ -972,6 +981,9 @@ static void pci_init_capabilities(struct pci_dev *dev)
 
        /* Alternative Routing-ID Forwarding */
        pci_enable_ari(dev);
+
+       /* Single Root I/O Virtualization */
+       pci_iov_init(dev);
 }
 
 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
@@ -1006,6 +1018,12 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
 {
        struct pci_dev *dev;
 
+       dev = pci_get_slot(bus, devfn);
+       if (dev) {
+               pci_dev_put(dev);
+               return dev;
+       }
+
        dev = pci_scan_device(bus, devfn);
        if (!dev)
                return NULL;
@@ -1024,35 +1042,27 @@ EXPORT_SYMBOL(pci_scan_single_device);
  * Scan a PCI slot on the specified PCI bus for devices, adding
  * discovered devices to the @bus->devices list.  New devices
  * will not have is_added set.
+ *
+ * Returns the number of new devices found.
  */
 int pci_scan_slot(struct pci_bus *bus, int devfn)
 {
-       int func, nr = 0;
-       int scan_all_fns;
-
-       scan_all_fns = pcibios_scan_all_fns(bus, devfn);
-
-       for (func = 0; func < 8; func++, devfn++) {
-               struct pci_dev *dev;
-
-               dev = pci_scan_single_device(bus, devfn);
-               if (dev) {
-                       nr++;
+       int fn, nr = 0;
+       struct pci_dev *dev;
 
-                       /*
-                        * If this is a single function device,
-                        * don't scan past the first function.
-                        */
-                       if (!dev->multifunction) {
-                               if (func > 0) {
-                                       dev->multifunction = 1;
-                               } else {
-                                       break;
-                               }
+       dev = pci_scan_single_device(bus, devfn);
+       if (dev && !dev->is_added)      /* new device? */
+               nr++;
+
+       if ((dev && dev->multifunction) ||
+           (!dev && pcibios_scan_all_fns(bus, devfn))) {
+               for (fn = 1; fn < 8; fn++) {
+                       dev = pci_scan_single_device(bus, devfn + fn);
+                       if (dev) {
+                               if (!dev->is_added)
+                                       nr++;
+                               dev->multifunction = 1;
                        }
-               } else {
-                       if (func == 0 && !scan_all_fns)
-                               break;
                }
        }
 
@@ -1074,12 +1084,21 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
        for (devfn = 0; devfn < 0x100; devfn += 8)
                pci_scan_slot(bus, devfn);
 
+       /* Reserve buses for SR-IOV capability. */
+       max += pci_iov_bus_range(bus);
+
        /*
         * After performing arch-dependent fixup of the bus, look behind
         * all PCI-to-PCI bridges on this bus.
         */
-       pr_debug("PCI: Fixups for bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
-       pcibios_fixup_bus(bus);
+       if (!bus->is_added) {
+               pr_debug("PCI: Fixups for bus %04x:%02x\n",
+                        pci_domain_nr(bus), bus->number);
+               pcibios_fixup_bus(bus);
+               if (pci_is_root_bus(bus))
+                       bus->is_added = 1;
+       }
+
        for (pass=0; pass < 2; pass++)
                list_for_each_entry(dev, &bus->devices, bus_list) {
                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
@@ -1114,7 +1133,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
        if (!b)
                return NULL;
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev){
                kfree(b);
                return NULL;
@@ -1133,7 +1152,6 @@ struct pci_bus * pci_create_bus(struct device *parent,
        list_add_tail(&b->node, &pci_root_buses);
        up_write(&pci_bus_sem);
 
-       memset(dev, 0, sizeof(*dev));
        dev->parent = parent;
        dev->release = pci_release_bus_bridge_dev;
        dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus);
@@ -1193,6 +1211,38 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
 EXPORT_SYMBOL(pci_scan_bus_parented);
 
 #ifdef CONFIG_HOTPLUG
+/**
+ * pci_rescan_bus - scan a PCI bus for devices.
+ * @bus: PCI bus to scan
+ *
+ * Scan a PCI bus and child buses for new devices, adds them,
+ * and enables them.
+ *
+ * Returns the max number of subordinate bus discovered.
+ */
+unsigned int __devinit pci_rescan_bus(struct pci_bus *bus)
+{
+       unsigned int max;
+       struct pci_dev *dev;
+
+       max = pci_scan_child_bus(bus);
+
+       down_read(&pci_bus_sem);
+       list_for_each_entry(dev, &bus->devices, bus_list)
+               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+                   dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+                       if (dev->subordinate)
+                               pci_bus_size_bridges(dev->subordinate);
+       up_read(&pci_bus_sem);
+
+       pci_bus_assign_resources(bus);
+       pci_enable_bridges(bus);
+       pci_bus_add_devices(bus);
+
+       return max;
+}
+EXPORT_SYMBOL_GPL(pci_rescan_bus);
+
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bridge);
index 92b9efe9bcaf628faa260c0e919eece0d2610e9f..9b2f0d96900def68ff56606f27e056e6d77dff7d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/kallsyms.h>
 #include <linux/dmi.h>
 #include <linux/pci-aspm.h>
+#include <linux/ioport.h>
 #include "pci.h"
 
 int isa_dma_bridge_buggy;
@@ -34,6 +35,65 @@ int pcie_mch_quirk;
 EXPORT_SYMBOL(pcie_mch_quirk);
 
 #ifdef CONFIG_PCI_QUIRKS
+/*
+ * This quirk function disables the device and releases resources
+ * which is specified by kernel's boot parameter 'pci=resource_alignment='.
+ * It also rounds up size to specified alignment.
+ * Later on, the kernel will assign page-aligned memory resource back
+ * to that device.
+ */
+static void __devinit quirk_resource_alignment(struct pci_dev *dev)
+{
+       int i;
+       struct resource *r;
+       resource_size_t align, size;
+
+       if (!pci_is_reassigndev(dev))
+               return;
+
+       if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
+               dev_warn(&dev->dev,
+                       "Can't reassign resources to host bridge.\n");
+               return;
+       }
+
+       dev_info(&dev->dev, "Disabling device and release resources.\n");
+       pci_disable_device(dev);
+
+       align = pci_specified_resource_alignment(dev);
+       for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
+               r = &dev->resource[i];
+               if (!(r->flags & IORESOURCE_MEM))
+                       continue;
+               size = resource_size(r);
+               if (size < align) {
+                       size = align;
+                       dev_info(&dev->dev,
+                               "Rounding up size of resource #%d to %#llx.\n",
+                               i, (unsigned long long)size);
+               }
+               r->end = size - 1;
+               r->start = 0;
+       }
+       /* Need to disable bridge's resource window,
+        * to enable the kernel to reassign new resource
+        * window later on.
+        */
+       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+                       r = &dev->resource[i];
+                       if (!(r->flags & IORESOURCE_MEM))
+                               continue;
+                       r->end = resource_size(r) - 1;
+                       r->start = 0;
+               }
+               pci_disable_bridge_window(dev);
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
+
 /* The Mellanox Tavor device gives false positive parity errors
  * Mark this device with a broken_parity_status, to allow
  * PCI scanning code to "skip" this now blacklisted device.
@@ -1126,10 +1186,15 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                                 * its on-board VGA controller */
                                asus_hides_smbus = 1;
                        }
-               else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_IG)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_2)
                        switch(dev->subsystem_device) {
                        case 0x00b8: /* Compaq Evo D510 CMT */
                        case 0x00b9: /* Compaq Evo D510 SFF */
+                               /* Motherboard doesn't have Host bridge
+                                * subvendor/subdevice IDs and on-board VGA
+                                * controller is disabled if an AGP card is
+                                * inserted, therefore checking USB UHCI
+                                * Controller #1 */
                                asus_hides_smbus = 1;
                        }
                else if (dev->device == PCI_DEVICE_ID_INTEL_82815_CGC)
@@ -1154,7 +1219,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,     PCI_DEVICE_ID_INTEL_82855GM_HB, as
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge);
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82810_IG3,  asus_hides_smbus_hostbridge);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82845G_IG,  asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_2,  asus_hides_smbus_hostbridge);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82815_CGC,  asus_hides_smbus_hostbridge);
 
 static void asus_hides_smbus_lpc(struct pci_dev *dev)
@@ -1664,9 +1729,13 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
         * of parallel ports and <S> is the number of serial ports.
         */
        switch (dev->device) {
+       case PCI_DEVICE_ID_NETMOS_9835:
+               /* Well, this rule doesn't hold for the following 9835 device */
+               if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
+                               dev->subsystem_device == 0x0299)
+                       return;
        case PCI_DEVICE_ID_NETMOS_9735:
        case PCI_DEVICE_ID_NETMOS_9745:
-       case PCI_DEVICE_ID_NETMOS_9835:
        case PCI_DEVICE_ID_NETMOS_9845:
        case PCI_DEVICE_ID_NETMOS_9855:
                if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
@@ -2078,6 +2147,92 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
                        PCI_DEVICE_ID_NVIDIA_NVENET_15,
                        nvenet_msi_disable);
 
+static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
+{
+       int pos, ttl = 48;
+       int found = 0;
+
+       /* check if there is HT MSI cap or enabled on this device */
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (found < 1)
+                       found = 1;
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+                                        &flags) == 0) {
+                       if (flags & HT_MSI_FLAGS_ENABLE) {
+                               if (found < 2) {
+                                       found = 2;
+                                       break;
+                               }
+                       }
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+
+       return found;
+}
+
+static int __devinit host_bridge_with_leaf(struct pci_dev *host_bridge)
+{
+       struct pci_dev *dev;
+       int pos;
+       int i, dev_no;
+       int found = 0;
+
+       dev_no = host_bridge->devfn >> 3;
+       for (i = dev_no + 1; i < 0x20; i++) {
+               dev = pci_get_slot(host_bridge->bus, PCI_DEVFN(i, 0));
+               if (!dev)
+                       continue;
+
+               /* found next host bridge ?*/
+               pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE);
+               if (pos != 0) {
+                       pci_dev_put(dev);
+                       break;
+               }
+
+               if (ht_check_msi_mapping(dev)) {
+                       found = 1;
+                       pci_dev_put(dev);
+                       break;
+               }
+               pci_dev_put(dev);
+       }
+
+       return found;
+}
+
+#define PCI_HT_CAP_SLAVE_CTRL0     4    /* link control */
+#define PCI_HT_CAP_SLAVE_CTRL1     8    /* link control to */
+
+static int __devinit is_end_of_ht_chain(struct pci_dev *dev)
+{
+       int pos, ctrl_off;
+       int end = 0;
+       u16 flags, ctrl;
+
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE);
+
+       if (!pos)
+               goto out;
+
+       pci_read_config_word(dev, pos + PCI_CAP_FLAGS, &flags);
+
+       ctrl_off = ((flags >> 10) & 1) ?
+                       PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1;
+       pci_read_config_word(dev, pos + ctrl_off, &ctrl);
+
+       if (ctrl & (1 << 6))
+               end = 1;
+
+out:
+       return end;
+}
+
 static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
 {
        struct pci_dev *host_bridge;
@@ -2102,6 +2257,11 @@ static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
        if (!found)
                return;
 
+       /* don't enable end_device/host_bridge with leaf directly here */
+       if (host_bridge == dev && is_end_of_ht_chain(host_bridge) &&
+           host_bridge_with_leaf(host_bridge))
+               goto out;
+
        /* root did that ! */
        if (msi_ht_cap_enabled(host_bridge))
                goto out;
@@ -2132,44 +2292,12 @@ static void __devinit ht_disable_msi_mapping(struct pci_dev *dev)
        }
 }
 
-static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
-{
-       int pos, ttl = 48;
-       int found = 0;
-
-       /* check if there is HT MSI cap or enabled on this device */
-       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
-       while (pos && ttl--) {
-               u8 flags;
-
-               if (found < 1)
-                       found = 1;
-               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
-                                        &flags) == 0) {
-                       if (flags & HT_MSI_FLAGS_ENABLE) {
-                               if (found < 2) {
-                                       found = 2;
-                                       break;
-                               }
-                       }
-               }
-               pos = pci_find_next_ht_capability(dev, pos,
-                                                 HT_CAPTYPE_MSI_MAPPING);
-       }
-
-       return found;
-}
-
-static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all)
 {
        struct pci_dev *host_bridge;
        int pos;
        int found;
 
-       /* Enabling HT MSI mapping on this device breaks MCP51 */
-       if (dev->device == 0x270)
-               return;
-
        /* check if there is HT MSI cap or enabled on this device */
        found = ht_check_msi_mapping(dev);
 
@@ -2193,7 +2321,10 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
                /* Host bridge is to HT */
                if (found == 1) {
                        /* it is not enabled, try to enable it */
-                       nv_ht_enable_msi_mapping(dev);
+                       if (all)
+                               ht_enable_msi_mapping(dev);
+                       else
+                               nv_ht_enable_msi_mapping(dev);
                }
                return;
        }
@@ -2205,8 +2336,20 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
        /* Host bridge is not to HT, disable HT MSI mapping on this device */
        ht_disable_msi_mapping(dev);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+
+static void __devinit nv_msi_ht_cap_quirk_all(struct pci_dev *dev)
+{
+       return __nv_msi_ht_cap_quirk(dev, 1);
+}
+
+static void __devinit nv_msi_ht_cap_quirk_leaf(struct pci_dev *dev)
+{
+       return __nv_msi_ht_cap_quirk(dev, 0);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf);
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all);
 
 static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
 {
index 042e08924421bbd8d3c773a1ee40dfb50d9a2a1e..86503c14ce7e610119ae8b8f0a1e3f5148a1d0b5 100644 (file)
@@ -71,6 +71,9 @@ void pci_remove_bus(struct pci_bus *pci_bus)
        down_write(&pci_bus_sem);
        list_del(&pci_bus->node);
        up_write(&pci_bus_sem);
+       if (!pci_bus->is_added)
+               return;
+
        pci_remove_legacy_files(pci_bus);
        device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity);
        device_remove_file(&pci_bus->dev, &dev_attr_cpulistaffinity);
@@ -92,6 +95,7 @@ EXPORT_SYMBOL(pci_remove_bus);
  */
 void pci_remove_bus_device(struct pci_dev *dev)
 {
+       pci_stop_bus_device(dev);
        if (dev->subordinate) {
                struct pci_bus *b = dev->subordinate;
 
index 5af8bd5381497656291ec61de58e678e8b874dd6..710d4ea6956860bdadad1951408ae5999ae68654 100644 (file)
@@ -29,7 +29,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
        if (pdev->is_pcie)
                return NULL;
        while (1) {
-               if (!pdev->bus->self)
+               if (!pdev->bus->parent)
                        break;
                pdev = pdev->bus->self;
                /* a p2p bridge */
index 7046089457805bea53eb9efdce66a4c13f41f018..334285a8e23760f7b36eda595e9ef7aa0da0ecf4 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 
 
-static void pbus_assign_resources_sorted(struct pci_bus *bus)
+static void pbus_assign_resources_sorted(const struct pci_bus *bus)
 {
        struct pci_dev *dev;
        struct resource *res;
@@ -144,6 +144,9 @@ static void pci_setup_bridge(struct pci_bus *bus)
        struct pci_bus_region region;
        u32 l, bu, lu, io_upper16;
 
+       if (!pci_is_root_bus(bus) && bus->is_added)
+               return;
+
        dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n",
                 pci_domain_nr(bus), bus->number);
 
@@ -495,7 +498,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
-void __ref pci_bus_assign_resources(struct pci_bus *bus)
+void __ref pci_bus_assign_resources(const struct pci_bus *bus)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
index 32e8d88a46192fcdd2ab2248f4feb71fe987ec1d..3039fcb86afc8481333fbf378904fd2853da2dbb 100644 (file)
@@ -120,6 +120,21 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
        return err;
 }
 
+#ifdef CONFIG_PCI_QUIRKS
+void pci_disable_bridge_window(struct pci_dev *dev)
+{
+       dev_dbg(&dev->dev, "Disabling bridge window.\n");
+
+       /* MMIO Base/Limit */
+       pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0);
+
+       /* Prefetchable MMIO Base/Limit */
+       pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
+       pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
+       pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
+}
+#endif /* CONFIG_PCI_QUIRKS */
+
 int pci_assign_resource(struct pci_dev *dev, int resno)
 {
        struct pci_bus *bus = dev->bus;
index 5a8ccb4f604deed50495b61ced5ba403e59e9484..21189447e54511679ab103dcd5a9ddc7b150bd96 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * drivers/pci/slot.c
  * Copyright (C) 2006 Matthew Wilcox <matthew@wil.cx>
- * Copyright (C) 2006-2008 Hewlett-Packard Development Company, L.P.
- *     Alex Chiang <achiang@hp.com>
+ * Copyright (C) 2006-2009 Hewlett-Packard Development Company, L.P.
+ *     Alex Chiang <achiang@hp.com>
  */
 
 #include <linux/kobject.h>
@@ -52,8 +52,8 @@ static void pci_slot_release(struct kobject *kobj)
        struct pci_dev *dev;
        struct pci_slot *slot = to_pci_slot(kobj);
 
-       pr_debug("%s: releasing pci_slot on %x:%d\n", __func__,
-                slot->bus->number, slot->number);
+       dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n",
+               slot->number, pci_slot_name(slot));
 
        list_for_each_entry(dev, &slot->bus->devices, bus_list)
                if (PCI_SLOT(dev->devfn) == slot->number)
@@ -248,9 +248,8 @@ placeholder:
                if (PCI_SLOT(dev->devfn) == slot_nr)
                        dev->slot = slot;
 
-       /* Don't care if debug printk has a -1 for slot_nr */
-       pr_debug("%s: created pci_slot on %04x:%02x:%02x\n",
-                __func__, pci_domain_nr(parent), parent->number, slot_nr);
+       dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n",
+               slot_nr, pci_slot_name(slot));
 
 out:
        kfree(slot_name);
@@ -299,9 +298,8 @@ EXPORT_SYMBOL_GPL(pci_renumber_slot);
  */
 void pci_destroy_slot(struct pci_slot *slot)
 {
-       pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__,
-                atomic_read(&slot->kobj.kref.refcount) - 1,
-                pci_domain_nr(slot->bus), slot->bus->number, slot->number);
+       dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n",
+               slot->number, atomic_read(&slot->kobj.kref.refcount) - 1);
 
        down_write(&pci_bus_sem);
        kobject_put(&slot->kobj);
index 4ed64d8e95e709dd432686486c963df413ea189b..5143a760153b9626aaf15df274e795732951ed80 100644 (file)
@@ -63,7 +63,7 @@ static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                       struct pcmcia_state *state)
 {
        int cd = skt->nr ? GPIO_PCMCIA_S1_CD_VALID : GPIO_PCMCIA_S0_CD_VALID;
-       int rdy = skt->nr ? GPIO_PCMCIA_S0_RDYINT : GPIO_PCMCIA_S1_RDYINT;
+       int rdy = skt->nr ? GPIO_PCMCIA_S1_RDYINT : GPIO_PCMCIA_S0_RDYINT;
 
        state->detect = !gpio_get_value(cd);
        state->ready  = !!gpio_get_value(rdy);
index d63f26e666a4c0c369d340f7f90646d48a814c59..ba1f7497e4b9a99f5be8d9d9d406ff1f6b170dbd 100644 (file)
@@ -987,7 +987,6 @@ asus_proc_add(char *name, proc_writefunc *writefunc,
        proc->write_proc = writefunc;
        proc->read_proc = readfunc;
        proc->data = acpi_driver_data(device);
-       proc->owner = THIS_MODULE;
        proc->uid = asus_uid;
        proc->gid = asus_gid;
        return 0;
@@ -1020,7 +1019,6 @@ static int asus_hotk_add_fs(struct acpi_device *device)
        if (proc) {
                proc->read_proc = proc_read_info;
                proc->data = acpi_driver_data(device);
-               proc->owner = THIS_MODULE;
                proc->uid = asus_uid;
                proc->gid = asus_gid;
        } else {
@@ -1436,7 +1434,6 @@ static int __init asus_acpi_init(void)
                printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
                return -ENODEV;
        }
-       asus_proc_dir->owner = THIS_MODULE;
 
        result = acpi_bus_register_driver(&asus_hotk_driver);
        if (result < 0) {
index 16e11c2ee19a2a4dfb54f8c95e6639aa26bbfe70..af9f430211722d71f85a79c762adb35ccda50b35 100644 (file)
@@ -103,7 +103,7 @@ static void parse_da_table(const struct dmi_header *dm)
        da_num_tokens += tokens;
 }
 
-static void find_tokens(const struct dmi_header *dm)
+static void find_tokens(const struct dmi_header *dm, void *dummy)
 {
        switch (dm->type) {
        case 0xd4: /* Indexed IO */
@@ -356,7 +356,7 @@ static int __init dell_init(void)
        if (!dmi_check_system(dell_device_table))
                return -ENODEV;
 
-       dmi_walk(find_tokens);
+       dmi_walk(find_tokens, NULL);
 
        if (!da_tokens)  {
                printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n");
index d2433204a40c056721d76c9f8bc2798e43feeb04..d99f1cd435a281009f05839a8265a513890b63bd 100644 (file)
@@ -5811,7 +5811,7 @@ static struct ibm_struct volume_driver_data = {
  *     ThinkPads from this same time period (and earlier) probably lack the
  *     tachometer as well.
  *
- *     Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ *     Unfortunately a lot of ThinkPads with new-style ECs but whose firmware
  *     was never fixed by IBM to report the EC firmware version string
  *     probably support the tachometer (like the early X models), so
  *     detecting it is quite hard.  We need more data to know for sure.
@@ -6992,7 +6992,6 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                        ret = -ENODEV;
                        goto err_out;
                }
-               entry->owner = THIS_MODULE;
                entry->data = ibm;
                entry->read_proc = &dispatch_procfs_read;
                if (ibm->write)
@@ -7405,7 +7404,6 @@ static int __init thinkpad_acpi_module_init(void)
                thinkpad_acpi_module_exit();
                return -ENODEV;
        }
-       proc_dir->owner = THIS_MODULE;
 
        ret = platform_driver_register(&tpacpi_pdriver);
        if (ret) {
index 40e60fc2e596daead5c656396aa84fca0587868b..9f187265db8e260d201b167bc0095e8bd4757765 100644 (file)
@@ -679,8 +679,6 @@ static acpi_status __init add_device(void)
                                              toshiba_proc_dir,
                                              (read_proc_t *) dispatch_read,
                                              item);
-               if (proc)
-                       proc->owner = THIS_MODULE;
                if (proc && item->write_func)
                        proc->write_proc = (write_proc_t *) dispatch_write;
        }
@@ -772,7 +770,6 @@ static int __init toshiba_acpi_init(void)
                toshiba_acpi_exit();
                return -ENODEV;
        } else {
-               toshiba_proc_dir->owner = THIS_MODULE;
                status = add_device();
                if (ACPI_FAILURE(status)) {
                        toshiba_acpi_exit();
index 996f6483807909b3c773e6bbbace9997135cbcd9..cfe86853feb28a3c26750777e6f0f3397561945d 100644 (file)
@@ -94,7 +94,6 @@ struct pnp_dev_node_info node_info;
 
 #ifdef CONFIG_HOTPLUG
 
-static int unloading = 0;
 static struct completion unload_sem;
 
 /*
@@ -158,7 +157,7 @@ static int pnp_dock_thread(void *unused)
        int docked = -1, d = 0;
 
        set_freezable();
-       while (!unloading) {
+       while (1) {
                int status;
 
                /*
@@ -575,8 +574,6 @@ fs_initcall(pnpbios_init);
 
 static int __init pnpbios_thread_init(void)
 {
-       struct task_struct *task;
-
 #if defined(CONFIG_PPC)
        if (check_legacy_ioport(PNPBIOS_BASE))
                return 0;
@@ -584,10 +581,13 @@ static int __init pnpbios_thread_init(void)
        if (pnpbios_disabled)
                return 0;
 #ifdef CONFIG_HOTPLUG
-       init_completion(&unload_sem);
-       task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd");
-       if (!IS_ERR(task))
-               unloading = 0;
+       {
+               struct task_struct *task;
+               init_completion(&unload_sem);
+               task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd");
+               if (IS_ERR(task))
+                       return PTR_ERR(task);
+       }
 #endif
        return 0;
 }
index 0c056fcc01ce540b7e3ac3c6f27c52d6a6a9c0b6..62bb98124e26e0b273de974e9ee357ce875dcf87 100644 (file)
@@ -83,7 +83,7 @@ static int bq27x00_read(u8 reg, int *rt_value, int b_single,
 }
 
 /*
- * Return the battery temperature in Celcius degrees
+ * Return the battery temperature in Celsius degrees
  * Or < 0 if something fails.
  */
 static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
index e7e0cf102d6dcacc00272bd299c5366dbfc4f527..e58c0ce65aa6d4f6cf750feba06591df4d4ca33c 100644 (file)
@@ -29,8 +29,12 @@ config REGULATOR_DEBUG
          Say yes here to enable debugging support.
 
 config REGULATOR_FIXED_VOLTAGE
-       tristate
+       tristate "Fixed voltage regulator support"
        default n
+       help
+         This driver provides support for fixed voltage regulators,
+         useful for systems which use a combination of software
+         managed regulators and simple non-configurable regulators.
 
 config REGULATOR_VIRTUAL_CONSUMER
        tristate "Virtual regulator consumer support"
@@ -52,6 +56,13 @@ config REGULATOR_BQ24022
          charging select between 100 mA and 500 mA charging current
          limit.
 
+config REGULATOR_TWL4030
+       bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
+       depends on TWL4030_CORE
+       help
+         This driver supports the voltage regulators provided by
+         this family of companion chips.
+
 config REGULATOR_WM8350
        tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
        depends on MFD_WM8350
index 61b30c6ddecc1cf86b43b694a9939300ddbf941c..bac133afc061473f8cd74662fe9a7af091bba239 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 
 obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
 obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
index c175e38a4cd56477e364ade9e5b4295b0b76142b..7ecb820ceebc5b21568ef80c07b019041df7a2d6 100644 (file)
@@ -105,7 +105,8 @@ static int __init bq24022_probe(struct platform_device *pdev)
        ret = gpio_direction_output(pdata->gpio_iset2, 0);
        ret = gpio_direction_output(pdata->gpio_nce, 1);
 
-       bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
+       bq24022 = regulator_register(&bq24022_desc, &pdev->dev,
+                                    pdata->init_data, pdata);
        if (IS_ERR(bq24022)) {
                dev_dbg(&pdev->dev, "couldn't register regulator\n");
                ret = PTR_ERR(bq24022);
index f511a406fcaac4fca414bb954124d3e11f55cc86..01f7702a805dc462f29d59110c1c76bb9985c480 100644 (file)
 static DEFINE_MUTEX(regulator_list_mutex);
 static LIST_HEAD(regulator_list);
 static LIST_HEAD(regulator_map_list);
-
-/*
- * struct regulator_dev
- *
- * Voltage / Current regulator class device. One for each regulator.
- */
-struct regulator_dev {
-       struct regulator_desc *desc;
-       int use_count;
-
-       /* lists we belong to */
-       struct list_head list; /* list of all regulators */
-       struct list_head slist; /* list of supplied regulators */
-
-       /* lists we own */
-       struct list_head consumer_list; /* consumers we supply */
-       struct list_head supply_list; /* regulators we supply */
-
-       struct blocking_notifier_head notifier;
-       struct mutex mutex; /* consumer lock */
-       struct module *owner;
-       struct device dev;
-       struct regulation_constraints *constraints;
-       struct regulator_dev *supply;   /* for tree */
-
-       void *reg_data;         /* regulator_dev data */
-};
+static int has_full_constraints;
 
 /*
  * struct regulator_map
@@ -79,7 +53,6 @@ struct regulator {
        int uA_load;
        int min_uV;
        int max_uV;
-       int enabled; /* count of client enables */
        char *supply_name;
        struct device_attribute dev_attr;
        struct regulator_dev *rdev;
@@ -312,6 +285,47 @@ static ssize_t regulator_state_show(struct device *dev,
 }
 static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
 
+static ssize_t regulator_status_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
+       int status;
+       char *label;
+
+       status = rdev->desc->ops->get_status(rdev);
+       if (status < 0)
+               return status;
+
+       switch (status) {
+       case REGULATOR_STATUS_OFF:
+               label = "off";
+               break;
+       case REGULATOR_STATUS_ON:
+               label = "on";
+               break;
+       case REGULATOR_STATUS_ERROR:
+               label = "error";
+               break;
+       case REGULATOR_STATUS_FAST:
+               label = "fast";
+               break;
+       case REGULATOR_STATUS_NORMAL:
+               label = "normal";
+               break;
+       case REGULATOR_STATUS_IDLE:
+               label = "idle";
+               break;
+       case REGULATOR_STATUS_STANDBY:
+               label = "standby";
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       return sprintf(buf, "%s\n", label);
+}
+static DEVICE_ATTR(status, 0444, regulator_status_show, NULL);
+
 static ssize_t regulator_min_uA_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
@@ -678,6 +692,73 @@ static int set_machine_constraints(struct regulator_dev *rdev,
        else
                name = "regulator";
 
+       /* constrain machine-level voltage specs to fit
+        * the actual range supported by this regulator.
+        */
+       if (ops->list_voltage && rdev->desc->n_voltages) {
+               int     count = rdev->desc->n_voltages;
+               int     i;
+               int     min_uV = INT_MAX;
+               int     max_uV = INT_MIN;
+               int     cmin = constraints->min_uV;
+               int     cmax = constraints->max_uV;
+
+               /* it's safe to autoconfigure fixed-voltage supplies */
+               if (count == 1 && !cmin) {
+                       cmin = INT_MIN;
+                       cmax = INT_MAX;
+               }
+
+               /* voltage constraints are optional */
+               if ((cmin == 0) && (cmax == 0))
+                       goto out;
+
+               /* else require explicit machine-level constraints */
+               if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
+                       pr_err("%s: %s '%s' voltage constraints\n",
+                                      __func__, "invalid", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               /* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
+               for (i = 0; i < count; i++) {
+                       int     value;
+
+                       value = ops->list_voltage(rdev, i);
+                       if (value <= 0)
+                               continue;
+
+                       /* maybe adjust [min_uV..max_uV] */
+                       if (value >= cmin && value < min_uV)
+                               min_uV = value;
+                       if (value <= cmax && value > max_uV)
+                               max_uV = value;
+               }
+
+               /* final: [min_uV..max_uV] valid iff constraints valid */
+               if (max_uV < min_uV) {
+                       pr_err("%s: %s '%s' voltage constraints\n",
+                                      __func__, "unsupportable", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               /* use regulator's subset of machine constraints */
+               if (constraints->min_uV < min_uV) {
+                       pr_debug("%s: override '%s' %s, %d -> %d\n",
+                                      __func__, name, "min_uV",
+                                       constraints->min_uV, min_uV);
+                       constraints->min_uV = min_uV;
+               }
+               if (constraints->max_uV > max_uV) {
+                       pr_debug("%s: override '%s' %s, %d -> %d\n",
+                                      __func__, name, "max_uV",
+                                       constraints->max_uV, max_uV);
+                       constraints->max_uV = max_uV;
+               }
+       }
+
        rdev->constraints = constraints;
 
        /* do we need to apply the constraint voltage */
@@ -695,10 +776,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                        }
        }
 
-       /* are we enabled at boot time by firmware / bootloader */
-       if (rdev->constraints->boot_on)
-               rdev->use_count = 1;
-
        /* do we need to setup our suspend state */
        if (constraints->initial_state) {
                ret = suspend_prepare(rdev, constraints->initial_state);
@@ -710,11 +787,27 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                }
        }
 
-       /* if always_on is set then turn the regulator on if it's not
-        * already on. */
-       if (constraints->always_on && ops->enable &&
-           ((ops->is_enabled && !ops->is_enabled(rdev)) ||
-            (!ops->is_enabled && !constraints->boot_on))) {
+       if (constraints->initial_mode) {
+               if (!ops->set_mode) {
+                       printk(KERN_ERR "%s: no set_mode operation for %s\n",
+                              __func__, name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               ret = ops->set_mode(rdev, constraints->initial_mode);
+               if (ret < 0) {
+                       printk(KERN_ERR
+                              "%s: failed to set initial mode for %s: %d\n",
+                              __func__, name, ret);
+                       goto out;
+               }
+       }
+
+       /* If the constraints say the regulator should be on at this point
+        * and we have control then make sure it is enabled.
+        */
+       if ((constraints->always_on || constraints->boot_on) && ops->enable) {
                ret = ops->enable(rdev);
                if (ret < 0) {
                        printk(KERN_ERR "%s: failed to enable %s\n",
@@ -817,6 +910,19 @@ static void unset_consumer_device_supply(struct regulator_dev *rdev,
        }
 }
 
+static void unset_regulator_supplies(struct regulator_dev *rdev)
+{
+       struct regulator_map *node, *n;
+
+       list_for_each_entry_safe(node, n, &regulator_map_list, list) {
+               if (rdev == node->regulator) {
+                       list_del(&node->list);
+                       kfree(node);
+                       return;
+               }
+       }
+}
+
 #define REG_STR_SIZE   32
 
 static struct regulator *create_regulator(struct regulator_dev *rdev,
@@ -898,9 +1004,12 @@ overflow_err:
  * @id: Supply name or regulator ID.
  *
  * Returns a struct regulator corresponding to the regulator producer,
- * or IS_ERR() condition containing errno.  Use of supply names
- * configured via regulator_set_device_supply() is strongly
- * encouraged.
+ * or IS_ERR() condition containing errno.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged.  It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
  */
 struct regulator *regulator_get(struct device *dev, const char *id)
 {
@@ -922,8 +1031,6 @@ struct regulator *regulator_get(struct device *dev, const char *id)
                        goto found;
                }
        }
-       printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",
-              id);
        mutex_unlock(&regulator_list_mutex);
        return regulator;
 
@@ -961,10 +1068,6 @@ void regulator_put(struct regulator *regulator)
        mutex_lock(&regulator_list_mutex);
        rdev = regulator->rdev;
 
-       if (WARN(regulator->enabled, "Releasing supply %s while enabled\n",
-                              regulator->supply_name))
-               _regulator_disable(rdev);
-
        /* remove any sysfs entries */
        if (regulator->dev) {
                sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
@@ -1039,12 +1142,7 @@ int regulator_enable(struct regulator *regulator)
        int ret = 0;
 
        mutex_lock(&rdev->mutex);
-       if (regulator->enabled == 0)
-               ret = _regulator_enable(rdev);
-       else if (regulator->enabled < 0)
-               ret = -EIO;
-       if (ret == 0)
-               regulator->enabled++;
+       ret = _regulator_enable(rdev);
        mutex_unlock(&rdev->mutex);
        return ret;
 }
@@ -1055,6 +1153,11 @@ static int _regulator_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
 
+       if (WARN(rdev->use_count <= 0,
+                       "unbalanced disables for %s\n",
+                       rdev->desc->name))
+               return -EIO;
+
        /* are we the last user and permitted to disable ? */
        if (rdev->use_count == 1 && !rdev->constraints->always_on) {
 
@@ -1103,16 +1206,7 @@ int regulator_disable(struct regulator *regulator)
        int ret = 0;
 
        mutex_lock(&rdev->mutex);
-       if (regulator->enabled == 1) {
-               ret = _regulator_disable(rdev);
-               if (ret == 0)
-                       regulator->uA_load = 0;
-       } else if (WARN(regulator->enabled <= 0,
-                       "unbalanced disables for supply %s\n",
-                       regulator->supply_name))
-               ret = -EIO;
-       if (ret == 0)
-               regulator->enabled--;
+       ret = _regulator_disable(rdev);
        mutex_unlock(&rdev->mutex);
        return ret;
 }
@@ -1159,7 +1253,6 @@ int regulator_force_disable(struct regulator *regulator)
        int ret;
 
        mutex_lock(&regulator->rdev->mutex);
-       regulator->enabled = 0;
        regulator->uA_load = 0;
        ret = _regulator_force_disable(regulator->rdev);
        mutex_unlock(&regulator->rdev->mutex);
@@ -1203,6 +1296,56 @@ int regulator_is_enabled(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_is_enabled);
 
+/**
+ * regulator_count_voltages - count regulator_list_voltage() selectors
+ * @regulator: regulator source
+ *
+ * Returns number of selectors, or negative errno.  Selectors are
+ * numbered starting at zero, and typically correspond to bitfields
+ * in hardware registers.
+ */
+int regulator_count_voltages(struct regulator *regulator)
+{
+       struct regulator_dev    *rdev = regulator->rdev;
+
+       return rdev->desc->n_voltages ? : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_count_voltages);
+
+/**
+ * regulator_list_voltage - enumerate supported voltages
+ * @regulator: regulator source
+ * @selector: identify voltage to list
+ * Context: can sleep
+ *
+ * Returns a voltage that can be passed to @regulator_set_voltage(),
+ * zero if this selector code can't be used on this sytem, or a
+ * negative errno.
+ */
+int regulator_list_voltage(struct regulator *regulator, unsigned selector)
+{
+       struct regulator_dev    *rdev = regulator->rdev;
+       struct regulator_ops    *ops = rdev->desc->ops;
+       int                     ret;
+
+       if (!ops->list_voltage || selector >= rdev->desc->n_voltages)
+               return -EINVAL;
+
+       mutex_lock(&rdev->mutex);
+       ret = ops->list_voltage(rdev, selector);
+       mutex_unlock(&rdev->mutex);
+
+       if (ret > 0) {
+               if (ret < rdev->constraints->min_uV)
+                       ret = 0;
+               else if (ret > rdev->constraints->max_uV)
+                       ret = 0;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage);
+
 /**
  * regulator_set_voltage - set regulator output voltage
  * @regulator: regulator source
@@ -1243,6 +1386,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
        ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV);
 
 out:
+       _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL);
        mutex_unlock(&rdev->mutex);
        return ret;
 }
@@ -1543,20 +1687,23 @@ int regulator_unregister_notifier(struct regulator *regulator,
 }
 EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
 
-/* notify regulator consumers and downstream regulator consumers */
+/* notify regulator consumers and downstream regulator consumers.
+ * Note mutex must be held by caller.
+ */
 static void _notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data)
 {
        struct regulator_dev *_rdev;
 
        /* call rdev chain first */
-       mutex_lock(&rdev->mutex);
        blocking_notifier_call_chain(&rdev->notifier, event, NULL);
-       mutex_unlock(&rdev->mutex);
 
        /* now notify regulator we supply */
-       list_for_each_entry(_rdev, &rdev->supply_list, slist)
-               _notifier_call_chain(_rdev, event, data);
+       list_for_each_entry(_rdev, &rdev->supply_list, slist) {
+         mutex_lock(&_rdev->mutex);
+         _notifier_call_chain(_rdev, event, data);
+         mutex_unlock(&_rdev->mutex);
+       }
 }
 
 /**
@@ -1703,6 +1850,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
  *
  * Called by regulator drivers to notify clients a regulator event has
  * occurred. We also notify regulator clients downstream.
+ * Note lock must be held by caller.
  */
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data)
@@ -1744,6 +1892,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
                if (status < 0)
                        return status;
        }
+       if (ops->get_status) {
+               status = device_create_file(dev, &dev_attr_status);
+               if (status < 0)
+                       return status;
+       }
 
        /* some attributes are type-specific */
        if (rdev->desc->type == REGULATOR_CURRENT) {
@@ -1828,17 +1981,18 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
  * regulator_register - register regulator
  * @regulator_desc: regulator to register
  * @dev: struct device for the regulator
+ * @init_data: platform provided init data, passed through by driver
  * @driver_data: private regulator data
  *
  * Called by regulator drivers to register a regulator.
  * Returns 0 on success.
  */
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-       struct device *dev, void *driver_data)
+       struct device *dev, struct regulator_init_data *init_data,
+       void *driver_data)
 {
        static atomic_t regulator_no = ATOMIC_INIT(0);
        struct regulator_dev *rdev;
-       struct regulator_init_data *init_data = dev->platform_data;
        int ret, i;
 
        if (regulator_desc == NULL)
@@ -1945,6 +2099,7 @@ void regulator_unregister(struct regulator_dev *rdev)
                return;
 
        mutex_lock(&regulator_list_mutex);
+       unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        if (rdev->supply)
                sysfs_remove_link(&rdev->dev.kobj, "supply");
@@ -1988,6 +2143,23 @@ out:
 }
 EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
 
+/**
+ * regulator_has_full_constraints - the system has fully specified constraints
+ *
+ * Calling this function will cause the regulator API to disable all
+ * regulators which have a zero use count and don't have an always_on
+ * constraint in a late_initcall.
+ *
+ * The intention is that this will become the default behaviour in a
+ * future kernel release so users are encouraged to use this facility
+ * now.
+ */
+void regulator_has_full_constraints(void)
+{
+       has_full_constraints = 1;
+}
+EXPORT_SYMBOL_GPL(regulator_has_full_constraints);
+
 /**
  * rdev_get_drvdata - get rdev regulator driver data
  * @rdev: regulator
@@ -2055,3 +2227,77 @@ static int __init regulator_init(void)
 
 /* init early to allow our consumers to complete system booting */
 core_initcall(regulator_init);
+
+static int __init regulator_init_complete(void)
+{
+       struct regulator_dev *rdev;
+       struct regulator_ops *ops;
+       struct regulation_constraints *c;
+       int enabled, ret;
+       const char *name;
+
+       mutex_lock(&regulator_list_mutex);
+
+       /* If we have a full configuration then disable any regulators
+        * which are not in use or always_on.  This will become the
+        * default behaviour in the future.
+        */
+       list_for_each_entry(rdev, &regulator_list, list) {
+               ops = rdev->desc->ops;
+               c = rdev->constraints;
+
+               if (c->name)
+                       name = c->name;
+               else if (rdev->desc->name)
+                       name = rdev->desc->name;
+               else
+                       name = "regulator";
+
+               if (!ops->disable || c->always_on)
+                       continue;
+
+               mutex_lock(&rdev->mutex);
+
+               if (rdev->use_count)
+                       goto unlock;
+
+               /* If we can't read the status assume it's on. */
+               if (ops->is_enabled)
+                       enabled = ops->is_enabled(rdev);
+               else
+                       enabled = 1;
+
+               if (!enabled)
+                       goto unlock;
+
+               if (has_full_constraints) {
+                       /* We log since this may kill the system if it
+                        * goes wrong. */
+                       printk(KERN_INFO "%s: disabling %s\n",
+                              __func__, name);
+                       ret = ops->disable(rdev);
+                       if (ret != 0) {
+                               printk(KERN_ERR
+                                      "%s: couldn't disable %s: %d\n",
+                                      __func__, name, ret);
+                       }
+               } else {
+                       /* The intention is that in future we will
+                        * assume that full constraints are provided
+                        * so warn even if we aren't going to do
+                        * anything here.
+                        */
+                       printk(KERN_WARNING
+                              "%s: incomplete constraints, leaving %s on\n",
+                              __func__, name);
+               }
+
+unlock:
+               mutex_unlock(&rdev->mutex);
+       }
+
+       mutex_unlock(&regulator_list_mutex);
+
+       return 0;
+}
+late_initcall(regulator_init_complete);
index fe77730a7edb73442b088a4e325dd70d4c2a6366..72b15495183cfd290289fd9256babe296bbbf263 100644 (file)
@@ -471,7 +471,8 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
        if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
                ri->desc.ops = &da9030_regulator_ldo1_15_ops;
 
-       rdev = regulator_register(&ri->desc, &pdev->dev, ri);
+       rdev = regulator_register(&ri->desc, &pdev->dev,
+                                 pdev->dev.platform_data, ri);
        if (IS_ERR(rdev)) {
                dev_err(&pdev->dev, "failed to register regulator %s\n",
                                ri->desc.name);
index d31db3e14913fb1d1281c6a4eea49bf145242b76..23d554628a76128e6786bb9666a67c0179e4ec32 100644 (file)
@@ -73,7 +73,8 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
 
        drvdata->microvolts = config->microvolts;
 
-       drvdata->dev = regulator_register(&drvdata->desc, drvdata);
+       drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
+                                         config->init_data, drvdata);
        if (IS_ERR(drvdata->dev)) {
                ret = PTR_ERR(drvdata->dev);
                goto err_name;
index 4cc85ec6e1208b25abf0ed4121726002739adbc2..cd761d85c8fdbc39e42a6cf3d67864744c64c76b 100644 (file)
@@ -284,7 +284,8 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
        /* Already set by core driver */
        pcf = platform_get_drvdata(pdev);
 
-       rdev = regulator_register(&regulators[pdev->id], &pdev->dev, pcf);
+       rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+                                 pdev->dev.platform_data, pcf);
        if (IS_ERR(rdev))
                return PTR_ERR(rdev);
 
diff --git a/drivers/regulator/twl4030-regulator.c b/drivers/regulator/twl4030-regulator.c
new file mode 100644 (file)
index 0000000..e2032fb
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * twl4030-regulator.c -- support regulators in twl4030 family chips
+ *
+ * Copyright (C) 2008 David Brownell
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The TWL4030/TW5030/TPS659x0 family chips include power management, a
+ * USB OTG transceiver, an RTC, ADC, PWM, and lots more.  Some versions
+ * include an audio codec, battery charger, and more voltage regulators.
+ * These chips are often used in OMAP-based systems.
+ *
+ * This driver implements software-based resource control for various
+ * voltage regulators.  This is usually augmented with state machine
+ * based control.
+ */
+
+struct twlreg_info {
+       /* start of regulator's PM_RECEIVER control register bank */
+       u8                      base;
+
+       /* twl4030 resource ID, for resource control state machine */
+       u8                      id;
+
+       /* voltage in mV = table[VSEL]; table_len must be a power-of-two */
+       u8                      table_len;
+       const u16               *table;
+
+       /* chip constraints on regulator behavior */
+       u16                     min_mV;
+
+       /* used by regulator core */
+       struct regulator_desc   desc;
+};
+
+
+/* LDO control registers ... offset is from the base of its register bank.
+ * The first three registers of all power resource banks help hardware to
+ * manage the various resource groups.
+ */
+#define VREG_GRP               0
+#define VREG_TYPE              1
+#define VREG_REMAP             2
+#define VREG_DEDICATED         3       /* LDO control */
+
+
+static inline int
+twl4030reg_read(struct twlreg_info *info, unsigned offset)
+{
+       u8 value;
+       int status;
+
+       status = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER,
+                       &value, info->base + offset);
+       return (status < 0) ? status : value;
+}
+
+static inline int
+twl4030reg_write(struct twlreg_info *info, unsigned offset, u8 value)
+{
+       return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       value, info->base + offset);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* generic power resource operations, which work on all regulators */
+
+static int twl4030reg_grp(struct regulator_dev *rdev)
+{
+       return twl4030reg_read(rdev_get_drvdata(rdev), VREG_GRP);
+}
+
+/*
+ * Enable/disable regulators by joining/leaving the P1 (processor) group.
+ * We assume nobody else is updating the DEV_GRP registers.
+ */
+
+#define P3_GRP         BIT(7)          /* "peripherals" */
+#define P2_GRP         BIT(6)          /* secondary processor, modem, etc */
+#define P1_GRP         BIT(5)          /* CPU/Linux */
+
+static int twl4030reg_is_enabled(struct regulator_dev *rdev)
+{
+       int     state = twl4030reg_grp(rdev);
+
+       if (state < 0)
+               return state;
+
+       return (state & P1_GRP) != 0;
+}
+
+static int twl4030reg_enable(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp;
+
+       grp = twl4030reg_read(info, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       grp |= P1_GRP;
+       return twl4030reg_write(info, VREG_GRP, grp);
+}
+
+static int twl4030reg_disable(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp;
+
+       grp = twl4030reg_read(info, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       grp &= ~P1_GRP;
+       return twl4030reg_write(info, VREG_GRP, grp);
+}
+
+static int twl4030reg_get_status(struct regulator_dev *rdev)
+{
+       int     state = twl4030reg_grp(rdev);
+
+       if (state < 0)
+               return state;
+       state &= 0x0f;
+
+       /* assume state != WARM_RESET; we'd not be running...  */
+       if (!state)
+               return REGULATOR_STATUS_OFF;
+       return (state & BIT(3))
+               ? REGULATOR_STATUS_NORMAL
+               : REGULATOR_STATUS_STANDBY;
+}
+
+static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       unsigned                message;
+       int                     status;
+
+       /* We can only set the mode through state machine commands... */
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
+               break;
+       case REGULATOR_MODE_STANDBY:
+               message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Ensure the resource is associated with some group */
+       status = twl4030reg_grp(rdev);
+       if (status < 0)
+               return status;
+       if (!(status & (P3_GRP | P2_GRP | P1_GRP)))
+               return -EACCES;
+
+       status = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+                       message >> 8, 0x15 /* PB_WORD_MSB */ );
+       if (status >= 0)
+               return status;
+
+       return twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+                       message, 0x16 /* PB_WORD_LSB */ );
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Support for adjustable-voltage LDOs uses a four bit (or less) voltage
+ * select field in its control register.   We use tables indexed by VSEL
+ * to record voltages in milliVolts.  (Accuracy is about three percent.)
+ *
+ * Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
+ * currently handled by listing two slightly different VAUX2 regulators,
+ * only one of which will be configured.
+ *
+ * VSEL values documented as "TI cannot support these values" are flagged
+ * in these tables as UNSUP() values; we normally won't assign them.
+ *
+ * VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported.
+ * TI are revising the twl5030/tps659x0 specs to support that 3.0V setting.
+ */
+#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
+#define UNSUP_MASK     0x0000
+#else
+#define UNSUP_MASK     0x8000
+#endif
+
+#define UNSUP(x)       (UNSUP_MASK | (x))
+#define IS_UNSUP(x)    (UNSUP_MASK & (x))
+#define LDO_MV(x)      (~UNSUP_MASK & (x))
+
+
+static const u16 VAUX1_VSEL_table[] = {
+       UNSUP(1500), UNSUP(1800), 2500, 2800,
+       3000, 3000, 3000, 3000,
+};
+static const u16 VAUX2_4030_VSEL_table[] = {
+       UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
+       1500, 1800, UNSUP(1850), 2500,
+       UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VAUX2_VSEL_table[] = {
+       1700, 1700, 1900, 1300,
+       1500, 1800, 2000, 2500,
+       2100, 2800, 2200, 2300,
+       2400, 2400, 2400, 2400,
+};
+static const u16 VAUX3_VSEL_table[] = {
+       1500, 1800, 2500, 2800,
+       3000, 3000, 3000, 3000,
+};
+static const u16 VAUX4_VSEL_table[] = {
+       700, 1000, 1200, UNSUP(1300),
+       1500, 1800, UNSUP(1850), 2500,
+       UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VMMC1_VSEL_table[] = {
+       1850, 2850, 3000, 3150,
+};
+static const u16 VMMC2_VSEL_table[] = {
+       UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
+       UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
+       2600, 2800, 2850, 3000,
+       3150, 3150, 3150, 3150,
+};
+static const u16 VPLL1_VSEL_table[] = {
+       1000, 1200, 1300, 1800,
+       UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
+};
+static const u16 VPLL2_VSEL_table[] = {
+       700, 1000, 1200, 1300,
+       UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
+       UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
+       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VSIM_VSEL_table[] = {
+       UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
+       2800, 3000, 3000, 3000,
+};
+static const u16 VDAC_VSEL_table[] = {
+       1200, 1300, 1800, 1800,
+};
+
+
+static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     mV = info->table[index];
+
+       return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000);
+}
+
+static int
+twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     vsel;
+
+       for (vsel = 0; vsel < info->table_len; vsel++) {
+               int mV = info->table[vsel];
+               int uV;
+
+               if (IS_UNSUP(mV))
+                       continue;
+               uV = LDO_MV(mV) * 1000;
+
+               /* REVISIT for VAUX2, first match may not be best/lowest */
+
+               /* use the first in-range value */
+               if (min_uV <= uV && uV <= max_uV)
+                       return twl4030reg_write(info, VREG_DEDICATED, vsel);
+       }
+
+       return -EDOM;
+}
+
+static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     vsel = twl4030reg_read(info, VREG_DEDICATED);
+
+       if (vsel < 0)
+               return vsel;
+
+       vsel &= info->table_len - 1;
+       return LDO_MV(info->table[vsel]) * 1000;
+}
+
+static struct regulator_ops twl4030ldo_ops = {
+       .list_voltage   = twl4030ldo_list_voltage,
+
+       .set_voltage    = twl4030ldo_set_voltage,
+       .get_voltage    = twl4030ldo_get_voltage,
+
+       .enable         = twl4030reg_enable,
+       .disable        = twl4030reg_disable,
+       .is_enabled     = twl4030reg_is_enabled,
+
+       .set_mode       = twl4030reg_set_mode,
+
+       .get_status     = twl4030reg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Fixed voltage LDOs don't have a VSEL field to update.
+ */
+static int twl4030fixed_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       return info->min_mV * 1000;
+}
+
+static int twl4030fixed_get_voltage(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       return info->min_mV * 1000;
+}
+
+static struct regulator_ops twl4030fixed_ops = {
+       .list_voltage   = twl4030fixed_list_voltage,
+
+       .get_voltage    = twl4030fixed_get_voltage,
+
+       .enable         = twl4030reg_enable,
+       .disable        = twl4030reg_disable,
+       .is_enabled     = twl4030reg_is_enabled,
+
+       .set_mode       = twl4030reg_set_mode,
+
+       .get_status     = twl4030reg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+#define TWL_ADJUSTABLE_LDO(label, offset, num) { \
+       .base = offset, \
+       .id = num, \
+       .table_len = ARRAY_SIZE(label##_VSEL_table), \
+       .table = label##_VSEL_table, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL4030_REG_##label, \
+               .n_voltages = ARRAY_SIZE(label##_VSEL_table), \
+               .ops = &twl4030ldo_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
+#define TWL_FIXED_LDO(label, offset, mVolts, num) { \
+       .base = offset, \
+       .id = num, \
+       .min_mV = mVolts, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL4030_REG_##label, \
+               .n_voltages = 1, \
+               .ops = &twl4030fixed_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
+/*
+ * We list regulators here if systems need some level of
+ * software control over them after boot.
+ */
+static struct twlreg_info twl4030_regs[] = {
+       TWL_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
+       TWL_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
+       TWL_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
+       TWL_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
+       TWL_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
+       TWL_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
+       TWL_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
+       /*
+       TWL_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
+       */
+       TWL_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
+       TWL_ADJUSTABLE_LDO(VSIM, 0x37, 9),
+       TWL_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
+       /*
+       TWL_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
+       TWL_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
+       TWL_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
+       TWL_SMPS(VIO, 0x4b, 14),
+       TWL_SMPS(VDD1, 0x55, 15),
+       TWL_SMPS(VDD2, 0x63, 16),
+        */
+       TWL_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
+       TWL_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
+       TWL_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
+       /* VUSBCP is managed *only* by the USB subchip */
+};
+
+static int twl4030reg_probe(struct platform_device *pdev)
+{
+       int                             i;
+       struct twlreg_info              *info;
+       struct regulator_init_data      *initdata;
+       struct regulation_constraints   *c;
+       struct regulator_dev            *rdev;
+
+       for (i = 0, info = NULL; i < ARRAY_SIZE(twl4030_regs); i++) {
+               if (twl4030_regs[i].desc.id != pdev->id)
+                       continue;
+               info = twl4030_regs + i;
+               break;
+       }
+       if (!info)
+               return -ENODEV;
+
+       initdata = pdev->dev.platform_data;
+       if (!initdata)
+               return -EINVAL;
+
+       /* Constrain board-specific capabilities according to what
+        * this driver and the chip itself can actually do.
+        */
+       c = &initdata->constraints;
+       c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
+       c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
+                               | REGULATOR_CHANGE_MODE
+                               | REGULATOR_CHANGE_STATUS;
+
+       rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "can't register %s, %ld\n",
+                               info->desc.name, PTR_ERR(rdev));
+               return PTR_ERR(rdev);
+       }
+       platform_set_drvdata(pdev, rdev);
+
+       /* NOTE:  many regulators support short-circuit IRQs (presentable
+        * as REGULATOR_OVER_CURRENT notifications?) configured via:
+        *  - SC_CONFIG
+        *  - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
+        *  - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
+        *  - IT_CONFIG
+        */
+
+       return 0;
+}
+
+static int __devexit twl4030reg_remove(struct platform_device *pdev)
+{
+       regulator_unregister(platform_get_drvdata(pdev));
+       return 0;
+}
+
+MODULE_ALIAS("platform:twl4030_reg");
+
+static struct platform_driver twl4030reg_driver = {
+       .probe          = twl4030reg_probe,
+       .remove         = __devexit_p(twl4030reg_remove),
+       /* NOTE: short name, to work around driver model truncation of
+        * "twl4030_regulator.12" (and friends) to "twl4030_regulator.1".
+        */
+       .driver.name    = "twl4030_reg",
+       .driver.owner   = THIS_MODULE,
+};
+
+static int __init twl4030reg_init(void)
+{
+       return platform_driver_register(&twl4030reg_driver);
+}
+subsys_initcall(twl4030reg_init);
+
+static void __exit twl4030reg_exit(void)
+{
+       platform_driver_unregister(&twl4030reg_driver);
+}
+module_exit(twl4030reg_exit)
+
+MODULE_DESCRIPTION("TWL4030 regulator driver");
+MODULE_LICENSE("GPL");
index 5ddb464b1c3f1a661efb669e36f898d063b194ad..3d08348584e1798e7d0c03a73c363a6c8d40a48a 100644 (file)
@@ -226,13 +226,17 @@ static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
        unsigned int mode;
        int ret;
 
-       if (strncmp(buf, "fast", strlen("fast")) == 0)
+       /*
+        * sysfs_streq() doesn't need the \n's, but we add them so the strings
+        * will be shared with show_mode(), above.
+        */
+       if (sysfs_streq(buf, "fast\n") == 0)
                mode = REGULATOR_MODE_FAST;
-       else if (strncmp(buf, "normal", strlen("normal")) == 0)
+       else if (sysfs_streq(buf, "normal\n") == 0)
                mode = REGULATOR_MODE_NORMAL;
-       else if (strncmp(buf, "idle", strlen("idle")) == 0)
+       else if (sysfs_streq(buf, "idle\n") == 0)
                mode = REGULATOR_MODE_IDLE;
-       else if (strncmp(buf, "standby", strlen("standby")) == 0)
+       else if (sysfs_streq(buf, "standby\n") == 0)
                mode = REGULATOR_MODE_STANDBY;
        else {
                dev_err(dev, "Configuring invalid mode\n");
@@ -256,7 +260,7 @@ static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
 static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
 static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
 
-struct device_attribute *attributes[] = {
+static struct device_attribute *attributes[] = {
        &dev_attr_min_microvolts,
        &dev_attr_max_microvolts,
        &dev_attr_min_microamps,
index 5056e23e441471f658276c802300d5a8aba3355f..771eca1066b5916378c0620387b3ecf8dae3342a 100644 (file)
@@ -24,6 +24,9 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 
+/* Maximum value possible for VSEL */
+#define WM8350_DCDC_MAX_VSEL 0x66
+
 /* Microamps */
 static const int isink_cur[] = {
        4,
@@ -385,6 +388,14 @@ static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
        return wm8350_dcdc_val_to_mvolts(val) * 1000;
 }
 
+static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
+                                   unsigned selector)
+{
+       if (selector > WM8350_DCDC_MAX_VSEL)
+               return -EINVAL;
+       return wm8350_dcdc_val_to_mvolts(selector) * 1000;
+}
+
 static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
        struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
@@ -775,6 +786,14 @@ static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
        return wm8350_ldo_val_to_mvolts(val) * 1000;
 }
 
+static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
+                                   unsigned selector)
+{
+       if (selector > WM8350_LDO1_VSEL_MASK)
+               return -EINVAL;
+       return wm8350_ldo_val_to_mvolts(selector) * 1000;
+}
+
 int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
                         u16 stop, u16 fault)
 {
@@ -1031,18 +1050,30 @@ static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
        int dcdc = rdev_get_id(rdev);
        u16 mask, sleep, active, force;
        int mode = REGULATOR_MODE_NORMAL;
+       int reg;
 
-       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
-               return -EINVAL;
-
-       if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               reg = WM8350_DCDC1_FORCE_PWM;
+               break;
+       case WM8350_DCDC_3:
+               reg = WM8350_DCDC3_FORCE_PWM;
+               break;
+       case WM8350_DCDC_4:
+               reg = WM8350_DCDC4_FORCE_PWM;
+               break;
+       case WM8350_DCDC_6:
+               reg = WM8350_DCDC6_FORCE_PWM;
+               break;
+       default:
                return -EINVAL;
+       }
 
        mask = 1 << (dcdc - WM8350_DCDC_1);
        active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
+       force = wm8350_reg_read(wm8350, reg) & WM8350_DCDC1_FORCE_PWM_ENA;
        sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
-       force = wm8350_reg_read(wm8350, WM8350_DCDC1_FORCE_PWM)
-           & WM8350_DCDC1_FORCE_PWM_ENA;
+
        dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
                mask, active, sleep, force);
 
@@ -1150,6 +1181,7 @@ static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
 static struct regulator_ops wm8350_dcdc_ops = {
        .set_voltage = wm8350_dcdc_set_voltage,
        .get_voltage = wm8350_dcdc_get_voltage,
+       .list_voltage = wm8350_dcdc_list_voltage,
        .enable = wm8350_dcdc_enable,
        .disable = wm8350_dcdc_disable,
        .get_mode = wm8350_dcdc_get_mode,
@@ -1173,6 +1205,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = {
 static struct regulator_ops wm8350_ldo_ops = {
        .set_voltage = wm8350_ldo_set_voltage,
        .get_voltage = wm8350_ldo_get_voltage,
+       .list_voltage = wm8350_ldo_list_voltage,
        .enable = wm8350_ldo_enable,
        .disable = wm8350_ldo_disable,
        .is_enabled = wm8350_ldo_is_enabled,
@@ -1197,6 +1230,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_dcdc_ops,
                .irq = WM8350_IRQ_UV_DC1,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1213,6 +1247,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_dcdc_ops,
                .irq = WM8350_IRQ_UV_DC3,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1221,6 +1256,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_dcdc_ops,
                .irq = WM8350_IRQ_UV_DC4,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1237,6 +1273,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_dcdc_ops,
                .irq = WM8350_IRQ_UV_DC6,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1245,6 +1282,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_ldo_ops,
                .irq = WM8350_IRQ_UV_LDO1,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_LDO1_VSEL_MASK + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1253,6 +1291,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_ldo_ops,
                .irq = WM8350_IRQ_UV_LDO2,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_LDO2_VSEL_MASK + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1261,6 +1300,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_ldo_ops,
                .irq = WM8350_IRQ_UV_LDO3,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_LDO3_VSEL_MASK + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1269,6 +1309,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_ldo_ops,
                .irq = WM8350_IRQ_UV_LDO4,
                .type = REGULATOR_VOLTAGE,
+               .n_voltages = WM8350_LDO4_VSEL_MASK + 1,
                .owner = THIS_MODULE,
        },
        {
@@ -1293,6 +1334,7 @@ static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
 {
        struct regulator_dev *rdev = (struct regulator_dev *)data;
 
+       mutex_lock(&rdev->mutex);
        if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
                regulator_notifier_call_chain(rdev,
                                              REGULATOR_EVENT_REGULATION_OUT,
@@ -1301,6 +1343,7 @@ static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
                regulator_notifier_call_chain(rdev,
                                              REGULATOR_EVENT_UNDER_VOLTAGE,
                                              wm8350);
+       mutex_unlock(&rdev->mutex);
 }
 
 static int wm8350_regulator_probe(struct platform_device *pdev)
@@ -1333,9 +1376,9 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
                break;
        }
 
-
        /* register regulator */
        rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
+                                 pdev->dev.platform_data,
                                  dev_get_drvdata(&pdev->dev));
        if (IS_ERR(rdev)) {
                dev_err(&pdev->dev, "failed to register %s\n",
index 56e23d44ba591383696ec9382a1a3c4b05ae32a9..157426029071fd72e5506c34dbeaecaf9ca9b619 100644 (file)
@@ -43,6 +43,18 @@ static int wm8400_ldo_disable(struct regulator_dev *dev)
                               WM8400_LDO1_ENA, 0);
 }
 
+static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
+                                  unsigned selector)
+{
+       if (selector > WM8400_LDO1_VSEL_MASK)
+               return -EINVAL;
+
+       if (selector < 15)
+               return 900000 + (selector * 50000);
+       else
+               return 1600000 + ((selector - 14) * 100000);
+}
+
 static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
 {
        struct wm8400 *wm8400 = rdev_get_drvdata(dev);
@@ -51,10 +63,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
        val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
        val &= WM8400_LDO1_VSEL_MASK;
 
-       if (val < 15)
-               return 900000 + (val * 50000);
-       else
-               return 1600000 + ((val - 14) * 100000);
+       return wm8400_ldo_list_voltage(dev, val);
 }
 
 static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
@@ -92,6 +101,7 @@ static struct regulator_ops wm8400_ldo_ops = {
        .is_enabled = wm8400_ldo_is_enabled,
        .enable = wm8400_ldo_enable,
        .disable = wm8400_ldo_disable,
+       .list_voltage = wm8400_ldo_list_voltage,
        .get_voltage = wm8400_ldo_get_voltage,
        .set_voltage = wm8400_ldo_set_voltage,
 };
@@ -124,6 +134,15 @@ static int wm8400_dcdc_disable(struct regulator_dev *dev)
                               WM8400_DC1_ENA, 0);
 }
 
+static int wm8400_dcdc_list_voltage(struct regulator_dev *dev,
+                                   unsigned selector)
+{
+       if (selector > WM8400_DC1_VSEL_MASK)
+               return -EINVAL;
+
+       return 850000 + (selector * 25000);
+}
+
 static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
 {
        struct wm8400 *wm8400 = rdev_get_drvdata(dev);
@@ -237,6 +256,7 @@ static struct regulator_ops wm8400_dcdc_ops = {
        .is_enabled = wm8400_dcdc_is_enabled,
        .enable = wm8400_dcdc_enable,
        .disable = wm8400_dcdc_disable,
+       .list_voltage = wm8400_dcdc_list_voltage,
        .get_voltage = wm8400_dcdc_get_voltage,
        .set_voltage = wm8400_dcdc_set_voltage,
        .get_mode = wm8400_dcdc_get_mode,
@@ -249,6 +269,7 @@ static struct regulator_desc regulators[] = {
                .name = "LDO1",
                .id = WM8400_LDO1,
                .ops = &wm8400_ldo_ops,
+               .n_voltages = WM8400_LDO1_VSEL_MASK + 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -256,6 +277,7 @@ static struct regulator_desc regulators[] = {
                .name = "LDO2",
                .id = WM8400_LDO2,
                .ops = &wm8400_ldo_ops,
+               .n_voltages = WM8400_LDO2_VSEL_MASK + 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -263,6 +285,7 @@ static struct regulator_desc regulators[] = {
                .name = "LDO3",
                .id = WM8400_LDO3,
                .ops = &wm8400_ldo_ops,
+               .n_voltages = WM8400_LDO3_VSEL_MASK + 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -270,6 +293,7 @@ static struct regulator_desc regulators[] = {
                .name = "LDO4",
                .id = WM8400_LDO4,
                .ops = &wm8400_ldo_ops,
+               .n_voltages = WM8400_LDO4_VSEL_MASK + 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -277,6 +301,7 @@ static struct regulator_desc regulators[] = {
                .name = "DCDC1",
                .id = WM8400_DCDC1,
                .ops = &wm8400_dcdc_ops,
+               .n_voltages = WM8400_DC1_VSEL_MASK + 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -284,6 +309,7 @@ static struct regulator_desc regulators[] = {
                .name = "DCDC2",
                .id = WM8400_DCDC2,
                .ops = &wm8400_dcdc_ops,
+               .n_voltages = WM8400_DC2_VSEL_MASK + 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -294,7 +320,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
        struct regulator_dev *rdev;
 
        rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
-               pdev->dev.driver_data);
+               pdev->dev.platform_data, pdev->dev.driver_data);
 
        if (IS_ERR(rdev))
                return PTR_ERR(rdev);
index 81450fbd8b1246c3bca1841f8cd314af79264081..ffe34a12f446d22ad8ad9a0963e15a2cef54f4a4 100644 (file)
@@ -129,13 +129,14 @@ comment "I2C RTC drivers"
 if I2C
 
 config RTC_DRV_DS1307
-       tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
+       tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
        help
          If you say yes here you get support for various compatible RTC
          chips (often with battery backup) connected with I2C. This driver
          should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
-         and probably other chips. In some cases the RTC must already
-         have been initialized (by manufacturing or a bootloader).
+         EPSON RX-8025 and probably other chips. In some cases the RTC
+         must already have been initialized (by manufacturing or a
+         bootloader).
 
          The first seven registers on these chips hold an RTC, and other
          registers may add features such as NVRAM, a trickle charger for
@@ -224,11 +225,11 @@ config RTC_DRV_PCF8583
          will be called rtc-pcf8583.
 
 config RTC_DRV_M41T80
-       tristate "ST M41T65/M41T80/81/82/83/84/85/87"
+       tristate "ST M41T62/65/M41T80/81/82/83/84/85/87"
        help
          If you say Y here you will get support for the ST M41T60
          and M41T80 RTC chips series. Currently, the following chips are
-         supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
+         supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
          M41ST85, and M41ST87.
 
          This driver can also be built as a module. If so, the module
@@ -440,6 +441,16 @@ config RTC_DRV_DS1742
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1742.
 
+config RTC_DRV_EFI
+       tristate "EFI RTC"
+       depends on IA64
+       help
+         If you say yes here you will get support for the EFI
+         Real Time Clock.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-efi.
+
 config RTC_DRV_STK17TA8
        tristate "Simtek STK17TA8"
        depends on RTC_CLASS
@@ -677,22 +688,16 @@ config RTC_DRV_RS5C313
        help
          If you say yes here you get support for the Ricoh RS5C313 RTC chips.
 
-config RTC_DRV_PARISC
-       tristate "PA-RISC firmware RTC support"
-       depends on PARISC
+config RTC_DRV_GENERIC
+       tristate "Generic RTC support"
+       # Please consider writing a new RTC driver instead of using the generic
+       # RTC abstraction
+       depends on PARISC || M68K || PPC
        help
-         Say Y or M here to enable RTC support on PA-RISC systems using
-         firmware calls. If you do not know what you are doing, you should
+         Say Y or M here to enable RTC support on systems using the generic
+         RTC abstraction. If you do not know what you are doing, you should
          just say Y.
 
-config RTC_DRV_PPC
-       tristate "PowerPC machine dependent RTC support"
-       depends on PPC
-       help
-        The PowerPC kernel has machine-specific functions for accessing
-        the RTC. This exposes that functionality through the generic RTC
-        class.
-
 config RTC_DRV_PXA
        tristate "PXA27x/PXA3xx"
        depends on ARCH_PXA
@@ -736,4 +741,13 @@ config RTC_DRV_MV
          This driver can also be built as a module. If so, the module
          will be called rtc-mv.
 
+config RTC_DRV_PS3
+       tristate "PS3 RTC"
+       depends on PPC_PS3
+       help
+         If you say yes here you will get support for the RTC on PS3.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ps3.
+
 endif # RTC_CLASS
index 0e697aa51caa5a2d8f891772ed793dd1d69d2f45..6c0639a14f09446d09de01f42a8a8a74314a95c5 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_RTC_DRV_DS1553)  += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)   += rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)   += rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_DS3234)   += rtc-ds3234.o
+obj-$(CONFIG_RTC_DRV_EFI)      += rtc-efi.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_FM3130)   += rtc-fm3130.o
 obj-$(CONFIG_RTC_DRV_ISL1208)  += rtc-isl1208.o
@@ -55,8 +56,7 @@ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_PL030)    += rtc-pl030.o
 obj-$(CONFIG_RTC_DRV_PL031)    += rtc-pl031.o
-obj-$(CONFIG_RTC_DRV_PARISC)   += rtc-parisc.o
-obj-$(CONFIG_RTC_DRV_PPC)      += rtc-ppc.o
+obj-$(CONFIG_RTC_DRV_GENERIC)  += rtc-generic.o
 obj-$(CONFIG_RTC_DRV_PXA)      += rtc-pxa.o
 obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
@@ -76,3 +76,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX)  += rtc-vr41xx.o
 obj-$(CONFIG_RTC_DRV_WM8350)   += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
+obj-$(CONFIG_RTC_DRV_PS3)      += rtc-ps3.o
index 7e5155e88ac75a19c9a4f6809298da344f020516..2c4a65302a9dbf55c5a73af88146aeb3e80dd872 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2005 James Chapman (ds1337 core)
  *  Copyright (C) 2006 David Brownell
+ *  Copyright (C) 2009 Matthias Fuchs (rx8025 support)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -31,6 +32,7 @@ enum ds_type {
        ds_1339,
        ds_1340,
        m41t00,
+       rx_8025,
        // rs5c372 too?  different address...
 };
 
@@ -83,6 +85,12 @@ enum ds_type {
 #define DS1339_REG_ALARM1_SECS 0x07
 #define DS1339_REG_TRICKLE     0x10
 
+#define RX8025_REG_CTRL1       0x0e
+#      define RX8025_BIT_2412          0x20
+#define RX8025_REG_CTRL2       0x0f
+#      define RX8025_BIT_PON           0x10
+#      define RX8025_BIT_VDET          0x40
+#      define RX8025_BIT_XST           0x20
 
 
 struct ds1307 {
@@ -94,6 +102,10 @@ struct ds1307 {
        struct i2c_client       *client;
        struct rtc_device       *rtc;
        struct work_struct      work;
+       s32 (*read_block_data)(struct i2c_client *client, u8 command,
+                              u8 length, u8 *values);
+       s32 (*write_block_data)(struct i2c_client *client, u8 command,
+                               u8 length, const u8 *values);
 };
 
 struct chip_desc {
@@ -117,6 +129,8 @@ static const struct chip_desc chips[] = {
 [ds_1340] = {
 },
 [m41t00] = {
+},
+[rx_8025] = {
 }, };
 
 static const struct i2c_device_id ds1307_id[] = {
@@ -126,12 +140,86 @@ static const struct i2c_device_id ds1307_id[] = {
        { "ds1339", ds_1339 },
        { "ds1340", ds_1340 },
        { "m41t00", m41t00 },
+       { "rx8025", rx_8025 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ds1307_id);
 
 /*----------------------------------------------------------------------*/
 
+#define BLOCK_DATA_MAX_TRIES 10
+
+static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
+                                 u8 length, u8 *values)
+{
+       s32 i, data;
+
+       for (i = 0; i < length; i++) {
+               data = i2c_smbus_read_byte_data(client, command + i);
+               if (data < 0)
+                       return data;
+               values[i] = data;
+       }
+       return i;
+}
+
+static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
+                                 u8 length, u8 *values)
+{
+       u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
+       s32 ret;
+       int tries = 0;
+
+       dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length);
+       ret = ds1307_read_block_data_once(client, command, length, values);
+       if (ret < 0)
+               return ret;
+       do {
+               if (++tries > BLOCK_DATA_MAX_TRIES) {
+                       dev_err(&client->dev,
+                               "ds1307_read_block_data failed\n");
+                       return -EIO;
+               }
+               memcpy(oldvalues, values, length);
+               ret = ds1307_read_block_data_once(client, command, length,
+                                                 values);
+               if (ret < 0)
+                       return ret;
+       } while (memcmp(oldvalues, values, length));
+       return length;
+}
+
+static s32 ds1307_write_block_data(struct i2c_client *client, u8 command,
+                                  u8 length, const u8 *values)
+{
+       u8 currvalues[I2C_SMBUS_BLOCK_MAX];
+       int tries = 0;
+
+       dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
+       do {
+               s32 i, ret;
+
+               if (++tries > BLOCK_DATA_MAX_TRIES) {
+                       dev_err(&client->dev,
+                               "ds1307_write_block_data failed\n");
+                       return -EIO;
+               }
+               for (i = 0; i < length; i++) {
+                       ret = i2c_smbus_write_byte_data(client, command + i,
+                                                       values[i]);
+                       if (ret < 0)
+                               return ret;
+               }
+               ret = ds1307_read_block_data_once(client, command, length,
+                                                 currvalues);
+               if (ret < 0)
+                       return ret;
+       } while (memcmp(currvalues, values, length));
+       return length;
+}
+
+/*----------------------------------------------------------------------*/
+
 /*
  * The IRQ logic includes a "real" handler running in IRQ context just
  * long enough to schedule this workqueue entry.   We need a task context
@@ -202,7 +290,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
        int             tmp;
 
        /* read the RTC date and time registers all at once */
-       tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+       tmp = ds1307->read_block_data(ds1307->client,
                DS1307_REG_SECS, 7, ds1307->regs);
        if (tmp != 7) {
                dev_err(dev, "%s error %d\n", "read", tmp);
@@ -279,7 +367,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                "write", buf[0], buf[1], buf[2], buf[3],
                buf[4], buf[5], buf[6]);
 
-       result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf);
+       result = ds1307->write_block_data(ds1307->client, 0, 7, buf);
        if (result < 0) {
                dev_err(dev, "%s error %d\n", "write", result);
                return result;
@@ -297,7 +385,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
                return -EINVAL;
 
        /* read all ALARM1, ALARM2, and status registers at once */
-       ret = i2c_smbus_read_i2c_block_data(client,
+       ret = ds1307->read_block_data(client,
                        DS1339_REG_ALARM1_SECS, 9, ds1307->regs);
        if (ret != 9) {
                dev_err(dev, "%s error %d\n", "alarm read", ret);
@@ -356,7 +444,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                t->enabled, t->pending);
 
        /* read current status of both alarms and the chip */
-       ret = i2c_smbus_read_i2c_block_data(client,
+       ret = ds1307->read_block_data(client,
                        DS1339_REG_ALARM1_SECS, 9, buf);
        if (ret != 9) {
                dev_err(dev, "%s error %d\n", "alarm write", ret);
@@ -391,7 +479,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        }
        buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
 
-       ret = i2c_smbus_write_i2c_block_data(client,
+       ret = ds1307->write_block_data(client,
                        DS1339_REG_ALARM1_SECS, 9, buf);
        if (ret < 0) {
                dev_err(dev, "can't set alarm time\n");
@@ -479,7 +567,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
        if (unlikely(!count))
                return count;
 
-       result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf);
+       result = ds1307->read_block_data(client, 8 + off, count, buf);
        if (result < 0)
                dev_err(&client->dev, "%s error %d\n", "nvram read", result);
        return result;
@@ -490,9 +578,11 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
                char *buf, loff_t off, size_t count)
 {
        struct i2c_client       *client;
+       struct ds1307           *ds1307;
        int                     result;
 
        client = kobj_to_i2c_client(kobj);
+       ds1307 = i2c_get_clientdata(client);
 
        if (unlikely(off >= NVRAM_SIZE))
                return -EFBIG;
@@ -501,7 +591,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
        if (unlikely(!count))
                return count;
 
-       result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf);
+       result = ds1307->write_block_data(client, 8 + off, count, buf);
        if (result < 0) {
                dev_err(&client->dev, "%s error %d\n", "nvram write", result);
                return result;
@@ -535,9 +625,8 @@ static int __devinit ds1307_probe(struct i2c_client *client,
        int                     want_irq = false;
        unsigned char           *buf;
 
-       if (!i2c_check_functionality(adapter,
-                       I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
-                       I2C_FUNC_SMBUS_I2C_BLOCK))
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
+           && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
                return -EIO;
 
        if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
@@ -547,6 +636,13 @@ static int __devinit ds1307_probe(struct i2c_client *client,
        i2c_set_clientdata(client, ds1307);
        ds1307->type = id->driver_data;
        buf = ds1307->regs;
+       if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
+               ds1307->read_block_data = i2c_smbus_read_i2c_block_data;
+               ds1307->write_block_data = i2c_smbus_write_i2c_block_data;
+       } else {
+               ds1307->read_block_data = ds1307_read_block_data;
+               ds1307->write_block_data = ds1307_write_block_data;
+       }
 
        switch (ds1307->type) {
        case ds_1337:
@@ -557,7 +653,7 @@ static int __devinit ds1307_probe(struct i2c_client *client,
                        want_irq = true;
                }
                /* get registers that the "rtc" read below won't read... */
-               tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+               tmp = ds1307->read_block_data(ds1307->client,
                                DS1337_REG_CONTROL, 2, buf);
                if (tmp != 2) {
                        pr_debug("read error %d\n", tmp);
@@ -589,13 +685,79 @@ static int __devinit ds1307_probe(struct i2c_client *client,
                        dev_warn(&client->dev, "SET TIME!\n");
                }
                break;
+
+       case rx_8025:
+               tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+                               RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
+               if (tmp != 2) {
+                       pr_debug("read error %d\n", tmp);
+                       err = -EIO;
+                       goto exit_free;
+               }
+
+               /* oscillator off?  turn it on, so clock can tick. */
+               if (!(ds1307->regs[1] & RX8025_BIT_XST)) {
+                       ds1307->regs[1] |= RX8025_BIT_XST;
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL2 << 4 | 0x08,
+                                                 ds1307->regs[1]);
+                       dev_warn(&client->dev,
+                                "oscillator stop detected - SET TIME!\n");
+               }
+
+               if (ds1307->regs[1] & RX8025_BIT_PON) {
+                       ds1307->regs[1] &= ~RX8025_BIT_PON;
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL2 << 4 | 0x08,
+                                                 ds1307->regs[1]);
+                       dev_warn(&client->dev, "power-on detected\n");
+               }
+
+               if (ds1307->regs[1] & RX8025_BIT_VDET) {
+                       ds1307->regs[1] &= ~RX8025_BIT_VDET;
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL2 << 4 | 0x08,
+                                                 ds1307->regs[1]);
+                       dev_warn(&client->dev, "voltage drop detected\n");
+               }
+
+               /* make sure we are running in 24hour mode */
+               if (!(ds1307->regs[0] & RX8025_BIT_2412)) {
+                       u8 hour;
+
+                       /* switch to 24 hour mode */
+                       i2c_smbus_write_byte_data(client,
+                                                 RX8025_REG_CTRL1 << 4 | 0x08,
+                                                 ds1307->regs[0] |
+                                                 RX8025_BIT_2412);
+
+                       tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+                                       RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
+                       if (tmp != 2) {
+                               pr_debug("read error %d\n", tmp);
+                               err = -EIO;
+                               goto exit_free;
+                       }
+
+                       /* correct hour */
+                       hour = bcd2bin(ds1307->regs[DS1307_REG_HOUR]);
+                       if (hour == 12)
+                               hour = 0;
+                       if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
+                               hour += 12;
+
+                       i2c_smbus_write_byte_data(client,
+                                                 DS1307_REG_HOUR << 4 | 0x08,
+                                                 hour);
+               }
+               break;
        default:
                break;
        }
 
 read_rtc:
        /* read RTC registers */
-       tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf);
+       tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf);
        if (tmp != 8) {
                pr_debug("read error %d\n", tmp);
                err = -EIO;
@@ -649,6 +811,7 @@ read_rtc:
                        dev_warn(&client->dev, "SET TIME!\n");
                }
                break;
+       case rx_8025:
        case ds_1337:
        case ds_1339:
                break;
@@ -662,6 +825,8 @@ read_rtc:
                 * systems that will run through year 2100.
                 */
                break;
+       case rx_8025:
+               break;
        default:
                if (!(tmp & DS1307_BIT_12HR))
                        break;
index a5b0fc09f0c673976720b10eca2cc3ecf8ff03bb..4d32e328f6cd6b7bb2e9cf9e72748b6031f30ef6 100644 (file)
@@ -222,16 +222,16 @@ static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        rtc_tm_to_time(&alarm->time, &new_alarm);
        rtc_tm_to_time(&now, &itime);
 
-       new_alarm -= itime;
-
        /* This can happen due to races, in addition to dates that are
         * truly in the past.  To avoid requiring the caller to check for
         * races, dates in the past are assumed to be in the recent past
         * (i.e. not something that we'd rather the caller know about via
         * an error), and the alarm is set to go off as soon as possible.
         */
-       if (new_alarm <= 0)
+       if (time_before_eq(new_alarm, itime))
                new_alarm = 1;
+       else
+               new_alarm -= itime;
 
        mutex_lock(&ds1374->mutex);
 
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
new file mode 100644 (file)
index 0000000..5502923
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * rtc-efi: RTC Class Driver for EFI-based systems
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Author: dann frazier <dannf@hp.com>
+ * Based on efirtc.c by Stephane Eranian
+ *
+ *  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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/efi.h>
+
+#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
+/*
+ * EFI Epoch is 1/1/1998
+ */
+#define EFI_RTC_EPOCH          1998
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(efi_time_t *eft)
+{
+       /* efi_time_t.month is in the [1-12] so, we need -1 */
+       return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
+}
+/*
+ * returns day of the week [0-6] 0=Sunday
+ *
+ * Don't try to provide a year that's before 1998, please !
+ */
+static int
+compute_wday(efi_time_t *eft)
+{
+       int y;
+       int ndays = 0;
+
+       if (eft->year < 1998) {
+               printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+               return -1;
+       }
+
+       for (y = EFI_RTC_EPOCH; y < eft->year; y++)
+               ndays += 365 + (is_leap_year(y) ? 1 : 0);
+
+       ndays += compute_yday(eft);
+
+       /*
+        * 4=1/1/1998 was a Thursday
+        */
+       return (ndays + 4) % 7;
+}
+
+static void
+convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
+{
+       eft->year       = wtime->tm_year + 1900;
+       eft->month      = wtime->tm_mon + 1;
+       eft->day        = wtime->tm_mday;
+       eft->hour       = wtime->tm_hour;
+       eft->minute     = wtime->tm_min;
+       eft->second     = wtime->tm_sec;
+       eft->nanosecond = 0;
+       eft->daylight   = wtime->tm_isdst ? EFI_ISDST : 0;
+       eft->timezone   = EFI_UNSPECIFIED_TIMEZONE;
+}
+
+static void
+convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
+{
+       memset(wtime, 0, sizeof(*wtime));
+       wtime->tm_sec  = eft->second;
+       wtime->tm_min  = eft->minute;
+       wtime->tm_hour = eft->hour;
+       wtime->tm_mday = eft->day;
+       wtime->tm_mon  = eft->month - 1;
+       wtime->tm_year = eft->year - 1900;
+
+       /* day of the week [0-6], Sunday=0 */
+       wtime->tm_wday = compute_wday(eft);
+
+       /* day in the year [1-365]*/
+       wtime->tm_yday = compute_yday(eft);
+
+
+       switch (eft->daylight & EFI_ISDST) {
+       case EFI_ISDST:
+               wtime->tm_isdst = 1;
+               break;
+       case EFI_TIME_ADJUST_DAYLIGHT:
+               wtime->tm_isdst = 0;
+               break;
+       default:
+               wtime->tm_isdst = -1;
+       }
+}
+
+static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       efi_time_t eft;
+       efi_status_t status;
+
+       /*
+        * As of EFI v1.10, this call always returns an unsupported status
+        */
+       status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
+                                    (efi_bool_t *)&wkalrm->pending, &eft);
+
+       if (status != EFI_SUCCESS)
+               return -EINVAL;
+
+       convert_from_efi_time(&eft, &wkalrm->time);
+
+       return rtc_valid_tm(&wkalrm->time);
+}
+
+static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       efi_time_t eft;
+       efi_status_t status;
+
+       convert_to_efi_time(&wkalrm->time, &eft);
+
+       /*
+        * XXX Fixme:
+        * As of EFI 0.92 with the firmware I have on my
+        * machine this call does not seem to work quite
+        * right
+        *
+        * As of v1.10, this call always returns an unsupported status
+        */
+       status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
+
+       printk(KERN_WARNING "write status is %d\n", (int)status);
+
+       return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static int efi_read_time(struct device *dev, struct rtc_time *tm)
+{
+       efi_status_t status;
+       efi_time_t eft;
+       efi_time_cap_t cap;
+
+       status = efi.get_time(&eft, &cap);
+
+       if (status != EFI_SUCCESS) {
+               /* should never happen */
+               printk(KERN_ERR "efitime: can't read time\n");
+               return -EINVAL;
+       }
+
+       convert_from_efi_time(&eft, tm);
+
+       return rtc_valid_tm(tm);
+}
+
+static int efi_set_time(struct device *dev, struct rtc_time *tm)
+{
+       efi_status_t status;
+       efi_time_t eft;
+
+       convert_to_efi_time(tm, &eft);
+
+       status = efi.set_time(&eft);
+
+       return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static const struct rtc_class_ops efi_rtc_ops = {
+       .read_time = efi_read_time,
+       .set_time = efi_set_time,
+       .read_alarm = efi_read_alarm,
+       .set_alarm = efi_set_alarm,
+};
+
+static int __init efi_rtc_probe(struct platform_device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+                                       THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       platform_set_drvdata(dev, rtc);
+
+       return 0;
+}
+
+static int __exit efi_rtc_remove(struct platform_device *dev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(dev);
+
+       rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+static struct platform_driver efi_rtc_driver = {
+       .driver = {
+               .name = "rtc-efi",
+               .owner = THIS_MODULE,
+       },
+       .probe = efi_rtc_probe,
+       .remove = __exit_p(efi_rtc_remove),
+};
+
+static int __init efi_rtc_init(void)
+{
+       return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
+}
+
+static void __exit efi_rtc_exit(void)
+{
+       platform_driver_unregister(&efi_rtc_driver);
+}
+
+module_init(efi_rtc_init);
+module_exit(efi_rtc_exit);
+
+MODULE_AUTHOR("dann frazier <dannf@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EFI RTC driver");
diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c
new file mode 100644 (file)
index 0000000..9832200
--- /dev/null
@@ -0,0 +1,84 @@
+/* rtc-generic: RTC driver using the generic RTC abstraction
+ *
+ * Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <asm/rtc.h>
+
+static int generic_get_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned int ret = get_rtc_time(tm);
+
+       if (ret & RTC_BATT_BAD)
+               return -EOPNOTSUPP;
+
+       return rtc_valid_tm(tm);
+}
+
+static int generic_set_time(struct device *dev, struct rtc_time *tm)
+{
+       if (set_rtc_time(tm) < 0)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+static const struct rtc_class_ops generic_rtc_ops = {
+       .read_time = generic_get_time,
+       .set_time = generic_set_time,
+};
+
+static int __init generic_rtc_probe(struct platform_device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = rtc_device_register("rtc-generic", &dev->dev, &generic_rtc_ops,
+                                 THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       platform_set_drvdata(dev, rtc);
+
+       return 0;
+}
+
+static int __exit generic_rtc_remove(struct platform_device *dev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(dev);
+
+       rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+static struct platform_driver generic_rtc_driver = {
+       .driver = {
+               .name = "rtc-generic",
+               .owner = THIS_MODULE,
+       },
+       .remove = __exit_p(generic_rtc_remove),
+};
+
+static int __init generic_rtc_init(void)
+{
+       return platform_driver_probe(&generic_rtc_driver, generic_rtc_probe);
+}
+
+static void __exit generic_rtc_fini(void)
+{
+       platform_driver_unregister(&generic_rtc_driver);
+}
+
+module_init(generic_rtc_init);
+module_exit(generic_rtc_fini);
+
+MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic RTC driver");
+MODULE_ALIAS("platform:rtc-generic");
index dd70bf73ce9d5e3dd5fa1686c12f1c46421b5624..773851f338b81df956913d57a80e198a40ffdb82 100644 (file)
@@ -26,14 +26,13 @@ static const unsigned short rtc_ydays[2][13] = {
 };
 
 #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
 
 /*
  * The number of days in the month.
  */
 int rtc_month_days(unsigned int month, unsigned int year)
 {
-       return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
+       return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
 }
 EXPORT_SYMBOL(rtc_month_days);
 
@@ -42,7 +41,7 @@ EXPORT_SYMBOL(rtc_month_days);
  */
 int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
 {
-       return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
+       return rtc_ydays[is_leap_year(year)][month] + day-1;
 }
 EXPORT_SYMBOL(rtc_year_days);
 
@@ -66,7 +65,7 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
                - LEAPS_THRU_END_OF(1970 - 1);
        if (days < 0) {
                year -= 1;
-               days += 365 + LEAP_YEAR(year);
+               days += 365 + is_leap_year(year);
        }
        tm->tm_year = year - 1900;
        tm->tm_yday = days + 1;
index 893f7dece239522afcca4579d2524dba58f645a0..60fe266f0f494c7bd5db9b93763f4f4b7e7b2745 100644 (file)
 #define M41T80_FEATURE_BL      (1 << 1)        /* Battery low indicator */
 #define M41T80_FEATURE_SQ      (1 << 2)        /* Squarewave feature */
 #define M41T80_FEATURE_WD      (1 << 3)        /* Extra watchdog resolution */
+#define M41T80_FEATURE_SQ_ALT  (1 << 4)        /* RSx bits are in reg 4 */
 
 #define DRV_VERSION "0.05"
 
 static const struct i2c_device_id m41t80_id[] = {
+       { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
        { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
        { "m41t80", M41T80_FEATURE_SQ },
        { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
@@ -393,12 +395,15 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int val;
+       int val, reg_sqw;
 
        if (!(clientdata->features & M41T80_FEATURE_SQ))
                return -EINVAL;
 
-       val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
+       reg_sqw = M41T80_REG_SQW;
+       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
+               reg_sqw = M41T80_REG_WDAY;
+       val = i2c_smbus_read_byte_data(client, reg_sqw);
        if (val < 0)
                return -EIO;
        val = (val >> 4) & 0xf;
@@ -419,7 +424,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int almon, sqw;
+       int almon, sqw, reg_sqw;
        int val = simple_strtoul(buf, NULL, 0);
 
        if (!(clientdata->features & M41T80_FEATURE_SQ))
@@ -440,13 +445,16 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
        almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
        if (almon < 0)
                return -EIO;
-       sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
+       reg_sqw = M41T80_REG_SQW;
+       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
+               reg_sqw = M41T80_REG_WDAY;
+       sqw = i2c_smbus_read_byte_data(client, reg_sqw);
        if (sqw < 0)
                return -EIO;
        sqw = (sqw & 0x0f) | (val << 4);
        if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
                                      almon & ~M41T80_ALMON_SQWE) < 0 ||
-           i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0)
+           i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0)
                return -EIO;
        if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
                                             almon | M41T80_ALMON_SQWE) < 0)
diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c
deleted file mode 100644 (file)
index c6bfa6f..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/* rtc-parisc: RTC for HP PA-RISC firmware
- *
- * Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/time.h>
-#include <linux/platform_device.h>
-
-#include <asm/rtc.h>
-
-/* as simple as can be, and no simpler. */
-struct parisc_rtc {
-       struct rtc_device *rtc;
-       spinlock_t lock;
-};
-
-static int parisc_get_time(struct device *dev, struct rtc_time *tm)
-{
-       struct parisc_rtc *p = dev_get_drvdata(dev);
-       unsigned long flags, ret;
-
-       spin_lock_irqsave(&p->lock, flags);
-       ret = get_rtc_time(tm);
-       spin_unlock_irqrestore(&p->lock, flags);
-
-       if (ret & RTC_BATT_BAD)
-               return -EOPNOTSUPP;
-
-       return 0;
-}
-
-static int parisc_set_time(struct device *dev, struct rtc_time *tm)
-{
-       struct parisc_rtc *p = dev_get_drvdata(dev);
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&p->lock, flags);
-       ret = set_rtc_time(tm);
-       spin_unlock_irqrestore(&p->lock, flags);
-
-       if (ret < 0)
-               return -EOPNOTSUPP;
-
-       return 0;
-}
-
-static const struct rtc_class_ops parisc_rtc_ops = {
-       .read_time = parisc_get_time,
-       .set_time = parisc_set_time,
-};
-
-static int __devinit parisc_rtc_probe(struct platform_device *dev)
-{
-       struct parisc_rtc *p;
-
-       p = kzalloc(sizeof (*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       spin_lock_init(&p->lock);
-
-       p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops,
-                                       THIS_MODULE);
-       if (IS_ERR(p->rtc)) {
-               int err = PTR_ERR(p->rtc);
-               kfree(p);
-               return err;
-       }
-
-       platform_set_drvdata(dev, p);
-
-       return 0;
-}
-
-static int __devexit parisc_rtc_remove(struct platform_device *dev)
-{
-       struct parisc_rtc *p = platform_get_drvdata(dev);
-
-       rtc_device_unregister(p->rtc);
-       kfree(p);
-
-       return 0;
-}
-
-static struct platform_driver parisc_rtc_driver = {
-       .driver = {
-               .name = "rtc-parisc",
-               .owner = THIS_MODULE,
-       },
-       .probe = parisc_rtc_probe,
-       .remove = __devexit_p(parisc_rtc_remove),
-};
-
-static int __init parisc_rtc_init(void)
-{
-       return platform_driver_register(&parisc_rtc_driver);
-}
-
-static void __exit parisc_rtc_fini(void)
-{
-       platform_driver_unregister(&parisc_rtc_driver);
-}
-
-module_init(parisc_rtc_init);
-module_exit(parisc_rtc_fini);
-
-MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("HP PA-RISC RTC driver");
diff --git a/drivers/rtc/rtc-ppc.c b/drivers/rtc/rtc-ppc.c
deleted file mode 100644 (file)
index c8e97e2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * RTC driver for ppc_md RTC functions
- *
- * Â© 2007 Red Hat, Inc.
- *
- * Author: David Woodhouse <dwmw2@infradead.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/rtc.h>
-#include <linux/platform_device.h>
-#include <asm/machdep.h>
-
-static int ppc_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
-       ppc_md.get_rtc_time(tm);
-       return 0;
-}
-
-static int ppc_rtc_set_time(struct device *dev, struct rtc_time *tm)
-{
-       return ppc_md.set_rtc_time(tm);
-}
-
-static const struct rtc_class_ops ppc_rtc_ops = {
-       .set_time = ppc_rtc_set_time,
-       .read_time = ppc_rtc_read_time,
-};
-
-static struct rtc_device *rtc;
-static struct platform_device *ppc_rtc_pdev;
-
-static int __init ppc_rtc_init(void)
-{
-       if (!ppc_md.get_rtc_time || !ppc_md.set_rtc_time)
-               return -ENODEV;
-
-       ppc_rtc_pdev = platform_device_register_simple("ppc-rtc", 0, NULL, 0);
-       if (IS_ERR(ppc_rtc_pdev))
-               return PTR_ERR(ppc_rtc_pdev);
-
-       rtc = rtc_device_register("ppc_md", &ppc_rtc_pdev->dev,
-                                 &ppc_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               platform_device_unregister(ppc_rtc_pdev);
-               return PTR_ERR(rtc);
-       }
-
-       return 0;
-}
-
-static void __exit ppc_rtc_exit(void)
-{
-       rtc_device_unregister(rtc);
-       platform_device_unregister(ppc_rtc_pdev);
-}
-
-module_init(ppc_rtc_init);
-module_exit(ppc_rtc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("Generic RTC class driver for PowerPC");
index 0c6257a034ff07b3dc85e9ce1db3847571c97fc4..c086fc30a84c9ad3b4e834559a4d433688758a1a 100644 (file)
@@ -105,14 +105,8 @@ static const struct file_operations rtc_proc_fops = {
 
 void rtc_proc_add_device(struct rtc_device *rtc)
 {
-       if (rtc->id == 0) {
-               struct proc_dir_entry *ent;
-
-               ent = proc_create_data("driver/rtc", 0, NULL,
-                                      &rtc_proc_fops, rtc);
-               if (ent)
-                       ent->owner = rtc->owner;
-       }
+       if (rtc->id == 0)
+               proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);
 }
 
 void rtc_proc_del_device(struct rtc_device *rtc)
diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c
new file mode 100644 (file)
index 0000000..968133c
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * PS3 RTC Driver
+ *
+ * Copyright 2009 Sony Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3.h>
+
+
+static u64 read_rtc(void)
+{
+       int result;
+       u64 rtc_val;
+       u64 tb_val;
+
+       result = lv1_get_rtc(&rtc_val, &tb_val);
+       BUG_ON(result);
+
+       return rtc_val;
+}
+
+static int ps3_get_time(struct device *dev, struct rtc_time *tm)
+{
+       rtc_time_to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm);
+       return rtc_valid_tm(tm);
+}
+
+static int ps3_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned long now;
+
+       rtc_tm_to_time(tm, &now);
+       ps3_os_area_set_rtc_diff(now - read_rtc());
+       return 0;
+}
+
+static const struct rtc_class_ops ps3_rtc_ops = {
+       .read_time = ps3_get_time,
+       .set_time = ps3_set_time,
+};
+
+static int __init ps3_rtc_probe(struct platform_device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = rtc_device_register("rtc-ps3", &dev->dev, &ps3_rtc_ops,
+                                 THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       platform_set_drvdata(dev, rtc);
+       return 0;
+}
+
+static int __exit ps3_rtc_remove(struct platform_device *dev)
+{
+       rtc_device_unregister(platform_get_drvdata(dev));
+       return 0;
+}
+
+static struct platform_driver ps3_rtc_driver = {
+       .driver = {
+               .name = "rtc-ps3",
+               .owner = THIS_MODULE,
+       },
+       .remove = __exit_p(ps3_rtc_remove),
+};
+
+static int __init ps3_rtc_init(void)
+{
+       return platform_driver_probe(&ps3_rtc_driver, ps3_rtc_probe);
+}
+
+static void __exit ps3_rtc_fini(void)
+{
+       platform_driver_unregister(&ps3_rtc_driver);
+}
+
+module_init(ps3_rtc_init);
+module_exit(ps3_rtc_fini);
+
+MODULE_AUTHOR("Sony Corporation");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ps3 RTC driver");
+MODULE_ALIAS("platform:rtc-ps3");
index 14d4f036a7686e7c637752c95ae620df99458f77..ad164056feb6692cf7e66896a1c9f0d6b050b073 100644 (file)
 #include <linux/bcd.h>
 #include <linux/rtc-v3020.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 #undef DEBUG
 
+struct v3020;
+
+struct v3020_chip_ops {
+       int (*map_io)(struct v3020 *chip, struct platform_device *pdev,
+                     struct v3020_platform_data *pdata);
+       void (*unmap_io)(struct v3020 *chip);
+       unsigned char (*read_bit)(struct v3020 *chip);
+       void (*write_bit)(struct v3020 *chip, unsigned char bit);
+};
+
+#define V3020_CS       0
+#define V3020_WR       1
+#define V3020_RD       2
+#define V3020_IO       3
+
+struct v3020_gpio {
+       const char *name;
+       unsigned int gpio;
+};
+
 struct v3020 {
+       /* MMIO access */
        void __iomem *ioaddress;
        int leftshift;
+
+       /* GPIO access */
+       struct v3020_gpio *gpio;
+
+       struct v3020_chip_ops *ops;
+
        struct rtc_device *rtc;
 };
 
+
+static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev,
+                         struct v3020_platform_data *pdata)
+{
+       if (pdev->num_resources != 1)
+               return -EBUSY;
+
+       if (pdev->resource[0].flags != IORESOURCE_MEM)
+               return -EBUSY;
+
+       chip->leftshift = pdata->leftshift;
+       chip->ioaddress = ioremap(pdev->resource[0].start, 1);
+       if (chip->ioaddress == NULL)
+               return -EBUSY;
+
+       return 0;
+}
+
+static void v3020_mmio_unmap(struct v3020 *chip)
+{
+       iounmap(chip->ioaddress);
+}
+
+static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit)
+{
+       writel(bit << chip->leftshift, chip->ioaddress);
+}
+
+static unsigned char v3020_mmio_read_bit(struct v3020 *chip)
+{
+       return readl(chip->ioaddress) & (1 << chip->leftshift);
+}
+
+static struct v3020_chip_ops v3020_mmio_ops = {
+       .map_io         = v3020_mmio_map,
+       .unmap_io       = v3020_mmio_unmap,
+       .read_bit       = v3020_mmio_read_bit,
+       .write_bit      = v3020_mmio_write_bit,
+};
+
+static struct v3020_gpio v3020_gpio[] = {
+       { "RTC CS", 0 },
+       { "RTC WR", 0 },
+       { "RTC RD", 0 },
+       { "RTC IO", 0 },
+};
+
+static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev,
+                         struct v3020_platform_data *pdata)
+{
+       int i, err;
+
+       v3020_gpio[V3020_CS].gpio = pdata->gpio_cs;
+       v3020_gpio[V3020_WR].gpio = pdata->gpio_wr;
+       v3020_gpio[V3020_RD].gpio = pdata->gpio_rd;
+       v3020_gpio[V3020_IO].gpio = pdata->gpio_io;
+
+       for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) {
+               err = gpio_request(v3020_gpio[i].gpio, v3020_gpio[i].name);
+               if (err)
+                       goto err_request;
+
+               gpio_direction_output(v3020_gpio[i].gpio, 1);
+       }
+
+       chip->gpio = v3020_gpio;
+
+       return 0;
+
+err_request:
+       while (--i >= 0)
+               gpio_free(v3020_gpio[i].gpio);
+
+       return err;
+}
+
+static void v3020_gpio_unmap(struct v3020 *chip)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++)
+               gpio_free(v3020_gpio[i].gpio);
+}
+
+static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit)
+{
+       gpio_direction_output(chip->gpio[V3020_IO].gpio, bit);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
+       gpio_set_value(chip->gpio[V3020_WR].gpio, 0);
+       udelay(1);
+       gpio_set_value(chip->gpio[V3020_WR].gpio, 1);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
+}
+
+static unsigned char v3020_gpio_read_bit(struct v3020 *chip)
+{
+       int bit;
+
+       gpio_direction_input(chip->gpio[V3020_IO].gpio);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
+       gpio_set_value(chip->gpio[V3020_RD].gpio, 0);
+       udelay(1);
+       bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio);
+       udelay(1);
+       gpio_set_value(chip->gpio[V3020_RD].gpio, 1);
+       gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
+
+       return bit;
+}
+
+static struct v3020_chip_ops v3020_gpio_ops = {
+       .map_io         = v3020_gpio_map,
+       .unmap_io       = v3020_gpio_unmap,
+       .read_bit       = v3020_gpio_read_bit,
+       .write_bit      = v3020_gpio_write_bit,
+};
+
 static void v3020_set_reg(struct v3020 *chip, unsigned char address,
                        unsigned char data)
 {
@@ -46,7 +191,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
 
        tmp = address;
        for (i = 0; i < 4; i++) {
-               writel((tmp & 1) << chip->leftshift, chip->ioaddress);
+               chip->ops->write_bit(chip, (tmp & 1));
                tmp >>= 1;
                udelay(1);
        }
@@ -54,7 +199,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
        /* Commands dont have data */
        if (!V3020_IS_COMMAND(address)) {
                for (i = 0; i < 8; i++) {
-                       writel((data & 1) << chip->leftshift, chip->ioaddress);
+                       chip->ops->write_bit(chip, (data & 1));
                        data >>= 1;
                        udelay(1);
                }
@@ -63,18 +208,18 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
 
 static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
 {
-       unsigned int data=0;
+       unsigned int data = 0;
        int i;
 
        for (i = 0; i < 4; i++) {
-               writel((address & 1) << chip->leftshift, chip->ioaddress);
+               chip->ops->write_bit(chip, (address & 1));
                address >>= 1;
                udelay(1);
        }
 
        for (i = 0; i < 8; i++) {
                data >>= 1;
-               if (readl(chip->ioaddress) & (1 << chip->leftshift))
+               if (chip->ops->read_bit(chip))
                        data |= 0x80;
                udelay(1);
        }
@@ -106,16 +251,14 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt)
        tmp = v3020_get_reg(chip, V3020_YEAR);
        dt->tm_year = bcd2bin(tmp)+100;
 
-#ifdef DEBUG
-       printk("\n%s : Read RTC values\n",__func__);
-       printk("tm_hour: %i\n",dt->tm_hour);
-       printk("tm_min : %i\n",dt->tm_min);
-       printk("tm_sec : %i\n",dt->tm_sec);
-       printk("tm_year: %i\n",dt->tm_year);
-       printk("tm_mon : %i\n",dt->tm_mon);
-       printk("tm_mday: %i\n",dt->tm_mday);
-       printk("tm_wday: %i\n",dt->tm_wday);
-#endif
+       dev_dbg(dev, "\n%s : Read RTC values\n", __func__);
+       dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+       dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+       dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+       dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
+       dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
+       dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+       dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
 
        return 0;
 }
@@ -125,15 +268,13 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt)
 {
        struct v3020 *chip = dev_get_drvdata(dev);
 
-#ifdef DEBUG
-       printk("\n%s : Setting RTC values\n",__func__);
-       printk("tm_sec : %i\n",dt->tm_sec);
-       printk("tm_min : %i\n",dt->tm_min);
-       printk("tm_hour: %i\n",dt->tm_hour);
-       printk("tm_mday: %i\n",dt->tm_mday);
-       printk("tm_wday: %i\n",dt->tm_wday);
-       printk("tm_year: %i\n",dt->tm_year);
-#endif
+       dev_dbg(dev, "\n%s : Setting RTC values\n", __func__);
+       dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+       dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+       dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+       dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+       dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
+       dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
 
        /* Write all the values to ram... */
        v3020_set_reg(chip, V3020_SECONDS,      bin2bcd(dt->tm_sec));
@@ -168,30 +309,28 @@ static int rtc_probe(struct platform_device *pdev)
        int i;
        int temp;
 
-       if (pdev->num_resources != 1)
-               return -EBUSY;
-
-       if (pdev->resource[0].flags != IORESOURCE_MEM)
-               return -EBUSY;
-
        chip = kzalloc(sizeof *chip, GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
-       chip->leftshift = pdata->leftshift;
-       chip->ioaddress = ioremap(pdev->resource[0].start, 1);
-       if (chip->ioaddress == NULL)
+       if (pdata->use_gpio)
+               chip->ops = &v3020_gpio_ops;
+       else
+               chip->ops = &v3020_mmio_ops;
+
+       retval = chip->ops->map_io(chip, pdev, pdata);
+       if (retval)
                goto err_chip;
 
        /* Make sure the v3020 expects a communication cycle
         * by reading 8 times */
        for (i = 0; i < 8; i++)
-               temp = readl(chip->ioaddress);
+               temp = chip->ops->read_bit(chip);
 
        /* Test chip by doing a write/read sequence
         * to the chip ram */
        v3020_set_reg(chip, V3020_SECONDS, 0x33);
-       if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
+       if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
                retval = -ENODEV;
                goto err_io;
        }
@@ -200,10 +339,17 @@ static int rtc_probe(struct platform_device *pdev)
         * are all disabled */
        v3020_set_reg(chip, V3020_STATUS_0, 0x0);
 
-       dev_info(&pdev->dev, "Chip available at physical address 0x%llx,"
-               "data connected to D%d\n",
-               (unsigned long long)pdev->resource[0].start,
-               chip->leftshift);
+       if (pdata->use_gpio)
+               dev_info(&pdev->dev, "Chip available at GPIOs "
+                        "%d, %d, %d, %d\n",
+                        chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio,
+                        chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio);
+       else
+               dev_info(&pdev->dev, "Chip available at "
+                        "physical address 0x%llx,"
+                        "data connected to D%d\n",
+                        (unsigned long long)pdev->resource[0].start,
+                        chip->leftshift);
 
        platform_set_drvdata(pdev, chip);
 
@@ -218,7 +364,7 @@ static int rtc_probe(struct platform_device *pdev)
        return 0;
 
 err_io:
-       iounmap(chip->ioaddress);
+       chip->ops->unmap_io(chip);
 err_chip:
        kfree(chip);
 
@@ -233,7 +379,7 @@ static int rtc_remove(struct platform_device *dev)
        if (rtc)
                rtc_device_unregister(rtc);
 
-       iounmap(chip->ioaddress);
+       chip->ops->unmap_io(chip);
        kfree(chip);
 
        return 0;
index 5c5e3aa91385bd7efa94f6ae831c03858e02a4f5..c91edc572eb609f3c78449099fabf04d0e76af8d 100644 (file)
@@ -122,7 +122,7 @@ static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm)
        do {
                rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
                schedule_timeout_uninterruptible(msecs_to_jiffies(1));
-       } while (retries-- && !(rtc_ctrl & WM8350_RTC_STS));
+       } while (--retries && !(rtc_ctrl & WM8350_RTC_STS));
 
        if (!retries) {
                dev_err(dev, "timed out on set confirmation\n");
@@ -236,6 +236,17 @@ static int wm8350_rtc_start_alarm(struct wm8350 *wm8350)
        return 0;
 }
 
+static int wm8350_rtc_alarm_irq_enable(struct device *dev,
+                                      unsigned int enabled)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+
+       if (enabled)
+               return wm8350_rtc_start_alarm(wm8350);
+       else
+               return wm8350_rtc_stop_alarm(wm8350);
+}
+
 static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct wm8350 *wm8350 = dev_get_drvdata(dev);
@@ -291,30 +302,15 @@ static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        return ret;
 }
 
-/*
- * Handle commands from user-space
- */
-static int wm8350_rtc_ioctl(struct device *dev, unsigned int cmd,
-                           unsigned long arg)
+static int wm8350_rtc_update_irq_enable(struct device *dev,
+                                       unsigned int enabled)
 {
        struct wm8350 *wm8350 = dev_get_drvdata(dev);
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               return wm8350_rtc_stop_alarm(wm8350);
-       case RTC_AIE_ON:
-               return wm8350_rtc_start_alarm(wm8350);
-
-       case RTC_UIE_OFF:
-               wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-               break;
-       case RTC_UIE_ON:
+       if (enabled)
                wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
+       else
+               wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
 
        return 0;
 }
@@ -345,11 +341,12 @@ static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq,
 }
 
 static const struct rtc_class_ops wm8350_rtc_ops = {
-       .ioctl = wm8350_rtc_ioctl,
        .read_time = wm8350_rtc_readtime,
        .set_time = wm8350_rtc_settime,
        .read_alarm = wm8350_rtc_readalarm,
        .set_alarm = wm8350_rtc_setalarm,
+       .alarm_irq_enable = wm8350_rtc_alarm_irq_enable,
+       .update_irq_enable = wm8350_rtc_update_irq_enable,
 };
 
 #ifdef CONFIG_PM
@@ -440,7 +437,7 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
                do {
                        timectl = wm8350_reg_read(wm8350,
                                                  WM8350_RTC_TIME_CONTROL);
-               } while (timectl & WM8350_RTC_STS && retries--);
+               } while (timectl & WM8350_RTC_STS && --retries);
 
                if (retries == 0) {
                        dev_err(&pdev->dev, "failed to start: timeout\n");
index 2fd64e5a9ab267ae38d6b79454125a41d929ec74..0570794ccf1c8f8d26c89f4d6825abd9d047738e 100644 (file)
@@ -2363,6 +2363,7 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
        ret = 0;
        switch (event) {
        case CIO_GONE:
+       case CIO_BOXED:
        case CIO_NO_PATH:
                /* First of all call extended error reporting. */
                dasd_eer_write(device, NULL, DASD_EER_NOPATH);
index 2080ba6a69b0ea5b906c0a3bfc1c6ed639651b8b..654daa3cdfda7bcb60ad0f51e4748c8ffdfd0da1 100644 (file)
@@ -320,7 +320,6 @@ dasd_proc_init(void)
        dasd_proc_root_entry = proc_mkdir("dasd", NULL);
        if (!dasd_proc_root_entry)
                goto out_nodasd;
-       dasd_proc_root_entry->owner = THIS_MODULE;
        dasd_devices_entry = proc_create("devices",
                                         S_IFREG | S_IRUGO | S_IWUSR,
                                         dasd_proc_root_entry,
@@ -334,7 +333,6 @@ dasd_proc_init(void)
                goto out_nostatistics;
        dasd_statistics_entry->read_proc = dasd_statistics_read;
        dasd_statistics_entry->write_proc = dasd_statistics_write;
-       dasd_statistics_entry->owner = THIS_MODULE;
        return 0;
 
  out_nostatistics:
index c4d2f667a2f685a8c887ca82d2e3346efb783125..35441fa16be1de86dcb72dd02d8e319da458edde 100644 (file)
@@ -310,8 +310,6 @@ static void ccw_device_remove_orphan_cb(struct work_struct *work)
        put_device(&cdev->dev);
 }
 
-static void ccw_device_call_sch_unregister(struct work_struct *work);
-
 static void
 ccw_device_remove_disconnected(struct ccw_device *cdev)
 {
@@ -335,11 +333,10 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
                spin_unlock_irqrestore(cdev->ccwlock, flags);
                PREPARE_WORK(&cdev->private->kick_work,
                                ccw_device_remove_orphan_cb);
+               queue_work(slow_path_wq, &cdev->private->kick_work);
        } else
                /* Deregister subchannel, which will kill the ccw device. */
-               PREPARE_WORK(&cdev->private->kick_work,
-                               ccw_device_call_sch_unregister);
-       queue_work(slow_path_wq, &cdev->private->kick_work);
+               ccw_device_schedule_sch_unregister(cdev);
 }
 
 /**
@@ -471,7 +468,7 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
        int ret;
 
        /* Do device recognition, if needed. */
-       if (cdev->id.cu_type == 0) {
+       if (cdev->private->state == DEV_STATE_BOXED) {
                ret = ccw_device_recognition(cdev);
                if (ret) {
                        CIO_MSG_EVENT(0, "Couldn't start recognition "
@@ -482,17 +479,21 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
                }
                wait_event(cdev->private->wait_q,
                           cdev->private->flags.recog_done);
+               if (cdev->private->state != DEV_STATE_OFFLINE)
+                       /* recognition failed */
+                       return -EAGAIN;
        }
        if (cdev->drv && cdev->drv->set_online)
                ccw_device_set_online(cdev);
        return 0;
 }
+
 static int online_store_handle_online(struct ccw_device *cdev, int force)
 {
        int ret;
 
        ret = online_store_recog_and_online(cdev);
-       if (ret)
+       if (ret && !force)
                return ret;
        if (force && cdev->private->state == DEV_STATE_BOXED) {
                ret = ccw_device_stlck(cdev);
@@ -500,7 +501,9 @@ static int online_store_handle_online(struct ccw_device *cdev, int force)
                        return ret;
                if (cdev->id.cu_type == 0)
                        cdev->private->state = DEV_STATE_NOT_OPER;
-               online_store_recog_and_online(cdev);
+               ret = online_store_recog_and_online(cdev);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -512,7 +515,11 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
        int force, ret;
        unsigned long i;
 
-       if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
+       if ((cdev->private->state != DEV_STATE_OFFLINE &&
+            cdev->private->state != DEV_STATE_ONLINE &&
+            cdev->private->state != DEV_STATE_BOXED &&
+            cdev->private->state != DEV_STATE_DISCONNECTED) ||
+           atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
                return -EAGAIN;
 
        if (cdev->drv && !try_module_get(cdev->drv->owner)) {
@@ -1014,6 +1021,13 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
        put_device(&sch->dev);
 }
 
+void ccw_device_schedule_sch_unregister(struct ccw_device *cdev)
+{
+       PREPARE_WORK(&cdev->private->kick_work,
+                    ccw_device_call_sch_unregister);
+       queue_work(slow_path_wq, &cdev->private->kick_work);
+}
+
 /*
  * subchannel recognition done. Called from the state machine.
  */
@@ -1025,19 +1039,17 @@ io_subchannel_recog_done(struct ccw_device *cdev)
                return;
        }
        switch (cdev->private->state) {
+       case DEV_STATE_BOXED:
+               /* Device did not respond in time. */
        case DEV_STATE_NOT_OPER:
                cdev->private->flags.recog_done = 1;
                /* Remove device found not operational. */
                if (!get_device(&cdev->dev))
                        break;
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_call_sch_unregister);
-               queue_work(slow_path_wq, &cdev->private->kick_work);
+               ccw_device_schedule_sch_unregister(cdev);
                if (atomic_dec_and_test(&ccw_device_init_count))
                        wake_up(&ccw_device_init_wq);
                break;
-       case DEV_STATE_BOXED:
-               /* Device did not respond in time. */
        case DEV_STATE_OFFLINE:
                /* 
                 * We can't register the device in interrupt context so
@@ -1551,8 +1563,7 @@ static int purge_fn(struct device *dev, void *data)
                goto out;
        CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
                      priv->dev_id.devno);
-       PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister);
-       queue_work(slow_path_wq, &cdev->private->kick_work);
+       ccw_device_schedule_sch_unregister(cdev);
 
 out:
        /* Abort loop in case of pending signal. */
index 85e01846ca658ca1ea6154985d9b142687937d6d..f1cbbd94ad4e76fbaaba927b1988ede2107d515c 100644 (file)
@@ -87,6 +87,7 @@ int ccw_device_is_orphan(struct ccw_device *);
 int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
+void ccw_device_schedule_sch_unregister(struct ccw_device *);
 int ccw_purge_blacklisted(void);
 
 /* Function prototypes for device status and basic sense stuff. */
index 87b4bfca080f86436691f5b08fcb539e37482c74..e46049261561986174c8448714e811ef6344a092 100644 (file)
@@ -256,13 +256,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                old_lpm = 0;
        if (sch->lpm != old_lpm)
                __recover_lost_chpids(sch, old_lpm);
-       if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
-               if (state == DEV_STATE_NOT_OPER) {
-                       cdev->private->flags.recog_done = 1;
-                       cdev->private->state = DEV_STATE_DISCONNECTED;
-                       return;
-               }
-               /* Boxed devices don't need extra treatment. */
+       if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID &&
+           (state == DEV_STATE_NOT_OPER || state == DEV_STATE_BOXED)) {
+               cdev->private->flags.recog_done = 1;
+               cdev->private->state = DEV_STATE_DISCONNECTED;
+               wake_up(&cdev->private->wait_q);
+               return;
        }
        notify = 0;
        same_dev = 0; /* Keep the compiler quiet... */
@@ -274,7 +273,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                              sch->schid.ssid, sch->schid.sch_no);
                break;
        case DEV_STATE_OFFLINE:
-               if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
+               if (cdev->online) {
                        same_dev = ccw_device_handle_oper(cdev);
                        notify = 1;
                }
@@ -307,12 +306,17 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                              " subchannel 0.%x.%04x\n",
                              cdev->private->dev_id.devno,
                              sch->schid.ssid, sch->schid.sch_no);
+               if (cdev->id.cu_type != 0) { /* device was recognized before */
+                       cdev->private->flags.recog_done = 1;
+                       cdev->private->state = DEV_STATE_BOXED;
+                       wake_up(&cdev->private->wait_q);
+                       return;
+               }
                break;
        }
        cdev->private->state = state;
        io_subchannel_recog_done(cdev);
-       if (state != DEV_STATE_NOT_OPER)
-               wake_up(&cdev->private->wait_q);
+       wake_up(&cdev->private->wait_q);
 }
 
 /*
@@ -390,10 +394,13 @@ ccw_device_done(struct ccw_device *cdev, int state)
 
        cdev->private->state = state;
 
-
-       if (state == DEV_STATE_BOXED)
+       if (state == DEV_STATE_BOXED) {
                CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
                              cdev->private->dev_id.devno, sch->schid.sch_no);
+               if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
+                       ccw_device_schedule_sch_unregister(cdev);
+               cdev->private->flags.donotify = 0;
+       }
 
        if (cdev->private->flags.donotify) {
                cdev->private->flags.donotify = 0;
diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/drivers/s390/net/qeth_core_offl.h b/drivers/s390/net/qeth_core_offl.h
deleted file mode 100644 (file)
index e69de29..0000000
index 1fe1e2eda5121187ecc9d060647c6159afb3cbf1..cfb0dcb6e3ff365354c85238c861140f60987577 100644 (file)
@@ -176,6 +176,11 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
                zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
                                        "ccnoti4", NULL);
                break;
+       case CIO_BOXED:
+               dev_warn(&adapter->ccw_device->dev,
+                        "The ccw device did not respond in time.\n");
+               zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
+               break;
        }
        return 1;
 }
index aab8123c59664f6b51098080868342b46001c73c..e8d032b9dfbd2a54668658a88db23b7ef76e4364 100644 (file)
@@ -94,7 +94,7 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
 
 static void zfcp_wka_port_offline(struct work_struct *work)
 {
-       struct delayed_work *dw = container_of(work, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(work);
        struct zfcp_wka_port *wka_port =
                        container_of(dw, struct zfcp_wka_port, work);
 
index e2f44e6c0bcb8cd19a7558357e012ef9d1dcb23f..20297c521e50ed7c968cd40b6779af5e45ea6423 100644 (file)
@@ -1380,7 +1380,7 @@ config SCSI_LPFC_DEBUG_FS
        bool "Emulex LightPulse Fibre Channel debugfs Support"
        depends on SCSI_LPFC && DEBUG_FS
        help
-         This makes debugging infomation from the lpfc driver
+         This makes debugging information from the lpfc driver
          available via the debugfs filesystem.
 
 config SCSI_SIM710
@@ -1388,7 +1388,7 @@ config SCSI_SIM710
        depends on (EISA || MCA) && SCSI
        select SCSI_SPI_ATTRS
        ---help---
-         This driver for NCR53c710 based SCSI host adapters.
+         This driver is for NCR53c710 based SCSI host adapters.
 
          It currently supports Compaq EISA cards and NCR MCA cards
 
index 099b5455bbce287f60ef888566913616f13e9908..b13481369642f272c34d7e021f2c32365177fb7c 100644 (file)
@@ -596,8 +596,6 @@ int __init scsi_init_devinfo(void)
                error = -ENOMEM;
                goto out;
        }
-
-       p->owner = THIS_MODULE;
 #endif /* CONFIG_SCSI_PROC_FS */
 
  out:
index 82f7b2dd08a23e934aa4d6e08ce76e3c84ab1dc4..77fbddb507fdcb65b5d4fc940e6780ae756f6da9 100644 (file)
@@ -115,8 +115,6 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
                if (!sht->proc_dir)
                        printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
                               __func__, sht->proc_name);
-               else
-                       sht->proc_dir->owner = sht->module;
        }
        mutex_unlock(&global_host_template_mutex);
 }
@@ -163,7 +161,6 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
        } 
 
        p->write_proc = proc_scsi_write_proc;
-       p->owner = sht->module;
 }
 
 /**
index 9be11b0963f2b796b21f5678466d3fd1793eacae..aa9d3a4c2d50ba86470fe3706e9d7193e72de9cf 100644 (file)
@@ -1374,7 +1374,7 @@ config SERIAL_BFIN_SPORT
        depends on BLACKFIN && EXPERIMENTAL
        select SERIAL_CORE
        help
-         Enble support SPORT emulate UART on Blackfin series.
+         Enable SPORT emulate UART on Blackfin series.
 
          To compile this driver as a module, choose M here: the
          module will be called bfin_sport_uart.
index 56841fe5f4839bd70d3e917bf32317ada965154e..0eefb07bebaf73708b7934588b54811bcc4615be 100644 (file)
@@ -513,7 +513,7 @@ static int __init mcf_console_setup(struct console *co, char *options)
        int parity = 'n';
        int flow = 'n';
 
-       if ((co->index >= 0) && (co->index <= MCF_MAXPORTS))
+       if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
                co->index = 0;
        port = &mcf_ports[co->index].port;
        if (port->membase == 0)
index 42f4e66fccafeb40cb9b97833d2a3e9da522fa89..b0bb29d804ae43620c7d0ce1ba5c94cc9f11a28a 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/console.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/serial_core.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
@@ -1682,20 +1684,20 @@ static const char *uart_type(struct uart_port *port)
 
 #ifdef CONFIG_PROC_FS
 
-static int uart_line_info(char *buf, struct uart_driver *drv, int i)
+static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
 {
        struct uart_state *state = drv->state + i;
        int pm_state;
        struct uart_port *port = state->port;
        char stat_buf[32];
        unsigned int status;
-       int mmio, ret;
+       int mmio;
 
        if (!port)
-               return 0;
+               return;
 
        mmio = port->iotype >= UPIO_MEM;
-       ret = sprintf(buf, "%d: uart:%s %s%08llX irq:%d",
+       seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
                        port->line, uart_type(port),
                        mmio ? "mmio:0x" : "port:",
                        mmio ? (unsigned long long)port->mapbase
@@ -1703,8 +1705,8 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
                        port->irq);
 
        if (port->type == PORT_UNKNOWN) {
-               strcat(buf, "\n");
-               return ret + 1;
+               seq_putc(m, '\n');
+               return;
        }
 
        if (capable(CAP_SYS_ADMIN)) {
@@ -1719,19 +1721,19 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
                        uart_change_pm(state, pm_state);
                mutex_unlock(&state->mutex);
 
-               ret += sprintf(buf + ret, " tx:%d rx:%d",
+               seq_printf(m, " tx:%d rx:%d",
                                port->icount.tx, port->icount.rx);
                if (port->icount.frame)
-                       ret += sprintf(buf + ret, " fe:%d",
+                       seq_printf(m, " fe:%d",
                                port->icount.frame);
                if (port->icount.parity)
-                       ret += sprintf(buf + ret, " pe:%d",
+                       seq_printf(m, " pe:%d",
                                port->icount.parity);
                if (port->icount.brk)
-                       ret += sprintf(buf + ret, " brk:%d",
+                       seq_printf(m, " brk:%d",
                                port->icount.brk);
                if (port->icount.overrun)
-                       ret += sprintf(buf + ret, " oe:%d",
+                       seq_printf(m, " oe:%d",
                                port->icount.overrun);
 
 #define INFOBIT(bit, str) \
@@ -1753,45 +1755,39 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
                STATBIT(TIOCM_RNG, "|RI");
                if (stat_buf[0])
                        stat_buf[0] = ' ';
-               strcat(stat_buf, "\n");
 
-               ret += sprintf(buf + ret, stat_buf);
-       } else {
-               strcat(buf, "\n");
-               ret++;
+               seq_puts(m, stat_buf);
        }
+       seq_putc(m, '\n');
 #undef STATBIT
 #undef INFOBIT
-       return ret;
 }
 
-static int uart_read_proc(char *page, char **start, off_t off,
-                         int count, int *eof, void *data)
+static int uart_proc_show(struct seq_file *m, void *v)
 {
-       struct tty_driver *ttydrv = data;
+       struct tty_driver *ttydrv = m->private;
        struct uart_driver *drv = ttydrv->driver_state;
-       int i, len = 0, l;
-       off_t begin = 0;
+       int i;
 
-       len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
                        "", "", "");
-       for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) {
-               l = uart_line_info(page + len, drv, i);
-               len += l;
-               if (len + begin > off + count)
-                       goto done;
-               if (len + begin < off) {
-                       begin += len;
-                       len = 0;
-               }
-       }
-       *eof = 1;
- done:
-       if (off >= len + begin)
-               return 0;
-       *start = page + (off - begin);
-       return (count < begin + len - off) ? count : (begin + len - off);
+       for (i = 0; i < drv->nr; i++)
+               uart_line_info(m, drv, i);
+       return 0;
 }
+
+static int uart_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, uart_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations uart_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = uart_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 #endif
 
 #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
@@ -2299,7 +2295,7 @@ static const struct tty_operations uart_ops = {
        .break_ctl      = uart_break_ctl,
        .wait_until_sent= uart_wait_until_sent,
 #ifdef CONFIG_PROC_FS
-       .read_proc      = uart_read_proc,
+       .proc_fops      = &uart_proc_fops,
 #endif
        .tiocmget       = uart_tiocmget,
        .tiocmset       = uart_tiocmset,
index d2866c293dee0a5f160e5342755ffc8be525f351..26bd03e61855fba412726f23b638066a90abcaa9 100644 (file)
@@ -178,8 +178,10 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
        if (is_active)
                setsck(spi, spi->mode & SPI_CPOL);
 
-       /* SPI is normally active-low */
-       gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+       if (cs != SPI_GPIO_NO_CHIPSELECT) {
+               /* SPI is normally active-low */
+               gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+       }
 }
 
 static int spi_gpio_setup(struct spi_device *spi)
@@ -191,15 +193,17 @@ static int spi_gpio_setup(struct spi_device *spi)
                return -EINVAL;
 
        if (!spi->controller_state) {
-               status = gpio_request(cs, dev_name(&spi->dev));
-               if (status)
-                       return status;
-               status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
+               if (cs != SPI_GPIO_NO_CHIPSELECT) {
+                       status = gpio_request(cs, dev_name(&spi->dev));
+                       if (status)
+                               return status;
+                       status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
+               }
        }
        if (!status)
                status = spi_bitbang_setup(spi);
        if (status) {
-               if (!spi->controller_state)
+               if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
                        gpio_free(cs);
        }
        return status;
@@ -209,7 +213,8 @@ static void spi_gpio_cleanup(struct spi_device *spi)
 {
        unsigned long   cs = (unsigned long) spi->controller_data;
 
-       gpio_free(cs);
+       if (cs != SPI_GPIO_NO_CHIPSELECT)
+               gpio_free(cs);
        spi_bitbang_cleanup(spi);
 }
 
index 44a2b46ccb795e8d6dd8ccef2f43dcad482d5ef1..f4573a96af2459620b0b4b4d5f09c6f87acaf11a 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_spi.h>
 
+#include <sysdev/fsl_soc.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -79,7 +87,7 @@ struct mpc83xx_spi {
        u32(*get_tx) (struct mpc83xx_spi *);
 
        unsigned int count;
-       int irq;
+       unsigned int irq;
 
        unsigned nsecs;         /* (clock cycle time)/2 */
 
@@ -89,9 +97,6 @@ struct mpc83xx_spi {
 
        bool qe_mode;
 
-       void (*activate_cs) (u8 cs, u8 polarity);
-       void (*deactivate_cs) (u8 cs, u8 polarity);
-
        u8 busy;
 
        struct workqueue_struct *workqueue;
@@ -123,6 +128,7 @@ static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg)
 }
 
 #define MPC83XX_SPI_RX_BUF(type)                                         \
+static                                                                   \
 void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
 {                                                                        \
        type * rx = mpc83xx_spi->rx;                                      \
@@ -131,6 +137,7 @@ void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
 }
 
 #define MPC83XX_SPI_TX_BUF(type)                               \
+static                                                         \
 u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
 {                                                              \
        u32 data;                                               \
@@ -151,15 +158,14 @@ MPC83XX_SPI_TX_BUF(u32)
 
 static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
 {
-       struct mpc83xx_spi *mpc83xx_spi;
-       u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+       struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
+       struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
+       bool pol = spi->mode & SPI_CS_HIGH;
        struct spi_mpc83xx_cs   *cs = spi->controller_state;
 
-       mpc83xx_spi = spi_master_get_devdata(spi->master);
-
        if (value == BITBANG_CS_INACTIVE) {
-               if (mpc83xx_spi->deactivate_cs)
-                       mpc83xx_spi->deactivate_cs(spi->chip_select, pol);
+               if (pdata->cs_control)
+                       pdata->cs_control(spi, !pol);
        }
 
        if (value == BITBANG_CS_ACTIVE) {
@@ -172,7 +178,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
 
                if (cs->hw_mode != regval) {
                        unsigned long flags;
-                       void *tmp_ptr = &mpc83xx_spi->base->mode;
+                       __be32 __iomem *mode = &mpc83xx_spi->base->mode;
 
                        regval = cs->hw_mode;
                        /* Turn off IRQs locally to minimize time that
@@ -180,12 +186,12 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
                         */
                        local_irq_save(flags);
                        /* Turn off SPI unit prior changing mode */
-                       mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
-                       mpc83xx_spi_write_reg(tmp_ptr, regval);
+                       mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+                       mpc83xx_spi_write_reg(mode, regval);
                        local_irq_restore(flags);
                }
-               if (mpc83xx_spi->activate_cs)
-                       mpc83xx_spi->activate_cs(spi->chip_select, pol);
+               if (pdata->cs_control)
+                       pdata->cs_control(spi, pol);
        }
 }
 
@@ -284,7 +290,7 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        regval =  mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
        if (cs->hw_mode != regval) {
                unsigned long flags;
-               void *tmp_ptr = &mpc83xx_spi->base->mode;
+               __be32 __iomem *mode = &mpc83xx_spi->base->mode;
 
                regval = cs->hw_mode;
                /* Turn off IRQs locally to minimize time
@@ -292,8 +298,8 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                 */
                local_irq_save(flags);
                /* Turn off SPI unit prior changing mode */
-               mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
-               mpc83xx_spi_write_reg(tmp_ptr, regval);
+               mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
+               mpc83xx_spi_write_reg(mode, regval);
                local_irq_restore(flags);
        }
        return 0;
@@ -483,7 +489,7 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
+static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
 {
        struct mpc83xx_spi *mpc83xx_spi = context_data;
        u32 event;
@@ -545,43 +551,28 @@ static void mpc83xx_spi_cleanup(struct spi_device *spi)
        kfree(spi->controller_state);
 }
 
-static int __init mpc83xx_spi_probe(struct platform_device *dev)
+static struct spi_master * __devinit
+mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 {
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
        struct spi_master *master;
        struct mpc83xx_spi *mpc83xx_spi;
-       struct fsl_spi_platform_data *pdata;
-       struct resource *r;
        u32 regval;
        int ret = 0;
 
-       /* Get resources(memory, IRQ) associated with the device */
-       master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi));
-
+       master = spi_alloc_master(dev, sizeof(struct mpc83xx_spi));
        if (master == NULL) {
                ret = -ENOMEM;
                goto err;
        }
 
-       platform_set_drvdata(dev, master);
-       pdata = dev->dev.platform_data;
+       dev_set_drvdata(dev, master);
 
-       if (pdata == NULL) {
-               ret = -ENODEV;
-               goto free_master;
-       }
-
-       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               ret = -ENODEV;
-               goto free_master;
-       }
        master->setup = mpc83xx_spi_setup;
        master->transfer = mpc83xx_spi_transfer;
        master->cleanup = mpc83xx_spi_cleanup;
 
        mpc83xx_spi = spi_master_get_devdata(master);
-       mpc83xx_spi->activate_cs = pdata->activate_cs;
-       mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
        mpc83xx_spi->qe_mode = pdata->qe_mode;
        mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
        mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
@@ -596,18 +587,13 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
 
        init_completion(&mpc83xx_spi->done);
 
-       mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
+       mpc83xx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
        if (mpc83xx_spi->base == NULL) {
                ret = -ENOMEM;
                goto put_master;
        }
 
-       mpc83xx_spi->irq = platform_get_irq(dev, 0);
-
-       if (mpc83xx_spi->irq < 0) {
-               ret = -ENXIO;
-               goto unmap_io;
-       }
+       mpc83xx_spi->irq = irq;
 
        /* Register for SPI Interrupt */
        ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
@@ -649,9 +635,9 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
 
        printk(KERN_INFO
               "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
-              dev_name(&dev->dev), mpc83xx_spi->base, mpc83xx_spi->irq);
+              dev_name(dev), mpc83xx_spi->base, mpc83xx_spi->irq);
 
-       return ret;
+       return master;
 
 unreg_master:
        destroy_workqueue(mpc83xx_spi->workqueue);
@@ -661,18 +647,16 @@ unmap_io:
        iounmap(mpc83xx_spi->base);
 put_master:
        spi_master_put(master);
-free_master:
-       kfree(master);
 err:
-       return ret;
+       return ERR_PTR(ret);
 }
 
-static int __exit mpc83xx_spi_remove(struct platform_device *dev)
+static int __devexit mpc83xx_spi_remove(struct device *dev)
 {
        struct mpc83xx_spi *mpc83xx_spi;
        struct spi_master *master;
 
-       master = platform_get_drvdata(dev);
+       master = dev_get_drvdata(dev);
        mpc83xx_spi = spi_master_get_devdata(master);
 
        flush_workqueue(mpc83xx_spi->workqueue);
@@ -685,23 +669,293 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev)
        return 0;
 }
 
+struct mpc83xx_spi_probe_info {
+       struct fsl_spi_platform_data pdata;
+       int *gpios;
+       bool *alow_flags;
+};
+
+static struct mpc83xx_spi_probe_info *
+to_of_pinfo(struct fsl_spi_platform_data *pdata)
+{
+       return container_of(pdata, struct mpc83xx_spi_probe_info, pdata);
+}
+
+static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
+{
+       struct device *dev = spi->dev.parent;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
+       u16 cs = spi->chip_select;
+       int gpio = pinfo->gpios[cs];
+       bool alow = pinfo->alow_flags[cs];
+
+       gpio_set_value(gpio, on ^ alow);
+}
+
+static int of_mpc83xx_spi_get_chipselects(struct device *dev)
+{
+       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+       unsigned int ngpios;
+       int i = 0;
+       int ret;
+
+       ngpios = of_gpio_count(np);
+       if (!ngpios) {
+               /*
+                * SPI w/o chip-select line. One SPI device is still permitted
+                * though.
+                */
+               pdata->max_chipselect = 1;
+               return 0;
+       }
+
+       pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL);
+       if (!pinfo->gpios)
+               return -ENOMEM;
+       memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios));
+
+       pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags),
+                                   GFP_KERNEL);
+       if (!pinfo->alow_flags) {
+               ret = -ENOMEM;
+               goto err_alloc_flags;
+       }
+
+       for (; i < ngpios; i++) {
+               int gpio;
+               enum of_gpio_flags flags;
+
+               gpio = of_get_gpio_flags(np, i, &flags);
+               if (!gpio_is_valid(gpio)) {
+                       dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
+                       goto err_loop;
+               }
+
+               ret = gpio_request(gpio, dev_name(dev));
+               if (ret) {
+                       dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
+                       goto err_loop;
+               }
+
+               pinfo->gpios[i] = gpio;
+               pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
+
+               ret = gpio_direction_output(pinfo->gpios[i],
+                                           pinfo->alow_flags[i]);
+               if (ret) {
+                       dev_err(dev, "can't set output direction for gpio "
+                               "#%d: %d\n", i, ret);
+                       goto err_loop;
+               }
+       }
+
+       pdata->max_chipselect = ngpios;
+       pdata->cs_control = mpc83xx_spi_cs_control;
+
+       return 0;
+
+err_loop:
+       while (i >= 0) {
+               if (gpio_is_valid(pinfo->gpios[i]))
+                       gpio_free(pinfo->gpios[i]);
+               i--;
+       }
+
+       kfree(pinfo->alow_flags);
+       pinfo->alow_flags = NULL;
+err_alloc_flags:
+       kfree(pinfo->gpios);
+       pinfo->gpios = NULL;
+       return ret;
+}
+
+static int of_mpc83xx_spi_free_chipselects(struct device *dev)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+       int i;
+
+       if (!pinfo->gpios)
+               return 0;
+
+       for (i = 0; i < pdata->max_chipselect; i++) {
+               if (gpio_is_valid(pinfo->gpios[i]))
+                       gpio_free(pinfo->gpios[i]);
+       }
+
+       kfree(pinfo->gpios);
+       kfree(pinfo->alow_flags);
+       return 0;
+}
+
+static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev,
+                                         const struct of_device_id *ofid)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->node;
+       struct mpc83xx_spi_probe_info *pinfo;
+       struct fsl_spi_platform_data *pdata;
+       struct spi_master *master;
+       struct resource mem;
+       struct resource irq;
+       const void *prop;
+       int ret = -ENOMEM;
+
+       pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       pdata = &pinfo->pdata;
+       dev->platform_data = pdata;
+
+       /* Allocate bus num dynamically. */
+       pdata->bus_num = -1;
+
+       /* SPI controller is either clocked from QE or SoC clock. */
+       pdata->sysclk = get_brgfreq();
+       if (pdata->sysclk == -1) {
+               pdata->sysclk = fsl_get_sys_freq();
+               if (pdata->sysclk == -1) {
+                       ret = -ENODEV;
+                       goto err_clk;
+               }
+       }
+
+       prop = of_get_property(np, "mode", NULL);
+       if (prop && !strcmp(prop, "cpu-qe"))
+               pdata->qe_mode = 1;
+
+       ret = of_mpc83xx_spi_get_chipselects(dev);
+       if (ret)
+               goto err;
+
+       ret = of_address_to_resource(np, 0, &mem);
+       if (ret)
+               goto err;
+
+       ret = of_irq_to_resource(np, 0, &irq);
+       if (!ret) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       master = mpc83xx_spi_probe(dev, &mem, irq.start);
+       if (IS_ERR(master)) {
+               ret = PTR_ERR(master);
+               goto err;
+       }
+
+       of_register_spi_devices(master, np);
+
+       return 0;
+
+err:
+       of_mpc83xx_spi_free_chipselects(dev);
+err_clk:
+       kfree(pinfo);
+       return ret;
+}
+
+static int __devexit of_mpc83xx_spi_remove(struct of_device *ofdev)
+{
+       int ret;
+
+       ret = mpc83xx_spi_remove(&ofdev->dev);
+       if (ret)
+               return ret;
+       of_mpc83xx_spi_free_chipselects(&ofdev->dev);
+       return 0;
+}
+
+static const struct of_device_id of_mpc83xx_spi_match[] = {
+       { .compatible = "fsl,spi" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_mpc83xx_spi_match);
+
+static struct of_platform_driver of_mpc83xx_spi_driver = {
+       .name           = "mpc83xx_spi",
+       .match_table    = of_mpc83xx_spi_match,
+       .probe          = of_mpc83xx_spi_probe,
+       .remove         = __devexit_p(of_mpc83xx_spi_remove),
+};
+
+#ifdef CONFIG_MPC832x_RDB
+/*
+ *                             XXX XXX XXX
+ * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
+ * only. The driver should go away soon, since newer MPC8323E-RDB's device
+ * tree can work with OpenFirmware driver. But for now we support old trees
+ * as well.
+ */
+static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev)
+{
+       struct resource *mem;
+       unsigned int irq;
+       struct spi_master *master;
+
+       if (!pdev->dev.platform_data)
+               return -EINVAL;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
+               return -EINVAL;
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq)
+               return -EINVAL;
+
+       master = mpc83xx_spi_probe(&pdev->dev, mem, irq);
+       if (IS_ERR(master))
+               return PTR_ERR(master);
+       return 0;
+}
+
+static int __devexit plat_mpc83xx_spi_remove(struct platform_device *pdev)
+{
+       return mpc83xx_spi_remove(&pdev->dev);
+}
+
 MODULE_ALIAS("platform:mpc83xx_spi");
 static struct platform_driver mpc83xx_spi_driver = {
-       .remove = __exit_p(mpc83xx_spi_remove),
+       .probe = plat_mpc83xx_spi_probe,
+       .remove = __exit_p(plat_mpc83xx_spi_remove),
        .driver = {
                .name = "mpc83xx_spi",
                .owner = THIS_MODULE,
        },
 };
 
+static bool legacy_driver_failed;
+
+static void __init legacy_driver_register(void)
+{
+       legacy_driver_failed = platform_driver_register(&mpc83xx_spi_driver);
+}
+
+static void __exit legacy_driver_unregister(void)
+{
+       if (legacy_driver_failed)
+               return;
+       platform_driver_unregister(&mpc83xx_spi_driver);
+}
+#else
+static void __init legacy_driver_register(void) {}
+static void __exit legacy_driver_unregister(void) {}
+#endif /* CONFIG_MPC832x_RDB */
+
 static int __init mpc83xx_spi_init(void)
 {
-       return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe);
+       legacy_driver_register();
+       return of_register_platform_driver(&of_mpc83xx_spi_driver);
 }
 
 static void __exit mpc83xx_spi_exit(void)
 {
-       platform_driver_unregister(&mpc83xx_spi_driver);
+       of_unregister_platform_driver(&of_mpc83xx_spi_driver);
+       legacy_driver_unregister();
 }
 
 module_init(mpc83xx_spi_init);
index 211af86a6c559a5ca9eff122436457ba6de43ed2..92981c2383ee54680a0d5f2a78900b99b6fc9f22 100644 (file)
@@ -4,7 +4,7 @@ menuconfig STAGING
        ---help---
          This option allows you to select a number of drivers that are
          not of the "normal" Linux kernel quality level.  These drivers
-         are placed here in order to get a wider audience for use of
+         are placed here in order to get a wider audience to make use of
          them.  Please note that these drivers are under heavy
          development, may or may not work, and may contain userspace
          interfaces that most likely will be changed in the near
@@ -12,7 +12,7 @@ menuconfig STAGING
 
          Using any of these drivers will taint your kernel which might
          affect support options from both the community, and various
-         commercial support orginizations.
+         commercial support organizations.
 
          If you wish to work on these drivers, to help improve them, or
          to report problems you have with them, please see the
index b47ca1e7e383325ef24adbc8d408e116180704af..83a93a5c63926593a829585b8b46e735fd912f6a 100644 (file)
@@ -1,9 +1,9 @@
 config COMEDI
-       tristate "Data Acquision support (comedi)"
+       tristate "Data acquisition support (comedi)"
        default N
        depends on m
        ---help---
-         Enable support a wide range of data acquision devices
+         Enable support a wide range of data acquisition devices
          for Linux.
 
 config COMEDI_RT
index f2cf7f66ae0550ee93629032914ef7ea564f9a68..ca6ade6c4b4775f69254d3b96efe13e446e336ad 100644 (file)
@@ -10,7 +10,7 @@ config VIDEO_GO7007
        select CRC32
        default N
        ---help---
-         This is a video4linux driver for some wierd device...
+         This is a video4linux driver for some weird device...
 
          To compile this driver as a module, choose M here: the
          module will be called go7007
@@ -20,7 +20,7 @@ config VIDEO_GO7007_USB
        depends on VIDEO_GO7007 && USB
        default N
        ---help---
-         This is a video4linux driver for some wierd device...
+         This is a video4linux driver for some weird device...
 
          To compile this driver as a module, choose M here: the
          module will be called go7007-usb
index 2e65c466aae8a16247811e6010dc7842d260f370..dab278326931bbee68b821265227ecbc2f821a2e 100644 (file)
@@ -152,7 +152,7 @@ u16_t zfHpInit(zdev_t* dev, u32_t frequency)
     else
     {
     #ifndef ZM_OTUS_LINUX_PHASE_2
-        /* donwload the normal frimware */
+        /* download the normal firmware */
         if ((ret = zfFirmwareDownload(dev, (u32_t*)zcFwImage,
                 (u32_t)zcFwImageSize, ZM_FIRMWARE_WLAN_ADDR)) != ZM_SUCCESS)
         {
index c4b30f2a549ba365b738848d26ef2c70169332e5..3abe7c9d558d70c0c3b6f8be743c4435dca8cb5f 100644 (file)
@@ -110,7 +110,7 @@ config PANEL_LCD_BWIDTH
        ---help---
          Most LCDs use a standard controller which supports hardware lines of 40
          characters, although sometimes only 16, 20 or 24 of them are really wired
-         to the terminal. This results in some non-visible but adressable characters,
+         to the terminal. This results in some non-visible but addressable characters,
          and is the case for most parallel LCDs. Other LCDs, and some serial ones,
          however, use the same line width internally as what is visible. The KS0074
          for example, uses 16 characters per line for 16 visible characters per line.
index e5752f615e0970d725cc3c005712547d5216092e..80f9cc7137c2dfe33818ee635992ac8cf744fc78 100644 (file)
@@ -719,7 +719,7 @@ void ieee80211_softmac_scan(struct ieee80211_device *ieee)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_softmac_scan_wq(struct work_struct *work)
 {
-       struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
 #else
 void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
@@ -777,7 +777,7 @@ out:
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_softmac_scan_wq(struct work_struct *work)
 {
-        struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
         struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, softmac_scan_wq);
 #else
 void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
@@ -2980,7 +2980,7 @@ void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_start_ibss_wq(struct work_struct *work)
 {
-       struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq);
 #else
 void ieee80211_start_ibss_wq(struct ieee80211_device *ieee)
@@ -3162,7 +3162,7 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void ieee80211_associate_retry_wq(struct work_struct *work)
 {
-       struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq);
 #else
 void ieee80211_associate_retry_wq(struct ieee80211_device *ieee)
index 66de5cc8ddf119a85d4b66c4829bfe4c97422b90..ff1f23f99f2743fff971d7b4a6bb7d48aecb88cf 100644 (file)
@@ -5438,7 +5438,7 @@ void rtl8180_hw_wakeup_wq (struct work_struct *work)
 //     struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
 //     struct ieee80211_device * ieee = (struct ieee80211_device*)
 //                                            container_of(work, struct ieee80211_device, watch_dog_wq);
-       struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq);
        struct net_device *dev = ieee->dev;
 #else
@@ -5459,7 +5459,7 @@ void rtl8180_hw_sleep_wq (struct work_struct *work)
 //      struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
 //      struct ieee80211_device * ieee = (struct ieee80211_device*)
 //                                             container_of(work, struct ieee80211_device, watch_dog_wq);
-        struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+       struct delayed_work *dwork = to_delayed_work(work);
         struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq);
         struct net_device *dev = ieee->dev;
 #else
@@ -6407,7 +6407,7 @@ priv->txnpring)/8);
 void rtl8180_tx_irq_wq(struct work_struct *work)
 {
        //struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq);
-        struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+       struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device * ieee = (struct ieee80211_device*)
                                               container_of(dwork, struct ieee80211_device, watch_dog_wq);
        struct net_device *dev = ieee->dev;
@@ -6691,7 +6691,7 @@ lizhaoming--------------------------- RF power on/power off -----------------
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
 void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
 {
-       //struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+       //struct delayed_work *dwork = to_delayed_work(work);
        struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work);
        struct net_device *dev = ieee->dev;
        struct r8180_priv *priv = ieee80211_priv(dev);
index b6483dd98acc46e8e3f82648c6b40d54f45f41dd..9cf9ff69e3e3505e08f9c2346b4d4095775a9981 100644 (file)
@@ -626,7 +626,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte
                goto err_fw_corrupted;
 
        /*
-        * Start to upload formware : send reset
+        * Start to upload firmware : send reset
         */
        value = 1;
        ret = uea_send_modem_cmd(usb, F8051_USBCS, sizeof(value), &value);
index 770b3eaa91847d633c2db26590480936f9c243a5..080bb1e4b847aebcd862b71480596edcf7f8b37e 100644 (file)
@@ -392,7 +392,7 @@ config USB_GADGET_FSL_QE
           controllers having QE or CPM2, given minor tweaks.
 
           Set CONFIG_USB_GADGET to "m" to build this driver as a
-          dynmically linked module called "fsl_qe_udc".
+          dynamically linked module called "fsl_qe_udc".
 
 config USB_FSL_QE
        tristate
index c1b279939bbf46f0a3a3ac0f5e5e7187c9304d99..f13fd488ebec104c967539b9c610febf980bcf69 100644 (file)
@@ -715,7 +715,7 @@ io_edgeport.c Change Log comments:
 
  0.2 (01/30/2000) greg kroah-hartman
        Milestone 1 release.
-       Device is found by USB subsystem, enumerated, fimware is downloaded
+       Device is found by USB subsystem, enumerated, firmware is downloaded
        and the descriptors are printed to the debug log, config is set, and
        green light starts to blink. Open port works, and data can be sent
        and received at the default settings of the UART. Loopback connector
index a65f9196b0a06e93df07bcb5ef0a9313c8f47f88..c480ea4c19f28797a79b1a5ad4fb11701f537dc9 100644 (file)
@@ -518,8 +518,8 @@ config USB_SERIAL_SIERRAWIRELESS
        help
          Say M here if you want to use Sierra Wireless devices.
 
-         Many deviecs have a feature known as TRU-Install, for those devices
-         to work properly the USB Storage Sierra feature must be enabled.
+         Many devices have a feature known as TRU-Install. For those devices
+         to work properly, the USB Storage Sierra feature must be enabled.
 
          To compile this driver as a module, choose M here: the
          module will be called sierra.
index 742a5bc44be8670bdaa1bfc06a93ccbfcc9cfc9a..2a70563bbee1003008a20a0f48b880a4503db9ab 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
@@ -421,57 +422,52 @@ static int serial_break(struct tty_struct *tty, int break_state)
        return 0;
 }
 
-static int serial_read_proc(char *page, char **start, off_t off, int count,
-                                                       int *eof, void *data)
+static int serial_proc_show(struct seq_file *m, void *v)
 {
        struct usb_serial *serial;
-       int length = 0;
        int i;
-       off_t begin = 0;
        char tmp[40];
 
        dbg("%s", __func__);
-       length += sprintf(page, "usbserinfo:1.0 driver:2.0\n");
-       for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
+       seq_puts(m, "usbserinfo:1.0 driver:2.0\n");
+       for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
                serial = usb_serial_get_by_index(i);
                if (serial == NULL)
                        continue;
 
-               length += sprintf(page+length, "%d:", i);
+               seq_printf(m, "%d:", i);
                if (serial->type->driver.owner)
-                       length += sprintf(page+length, " module:%s",
+                       seq_printf(m, " module:%s",
                                module_name(serial->type->driver.owner));
-               length += sprintf(page+length, " name:\"%s\"",
+               seq_printf(m, " name:\"%s\"",
                                serial->type->description);
-               length += sprintf(page+length, " vendor:%04x product:%04x",
+               seq_printf(m, " vendor:%04x product:%04x",
                        le16_to_cpu(serial->dev->descriptor.idVendor),
                        le16_to_cpu(serial->dev->descriptor.idProduct));
-               length += sprintf(page+length, " num_ports:%d",
-                                                       serial->num_ports);
-               length += sprintf(page+length, " port:%d",
-                                                       i - serial->minor + 1);
+               seq_printf(m, " num_ports:%d", serial->num_ports);
+               seq_printf(m, " port:%d", i - serial->minor + 1);
                usb_make_path(serial->dev, tmp, sizeof(tmp));
-               length += sprintf(page+length, " path:%s", tmp);
+               seq_printf(m, " path:%s", tmp);
 
-               length += sprintf(page+length, "\n");
-               if ((length + begin) > (off + count)) {
-                       usb_serial_put(serial);
-                       goto done;
-               }
-               if ((length + begin) < off) {
-                       begin += length;
-                       length = 0;
-               }
+               seq_putc(m, '\n');
                usb_serial_put(serial);
        }
-       *eof = 1;
-done:
-       if (off >= (length + begin))
-               return 0;
-       *start = page + (off-begin);
-       return (count < begin+length-off) ? count : begin+length-off;
+       return 0;
 }
 
+static int serial_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, serial_proc_show, NULL);
+}
+
+static const struct file_operations serial_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = serial_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int serial_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -1113,9 +1109,9 @@ static const struct tty_operations serial_ops = {
        .unthrottle =           serial_unthrottle,
        .break_ctl =            serial_break,
        .chars_in_buffer =      serial_chars_in_buffer,
-       .read_proc =            serial_read_proc,
        .tiocmget =             serial_tiocmget,
        .tiocmset =             serial_tiocmset,
+       .proc_fops =            &serial_proc_fops,
 };
 
 struct tty_driver *usb_serial_tty_driver;
index 882c57b399f7d94944ac93011807e4380bda6df6..fdba2f69d4c9ed2d390c69638f37e328960aab2b 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/ata.h>
 #include <linux/hdreg.h>
 #include <linux/scatterlist.h>
 
@@ -328,7 +329,7 @@ struct isd200_config {
 
 struct isd200_info {
        struct inquiry_data InquiryData;
-       struct hd_driveid *id;
+       u16 *id;
        struct isd200_config ConfigData;
        unsigned char *RegsBuf;
        unsigned char ATARegs[8];
@@ -419,19 +420,19 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
                buf->Flags = UNIT_ATTENTION;
                buf->AdditionalSenseCode = 0;
                buf->AdditionalSenseCodeQualifier = 0;
-       } else if(error & MCR_ERR) {
+       } else if (error & ATA_MCR) {
                buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
                buf->AdditionalSenseLength = 0xb;
                buf->Flags =  UNIT_ATTENTION;
                buf->AdditionalSenseCode = 0;
                buf->AdditionalSenseCodeQualifier = 0;
-       } else if(error & TRK0_ERR) {
+       } else if (error & ATA_TRK0NF) {
                buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
                buf->AdditionalSenseLength = 0xb;
                buf->Flags =  NOT_READY;
                buf->AdditionalSenseCode = 0;
                buf->AdditionalSenseCodeQualifier = 0;
-       } else if(error & ECC_ERR) {
+       } else if (error & ATA_UNC) {
                buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
                buf->AdditionalSenseLength = 0xb;
                buf->Flags =  DATA_PROTECT;
@@ -547,16 +548,16 @@ static int isd200_action( struct us_data *us, int action,
                ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;
                ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
                ata.write.DeviceHeadByte = info->DeviceHead;
-               ata.write.CommandByte = WIN_SRST;
+               ata.write.CommandByte = ATA_CMD_DEV_RESET;
                isd200_set_srb(info, DMA_NONE, NULL, 0);
                break;
 
        case ACTION_IDENTIFY:
                US_DEBUGP("   isd200_action(IDENTIFY)\n");
                ata.generic.RegisterSelect = REG_COMMAND;
-               ata.write.CommandByte = WIN_IDENTIFY;
+               ata.write.CommandByte = ATA_CMD_ID_ATA;
                isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
-                                               sizeof(struct hd_driveid));
+                               ATA_ID_WORDS * 2);
                break;
 
        default:
@@ -944,22 +945,22 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
                        break;
 
                if (!detect) {
-                       if (regs[ATA_REG_STATUS_OFFSET] & BUSY_STAT) {
+                       if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) {
                                US_DEBUGP("   %s status is still BSY, try again...\n",mstr);
                        } else {
                                US_DEBUGP("   %s status !BSY, continue with next operation\n",mstr);
                                break;
                        }
                }
-               /* check for BUSY_STAT and */
-               /* WRERR_STAT (workaround ATA Zip drive) and */ 
-               /* ERR_STAT (workaround for Archos CD-ROM) */
+               /* check for ATA_BUSY and */
+               /* ATA_DF (workaround ATA Zip drive) and */
+               /* ATA_ERR (workaround for Archos CD-ROM) */
                else if (regs[ATA_REG_STATUS_OFFSET] &
-                        (BUSY_STAT | WRERR_STAT | ERR_STAT )) {
+                        (ATA_BUSY | ATA_DF | ATA_ERR)) {
                        US_DEBUGP("   Status indicates it is not ready, try again...\n");
                }
                /* check for DRDY, ATA devices set DRDY after SRST */
-               else if (regs[ATA_REG_STATUS_OFFSET] & READY_STAT) {
+               else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) {
                        US_DEBUGP("   Identified ATA device\n");
                        info->DeviceFlags |= DF_ATA_DEVICE;
                        info->DeviceHead = master_slave;
@@ -1053,103 +1054,50 @@ static int isd200_manual_enum(struct us_data *us)
        return(retStatus);
 }
 
-static void isd200_fix_driveid (struct hd_driveid *id)
+static void isd200_fix_driveid(u16 *id)
 {
 #ifndef __LITTLE_ENDIAN
 # ifdef __BIG_ENDIAN
        int i;
-       u16 *stringcast;
-
-       id->config         = __le16_to_cpu(id->config);
-       id->cyls           = __le16_to_cpu(id->cyls);
-       id->reserved2      = __le16_to_cpu(id->reserved2);
-       id->heads          = __le16_to_cpu(id->heads);
-       id->track_bytes    = __le16_to_cpu(id->track_bytes);
-       id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-       id->sectors        = __le16_to_cpu(id->sectors);
-       id->vendor0        = __le16_to_cpu(id->vendor0);
-       id->vendor1        = __le16_to_cpu(id->vendor1);
-       id->vendor2        = __le16_to_cpu(id->vendor2);
-       stringcast = (u16 *)&id->serial_no[0];
-       for (i = 0; i < (20/2); i++)
-               stringcast[i] = __le16_to_cpu(stringcast[i]);
-       id->buf_type       = __le16_to_cpu(id->buf_type);
-       id->buf_size       = __le16_to_cpu(id->buf_size);
-       id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-       stringcast = (u16 *)&id->fw_rev[0];
-       for (i = 0; i < (8/2); i++)
-               stringcast[i] = __le16_to_cpu(stringcast[i]);
-       stringcast = (u16 *)&id->model[0];
-       for (i = 0; i < (40/2); i++)
-               stringcast[i] = __le16_to_cpu(stringcast[i]);
-       id->dword_io       = __le16_to_cpu(id->dword_io);
-       id->reserved50     = __le16_to_cpu(id->reserved50);
-       id->field_valid    = __le16_to_cpu(id->field_valid);
-       id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-       id->cur_heads      = __le16_to_cpu(id->cur_heads);
-       id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-       id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-       id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-       id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-       id->dma_1word      = __le16_to_cpu(id->dma_1word);
-       id->dma_mword      = __le16_to_cpu(id->dma_mword);
-       id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-       id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-       id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-       id->eide_pio       = __le16_to_cpu(id->eide_pio);
-       id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-       for (i = 0; i < 2; ++i)
-               id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-       for (i = 0; i < 4; ++i)
-               id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-       id->queue_depth    = __le16_to_cpu(id->queue_depth);
-       for (i = 0; i < 4; ++i)
-               id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-       id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-       id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-       id->command_set_1  = __le16_to_cpu(id->command_set_1);
-       id->command_set_2  = __le16_to_cpu(id->command_set_2);
-       id->cfsse          = __le16_to_cpu(id->cfsse);
-       id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-       id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-       id->csf_default    = __le16_to_cpu(id->csf_default);
-       id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-       id->trseuc         = __le16_to_cpu(id->trseuc);
-       id->trsEuc         = __le16_to_cpu(id->trsEuc);
-       id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-       id->mprc           = __le16_to_cpu(id->mprc);
-       id->hw_config      = __le16_to_cpu(id->hw_config);
-       id->acoustic       = __le16_to_cpu(id->acoustic);
-       id->msrqs          = __le16_to_cpu(id->msrqs);
-       id->sxfert         = __le16_to_cpu(id->sxfert);
-       id->sal            = __le16_to_cpu(id->sal);
-       id->spg            = __le32_to_cpu(id->spg);
-       id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-       for (i = 0; i < 22; i++)
-               id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-       id->last_lun       = __le16_to_cpu(id->last_lun);
-       id->word127        = __le16_to_cpu(id->word127);
-       id->dlf            = __le16_to_cpu(id->dlf);
-       id->csfo           = __le16_to_cpu(id->csfo);
-       for (i = 0; i < 26; i++)
-               id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-       id->word156        = __le16_to_cpu(id->word156);
-       for (i = 0; i < 3; i++)
-               id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-       id->cfa_power      = __le16_to_cpu(id->cfa_power);
-       for (i = 0; i < 14; i++)
-               id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-       for (i = 0; i < 31; i++)
-               id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-       for (i = 0; i < 48; i++)
-               id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-       id->integrity_word  = __le16_to_cpu(id->integrity_word);
+
+       for (i = 0; i < ATA_ID_WORDS; i++)
+               id[i] = __le16_to_cpu(id[i]);
 # else
 #  error "Please fix <asm/byteorder.h>"
 # endif
 #endif
 }
 
+static void isd200_dump_driveid(u16 *id)
+{
+       US_DEBUGP("   Identify Data Structure:\n");
+       US_DEBUGP("      config = 0x%x\n",        id[ATA_ID_CONFIG]);
+       US_DEBUGP("      cyls = 0x%x\n",          id[ATA_ID_CYLS]);
+       US_DEBUGP("      heads = 0x%x\n",         id[ATA_ID_HEADS]);
+       US_DEBUGP("      track_bytes = 0x%x\n",   id[4]);
+       US_DEBUGP("      sector_bytes = 0x%x\n",  id[5]);
+       US_DEBUGP("      sectors = 0x%x\n",       id[ATA_ID_SECTORS]);
+       US_DEBUGP("      serial_no[0] = 0x%x\n",  *(char *)&id[ATA_ID_SERNO]);
+       US_DEBUGP("      buf_type = 0x%x\n",      id[20]);
+       US_DEBUGP("      buf_size = 0x%x\n",      id[ATA_ID_BUF_SIZE]);
+       US_DEBUGP("      ecc_bytes = 0x%x\n",     id[22]);
+       US_DEBUGP("      fw_rev[0] = 0x%x\n",     *(char *)&id[ATA_ID_FW_REV]);
+       US_DEBUGP("      model[0] = 0x%x\n",      *(char *)&id[ATA_ID_PROD]);
+       US_DEBUGP("      max_multsect = 0x%x\n",  id[ATA_ID_MAX_MULTSECT] & 0xff);
+       US_DEBUGP("      dword_io = 0x%x\n",      id[ATA_ID_DWORD_IO]);
+       US_DEBUGP("      capability = 0x%x\n",    id[ATA_ID_CAPABILITY] >> 8);
+       US_DEBUGP("      tPIO = 0x%x\n",          id[ATA_ID_OLD_PIO_MODES] >> 8);
+       US_DEBUGP("      tDMA = 0x%x\n",          id[ATA_ID_OLD_DMA_MODES] >> 8);
+       US_DEBUGP("      field_valid = 0x%x\n",   id[ATA_ID_FIELD_VALID]);
+       US_DEBUGP("      cur_cyls = 0x%x\n",      id[ATA_ID_CUR_CYLS]);
+       US_DEBUGP("      cur_heads = 0x%x\n",     id[ATA_ID_CUR_HEADS]);
+       US_DEBUGP("      cur_sectors = 0x%x\n",   id[ATA_ID_CUR_SECTORS]);
+       US_DEBUGP("      cur_capacity = 0x%x\n",  ata_id_u32(id, 57));
+       US_DEBUGP("      multsect = 0x%x\n",      id[ATA_ID_MULTSECT] & 0xff);
+       US_DEBUGP("      lba_capacity = 0x%x\n",  ata_id_u32(id, ATA_ID_LBA_CAPACITY));
+       US_DEBUGP("      command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]);
+       US_DEBUGP("      command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]);
+}
 
 /**************************************************************************
  * isd200_get_inquiry_data
@@ -1163,7 +1111,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
 {
        struct isd200_info *info = (struct isd200_info *)us->extra;
        int retStatus = ISD200_GOOD;
-       struct hd_driveid *id = info->id;
+       u16 *id = info->id;
 
        US_DEBUGP("Entering isd200_get_inquiry_data\n");
 
@@ -1180,8 +1128,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
                        /* this must be an ATA device */
                        /* perform an ATA Command Identify */
                        transferStatus = isd200_action( us, ACTION_IDENTIFY,
-                                                       id, 
-                                                       sizeof(struct hd_driveid) );
+                                                       id, ATA_ID_WORDS * 2);
                        if (transferStatus != ISD200_TRANSPORT_GOOD) {
                                /* Error issuing ATA Command Identify */
                                US_DEBUGP("   Error issuing ATA Command Identify\n");
@@ -1191,35 +1138,9 @@ static int isd200_get_inquiry_data( struct us_data *us )
                                int i;
                                __be16 *src;
                                __u16 *dest;
-                               isd200_fix_driveid(id);
 
-                               US_DEBUGP("   Identify Data Structure:\n");
-                               US_DEBUGP("      config = 0x%x\n", id->config);
-                               US_DEBUGP("      cyls = 0x%x\n", id->cyls);
-                               US_DEBUGP("      heads = 0x%x\n", id->heads);
-                               US_DEBUGP("      track_bytes = 0x%x\n", id->track_bytes);
-                               US_DEBUGP("      sector_bytes = 0x%x\n", id->sector_bytes);
-                               US_DEBUGP("      sectors = 0x%x\n", id->sectors);
-                               US_DEBUGP("      serial_no[0] = 0x%x\n", id->serial_no[0]);
-                               US_DEBUGP("      buf_type = 0x%x\n", id->buf_type);
-                               US_DEBUGP("      buf_size = 0x%x\n", id->buf_size);
-                               US_DEBUGP("      ecc_bytes = 0x%x\n", id->ecc_bytes);
-                               US_DEBUGP("      fw_rev[0] = 0x%x\n", id->fw_rev[0]);
-                               US_DEBUGP("      model[0] = 0x%x\n", id->model[0]);
-                               US_DEBUGP("      max_multsect = 0x%x\n", id->max_multsect);
-                               US_DEBUGP("      dword_io = 0x%x\n", id->dword_io);
-                               US_DEBUGP("      capability = 0x%x\n", id->capability);
-                               US_DEBUGP("      tPIO = 0x%x\n", id->tPIO);
-                               US_DEBUGP("      tDMA = 0x%x\n", id->tDMA);
-                               US_DEBUGP("      field_valid = 0x%x\n", id->field_valid);
-                               US_DEBUGP("      cur_cyls = 0x%x\n", id->cur_cyls);
-                               US_DEBUGP("      cur_heads = 0x%x\n", id->cur_heads);
-                               US_DEBUGP("      cur_sectors = 0x%x\n", id->cur_sectors);
-                               US_DEBUGP("      cur_capacity = 0x%x\n", (id->cur_capacity1 << 16) + id->cur_capacity0 );
-                               US_DEBUGP("      multsect = 0x%x\n", id->multsect);
-                               US_DEBUGP("      lba_capacity = 0x%x\n", id->lba_capacity);
-                               US_DEBUGP("      command_set_1 = 0x%x\n", id->command_set_1);
-                               US_DEBUGP("      command_set_2 = 0x%x\n", id->command_set_2);
+                               isd200_fix_driveid(id);
+                               isd200_dump_driveid(id);
 
                                memset(&info->InquiryData, 0, sizeof(info->InquiryData));
 
@@ -1229,30 +1150,30 @@ static int isd200_get_inquiry_data( struct us_data *us )
                                /* The length must be at least 36 (5 + 31) */
                                info->InquiryData.AdditionalLength = 0x1F;
 
-                               if (id->command_set_1 & COMMANDSET_MEDIA_STATUS) {
+                               if (id[ATA_ID_COMMAND_SET_1] & COMMANDSET_MEDIA_STATUS) {
                                        /* set the removable bit */
                                        info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE;
                                        info->DeviceFlags |= DF_REMOVABLE_MEDIA;
                                }
 
                                /* Fill in vendor identification fields */
-                               src = (__be16*)id->model;
+                               src = (__be16 *)&id[ATA_ID_PROD];
                                dest = (__u16*)info->InquiryData.VendorId;
                                for (i=0;i<4;i++)
                                        dest[i] = be16_to_cpu(src[i]);
 
-                               src = (__be16*)(id->model+8);
+                               src = (__be16 *)&id[ATA_ID_PROD + 8/2];
                                dest = (__u16*)info->InquiryData.ProductId;
                                for (i=0;i<8;i++)
                                        dest[i] = be16_to_cpu(src[i]);
 
-                               src = (__be16*)id->fw_rev;
+                               src = (__be16 *)&id[ATA_ID_FW_REV];
                                dest = (__u16*)info->InquiryData.ProductRevisionLevel;
                                for (i=0;i<2;i++)
                                        dest[i] = be16_to_cpu(src[i]);
 
                                /* determine if it supports Media Status Notification */
-                               if (id->command_set_2 & COMMANDSET_MEDIA_STATUS) {
+                               if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) {
                                        US_DEBUGP("   Device supports Media Status Notification\n");
 
                                        /* Indicate that it is enabled, even though it is not
@@ -1301,7 +1222,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                              union ata_cdb * ataCdb)
 {
        struct isd200_info *info = (struct isd200_info *)us->extra;
-       struct hd_driveid *id = info->id;
+       u16 *id = info->id;
        int sendToTransport = 1;
        unsigned char sectnum, head;
        unsigned short cylinder;
@@ -1369,13 +1290,12 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
 
                US_DEBUGP("   ATA OUT - SCSIOP_READ_CAPACITY\n");
 
-               if (id->capability & CAPABILITY_LBA ) {
-                       capacity = id->lba_capacity - 1;
-               } else {
-                       capacity = (id->heads *
-                                   id->cyls *
-                                   id->sectors) - 1;
-               }
+               if (ata_id_has_lba(id))
+                       capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1;
+               else
+                       capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] *
+                                   id[ATA_ID_SECTORS]) - 1;
+
                readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity);
                readCapacityData.BytesPerBlock = cpu_to_be32(0x200);
 
@@ -1392,16 +1312,16 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
                blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
 
-               if (id->capability & CAPABILITY_LBA) {
+               if (ata_id_has_lba(id)) {
                        sectnum = (unsigned char)(lba);
                        cylinder = (unsigned short)(lba>>8);
                        head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
                } else {
-                       sectnum = (unsigned char)((lba % id->sectors) + 1);
-                       cylinder = (unsigned short)(lba / (id->sectors *
-                                                          id->heads));
-                       head = (unsigned char)((lba / id->sectors) %
-                                              id->heads);
+                       sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
+                       cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
+                                       id[ATA_ID_HEADS]));
+                       head = (u8)((lba / id[ATA_ID_SECTORS]) %
+                                       id[ATA_ID_HEADS]);
                }
                ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
                ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
@@ -1415,7 +1335,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
                ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
                ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
-               ataCdb->write.CommandByte = WIN_READ;
+               ataCdb->write.CommandByte = ATA_CMD_PIO_READ;
                break;
 
        case WRITE_10:
@@ -1424,14 +1344,16 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
                blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
 
-               if (id->capability & CAPABILITY_LBA) {
+               if (ata_id_has_lba(id)) {
                        sectnum = (unsigned char)(lba);
                        cylinder = (unsigned short)(lba>>8);
                        head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
                } else {
-                       sectnum = (unsigned char)((lba % id->sectors) + 1);
-                       cylinder = (unsigned short)(lba / (id->sectors * id->heads));
-                       head = (unsigned char)((lba / id->sectors) % id->heads);
+                       sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
+                       cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
+                                       id[ATA_ID_HEADS]));
+                       head = (u8)((lba / id[ATA_ID_SECTORS]) %
+                                       id[ATA_ID_HEADS]);
                }
                ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
                ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
@@ -1445,7 +1367,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
                ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
                ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
-               ataCdb->write.CommandByte = WIN_WRITE;
+               ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE;
                break;
 
        case ALLOW_MEDIUM_REMOVAL:
@@ -1459,7 +1381,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                        ataCdb->generic.TransferBlockSize = 1;
                        ataCdb->generic.RegisterSelect = REG_COMMAND;
                        ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
-                               WIN_DOORLOCK : WIN_DOORUNLOCK;
+                               ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
                        isd200_srb_set_bufflen(srb, 0);
                } else {
                        US_DEBUGP("   Not removeable media, just report okay\n");
@@ -1539,8 +1461,7 @@ static int isd200_init_info(struct us_data *us)
        if (!info)
                retStatus = ISD200_ERROR;
        else {
-               info->id = (struct hd_driveid *)
-                               kzalloc(sizeof(struct hd_driveid), GFP_KERNEL);
+               info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
                info->RegsBuf = (unsigned char *)
                                kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
                info->srb.sense_buffer =
index f0aac0cf315a5cdabcadfa2831a52377ff030b14..386eaa22d215fc84a3d1ac3b0405e4f511a453a1 100644 (file)
@@ -471,7 +471,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
  */
 static void wusbhc_keep_alive_run(struct work_struct *ws)
 {
-       struct delayed_work *dw = container_of(ws, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(ws);
        struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer);
 
        mutex_lock(&wusbhc->mutex);
index 8118db7f1d8ddd230b8f5e6c2dcc116d2eb64d89..b2f149fedcc50ce2a705c51c8f1148ec2346c8ed 100644 (file)
@@ -562,7 +562,7 @@ void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
                struct wusb_dev *wusb_dev;
 
                wusb_dev = wusbhc->port[p].wusb_dev;
-               if (!wusb_dev || !wusb_dev->usb_dev | !wusb_dev->usb_dev->authenticated)
+               if (!wusb_dev || !wusb_dev->usb_dev || !wusb_dev->usb_dev->authenticated)
                        continue;
 
                usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev,
index ca783127af3671cfb4dbe16d6c3405c864103c08..bac8e7a6f17bcda8d21ab8c874b2cc648975fe3b 100644 (file)
@@ -48,10 +48,10 @@ config UWB_WHCI
         help
           This driver enables the radio controller for WHCI cards.
 
-          WHCI is an specification developed by Intel
+          WHCI is a specification developed by Intel
           (http://www.intel.com/technology/comms/wusb/whci.htm) much
           in the spirit of USB's EHCI, but for UWB and Wireless USB
-          radio/host controllers connected via memmory mapping (eg:
+          radio/host controllers connected via memory mapping (eg:
           PCI). Most of these cards come also with a Wireless USB host
           controller.
 
index 7f907fb23b8a3414044eee2b8363b63f340ba1d7..0b17824b0eb5b3aa0db0772b76dc6f19b07e2be4 100644 (file)
@@ -471,9 +471,11 @@ int __init mc68x328fb_init(void)
        fb_info.pseudo_palette = &mc68x328fb_pseudo_palette;
        fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
 
-       fb_alloc_cmap(&fb_info.cmap, 256, 0);
+       if (fb_alloc_cmap(&fb_info.cmap, 256, 0))
+               return -ENOMEM;
 
        if (register_framebuffer(&fb_info) < 0) {
+               fb_dealloc_cmap(&fb_info.cmap);
                return -EINVAL;
        }
 
@@ -494,6 +496,7 @@ module_init(mc68x328fb_init);
 static void __exit mc68x328fb_cleanup(void)
 {
        unregister_framebuffer(&fb_info);
+       fb_dealloc_cmap(&fb_info.cmap);
 }
 
 module_exit(mc68x328fb_cleanup);
index 41c27a44bd82bf5ec95e937cdea0485f610a58ed..ffe2f2796e290ba55352bca2e64264eac59df0f4 100644 (file)
@@ -1597,32 +1597,8 @@ config FB_VT8623
          Driver for CastleRock integrated graphics core in the
          VIA VT8623 [Apollo CLE266] chipset.
 
-config FB_CYBLA
-       tristate "Cyberblade/i1 support"
-       depends on FB && PCI && X86_32 && !64BIT
-       select FB_CFB_IMAGEBLIT
-       ---help---
-         This driver is supposed to support the Trident Cyberblade/i1
-         graphics core integrated in the VIA VT8601A North Bridge,
-         also known as VIA Apollo PLE133.
-
-         Status:
-          - Developed, tested and working on EPIA 5000 and EPIA 800.
-          - Does work reliable on all systems with CRT/LCD connected to
-            normal VGA ports.
-          - Should work on systems that do use the internal LCD port, but
-            this is absolutely not tested.
-
-         Character imageblit, copyarea and rectangle fill are hw accelerated,
-         ypan scrolling is used by default.
-
-         Please do read <file:Documentation/fb/cyblafb/*>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called cyblafb.
-
 config FB_TRIDENT
-       tristate "Trident support"
+       tristate "Trident/CyberXXX/CyberBlade support"
        depends on FB && PCI
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
@@ -1633,21 +1609,14 @@ config FB_TRIDENT
          and Blade XP.
          There are also integrated versions of these chips called CyberXXXX,
          CyberImage or CyberBlade. These chips are mostly found in laptops
-         but also on some motherboards. For more information, read
-         <file:Documentation/fb/tridentfb.txt>
+         but also on some motherboards including early VIA EPIA motherboards.
+         For more information, read <file:Documentation/fb/tridentfb.txt>
 
          Say Y if you have such a graphics board.
 
          To compile this driver as a module, choose M here: the
          module will be called tridentfb.
 
-config FB_TRIDENT_ACCEL
-       bool "Trident Acceleration functions (EXPERIMENTAL)"
-       depends on FB_TRIDENT && EXPERIMENTAL
-       ---help---
-       This will compile the Trident frame buffer device with
-       acceleration functions.
-
 config FB_ARK
        tristate "ARK 2000PV support"
        depends on FB && PCI
@@ -1920,6 +1889,30 @@ config FB_TMIO_ACCELL
        depends on FB_TMIO
        default y
 
+config FB_S3C
+       tristate "Samsung S3C framebuffer support"
+       depends on FB && ARCH_S3C64XX
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Frame buffer driver for the built-in FB controller in the Samsung
+         SoC line from the S3C2443 onwards, including the S3C2416, S3C2450,
+         and the S3C64XX series such as the S3C6400 and S3C6410.
+
+         These chips all have the same basic framebuffer design with the
+         actual capabilities depending on the chip. For instance the S3C6400
+         and S3C6410 support 4 hardware windows whereas the S3C24XX series
+         currently only have two.
+
+         Currently the support is only for the S3C6400 and S3C6410 SoCs.
+
+config FB_S3C_DEBUG_REGWRITE
+       bool "Debug register writes"
+       depends on FB_S3C
+       ---help---
+         Show all register writes via printk(KERN_DEBUG)
+
 config FB_S3C2410
        tristate "S3C2410 LCD framebuffer support"
        depends on FB && ARCH_S3C2410
index bb265eca7d57c556c409f6ecf58e3cb76af9c4de..0dbd6c68d76bc50a3b984819aec83178ce5adba6 100644 (file)
@@ -76,6 +76,7 @@ obj-$(CONFIG_FB_ATARI)            += atafb.o c2p_iplan2.o atafb_mfb.o \
                                      atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
 obj-$(CONFIG_FB_MAC)              += macfb.o
 obj-$(CONFIG_FB_HECUBA)           += hecubafb.o
+obj-$(CONFIG_FB_N411)             += n411.o
 obj-$(CONFIG_FB_HGA)              += hgafb.o
 obj-$(CONFIG_FB_XVR500)           += sunxvr500.o
 obj-$(CONFIG_FB_XVR2500)          += sunxvr2500.o
@@ -110,6 +111,7 @@ obj-$(CONFIG_FB_BROADSHEET)       += broadsheetfb.o
 obj-$(CONFIG_FB_S1D13XXX)        += s1d13xxxfb.o
 obj-$(CONFIG_FB_SH7760)                  += sh7760fb.o
 obj-$(CONFIG_FB_IMX)              += imxfb.o
+obj-$(CONFIG_FB_S3C)             += s3c-fb.o
 obj-$(CONFIG_FB_S3C2410)         += s3c2410fb.o
 obj-$(CONFIG_FB_FSL_DIU)         += fsl-diu-fb.o
 obj-$(CONFIG_FB_COBALT)           += cobalt_lcdfb.o
index 4e046fed1380e7b4f158b4fe4c576b825b575eca..61050ab141288134a62f393533c31b24871ce233 100644 (file)
@@ -408,7 +408,9 @@ static int clcdfb_register(struct clcd_fb *fb)
        /*
         * Allocate colourmap.
         */
-       fb_alloc_cmap(&fb->fb.cmap, 256, 0);
+       ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
+       if (ret)
+               goto unmap;
 
        /*
         * Ensure interrupts are disabled.
@@ -426,6 +428,8 @@ static int clcdfb_register(struct clcd_fb *fb)
 
        printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
 
+       fb_dealloc_cmap(&fb->fb.cmap);
+ unmap:
        iounmap(fb->regs);
  free_clk:
        clk_put(fb->clk);
@@ -485,6 +489,8 @@ static int clcdfb_remove(struct amba_device *dev)
 
        clcdfb_disable(fb);
        unregister_framebuffer(&fb->fb);
+       if (fb->fb.cmap.len)
+               fb_dealloc_cmap(&fb->fb.cmap);
        iounmap(fb->regs);
        clk_put(fb->clk);
 
index 100f236614650f42337d7007adb5f32cf09ebf77..82bedd7f778967ee879258d27bc9183111107036 100644 (file)
@@ -2437,7 +2437,9 @@ default_chipset:
                goto amifb_error;
        }
 
-       fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
+       err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
+       if (err)
+               goto amifb_error;
 
        if (register_framebuffer(&fb_info) < 0) {
                err = -EINVAL;
@@ -2456,7 +2458,8 @@ amifb_error:
 
 static void amifb_deinit(void)
 {
-       fb_dealloc_cmap(&fb_info.cmap);
+       if (fb_info.cmap.len)
+               fb_dealloc_cmap(&fb_info.cmap);
        chipfree();
        if (videomemory)
                iounmap((void*)videomemory);
index 314d18694b6a38c2d3fd6eeca883e1448bcd0fd2..d583bea608fd755bfe1f16c24d5dc95e184aa316 100644 (file)
@@ -470,7 +470,7 @@ static void ark_dac_read_regs(void *data, u8 *code, int count)
 
        while (count != 0)
        {
-               vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+               vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
                code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
                count--;
                code += 2;
@@ -485,7 +485,7 @@ static void ark_dac_write_regs(void *data, u8 *code, int count)
 
        while (count != 0)
        {
-               vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+               vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
                vga_w(NULL, dac_regs[code[0] & 3], code[1]);
                count--;
                code += 2;
index 1fd22f460b0fa23e990cced9abe9c26f66b04791..1a1f946d8fef6145859275fe491f9c83bfbcf64a 100644 (file)
@@ -505,19 +505,27 @@ static struct fb_var_screeninfo asiliantfb_var __devinitdata = {
        .vsync_len      = 2,
 };
 
-static void __devinit init_asiliant(struct fb_info *p, unsigned long addr)
+static int __devinit init_asiliant(struct fb_info *p, unsigned long addr)
 {
+       int err;
+
        p->fix                  = asiliantfb_fix;
        p->fix.smem_start       = addr;
        p->var                  = asiliantfb_var;
        p->fbops                = &asiliantfb_ops;
        p->flags                = FBINFO_DEFAULT;
 
-       fb_alloc_cmap(&p->cmap, 256, 0);
+       err = fb_alloc_cmap(&p->cmap, 256, 0);
+       if (err) {
+               printk(KERN_ERR "C&T 69000 fb failed to alloc cmap memory\n");
+               return err;
+       }
 
-       if (register_framebuffer(p) < 0) {
+       err = register_framebuffer(p);
+       if (err < 0) {
                printk(KERN_ERR "C&T 69000 framebuffer failed to register\n");
-               return;
+               fb_dealloc_cmap(&p->cmap);
+               return err;
        }
 
        printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n",
@@ -532,6 +540,7 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 {
        unsigned long addr, size;
        struct fb_info *p;
+       int err;
 
        if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
                return -ENODEV;
@@ -560,7 +569,13 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
        pci_write_config_dword(dp, 4, 0x02800083);
        writeb(3, p->screen_base + 0x400784);
 
-       init_asiliant(p, addr);
+       err = init_asiliant(p, addr);
+       if (err) {
+               iounmap(p->screen_base);
+               release_mem_region(addr, size);
+               framebuffer_release(p);
+               return err;
+       }
 
        pci_set_drvdata(dp, p);
        return 0;
@@ -571,6 +586,7 @@ static void __devexit asiliantfb_remove(struct pci_dev *dp)
        struct fb_info *p = pci_get_drvdata(dp);
 
        unregister_framebuffer(p);
+       fb_dealloc_cmap(&p->cmap);
        iounmap(p->screen_base);
        release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
        pci_set_drvdata(dp, NULL);
index a8f60c33863c6f7df1e239e66de510347a107c22..0cc9724e61a268cc8e21acfbd5cd4ff05100a6f6 100644 (file)
@@ -39,7 +39,8 @@ void aty_reset_engine(const struct atyfb_par *par)
 {
        /* reset engine */
        aty_st_le32(GEN_TEST_CNTL,
-               aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par);
+               aty_ld_le32(GEN_TEST_CNTL, par) &
+               ~(GUI_ENGINE_ENABLE | HWCURSOR_ENABLE), par);
        /* enable engine */
        aty_st_le32(GEN_TEST_CNTL,
                aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par);
index faf95da8fcbc074ae7878944f66c2973436ea815..04c710804bb04e93e67cd1b81fe7b811d5c87bce 100644 (file)
@@ -77,9 +77,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        if (par->asleep)
                return -EPERM;
 
-       /* Hide cursor */
        wait_for_fifo(1, par);
-       aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par);
+       if (cursor->enable)
+               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
+                           | HWCURSOR_ENABLE, par);
+       else
+               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
+                               & ~HWCURSOR_ENABLE, par);
 
        /* set position */
        if (cursor->set & FB_CUR_SETPOS) {
@@ -109,7 +113,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
                        y<<=1;
                        h<<=1;
                }
-               wait_for_fifo(4, par);
+               wait_for_fifo(3, par);
                aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par);
                aty_st_le32(CUR_HORZ_VERT_OFF,
                            ((u32) (64 - h + yoff) << 16) | xoff, par);
@@ -177,11 +181,6 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
            }
        }
 
-       if (cursor->enable) {
-               wait_for_fifo(1, par);
-               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
-                           | HWCURSOR_ENABLE, par);
-       }
        return 0;
 }
 
index c6d7cc76516ff116edfff3643156fb5a18d19e7a..97a1f095f327115524bdb9fcd55da6162d8497d2 100644 (file)
@@ -89,6 +89,9 @@ static struct radeon_device_id radeon_workaround_list[] = {
        BUGFIX("Acer Aspire 2010",
               PCI_VENDOR_ID_AI, 0x0061,
               radeon_pm_off, radeon_reinitialize_M10),
+       BUGFIX("Acer Travelmate 290D/292LMi",
+              PCI_VENDOR_ID_AI, 0x005a,
+              radeon_pm_off, radeon_reinitialize_M10),
        { .ident = NULL }
 };
 
@@ -2582,7 +2585,7 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
                 * calling pci_set_power_state()
                 */
                radeonfb_whack_power_state(rinfo, PCI_D2);
-               pci_set_power_state(rinfo->pdev, PCI_D2);
+               __pci_complete_power_transition(rinfo->pdev, PCI_D2);
        } else {
                printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n",
                       pci_name(rinfo->pdev));
index 157057c79ca3760fc80d6df28236dc0bbf106044..dd37cbcaf8ce164a4ac5e7293a745204ede08ac4 100644 (file)
@@ -35,6 +35,8 @@ static int fb_notifier_callback(struct notifier_block *self,
                return 0;
 
        bd = container_of(self, struct backlight_device, fb_notif);
+       if (!lock_fb_info(evdata->info))
+               return -ENODEV;
        mutex_lock(&bd->ops_lock);
        if (bd->ops)
                if (!bd->ops->check_fb ||
@@ -47,6 +49,7 @@ static int fb_notifier_callback(struct notifier_block *self,
                        backlight_update_status(bd);
                }
        mutex_unlock(&bd->ops_lock);
+       unlock_fb_info(evdata->info);
        return 0;
 }
 
index b6449470106cd47e8db704edfd074c53dde8ec4b..0bb13df0fa89e2b3ca01c9468a47cadd2f5a8b88 100644 (file)
@@ -40,6 +40,8 @@ static int fb_notifier_callback(struct notifier_block *self,
        if (!ld->ops)
                return 0;
 
+       if (!lock_fb_info(evdata->info))
+               return -ENODEV;
        mutex_lock(&ld->ops_lock);
        if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) {
                if (event == FB_EVENT_BLANK) {
@@ -51,6 +53,7 @@ static int fb_notifier_callback(struct notifier_block *self,
                }
        }
        mutex_unlock(&ld->ops_lock);
+       unlock_fb_info(evdata->info);
        return 0;
 }
 
index a2aa6ddffbe25d6e764a0dc6bdc7dd298e9f1849..d42e385f091c7658418d844f7cc77db306bd0a93 100644 (file)
@@ -34,8 +34,6 @@
  *
  */
 
-#define CIRRUSFB_VERSION "2.0-pre2"
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
  *
  */
 
-/* enable debug output? */
-/* #define CIRRUSFB_DEBUG 1 */
-
 /* disable runtime assertions? */
 /* #define CIRRUSFB_NDEBUG */
 
-/* debug output */
-#ifdef CIRRUSFB_DEBUG
-#define DPRINTK(fmt, args...) \
-       printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
 /* debugging assertions */
 #ifndef CIRRUSFB_NDEBUG
 #define assert(expr) \
 /* board types */
 enum cirrus_board {
        BT_NONE = 0,
-       BT_SD64,
-       BT_PICCOLO,
-       BT_PICASSO,
-       BT_SPECTRUM,
+       BT_SD64,        /* GD5434 */
+       BT_PICCOLO,     /* GD5426 */
+       BT_PICASSO,     /* GD5426 or GD5428 */
+       BT_SPECTRUM,    /* GD5426 or GD5428 */
        BT_PICASSO4,    /* GD5446 */
        BT_ALPINE,      /* GD543x/4x */
        BT_GD5480,
-       BT_LAGUNA,      /* GD546x */
+       BT_LAGUNA,      /* GD5462/64 */
+       BT_LAGUNAB,     /* GD5465 */
 };
 
 /*
@@ -150,15 +138,17 @@ static const struct cirrusfb_board_info_rec {
                .maxclock               = {
                        /* guess */
                        /* the SD64/P4 have a higher max. videoclock */
-                       140000, 140000, 140000, 140000, 140000,
+                       135100, 135100, 85500, 85500, 0
                },
                .init_sr07              = true,
                .init_sr1f              = true,
                .scrn_start_bit19       = true,
                .sr07                   = 0xF0,
                .sr07_1bpp              = 0xF0,
+               .sr07_1bpp_mux          = 0xF6,
                .sr07_8bpp              = 0xF1,
-               .sr1f                   = 0x20
+               .sr07_8bpp_mux          = 0xF7,
+               .sr1f                   = 0x1E
        },
        [BT_PICCOLO] = {
                .name                   = "CL Piccolo",
@@ -210,9 +200,11 @@ static const struct cirrusfb_board_info_rec {
                .init_sr07              = true,
                .init_sr1f              = false,
                .scrn_start_bit19       = true,
-               .sr07                   = 0x20,
-               .sr07_1bpp              = 0x20,
-               .sr07_8bpp              = 0x21,
+               .sr07                   = 0xA0,
+               .sr07_1bpp              = 0xA0,
+               .sr07_1bpp_mux          = 0xA6,
+               .sr07_8bpp              = 0xA1,
+               .sr07_8bpp_mux          = 0xA7,
                .sr1f                   = 0
        },
        [BT_ALPINE] = {
@@ -225,8 +217,8 @@ static const struct cirrusfb_board_info_rec {
                .init_sr1f              = true,
                .scrn_start_bit19       = true,
                .sr07                   = 0xA0,
-               .sr07_1bpp              = 0xA1,
-               .sr07_1bpp_mux          = 0xA7,
+               .sr07_1bpp              = 0xA0,
+               .sr07_1bpp_mux          = 0xA6,
                .sr07_8bpp              = 0xA1,
                .sr07_8bpp_mux          = 0xA7,
                .sr1f                   = 0x1C
@@ -247,8 +239,18 @@ static const struct cirrusfb_board_info_rec {
        [BT_LAGUNA] = {
                .name                   = "CL Laguna",
                .maxclock               = {
-                       /* guess */
-                       135100, 135100, 135100, 135100, 135100,
+                       /* taken from X11 code */
+                       170000, 170000, 170000, 170000, 135100,
+               },
+               .init_sr07              = false,
+               .init_sr1f              = false,
+               .scrn_start_bit19       = true,
+       },
+       [BT_LAGUNAB] = {
+               .name                   = "CL Laguna AGP",
+               .maxclock               = {
+                       /* taken from X11 code */
+                       170000, 250000, 170000, 170000, 135100,
                },
                .init_sr07              = false,
                .init_sr1f              = false,
@@ -262,8 +264,8 @@ static const struct cirrusfb_board_info_rec {
 
 static struct pci_device_id cirrusfb_pci_table[] = {
        CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
-       CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE),
-       CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE),
+       CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64),
+       CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64),
        CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
        CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
        CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
@@ -271,7 +273,7 @@ static struct pci_device_id cirrusfb_pci_table[] = {
        CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
        CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
        CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
-       CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/
+       CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
@@ -326,10 +328,6 @@ static const struct {
 };
 #endif /* CONFIG_ZORRO */
 
-struct cirrusfb_regs {
-       int multiplexing;
-};
-
 #ifdef CIRRUSFB_DEBUG
 enum cirrusfb_dbg_reg_class {
        CRT,
@@ -340,10 +338,12 @@ enum cirrusfb_dbg_reg_class {
 /* info about board */
 struct cirrusfb_info {
        u8 __iomem *regbase;
+       u8 __iomem *laguna_mmio;
        enum cirrus_board btype;
        unsigned char SFR;      /* Shadow of special function register */
 
-       struct cirrusfb_regs currentmode;
+       int multiplexing;
+       int doubleVCLK;
        int blank_mode;
        u32 pseudo_palette[16];
 
@@ -357,43 +357,8 @@ static char *mode_option __devinitdata = "640x480@60";
 /**** BEGIN PROTOTYPES ******************************************************/
 
 /*--- Interface used by the world ------------------------------------------*/
-static int cirrusfb_init(void);
-#ifndef MODULE
-static int cirrusfb_setup(char *options);
-#endif
-
-static int cirrusfb_open(struct fb_info *info, int user);
-static int cirrusfb_release(struct fb_info *info, int user);
-static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                             unsigned blue, unsigned transp,
-                             struct fb_info *info);
-static int cirrusfb_check_var(struct fb_var_screeninfo *var,
-                             struct fb_info *info);
-static int cirrusfb_set_par(struct fb_info *info);
 static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
                                struct fb_info *info);
-static int cirrusfb_blank(int blank_mode, struct fb_info *info);
-static void cirrusfb_fillrect(struct fb_info *info,
-                             const struct fb_fillrect *region);
-static void cirrusfb_copyarea(struct fb_info *info,
-                             const struct fb_copyarea *area);
-static void cirrusfb_imageblit(struct fb_info *info,
-                              const struct fb_image *image);
-
-/* function table of the above functions */
-static struct fb_ops cirrusfb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_open        = cirrusfb_open,
-       .fb_release     = cirrusfb_release,
-       .fb_setcolreg   = cirrusfb_setcolreg,
-       .fb_check_var   = cirrusfb_check_var,
-       .fb_set_par     = cirrusfb_set_par,
-       .fb_pan_display = cirrusfb_pan_display,
-       .fb_blank       = cirrusfb_blank,
-       .fb_fillrect    = cirrusfb_fillrect,
-       .fb_copyarea    = cirrusfb_copyarea,
-       .fb_imageblit   = cirrusfb_imageblit,
-};
 
 /*--- Internal routines ----------------------------------------------------*/
 static void init_vgachip(struct fb_info *info);
@@ -421,22 +386,27 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
 static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
                              u_short x, u_short y,
                              u_short width, u_short height,
-                             u_char color, u_short line_length);
+                             u32 fg_color, u32 bg_color,
+                             u_short line_length, u_char blitmode);
 
 static void bestclock(long freq, int *nom, int *den, int *div);
 
 #ifdef CIRRUSFB_DEBUG
-static void cirrusfb_dump(void);
-static void cirrusfb_dbg_reg_dump(caddr_t regbase);
-static void cirrusfb_dbg_print_regs(caddr_t regbase,
+static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase);
+static void cirrusfb_dbg_print_regs(struct fb_info *info,
+                                   caddr_t regbase,
                                    enum cirrusfb_dbg_reg_class reg_class, ...);
-static void cirrusfb_dbg_print_byte(const char *name, unsigned char val);
 #endif /* CIRRUSFB_DEBUG */
 
 /*** END   PROTOTYPES ********************************************************/
 /*****************************************************************************/
 /*** BEGIN Interface Used by the World ***************************************/
 
+static inline int is_laguna(const struct cirrusfb_info *cinfo)
+{
+       return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB;
+}
+
 static int opencount;
 
 /*--- Open /dev/fbx ---------------------------------------------------------*/
@@ -460,85 +430,94 @@ static int cirrusfb_release(struct fb_info *info, int user)
 /**** BEGIN Hardware specific Routines **************************************/
 
 /* Check if the MCLK is not a better clock source */
-static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq)
+static int cirrusfb_check_mclk(struct fb_info *info, long freq)
 {
+       struct cirrusfb_info *cinfo = info->par;
        long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
 
        /* Read MCLK value */
        mclk = (14318 * mclk) >> 3;
-       DPRINTK("Read MCLK of %ld kHz\n", mclk);
+       dev_dbg(info->device, "Read MCLK of %ld kHz\n", mclk);
 
        /* Determine if we should use MCLK instead of VCLK, and if so, what we
         * should divide it by to get VCLK
         */
 
        if (abs(freq - mclk) < 250) {
-               DPRINTK("Using VCLK = MCLK\n");
+               dev_dbg(info->device, "Using VCLK = MCLK\n");
                return 1;
        } else if (abs(freq - (mclk / 2)) < 250) {
-               DPRINTK("Using VCLK = MCLK/2\n");
+               dev_dbg(info->device, "Using VCLK = MCLK/2\n");
                return 2;
        }
 
        return 0;
 }
 
-static int cirrusfb_check_var(struct fb_var_screeninfo *var,
-                             struct fb_info *info)
+static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var,
+                                  struct fb_info *info)
 {
-       int yres;
-       /* memory size in pixels */
-       unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
+       long freq;
+       long maxclock;
+       struct cirrusfb_info *cinfo = info->par;
+       unsigned maxclockidx = var->bits_per_pixel >> 3;
 
-       switch (var->bits_per_pixel) {
-       case 1:
-               pixels /= 4;
-               break;          /* 8 pixel per byte, only 1/4th of mem usable */
-       case 8:
-       case 16:
-       case 32:
-               break;          /* 1 pixel == 1 byte */
-       default:
-               printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
-                       "color depth not supported.\n",
-                       var->xres, var->yres, var->bits_per_pixel);
-               DPRINTK("EXIT - EINVAL error\n");
-               return -EINVAL;
-       }
+       /* convert from ps to kHz */
+       freq = PICOS2KHZ(var->pixclock);
 
-       if (var->xres_virtual < var->xres)
-               var->xres_virtual = var->xres;
-       /* use highest possible virtual resolution */
-       if (var->yres_virtual == -1) {
-               var->yres_virtual = pixels / var->xres_virtual;
+       dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq);
 
-               printk(KERN_INFO "cirrusfb: virtual resolution set to "
-                       "maximum of %dx%d\n", var->xres_virtual,
-                       var->yres_virtual);
-       }
-       if (var->yres_virtual < var->yres)
-               var->yres_virtual = var->yres;
+       maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
+       cinfo->multiplexing = 0;
 
-       if (var->xres_virtual * var->yres_virtual > pixels) {
-               printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... "
-                     "virtual resolution too high to fit into video memory!\n",
-                       var->xres_virtual, var->yres_virtual,
-                       var->bits_per_pixel);
-               DPRINTK("EXIT - EINVAL error\n");
+       /* If the frequency is greater than we can support, we might be able
+        * to use multiplexing for the video mode */
+       if (freq > maxclock) {
+               dev_err(info->device,
+                       "Frequency greater than maxclock (%ld kHz)\n",
+                       maxclock);
                return -EINVAL;
        }
+       /*
+        * Additional constraint: 8bpp uses DAC clock doubling to allow maximum
+        * pixel clock
+        */
+       if (var->bits_per_pixel == 8) {
+               switch (cinfo->btype) {
+               case BT_ALPINE:
+               case BT_SD64:
+               case BT_PICASSO4:
+                       if (freq > 85500)
+                               cinfo->multiplexing = 1;
+                       break;
+               case BT_GD5480:
+                       if (freq > 135100)
+                               cinfo->multiplexing = 1;
+                       break;
 
+               default:
+                       break;
+               }
+       }
 
-       if (var->xoffset < 0)
-               var->xoffset = 0;
-       if (var->yoffset < 0)
-               var->yoffset = 0;
+       /* If we have a 1MB 5434, we need to put ourselves in a mode where
+        * the VCLK is double the pixel clock. */
+       cinfo->doubleVCLK = 0;
+       if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ &&
+           var->bits_per_pixel == 16) {
+               cinfo->doubleVCLK = 1;
+       }
 
-       /* truncate xoffset and yoffset to maximum if too high */
-       if (var->xoffset > var->xres_virtual - var->xres)
-               var->xoffset = var->xres_virtual - var->xres - 1;
-       if (var->yoffset > var->yres_virtual - var->yres)
-               var->yoffset = var->yres_virtual - var->yres - 1;
+       return 0;
+}
+
+static int cirrusfb_check_var(struct fb_var_screeninfo *var,
+                             struct fb_info *info)
+{
+       int yres;
+       /* memory size in pixels */
+       unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
+       struct cirrusfb_info *cinfo = info->par;
 
        switch (var->bits_per_pixel) {
        case 1:
@@ -550,7 +529,7 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
 
        case 8:
                var->red.offset = 0;
-               var->red.length = 6;
+               var->red.length = 8;
                var->green = var->red;
                var->blue = var->red;
                break;
@@ -561,20 +540,20 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                        var->green.offset = -3;
                        var->blue.offset = 8;
                } else {
-                       var->red.offset = 10;
+                       var->red.offset = 11;
                        var->green.offset = 5;
                        var->blue.offset = 0;
                }
                var->red.length = 5;
-               var->green.length = 5;
+               var->green.length = 6;
                var->blue.length = 5;
                break;
 
-       case 32:
+       case 24:
                if (isPReP) {
-                       var->red.offset = 8;
-                       var->green.offset = 16;
-                       var->blue.offset = 24;
+                       var->red.offset = 0;
+                       var->green.offset = 8;
+                       var->blue.offset = 16;
                } else {
                        var->red.offset = 16;
                        var->green.offset = 8;
@@ -586,12 +565,45 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                break;
 
        default:
-               DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
+               dev_dbg(info->device,
+                       "Unsupported bpp size: %d\n", var->bits_per_pixel);
                assert(false);
                /* should never occur */
                break;
        }
 
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+       /* use highest possible virtual resolution */
+       if (var->yres_virtual == -1) {
+               var->yres_virtual = pixels / var->xres_virtual;
+
+               dev_info(info->device,
+                        "virtual resolution set to maximum of %dx%d\n",
+                        var->xres_virtual, var->yres_virtual);
+       }
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
+
+       if (var->xres_virtual * var->yres_virtual > pixels) {
+               dev_err(info->device, "mode %dx%dx%d rejected... "
+                     "virtual resolution too high to fit into video memory!\n",
+                       var->xres_virtual, var->yres_virtual,
+                       var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       if (var->xoffset < 0)
+               var->xoffset = 0;
+       if (var->yoffset < 0)
+               var->yoffset = 0;
+
+       /* truncate xoffset and yoffset to maximum if too high */
+       if (var->xoffset > var->xres_virtual - var->xres)
+               var->xoffset = var->xres_virtual - var->xres - 1;
+       if (var->yoffset > var->yres_virtual - var->yres)
+               var->yoffset = var->yres_virtual - var->yres - 1;
+
        var->red.msb_right =
            var->green.msb_right =
            var->blue.msb_right =
@@ -606,99 +618,31 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                yres = (yres + 1) / 2;
 
        if (yres >= 1280) {
-               printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; "
+               dev_err(info->device, "ERROR: VerticalTotal >= 1280; "
                        "special treatment required! (TODO)\n");
-               DPRINTK("EXIT - EINVAL error\n");
                return -EINVAL;
        }
 
-       return 0;
-}
-
-static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
-                               struct cirrusfb_regs *regs,
-                               struct fb_info *info)
-{
-       long freq;
-       long maxclock;
-       int maxclockidx = var->bits_per_pixel >> 3;
-       struct cirrusfb_info *cinfo = info->par;
-
-       switch (var->bits_per_pixel) {
-       case 1:
-               info->fix.line_length = var->xres_virtual / 8;
-               info->fix.visual = FB_VISUAL_MONO10;
-               break;
-
-       case 8:
-               info->fix.line_length = var->xres_virtual;
-               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-               break;
-
-       case 16:
-       case 32:
-               info->fix.line_length = var->xres_virtual * maxclockidx;
-               info->fix.visual = FB_VISUAL_TRUECOLOR;
-               break;
-
-       default:
-               DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
-               assert(false);
-               /* should never occur */
-               break;
-       }
-
-       info->fix.type = FB_TYPE_PACKED_PIXELS;
-
-       /* convert from ps to kHz */
-       freq = PICOS2KHZ(var->pixclock);
-
-       DPRINTK("desired pixclock: %ld kHz\n", freq);
-
-       maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
-       regs->multiplexing = 0;
+       if (cirrusfb_check_pixclock(var, info))
+               return -EINVAL;
 
-       /* If the frequency is greater than we can support, we might be able
-        * to use multiplexing for the video mode */
-       if (freq > maxclock) {
-               switch (cinfo->btype) {
-               case BT_ALPINE:
-               case BT_GD5480:
-                       regs->multiplexing = 1;
-                       break;
+       if (!is_laguna(cinfo))
+               var->accel_flags = FB_ACCELF_TEXT;
 
-               default:
-                       printk(KERN_ERR "cirrusfb: Frequency greater "
-                               "than maxclock (%ld kHz)\n", maxclock);
-                       DPRINTK("EXIT - return -EINVAL\n");
-                       return -EINVAL;
-               }
-       }
-#if 0
-       /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
-        * the VCLK is double the pixel clock. */
-       switch (var->bits_per_pixel) {
-       case 16:
-       case 32:
-               if (var->xres <= 800)
-                       /* Xbh has this type of clock for 32-bit */
-                       freq /= 2;
-               break;
-       }
-#endif
        return 0;
 }
 
-static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo,
-                                       int div)
+static void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div)
 {
+       struct cirrusfb_info *cinfo = info->par;
        unsigned char old1f, old1e;
+
        assert(cinfo != NULL);
        old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
 
        if (div) {
-               DPRINTK("Set %s as pixclock source.\n",
-                                       (div == 2) ? "MCLK/2" : "MCLK");
+               dev_dbg(info->device, "Set %s as pixclock source.\n",
+                       (div == 2) ? "MCLK/2" : "MCLK");
                old1f |= 0x40;
                old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
                if (div == 2)
@@ -718,101 +662,119 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        struct fb_var_screeninfo *var = &info->var;
-       struct cirrusfb_regs regs;
        u8 __iomem *regbase = cinfo->regbase;
        unsigned char tmp;
-       int offset = 0, err;
+       int pitch;
        const struct cirrusfb_board_info_rec *bi;
        int hdispend, hsyncstart, hsyncend, htotal;
        int yres, vdispend, vsyncstart, vsyncend, vtotal;
        long freq;
        int nom, den, div;
+       unsigned int control = 0, format = 0, threshold = 0;
 
-       DPRINTK("ENTER\n");
-       DPRINTK("Requested mode: %dx%dx%d\n",
+       dev_dbg(info->device, "Requested mode: %dx%dx%d\n",
               var->xres, var->yres, var->bits_per_pixel);
-       DPRINTK("pixclock: %d\n", var->pixclock);
 
-       init_vgachip(info);
+       switch (var->bits_per_pixel) {
+       case 1:
+               info->fix.line_length = var->xres_virtual / 8;
+               info->fix.visual = FB_VISUAL_MONO10;
+               break;
 
-       err = cirrusfb_decode_var(var, &regs, info);
-       if (err) {
-               /* should never happen */
-               DPRINTK("mode change aborted.  invalid var.\n");
-               return -EINVAL;
+       case 8:
+               info->fix.line_length = var->xres_virtual;
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+
+       case 16:
+       case 24:
+               info->fix.line_length = var->xres_virtual *
+                                       var->bits_per_pixel >> 3;
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
        }
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+
+       init_vgachip(info);
 
        bi = &cirrusfb_board_info[cinfo->btype];
 
        hsyncstart = var->xres + var->right_margin;
        hsyncend = hsyncstart + var->hsync_len;
-       htotal = (hsyncend + var->left_margin) / 8 - 5;
-       hdispend = var->xres / 8 - 1;
-       hsyncstart = hsyncstart / 8 + 1;
-       hsyncend = hsyncend / 8 + 1;
+       htotal = (hsyncend + var->left_margin) / 8;
+       hdispend = var->xres / 8;
+       hsyncstart = hsyncstart / 8;
+       hsyncend = hsyncend / 8;
 
-       yres = var->yres;
-       vsyncstart = yres + var->lower_margin;
+       vdispend = var->yres;
+       vsyncstart = vdispend + var->lower_margin;
        vsyncend = vsyncstart + var->vsync_len;
        vtotal = vsyncend + var->upper_margin;
-       vdispend = yres - 1;
 
        if (var->vmode & FB_VMODE_DOUBLE) {
-               yres *= 2;
+               vdispend *= 2;
                vsyncstart *= 2;
                vsyncend *= 2;
                vtotal *= 2;
        } else if (var->vmode & FB_VMODE_INTERLACED) {
-               yres = (yres + 1) / 2;
+               vdispend = (vdispend + 1) / 2;
                vsyncstart = (vsyncstart + 1) / 2;
                vsyncend = (vsyncend + 1) / 2;
                vtotal = (vtotal + 1) / 2;
        }
-
-       vtotal -= 2;
-       vsyncstart -= 1;
-       vsyncend -= 1;
-
+       yres = vdispend;
        if (yres >= 1024) {
                vtotal /= 2;
                vsyncstart /= 2;
                vsyncend /= 2;
                vdispend /= 2;
        }
-       if (regs.multiplexing) {
+
+       vdispend -= 1;
+       vsyncstart -= 1;
+       vsyncend -= 1;
+       vtotal -= 2;
+
+       if (cinfo->multiplexing) {
                htotal /= 2;
                hsyncstart /= 2;
                hsyncend /= 2;
                hdispend /= 2;
        }
+
+       htotal -= 5;
+       hdispend -= 1;
+       hsyncstart += 1;
+       hsyncend += 1;
+
        /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
        vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);   /* previously: 0x00) */
 
        /* if debugging is enabled, all parameters get output before writing */
-       DPRINTK("CRT0: %d\n", htotal);
+       dev_dbg(info->device, "CRT0: %d\n", htotal);
        vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
 
-       DPRINTK("CRT1: %d\n", hdispend);
+       dev_dbg(info->device, "CRT1: %d\n", hdispend);
        vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
 
-       DPRINTK("CRT2: %d\n", var->xres / 8);
+       dev_dbg(info->device, "CRT2: %d\n", var->xres / 8);
        vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
 
        /*  + 128: Compatible read */
-       DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32);
+       dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32);
        vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
                 128 + ((htotal + 5) % 32));
 
-       DPRINTK("CRT4: %d\n", hsyncstart);
+       dev_dbg(info->device, "CRT4: %d\n", hsyncstart);
        vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
 
        tmp = hsyncend % 32;
        if ((htotal + 5) & 32)
                tmp += 128;
-       DPRINTK("CRT5: %d\n", tmp);
+       dev_dbg(info->device, "CRT5: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
 
-       DPRINTK("CRT6: %d\n", vtotal & 0xff);
+       dev_dbg(info->device, "CRT6: %d\n", vtotal & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
 
        tmp = 16;               /* LineCompare bit #9 */
@@ -830,7 +792,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                tmp |= 64;
        if (vsyncstart & 512)
                tmp |= 128;
-       DPRINTK("CRT7: %d\n", tmp);
+       dev_dbg(info->device, "CRT7: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
 
        tmp = 0x40;             /* LineCompare bit #8 */
@@ -838,25 +800,25 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                tmp |= 0x20;
        if (var->vmode & FB_VMODE_DOUBLE)
                tmp |= 0x80;
-       DPRINTK("CRT9: %d\n", tmp);
+       dev_dbg(info->device, "CRT9: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
 
-       DPRINTK("CRT10: %d\n", vsyncstart & 0xff);
+       dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
 
-       DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16);
+       dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16);
        vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
 
-       DPRINTK("CRT12: %d\n", vdispend & 0xff);
+       dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
 
-       DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff);
+       dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
 
-       DPRINTK("CRT16: %d\n", vtotal & 0xff);
+       dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff);
        vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
 
-       DPRINTK("CRT18: 0xff\n");
+       dev_dbg(info->device, "CRT18: 0xff\n");
        vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
 
        tmp = 0;
@@ -871,41 +833,75 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        if (vtotal & 512)
                tmp |= 128;
 
-       DPRINTK("CRT1a: %d\n", tmp);
+       dev_dbg(info->device, "CRT1a: %d\n", tmp);
        vga_wcrt(regbase, CL_CRT1A, tmp);
 
        freq = PICOS2KHZ(var->pixclock);
+       if (var->bits_per_pixel == 24)
+               if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64)
+                       freq *= 3;
+       if (cinfo->multiplexing)
+               freq /= 2;
+       if (cinfo->doubleVCLK)
+               freq *= 2;
+
        bestclock(freq, &nom, &den, &div);
 
+       dev_dbg(info->device, "VCLK freq: %ld kHz  nom: %d  den: %d  div: %d\n",
+               freq, nom, den, div);
+
        /* set VCLK0 */
        /* hardware RefClock: 14.31818 MHz */
        /* formula: VClk = (OSC * N) / (D * (1+P)) */
        /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
 
-       if (cinfo->btype == BT_ALPINE) {
+       if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 ||
+           cinfo->btype == BT_SD64) {
                /* if freq is close to mclk or mclk/2 select mclk
                 * as clock source
                 */
-               int divMCLK = cirrusfb_check_mclk(cinfo, freq);
-               if (divMCLK)  {
+               int divMCLK = cirrusfb_check_mclk(info, freq);
+               if (divMCLK)
                        nom = 0;
-                       cirrusfb_set_mclk_as_source(cinfo, divMCLK);
+               cirrusfb_set_mclk_as_source(info, divMCLK);
+       }
+       if (is_laguna(cinfo)) {
+               long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
+               unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
+               unsigned short tile_control;
+
+               if (cinfo->btype == BT_LAGUNAB) {
+                       tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
+                       tile_control &= ~0x80;
+                       fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4);
                }
+
+               fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
+               fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
+               control = fb_readw(cinfo->laguna_mmio + 0x402);
+               threshold = fb_readw(cinfo->laguna_mmio + 0xea);
+               control &= ~0x6800;
+               format = 0;
+               threshold &= 0xffc0 & 0x3fbf;
        }
        if (nom) {
-               vga_wseq(regbase, CL_SEQRB, nom);
                tmp = den << 1;
                if (div != 0)
                        tmp |= 1;
-
                /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
                if ((cinfo->btype == BT_SD64) ||
                    (cinfo->btype == BT_ALPINE) ||
                    (cinfo->btype == BT_GD5480))
                        tmp |= 0x80;
 
-               DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
-               vga_wseq(regbase, CL_SEQR1B, tmp);
+               /* Laguna chipset has reversed clock registers */
+               if (is_laguna(cinfo)) {
+                       vga_wseq(regbase, CL_SEQRE, tmp);
+                       vga_wseq(regbase, CL_SEQR1E, nom);
+               } else {
+                       vga_wseq(regbase, CL_SEQRE, nom);
+                       vga_wseq(regbase, CL_SEQR1E, tmp);
+               }
        }
 
        if (yres >= 1024)
@@ -916,9 +912,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                 * address wrap, no compat. */
                vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
 
-/* HAEH?       vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);
- * previously: 0x00  unlock VGA_CRTC_H_TOTAL..CRT7 */
-
        /* don't know if it would hurt to also program this if no interlaced */
        /* mode is used, but I feel better this way.. :-) */
        if (var->vmode & FB_VMODE_INTERLACED)
@@ -926,19 +919,15 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        else
                vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
 
-       vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0);
-
-       /* adjust horizontal/vertical sync type (low/high) */
+       /* adjust horizontal/vertical sync type (low/high), use VCLK3 */
        /* enable display memory & CRTC I/O address for color mode */
-       tmp = 0x03;
+       tmp = 0x03 | 0xc;
        if (var->sync & FB_SYNC_HOR_HIGH_ACT)
                tmp |= 0x40;
        if (var->sync & FB_SYNC_VERT_HIGH_ACT)
                tmp |= 0x80;
        WGen(cinfo, VGA_MIS_W, tmp);
 
-       /* Screen A Preset Row-Scan register */
-       vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
        /* text cursor on and start line */
        vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
        /* text cursor end line */
@@ -952,7 +941,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 
        /* programming for different color depths */
        if (var->bits_per_pixel == 1) {
-               DPRINTK("cirrusfb: preparing for 1 bit deep display\n");
+               dev_dbg(info->device, "preparing for 1 bit deep display\n");
                vga_wgfx(regbase, VGA_GFX_MODE, 0);     /* mode register */
 
                /* SR07 */
@@ -964,68 +953,53 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                case BT_PICASSO4:
                case BT_ALPINE:
                case BT_GD5480:
-                       DPRINTK(" (for GD54xx)\n");
                        vga_wseq(regbase, CL_SEQR7,
-                                 regs.multiplexing ?
+                                cinfo->multiplexing ?
                                        bi->sr07_1bpp_mux : bi->sr07_1bpp);
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) & ~0x01);
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* Extended Sequencer Mode */
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* setting the SEQRF on SD64 is not necessary
-                        * (only during init)
-                        */
-                       DPRINTK("(for SD64)\n");
-                       /*  MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1a);
-                       break;
 
                case BT_PICCOLO:
                case BT_SPECTRUM:
-                       DPRINTK("(for Piccolo/Spectrum)\n");
-                       /* ### ueberall 0x22? */
-                       /* ##vorher 1c MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
                        break;
 
                case BT_PICASSO:
-                       DPRINTK("(for Picasso)\n");
-                       /* ##vorher 22 MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        /* ## vorher d0 avoid FIFO underruns..? */
                        vga_wseq(regbase, CL_SEQRF, 0xd0);
                        break;
 
+               case BT_SD64:
                case BT_PICASSO4:
                case BT_ALPINE:
                case BT_GD5480:
                case BT_LAGUNA:
-                       DPRINTK(" (for GD54xx)\n");
+               case BT_LAGUNAB:
                        /* do nothing */
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* pixel mask: pass-through for first plane */
                WGen(cinfo, VGA_PEL_MSK, 0x01);
-               if (regs.multiplexing)
+               if (cinfo->multiplexing)
                        /* hidden dac reg: 1280x1024 */
                        WHDR(cinfo, 0x4a);
                else
@@ -1035,7 +1009,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
                /* plane mask: only write to first plane */
                vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
-               offset = var->xres_virtual / 16;
        }
 
        /******************************************************
@@ -1045,7 +1018,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
         */
 
        else if (var->bits_per_pixel == 8) {
-               DPRINTK("cirrusfb: preparing for 8 bit deep display\n");
+               dev_dbg(info->device, "preparing for 8 bit deep display\n");
                switch (cinfo->btype) {
                case BT_SD64:
                case BT_PICCOLO:
@@ -1054,34 +1027,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                case BT_PICASSO4:
                case BT_ALPINE:
                case BT_GD5480:
-                       DPRINTK(" (for GD54xx)\n");
                        vga_wseq(regbase, CL_SEQR7,
-                                 regs.multiplexing ?
+                                 cinfo->multiplexing ?
                                        bi->sr07_8bpp_mux : bi->sr07_8bpp);
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) | 0x01);
+                       threshold |= 0x10;
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1d);
-                       break;
-
                case BT_PICCOLO:
                case BT_PICASSO:
                case BT_SPECTRUM:
-                       /* ### vorher 1c MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
                        break;
@@ -1091,40 +1057,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        /* ### INCOMPLETE!! */
                        vga_wseq(regbase, CL_SEQRF, 0xb8);
 #endif
-/*                     vga_wseq(regbase, CL_SEQR1F, 0x1c); */
-                       break;
-
                case BT_ALPINE:
-                       DPRINTK(" (for GD543x)\n");
-                       /* We already set SRF and SR1F */
-                       break;
-
+               case BT_SD64:
                case BT_GD5480:
                case BT_LAGUNA:
-                       DPRINTK(" (for GD54xx)\n");
+               case BT_LAGUNAB:
                        /* do nothing */
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown board\n");
                        break;
                }
 
                /* mode register: 256 color mode */
                vga_wgfx(regbase, VGA_GFX_MODE, 64);
-               /* pixel mask: pass-through all planes */
-               WGen(cinfo, VGA_PEL_MSK, 0xff);
-               if (regs.multiplexing)
+               if (cinfo->multiplexing)
                        /* hidden dac reg: 1280x1024 */
                        WHDR(cinfo, 0x4a);
                else
                        /* hidden dac: nothing */
                        WHDR(cinfo, 0);
-               /* memory mode: chain4, ext. memory */
-               vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
-               /* plane mask: enable writing to all 4 planes */
-               vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
-               offset = var->xres_virtual / 8;
        }
 
        /******************************************************
@@ -1134,147 +1087,110 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
         */
 
        else if (var->bits_per_pixel == 16) {
-               DPRINTK("cirrusfb: preparing for 16 bit deep display\n");
+               dev_dbg(info->device, "preparing for 16 bit deep display\n");
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* Extended Sequencer Mode: 256c col. mode */
-                       vga_wseq(regbase, CL_SEQR7, 0xf7);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1e);
-                       break;
-
                case BT_PICCOLO:
                case BT_SPECTRUM:
                        vga_wseq(regbase, CL_SEQR7, 0x87);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
                case BT_PICASSO:
                        vga_wseq(regbase, CL_SEQR7, 0x27);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
+               case BT_SD64:
                case BT_PICASSO4:
-                       vga_wseq(regbase, CL_SEQR7, 0x27);
-/*                     vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
-                       break;
-
                case BT_ALPINE:
-                       DPRINTK(" (for GD543x)\n");
-                       vga_wseq(regbase, CL_SEQR7, 0xa7);
+                       /* Extended Sequencer Mode: 256c col. mode */
+                       vga_wseq(regbase, CL_SEQR7,
+                                       cinfo->doubleVCLK ? 0xa3 : 0xa7);
                        break;
 
                case BT_GD5480:
-                       DPRINTK(" (for GD5480)\n");
                        vga_wseq(regbase, CL_SEQR7, 0x17);
                        /* We already set SRF and SR1F */
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) & ~0x01);
+                       control |= 0x2000;
+                       format |= 0x1400;
+                       threshold |= 0x10;
                        break;
 
                default:
-                       printk(KERN_WARNING "CIRRUSFB: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* mode register: 256 color mode */
                vga_wgfx(regbase, VGA_GFX_MODE, 64);
-               /* pixel mask: pass-through all planes */
-               WGen(cinfo, VGA_PEL_MSK, 0xff);
 #ifdef CONFIG_PCI
-               WHDR(cinfo, 0xc0);      /* Copy Xbh */
+               WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1);
 #elif defined(CONFIG_ZORRO)
                /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
                WHDR(cinfo, 0xa0);      /* hidden dac reg: nothing special */
 #endif
-               /* memory mode: chain4, ext. memory */
-               vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
-               /* plane mask: enable writing to all 4 planes */
-               vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
-               offset = var->xres_virtual / 4;
        }
 
        /******************************************************
         *
-        * 32 bpp
+        * 24 bpp
         *
         */
 
-       else if (var->bits_per_pixel == 32) {
-               DPRINTK("cirrusfb: preparing for 32 bit deep display\n");
+       else if (var->bits_per_pixel == 24) {
+               dev_dbg(info->device, "preparing for 24 bit deep display\n");
                switch (cinfo->btype) {
-               case BT_SD64:
-                       /* Extended Sequencer Mode: 256c col. mode */
-                       vga_wseq(regbase, CL_SEQR7, 0xf9);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x1e);
-                       break;
-
                case BT_PICCOLO:
                case BT_SPECTRUM:
                        vga_wseq(regbase, CL_SEQR7, 0x85);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
                case BT_PICASSO:
                        vga_wseq(regbase, CL_SEQR7, 0x25);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
+               case BT_SD64:
                case BT_PICASSO4:
-                       vga_wseq(regbase, CL_SEQR7, 0x25);
-/*                     vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
-                       break;
-
                case BT_ALPINE:
-                       DPRINTK(" (for GD543x)\n");
-                       vga_wseq(regbase, CL_SEQR7, 0xa9);
+                       /* Extended Sequencer Mode: 256c col. mode */
+                       vga_wseq(regbase, CL_SEQR7, 0xa5);
                        break;
 
                case BT_GD5480:
-                       DPRINTK(" (for GD5480)\n");
-                       vga_wseq(regbase, CL_SEQR7, 0x19);
+                       vga_wseq(regbase, CL_SEQR7, 0x15);
                        /* We already set SRF and SR1F */
                        break;
 
                case BT_LAGUNA:
-                       DPRINTK(" (for GD546x)\n");
+               case BT_LAGUNAB:
                        vga_wseq(regbase, CL_SEQR7,
                                vga_rseq(regbase, CL_SEQR7) & ~0x01);
+                       control |= 0x4000;
+                       format |= 0x2400;
+                       threshold |= 0x20;
                        break;
 
                default:
-                       printk(KERN_WARNING "cirrusfb: unknown Board\n");
+                       dev_warn(info->device, "unknown Board\n");
                        break;
                }
 
                /* mode register: 256 color mode */
                vga_wgfx(regbase, VGA_GFX_MODE, 64);
-               /* pixel mask: pass-through all planes */
-               WGen(cinfo, VGA_PEL_MSK, 0xff);
                /* hidden dac reg: 8-8-8 mode (24 or 32) */
                WHDR(cinfo, 0xc5);
-               /* memory mode: chain4, ext. memory */
-               vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
-               /* plane mask: enable writing to all 4 planes */
-               vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
-               offset = var->xres_virtual / 4;
        }
 
        /******************************************************
@@ -1284,67 +1200,55 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
         */
 
        else
-               printk(KERN_ERR "cirrusfb: What's this?? "
-                       " requested color depth == %d.\n",
+               dev_err(info->device,
+                       "What's this? requested color depth == %d.\n",
                        var->bits_per_pixel);
 
-       vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff);
+       pitch = info->fix.line_length >> 3;
+       vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff);
        tmp = 0x22;
-       if (offset & 0x100)
+       if (pitch & 0x100)
                tmp |= 0x10;    /* offset overflow bit */
 
        /* screen start addr #16-18, fastpagemode cycles */
        vga_wcrt(regbase, CL_CRT1B, tmp);
 
-       if (cinfo->btype == BT_SD64 ||
-           cinfo->btype == BT_PICASSO4 ||
-           cinfo->btype == BT_ALPINE ||
-           cinfo->btype == BT_GD5480)
-               /* screen start address bit 19 */
-               vga_wcrt(regbase, CL_CRT1D, 0x00);
-
-       /* text cursor location high */
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0);
-       /* text cursor location low */
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0);
-       /* underline row scanline = at very bottom */
-       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
-
-       /* controller mode */
-       vga_wattr(regbase, VGA_ATC_MODE, 1);
-       /* overscan (border) color */
-       vga_wattr(regbase, VGA_ATC_OVERSCAN, 0);
-       /* color plane enable */
-       vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15);
+       /* screen start address bit 19 */
+       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
+               vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1);
+
+       if (is_laguna(cinfo)) {
+               tmp = 0;
+               if ((htotal + 5) & 256)
+                       tmp |= 128;
+               if (hdispend & 256)
+                       tmp |= 64;
+               if (hsyncstart & 256)
+                       tmp |= 48;
+               if (vtotal & 1024)
+                       tmp |= 8;
+               if (vdispend & 1024)
+                       tmp |= 4;
+               if (vsyncstart & 1024)
+                       tmp |= 3;
+
+               vga_wcrt(regbase, CL_CRT1E, tmp);
+               dev_dbg(info->device, "CRT1e: %d\n", tmp);
+       }
+
        /* pixel panning */
        vga_wattr(regbase, CL_AR33, 0);
-       /* color select */
-       vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0);
 
        /* [ EGS: SetOffset(); ] */
        /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
        AttrOn(cinfo);
 
-       /* set/reset register */
-       vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0);
-       /* set/reset enable */
-       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0);
-       /* color compare */
-       vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0);
-       /* data rotate */
-       vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0);
-       /* read map select */
-       vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0);
-       /* miscellaneous register */
-       vga_wgfx(regbase, VGA_GFX_MISC, 1);
-       /* color don't care */
-       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15);
-       /* bit mask */
-       vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255);
-
-       /* graphics cursor attributes: nothing special */
-       vga_wseq(regbase, CL_SEQR12, 0x0);
-
+       if (is_laguna(cinfo)) {
+               /* no tiles */
+               fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
+               fb_writew(format, cinfo->laguna_mmio + 0xc0);
+               fb_writew(threshold, cinfo->laguna_mmio + 0xea);
+       }
        /* finally, turn on everything - turn off "FullBandwidth" bit */
        /* also, set "DotClock%2" bit where requested */
        tmp = 0x01;
@@ -1355,18 +1259,12 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 */
 
        vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
-       DPRINTK("CL_SEQR1: %d\n", tmp);
-
-       cinfo->currentmode = regs;
-
-       /* pan to requested offset */
-       cirrusfb_pan_display(var, info);
+       dev_dbg(info->device, "CL_SEQR1: %d\n", tmp);
 
 #ifdef CIRRUSFB_DEBUG
-       cirrusfb_dump();
+       cirrusfb_dbg_reg_dump(info, NULL);
 #endif
 
-       DPRINTK("EXIT\n");
        return 0;
 }
 
@@ -1418,27 +1316,19 @@ static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
                                struct fb_info *info)
 {
-       int xoffset = 0;
-       int yoffset = 0;
+       int xoffset;
        unsigned long base;
-       unsigned char tmp = 0, tmp2 = 0, xpix;
+       unsigned char tmp, xpix;
        struct cirrusfb_info *cinfo = info->par;
 
-       DPRINTK("ENTER\n");
-       DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
-
        /* no range checks for xoffset and yoffset,   */
        /* as fb_pan_display has already done this */
        if (var->vmode & FB_VMODE_YWRAP)
                return -EINVAL;
 
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-
        xoffset = var->xoffset * info->var.bits_per_pixel / 8;
-       yoffset = var->yoffset;
 
-       base = yoffset * info->fix.line_length + xoffset;
+       base = var->yoffset * info->fix.line_length + xoffset;
 
        if (info->var.bits_per_pixel == 1) {
                /* base is already correct */
@@ -1448,14 +1338,15 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
                xpix = (unsigned char) ((xoffset % 4) * 2);
        }
 
-       cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
+       if (!is_laguna(cinfo))
+               cirrusfb_WaitBLT(cinfo->regbase);
 
        /* lower 8 + 8 bits of screen start address */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO,
-                (unsigned char) (base & 0xff));
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI,
-                (unsigned char) (base >> 8));
+       vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff);
+       vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff);
 
+       /* 0xf2 is %11110010, exclude tmp bits */
+       tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2;
        /* construct bits 16, 17 and 18 of screen start address */
        if (base & 0x10000)
                tmp |= 0x01;
@@ -1464,13 +1355,17 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
        if (base & 0x40000)
                tmp |= 0x08;
 
-       /* 0xf2 is %11110010, exclude tmp bits */
-       tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp;
-       vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2);
+       vga_wcrt(cinfo->regbase, CL_CRT1B, tmp);
 
        /* construct bit 19 of screen start address */
-       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
-               vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80);
+       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
+               tmp = vga_rcrt(cinfo->regbase, CL_CRT1D);
+               if (is_laguna(cinfo))
+                       tmp = (tmp & ~0x18) | ((base >> 16) & 0x18);
+               else
+                       tmp = (tmp & ~0x80) | ((base >> 12) & 0x80);
+               vga_wcrt(cinfo->regbase, CL_CRT1D, tmp);
+       }
 
        /* write pixel panning value to AR33; this does not quite work in 8bpp
         *
@@ -1479,9 +1374,6 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
        if (info->var.bits_per_pixel == 1)
                vga_wattr(cinfo->regbase, CL_AR33, xpix);
 
-       cirrusfb_WaitBLT(cinfo->regbase);
-
-       DPRINTK("EXIT\n");
        return 0;
 }
 
@@ -1502,57 +1394,54 @@ static int cirrusfb_blank(int blank_mode, struct fb_info *info)
        struct cirrusfb_info *cinfo = info->par;
        int current_mode = cinfo->blank_mode;
 
-       DPRINTK("ENTER, blank mode = %d\n", blank_mode);
+       dev_dbg(info->device, "ENTER, blank mode = %d\n", blank_mode);
 
        if (info->state != FBINFO_STATE_RUNNING ||
            current_mode == blank_mode) {
-               DPRINTK("EXIT, returning 0\n");
+               dev_dbg(info->device, "EXIT, returning 0\n");
                return 0;
        }
 
        /* Undo current */
        if (current_mode == FB_BLANK_NORMAL ||
-           current_mode == FB_BLANK_UNBLANK) {
-               /* unblank the screen */
-               val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+           current_mode == FB_BLANK_UNBLANK)
                /* clear "FullBandwidth" bit */
-               vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf);
-               /* and undo VESA suspend trickery */
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x00);
-       }
-
-       /* set new */
-       if (blank_mode > FB_BLANK_NORMAL) {
-               /* blank the screen */
-               val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+               val = 0;
+       else
                /* set "FullBandwidth" bit */
-               vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20);
-       }
+               val = 0x20;
+
+       val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf;
+       vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val);
 
        switch (blank_mode) {
        case FB_BLANK_UNBLANK:
        case FB_BLANK_NORMAL:
+               val = 0x00;
                break;
        case FB_BLANK_VSYNC_SUSPEND:
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x04);
+               val = 0x04;
                break;
        case FB_BLANK_HSYNC_SUSPEND:
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x02);
+               val = 0x02;
                break;
        case FB_BLANK_POWERDOWN:
-               vga_wgfx(cinfo->regbase, CL_GRE, 0x06);
+               val = 0x06;
                break;
        default:
-               DPRINTK("EXIT, returning 1\n");
+               dev_dbg(info->device, "EXIT, returning 1\n");
                return 1;
        }
 
+       vga_wgfx(cinfo->regbase, CL_GRE, val);
+
        cinfo->blank_mode = blank_mode;
-       DPRINTK("EXIT, returning 0\n");
+       dev_dbg(info->device, "EXIT, returning 0\n");
 
        /* Let fbcon do a soft blank for us */
        return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
 }
+
 /**** END   Hardware specific Routines **************************************/
 /****************************************************************************/
 /**** BEGIN Internal Routines ***********************************************/
@@ -1562,8 +1451,6 @@ static void init_vgachip(struct fb_info *info)
        struct cirrusfb_info *cinfo = info->par;
        const struct cirrusfb_board_info_rec *bi;
 
-       DPRINTK("ENTER\n");
-
        assert(cinfo != NULL);
 
        bi = &cirrusfb_board_info[cinfo->btype];
@@ -1591,25 +1478,23 @@ static void init_vgachip(struct fb_info *info)
                /* disable flickerfixer */
                vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
                mdelay(100);
-               /* from Klaus' NetBSD driver: */
-               vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
-               /* put blitter into 542x compat */
-               vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
                /* mode */
                vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
-               break;
-
-       case BT_GD5480:
+       case BT_GD5480:  /* fall through */
                /* from Klaus' NetBSD driver: */
                vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
+       case BT_ALPINE:  /* fall through */
+               /* put blitter into 542x compat */
+               vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
                break;
 
-       case BT_ALPINE:
+       case BT_LAGUNA:
+       case BT_LAGUNAB:
                /* Nothing to do to reset the board. */
                break;
 
        default:
-               printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n");
+               dev_err(info->device, "Warning: Unknown board type\n");
                break;
        }
 
@@ -1629,31 +1514,28 @@ static void init_vgachip(struct fb_info *info)
                        WGen(cinfo, CL_VSSM2, 0x01);
 
                /* reset sequencer logic */
-               vga_wseq(cinfo->regbase, CL_SEQR0, 0x03);
+               vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03);
 
                /* FullBandwidth (video off) and 8/9 dot clock */
                vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
-               /* polarity (-/-), disable access to display memory,
-                * VGA_CRTC_START_HI base address: color
-                */
-               WGen(cinfo, VGA_MIS_W, 0xc1);
 
                /* "magic cookie" - doesn't make any sense to me.. */
 /*      vga_wgfx(cinfo->regbase, CL_GRA, 0xce);   */
                /* unlock all extension registers */
                vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
 
-               /* reset blitter */
-               vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
-
                switch (cinfo->btype) {
                case BT_GD5480:
                        vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
                        break;
                case BT_ALPINE:
+               case BT_LAGUNA:
+               case BT_LAGUNAB:
                        break;
                case BT_SD64:
+#ifdef CONFIG_ZORRO
                        vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
+#endif
                        break;
                default:
                        vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
@@ -1665,8 +1547,8 @@ static void init_vgachip(struct fb_info *info)
        vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
        /* character map select: doesn't even matter in gx mode */
        vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
-       /* memory mode: chain-4, no odd/even, ext. memory */
-       vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e);
+       /* memory mode: chain4, ext. memory */
+       vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
 
        /* controller-internal base address of video memory */
        if (bi->init_sr07)
@@ -1692,20 +1574,12 @@ static void init_vgachip(struct fb_info *info)
                vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
        }
 
-       /* MCLK select etc. */
-       if (bi->init_sr1f)
-               vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f);
-
        /* Screen A preset row scan: none */
        vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
        /* Text cursor start: disable text cursor */
        vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
        /* Text cursor end: - */
        vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
-       /* Screen start address high: 0 */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00);
-       /* Screen start address low: 0 */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00);
        /* text cursor location high: 0 */
        vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
        /* text cursor location low: 0 */
@@ -1713,10 +1587,6 @@ static void init_vgachip(struct fb_info *info)
 
        /* Underline Row scanline: - */
        vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
-       /* mode control: timing enable, byte mode, no compat modes */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3);
-       /* Line Compare: not needed */
-       vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00);
        /* ### add 0x40 for text modes with > 30 MHz pixclock */
        /* ext. display controls: ext.adr. wrap */
        vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
@@ -1739,7 +1609,9 @@ static void init_vgachip(struct fb_info *info)
        vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
        /* Bit Mask: no mask at all */
        vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
-       if (cinfo->btype == BT_ALPINE)
+
+       if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 ||
+           is_laguna(cinfo))
                /* (5434 can't have bit 3 set for bitblt) */
                vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
        else
@@ -1779,18 +1651,11 @@ static void init_vgachip(struct fb_info *info)
        vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
        /* Color Plane enable: Enable all 4 planes */
        vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
-/* ###  vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
        /* Color Select: - */
        vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
 
        WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
 
-       if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
-       /* polarity (-/-), enable display mem,
-        * VGA_CRTC_START_HI i/o base = color
-        */
-               WGen(cinfo, VGA_MIS_W, 0xc3);
-
        /* BLT Start/status: Blitter reset */
        vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
        /* - " -           : "end-of-reset" */
@@ -1798,8 +1663,6 @@ static void init_vgachip(struct fb_info *info)
 
        /* misc... */
        WHDR(cinfo, 0); /* Hidden DAC register: - */
-
-       DPRINTK("EXIT\n");
        return;
 }
 
@@ -1808,8 +1671,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
 #ifdef CONFIG_ZORRO /* only works on Zorro boards */
        static int IsOn = 0;    /* XXX not ok for multiple boards */
 
-       DPRINTK("ENTER\n");
-
        if (cinfo->btype == BT_PICASSO4)
                return;         /* nothing to switch */
        if (cinfo->btype == BT_ALPINE)
@@ -1819,8 +1680,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
        if (cinfo->btype == BT_PICASSO) {
                if ((on && !IsOn) || (!on && IsOn))
                        WSFR(cinfo, 0xff);
-
-               DPRINTK("EXIT\n");
                return;
        }
        if (on) {
@@ -1847,11 +1706,10 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
                case BT_SPECTRUM:
                        WSFR(cinfo, 0x4f);
                        break;
-               default: /* do nothing */ break;
+               default: /* do nothing */
+                       break;
                }
        }
-
-       DPRINTK("EXIT\n");
 #endif /* CONFIG_ZORRO */
 }
 
@@ -1859,6 +1717,17 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
 /* Linux 2.6-style  accelerated functions */
 /******************************************/
 
+static int cirrusfb_sync(struct fb_info *info)
+{
+       struct cirrusfb_info *cinfo = info->par;
+
+       if (!is_laguna(cinfo)) {
+               while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03)
+                       cpu_relax();
+       }
+       return 0;
+}
+
 static void cirrusfb_fillrect(struct fb_info *info,
                              const struct fb_fillrect *region)
 {
@@ -1894,8 +1763,8 @@ static void cirrusfb_fillrect(struct fb_info *info,
                          info->var.bits_per_pixel,
                          (region->dx * m) / 8, region->dy,
                          (region->width * m) / 8, region->height,
-                         color,
-                         info->fix.line_length);
+                         color, color,
+                         info->fix.line_length, 0x40);
 }
 
 static void cirrusfb_copyarea(struct fb_info *info,
@@ -1943,9 +1812,46 @@ static void cirrusfb_imageblit(struct fb_info *info,
                               const struct fb_image *image)
 {
        struct cirrusfb_info *cinfo = info->par;
+       unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4;
 
-       cirrusfb_WaitBLT(cinfo->regbase);
-       cfb_imageblit(info, image);
+       if (info->state != FBINFO_STATE_RUNNING)
+               return;
+       /* Alpine/SD64 does not work at 24bpp ??? */
+       if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
+               cfb_imageblit(info, image);
+       else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) &&
+                 op == 0xc)
+               cfb_imageblit(info, image);
+       else {
+               unsigned size = ((image->width + 7) >> 3) * image->height;
+               int m = info->var.bits_per_pixel;
+               u32 fg, bg;
+
+               if (info->var.bits_per_pixel == 8) {
+                       fg = image->fg_color;
+                       bg = image->bg_color;
+               } else {
+                       fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
+                       bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
+               }
+               if (info->var.bits_per_pixel == 24) {
+                       /* clear background first */
+                       cirrusfb_RectFill(cinfo->regbase,
+                                         info->var.bits_per_pixel,
+                                         (image->dx * m) / 8, image->dy,
+                                         (image->width * m) / 8,
+                                         image->height,
+                                         bg, bg,
+                                         info->fix.line_length, 0x40);
+               }
+               cirrusfb_RectFill(cinfo->regbase,
+                                 info->var.bits_per_pixel,
+                                 (image->dx * m) / 8, image->dy,
+                                 (image->width * m) / 8, image->height,
+                                 fg, bg,
+                                 info->fix.line_length, op);
+               memcpy(info->screen_base, image->data, size);
+       }
 }
 
 #ifdef CONFIG_PPC_PREP
@@ -1953,12 +1859,8 @@ static void cirrusfb_imageblit(struct fb_info *info,
 #define PREP_IO_BASE    ((volatile unsigned char *) 0x80000000)
 static void get_prep_addrs(unsigned long *display, unsigned long *registers)
 {
-       DPRINTK("ENTER\n");
-
        *display = PREP_VIDEO_BASE;
        *registers = (unsigned long) PREP_IO_BASE;
-
-       DPRINTK("EXIT\n");
 }
 
 #endif                         /* CONFIG_PPC_PREP */
@@ -1970,40 +1872,43 @@ static int release_io_ports;
  * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
  * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
  * seem to have. */
-static unsigned int __devinit cirrusfb_get_memsize(u8 __iomem *regbase)
+static unsigned int __devinit cirrusfb_get_memsize(struct fb_info *info,
+                                                  u8 __iomem *regbase)
 {
        unsigned long mem;
-       unsigned char SRF;
+       struct cirrusfb_info *cinfo = info->par;
 
-       DPRINTK("ENTER\n");
+       if (is_laguna(cinfo)) {
+               unsigned char SR14 = vga_rseq(regbase, CL_SEQR14);
 
-       SRF = vga_rseq(regbase, CL_SEQRF);
-       switch ((SRF & 0x18)) {
-       case 0x08:
-               mem = 512 * 1024;
-               break;
-       case 0x10:
-               mem = 1024 * 1024;
-               break;
-       /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
-        * on the 5430.
-        */
-       case 0x18:
-               mem = 2048 * 1024;
-               break;
-       default:
-               printk(KERN_WARNING "CLgenfb: Unknown memory size!\n");
-               mem = 1024 * 1024;
+               mem = ((SR14 & 7) + 1) << 20;
+       } else {
+               unsigned char SRF = vga_rseq(regbase, CL_SEQRF);
+               switch ((SRF & 0x18)) {
+               case 0x08:
+                       mem = 512 * 1024;
+                       break;
+               case 0x10:
+                       mem = 1024 * 1024;
+                       break;
+               /* 64-bit DRAM data bus width; assume 2MB.
+                * Also indicates 2MB memory on the 5430.
+                */
+               case 0x18:
+                       mem = 2048 * 1024;
+                       break;
+               default:
+                       dev_warn(info->device, "Unknown memory size!\n");
+                       mem = 1024 * 1024;
+               }
+               /* If DRAM bank switching is enabled, there must be
+                * twice as much memory installed. (4MB on the 5434)
+                */
+               if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0)
+                       mem *= 2;
        }
-       if (SRF & 0x80)
-       /* If DRAM bank switching is enabled, there must be twice as much
-        * memory installed. (4MB on the 5434)
-        */
-               mem *= 2;
 
        /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
-
-       DPRINTK("EXIT\n");
        return mem;
 }
 
@@ -2014,8 +1919,6 @@ static void get_pci_addrs(const struct pci_dev *pdev,
        assert(display != NULL);
        assert(registers != NULL);
 
-       DPRINTK("ENTER\n");
-
        *display = 0;
        *registers = 0;
 
@@ -2030,14 +1933,15 @@ static void get_pci_addrs(const struct pci_dev *pdev,
        }
 
        assert(*display != 0);
-
-       DPRINTK("EXIT\n");
 }
 
 static void cirrusfb_pci_unmap(struct fb_info *info)
 {
        struct pci_dev *pdev = to_pci_dev(info->device);
+       struct cirrusfb_info *cinfo = info->par;
 
+       if (cinfo->laguna_mmio == NULL)
+               iounmap(cinfo->laguna_mmio);
        iounmap(info->screen_base);
 #if 0 /* if system didn't claim this region, we would... */
        release_mem_region(0xA0000, 65535);
@@ -2067,6 +1971,22 @@ static void cirrusfb_zorro_unmap(struct fb_info *info)
 }
 #endif /* CONFIG_ZORRO */
 
+/* function table of the above functions */
+static struct fb_ops cirrusfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open        = cirrusfb_open,
+       .fb_release     = cirrusfb_release,
+       .fb_setcolreg   = cirrusfb_setcolreg,
+       .fb_check_var   = cirrusfb_check_var,
+       .fb_set_par     = cirrusfb_set_par,
+       .fb_pan_display = cirrusfb_pan_display,
+       .fb_blank       = cirrusfb_blank,
+       .fb_fillrect    = cirrusfb_fillrect,
+       .fb_copyarea    = cirrusfb_copyarea,
+       .fb_sync        = cirrusfb_sync,
+       .fb_imageblit   = cirrusfb_imageblit,
+};
+
 static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
@@ -2077,10 +1997,16 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
                    | FBINFO_HWACCEL_XPAN
                    | FBINFO_HWACCEL_YPAN
                    | FBINFO_HWACCEL_FILLRECT
+                   | FBINFO_HWACCEL_IMAGEBLIT
                    | FBINFO_HWACCEL_COPYAREA;
-       if (noaccel)
+       if (noaccel || is_laguna(cinfo)) {
                info->flags |= FBINFO_HWACCEL_DISABLED;
+               info->fix.accel = FB_ACCEL_NONE;
+       } else
+               info->fix.accel = FB_ACCEL_CIRRUS_ALPINE;
+
        info->fbops = &cirrusfb_ops;
+
        if (cinfo->btype == BT_GD5480) {
                if (var->bits_per_pixel == 16)
                        info->screen_base += 1 * MB_;
@@ -2104,7 +2030,6 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
 
        /* FIXME: map region at 0xB8000 if available, fill in here */
        info->fix.mmio_len   = 0;
-       info->fix.accel = FB_ACCEL_NONE;
 
        fb_alloc_cmap(&info->cmap, 256, 0);
 
@@ -2115,70 +2040,56 @@ static int __devinit cirrusfb_register(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        int err;
-       enum cirrus_board btype;
-
-       DPRINTK("ENTER\n");
-
-       printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based "
-               "graphic boards, v" CIRRUSFB_VERSION "\n");
-
-       btype = cinfo->btype;
 
        /* sanity checks */
-       assert(btype != BT_NONE);
+       assert(cinfo->btype != BT_NONE);
 
        /* set all the vital stuff */
        cirrusfb_set_fbinfo(info);
 
-       DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base);
+       dev_dbg(info->device, "(RAM start set to: 0x%p)\n", info->screen_base);
 
        err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
        if (!err) {
-               DPRINTK("wrong initial video mode\n");
+               dev_dbg(info->device, "wrong initial video mode\n");
                err = -EINVAL;
                goto err_dealloc_cmap;
        }
 
        info->var.activate = FB_ACTIVATE_NOW;
 
-       err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
+       err = cirrusfb_check_var(&info->var, info);
        if (err < 0) {
                /* should never happen */
-               DPRINTK("choking on default var... umm, no good.\n");
+               dev_dbg(info->device,
+                       "choking on default var... umm, no good.\n");
                goto err_dealloc_cmap;
        }
 
        err = register_framebuffer(info);
        if (err < 0) {
-               printk(KERN_ERR "cirrusfb: could not register "
-                       "fb device; err = %d!\n", err);
+               dev_err(info->device,
+                       "could not register fb device; err = %d!\n", err);
                goto err_dealloc_cmap;
        }
 
-       DPRINTK("EXIT, returning 0\n");
        return 0;
 
 err_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
-       cinfo->unmap(info);
-       framebuffer_release(info);
        return err;
 }
 
 static void __devexit cirrusfb_cleanup(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
-       DPRINTK("ENTER\n");
 
        switch_monitor(cinfo, 0);
-
        unregister_framebuffer(info);
        fb_dealloc_cmap(&info->cmap);
-       printk("Framebuffer unregistered\n");
+       dev_dbg(info->device, "Framebuffer unregistered\n");
        cinfo->unmap(info);
        framebuffer_release(info);
-
-       DPRINTK("EXIT\n");
 }
 
 #ifdef CONFIG_PCI
@@ -2187,7 +2098,6 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
 {
        struct cirrusfb_info *cinfo;
        struct fb_info *info;
-       enum cirrus_board btype;
        unsigned long board_addr, board_size;
        int ret;
 
@@ -2201,15 +2111,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
        if (!info) {
                printk(KERN_ERR "cirrusfb: could not allocate memory\n");
                ret = -ENOMEM;
-               goto err_disable;
+               goto err_out;
        }
 
        cinfo = info->par;
-       cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
+       cinfo->btype = (enum cirrus_board) ent->driver_data;
 
-       DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
-               pdev->resource[0].start, btype);
-       DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start);
+       dev_dbg(info->device,
+               " Found PCI device, base address 0 is 0x%Lx, btype set to %d\n",
+               (unsigned long long)pdev->resource[0].start,  cinfo->btype);
+       dev_dbg(info->device, " base address 1 is 0x%Lx\n",
+               (unsigned long long)pdev->resource[1].start);
 
        if (isPReP) {
                pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000);
@@ -2219,30 +2131,30 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
        /* PReP dies if we ioremap the IO registers, but it works w/out... */
                cinfo->regbase = (char __iomem *) info->fix.mmio_start;
        } else {
-               DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n");
+               dev_dbg(info->device,
+                       "Attempt to get PCI info for Cirrus Graphics Card\n");
                get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
                /* FIXME: this forces VGA.  alternatives? */
                cinfo->regbase = NULL;
+               cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000);
        }
 
-       DPRINTK("Board address: 0x%lx, register address: 0x%lx\n",
+       dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n",
                board_addr, info->fix.mmio_start);
 
-       board_size = (btype == BT_GD5480) ?
-               32 * MB_ : cirrusfb_get_memsize(cinfo->regbase);
+       board_size = (cinfo->btype == BT_GD5480) ?
+               32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase);
 
        ret = pci_request_regions(pdev, "cirrusfb");
        if (ret < 0) {
-               printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
-                      "abort\n",
-                      board_addr);
+               dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
+                       board_addr);
                goto err_release_fb;
        }
 #if 0 /* if the system didn't claim this region, we would... */
        if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
-               printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
-,
-                      0xA0000L);
+               dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
+                       0xA0000L);
                ret = -EBUSY;
                goto err_release_regions;
        }
@@ -2260,16 +2172,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
        info->screen_size = board_size;
        cinfo->unmap = cirrusfb_pci_unmap;
 
-       printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus "
-                       "Logic chipset on PCI bus\n",
-                       info->screen_size >> 10, board_addr);
+       dev_info(info->device,
+                "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx\n",
+                info->screen_size >> 10, board_addr);
        pci_set_drvdata(pdev, info);
 
        ret = cirrusfb_register(info);
-       if (ret)
-               iounmap(info->screen_base);
-       return ret;
+       if (!ret)
+               return 0;
 
+       pci_set_drvdata(pdev, NULL);
+       iounmap(info->screen_base);
 err_release_legacy:
        if (release_io_ports)
                release_region(0x3C0, 32);
@@ -2279,8 +2192,9 @@ err_release_regions:
 #endif
        pci_release_regions(pdev);
 err_release_fb:
+       if (cinfo->laguna_mmio != NULL)
+               iounmap(cinfo->laguna_mmio);
        framebuffer_release(info);
-err_disable:
 err_out:
        return ret;
 }
@@ -2288,11 +2202,8 @@ err_out:
 static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
-       DPRINTK("ENTER\n");
 
        cirrusfb_cleanup(info);
-
-       DPRINTK("EXIT\n");
 }
 
 static struct pci_driver cirrusfb_pci_driver = {
@@ -2324,8 +2235,6 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
        if (cirrusfb_zorro_table2[btype].id2)
                z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
        size = cirrusfb_zorro_table2[btype].size;
-       printk(KERN_INFO "cirrusfb: %s board detected; ",
-              cirrusfb_board_info[btype].name);
 
        info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
        if (!info) {
@@ -2334,6 +2243,9 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                goto err_out;
        }
 
+       dev_info(info->device, "%s board detected\n",
+                cirrusfb_board_info[btype].name);
+
        cinfo = info->par;
        cinfo->btype = btype;
 
@@ -2345,19 +2257,16 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
        info->screen_size = size;
 
        if (!zorro_request_device(z, "cirrusfb")) {
-               printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
-                      "abort\n",
-                      board_addr);
+               dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
+                       board_addr);
                ret = -EBUSY;
                goto err_release_fb;
        }
 
-       printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
-
        ret = -EIO;
 
        if (btype == BT_PICASSO4) {
-               printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000);
+               dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000);
 
                /* To be precise, for the P4 this is not the */
                /* begin of the board, but the begin of RAM. */
@@ -2367,7 +2276,7 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                if (!cinfo->regbase)
                        goto err_release_region;
 
-               DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
+               dev_dbg(info->device, "Virtual address for board set to: $%p\n",
                        cinfo->regbase);
                cinfo->regbase += 0x600000;
                info->fix.mmio_start = board_addr + 0x600000;
@@ -2377,8 +2286,8 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                if (!info->screen_base)
                        goto err_unmap_regbase;
        } else {
-               printk(KERN_INFO " REG at $%lx\n",
-                       (unsigned long) z2->resource.start);
+               dev_info(info->device, " REG at $%lx\n",
+                        (unsigned long) z2->resource.start);
 
                info->fix.smem_start = board_addr;
                if (board_addr > 0x01000000)
@@ -2392,27 +2301,32 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start);
                info->fix.mmio_start = z2->resource.start;
 
-               DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
+               dev_dbg(info->device, "Virtual address for board set to: $%p\n",
                        cinfo->regbase);
        }
        cinfo->unmap = cirrusfb_zorro_unmap;
 
-       printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
+       dev_info(info->device,
+                "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n",
+                board_size / MB_, board_addr);
+
        zorro_set_drvdata(z, info);
 
+       /* MCLK select etc. */
+       if (cirrusfb_board_info[btype].init_sr1f)
+               vga_wseq(cinfo->regbase, CL_SEQR1F,
+                        cirrusfb_board_info[btype].sr1f);
+
        ret = cirrusfb_register(info);
-       if (ret) {
-               if (btype == BT_PICASSO4) {
-                       iounmap(info->screen_base);
-                       iounmap(cinfo->regbase - 0x600000);
-               } else if (board_addr > 0x01000000)
-                       iounmap(info->screen_base);
-       }
-       return ret;
+       if (!ret)
+               return 0;
+
+       if (btype == BT_PICASSO4 || board_addr > 0x01000000)
+               iounmap(info->screen_base);
 
 err_unmap_regbase:
-       /* Parental advisory: explicit hack */
-       iounmap(cinfo->regbase - 0x600000);
+       if (btype == BT_PICASSO4)
+               iounmap(cinfo->regbase - 0x600000);
 err_release_region:
        release_region(board_addr, board_size);
 err_release_fb:
@@ -2424,11 +2338,8 @@ err_out:
 void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
 {
        struct fb_info *info = zorro_get_drvdata(z);
-       DPRINTK("ENTER\n");
 
        cirrusfb_cleanup(info);
-
-       DPRINTK("EXIT\n");
 }
 
 static struct zorro_driver cirrusfb_zorro_driver = {
@@ -2439,33 +2350,11 @@ static struct zorro_driver cirrusfb_zorro_driver = {
 };
 #endif /* CONFIG_ZORRO */
 
-static int __init cirrusfb_init(void)
-{
-       int error = 0;
-
-#ifndef MODULE
-       char *option = NULL;
-
-       if (fb_get_options("cirrusfb", &option))
-               return -ENODEV;
-       cirrusfb_setup(option);
-#endif
-
-#ifdef CONFIG_ZORRO
-       error |= zorro_register_driver(&cirrusfb_zorro_driver);
-#endif
-#ifdef CONFIG_PCI
-       error |= pci_register_driver(&cirrusfb_pci_driver);
-#endif
-       return error;
-}
-
 #ifndef MODULE
-static int __init cirrusfb_setup(char *options) {
+static int __init cirrusfb_setup(char *options)
+{
        char *this_opt;
 
-       DPRINTK("ENTER\n");
-
        if (!options || !*options)
                return 0;
 
@@ -2473,8 +2362,6 @@ static int __init cirrusfb_setup(char *options) {
                if (!*this_opt)
                        continue;
 
-               DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
-
                if (!strcmp(this_opt, "noaccel"))
                        noaccel = 1;
                else if (!strncmp(this_opt, "mode:", 5))
@@ -2494,6 +2381,27 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
 MODULE_LICENSE("GPL");
 
+static int __init cirrusfb_init(void)
+{
+       int error = 0;
+
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("cirrusfb", &option))
+               return -ENODEV;
+       cirrusfb_setup(option);
+#endif
+
+#ifdef CONFIG_ZORRO
+       error |= zorro_register_driver(&cirrusfb_zorro_driver);
+#endif
+#ifdef CONFIG_PCI
+       error |= pci_register_driver(&cirrusfb_pci_driver);
+#endif
+       return error;
+}
+
 static void __exit cirrusfb_exit(void)
 {
 #ifdef CONFIG_PCI
@@ -2560,8 +2468,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo)
 {
        assert(cinfo != NULL);
 
-       DPRINTK("ENTER\n");
-
        if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
                /* if we're just in "write value" mode, write back the */
                /* same value as before to not modify anything */
@@ -2574,8 +2480,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo)
 
        /* dummy write on Reg0 to be on "write index" mode next time */
        vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
-
-       DPRINTK("EXIT\n");
 }
 
 /*** WHDR() - write into the Hidden DAC register ***/
@@ -2588,6 +2492,8 @@ static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
 {
        unsigned char dummy;
 
+       if (is_laguna(cinfo))
+               return;
        if (cinfo->btype == BT_PICASSO) {
                /* Klaus' hint for correct access to HDR on some boards */
                /* first write 0 to pixel mask (3c6) */
@@ -2655,7 +2561,8 @@ static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch
        vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
 
        if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
-           cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
+           cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 ||
+           cinfo->btype == BT_SD64 || is_laguna(cinfo)) {
                /* but DAC data register IS, at least for Picasso II */
                if (cinfo->btype == BT_PICASSO)
                        data += 0xfff;
@@ -2702,9 +2609,8 @@ static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch
 /* FIXME: use interrupts instead */
 static void cirrusfb_WaitBLT(u8 __iomem *regbase)
 {
-       /* now busy-wait until we're done */
        while (vga_rgfx(regbase, CL_GR31) & 0x08)
-               /* do nothing */ ;
+               cpu_relax();
 }
 
 /*******************************************************************
@@ -2713,60 +2619,12 @@ static void cirrusfb_WaitBLT(u8 __iomem *regbase)
        perform accelerated "scrolling"
 ********************************************************************/
 
-static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
-                           u_short curx, u_short cury,
-                           u_short destx, u_short desty,
-                           u_short width, u_short height,
-                           u_short line_length)
-{
-       u_short nwidth, nheight;
-       u_long nsrc, ndest;
-       u_char bltmode;
-
-       DPRINTK("ENTER\n");
-
-       nwidth = width - 1;
-       nheight = height - 1;
-
-       bltmode = 0x00;
-       /* if source adr < dest addr, do the Blt backwards */
-       if (cury <= desty) {
-               if (cury == desty) {
-                       /* if src and dest are on the same line, check x */
-                       if (curx < destx)
-                               bltmode |= 0x01;
-               } else
-                       bltmode |= 0x01;
-       }
-       if (!bltmode) {
-               /* standard case: forward blitting */
-               nsrc = (cury * line_length) + curx;
-               ndest = (desty * line_length) + destx;
-       } else {
-               /* this means start addresses are at the end,
-                * counting backwards
-                */
-               nsrc = cury * line_length + curx +
-                       nheight * line_length + nwidth;
-               ndest = desty * line_length + destx +
-                       nheight * line_length + nwidth;
-       }
-
-       /*
-          run-down of registers to be programmed:
-          destination pitch
-          source pitch
-          BLT width/height
-          source start
-          destination start
-          BLT mode
-          BLT ROP
-          VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
-          start/stop
-        */
-
-       cirrusfb_WaitBLT(regbase);
+static void cirrusfb_set_blitter(u8 __iomem *regbase,
+                           u_short nwidth, u_short nheight,
+                           u_long nsrc, u_long ndest,
+                           u_short bltmode, u_short line_length)
 
+{
        /* pitch: set to line_length */
        /* dest pitch low */
        vga_wgfx(regbase, CL_GR24, line_length & 0xff);
@@ -2813,91 +2671,91 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
 
        /* and finally: GO! */
        vga_wgfx(regbase, CL_GR31, 0x02);       /* BLT Start/status */
-
-       DPRINTK("EXIT\n");
 }
 
 /*******************************************************************
-       cirrusfb_RectFill()
+       cirrusfb_BitBLT()
 
-       perform accelerated rectangle fill
+       perform accelerated "scrolling"
 ********************************************************************/
 
-static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
-                    u_short x, u_short y, u_short width, u_short height,
-                    u_char color, u_short line_length)
+static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
+                           u_short curx, u_short cury,
+                           u_short destx, u_short desty,
+                           u_short width, u_short height,
+                           u_short line_length)
 {
-       u_short nwidth, nheight;
-       u_long ndest;
-       u_char op;
-
-       DPRINTK("ENTER\n");
-
-       nwidth = width - 1;
-       nheight = height - 1;
+       u_short nwidth = width - 1;
+       u_short nheight = height - 1;
+       u_long nsrc, ndest;
+       u_char bltmode;
 
-       ndest = (y * line_length) + x;
+       bltmode = 0x00;
+       /* if source adr < dest addr, do the Blt backwards */
+       if (cury <= desty) {
+               if (cury == desty) {
+                       /* if src and dest are on the same line, check x */
+                       if (curx < destx)
+                               bltmode |= 0x01;
+               } else
+                       bltmode |= 0x01;
+       }
+       /* standard case: forward blitting */
+       nsrc = (cury * line_length) + curx;
+       ndest = (desty * line_length) + destx;
+       if (bltmode) {
+               /* this means start addresses are at the end,
+                * counting backwards
+                */
+               nsrc += nheight * line_length + nwidth;
+               ndest += nheight * line_length + nwidth;
+       }
 
        cirrusfb_WaitBLT(regbase);
 
-       /* pitch: set to line_length */
-       vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
-       vga_wgfx(regbase, CL_GR25, line_length >> 8);   /* dest pitch hi */
-       vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */
-       vga_wgfx(regbase, CL_GR27, line_length >> 8);   /* source pitch hi */
+       cirrusfb_set_blitter(regbase, nwidth, nheight,
+                           nsrc, ndest, bltmode, line_length);
+}
 
-       /* BLT width: actual number of pixels - 1 */
-       vga_wgfx(regbase, CL_GR20, nwidth & 0xff);      /* BLT width low */
-       vga_wgfx(regbase, CL_GR21, nwidth >> 8);        /* BLT width hi */
+/*******************************************************************
+       cirrusfb_RectFill()
 
-       /* BLT height: actual number of lines -1 */
-       vga_wgfx(regbase, CL_GR22, nheight & 0xff);     /* BLT height low */
-       vga_wgfx(regbase, CL_GR23, nheight >> 8);       /* BLT width hi */
+       perform accelerated rectangle fill
+********************************************************************/
 
-       /* BLT destination */
-       /* BLT dest low */
-       vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
-       /* BLT dest mid */
-       vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
-       /* BLT dest hi */
-       vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
+static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
+                    u_short x, u_short y, u_short width, u_short height,
+                    u32 fg_color, u32 bg_color, u_short line_length,
+                    u_char blitmode)
+{
+       u_long ndest = (y * line_length) + x;
+       u_char op;
 
-       /* BLT source: set to 0 (is a dummy here anyway) */
-       vga_wgfx(regbase, CL_GR2C, 0x00);       /* BLT src low */
-       vga_wgfx(regbase, CL_GR2D, 0x00);       /* BLT src mid */
-       vga_wgfx(regbase, CL_GR2E, 0x00);       /* BLT src hi */
+       cirrusfb_WaitBLT(regbase);
 
        /* This is a ColorExpand Blt, using the */
        /* same color for foreground and background */
-       vga_wgfx(regbase, VGA_GFX_SR_VALUE, color);     /* foreground color */
-       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color);    /* background color */
-
-       op = 0xc0;
-       if (bits_per_pixel == 16) {
-               vga_wgfx(regbase, CL_GR10, color);      /* foreground color */
-               vga_wgfx(regbase, CL_GR11, color);      /* background color */
-               op = 0x50;
-               op = 0xd0;
-       } else if (bits_per_pixel == 32) {
-               vga_wgfx(regbase, CL_GR10, color);      /* foreground color */
-               vga_wgfx(regbase, CL_GR11, color);      /* background color */
-               vga_wgfx(regbase, CL_GR12, color);      /* foreground color */
-               vga_wgfx(regbase, CL_GR13, color);      /* background color */
-               vga_wgfx(regbase, CL_GR14, 0);  /* foreground color */
-               vga_wgfx(regbase, CL_GR15, 0);  /* background color */
-               op = 0x50;
-               op = 0xf0;
-       }
-       /* BLT mode: color expand, Enable 8x8 copy (faster?) */
-       vga_wgfx(regbase, CL_GR30, op); /* BLT mode */
-
-       /* BLT ROP: SrcCopy */
-       vga_wgfx(regbase, CL_GR32, 0x0d);       /* BLT ROP */
-
-       /* and finally: GO! */
-       vga_wgfx(regbase, CL_GR31, 0x02);       /* BLT Start/status */
-
-       DPRINTK("EXIT\n");
+       vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color);
+       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color);
+
+       op = 0x80;
+       if (bits_per_pixel >= 16) {
+               vga_wgfx(regbase, CL_GR10, bg_color >> 8);
+               vga_wgfx(regbase, CL_GR11, fg_color >> 8);
+               op = 0x90;
+       }
+       if (bits_per_pixel >= 24) {
+               vga_wgfx(regbase, CL_GR12, bg_color >> 16);
+               vga_wgfx(regbase, CL_GR13, fg_color >> 16);
+               op = 0xa0;
+       }
+       if (bits_per_pixel == 32) {
+               vga_wgfx(regbase, CL_GR14, bg_color >> 24);
+               vga_wgfx(regbase, CL_GR15, fg_color >> 24);
+               op = 0xb0;
+       }
+       cirrusfb_set_blitter(regbase, width - 1, height - 1,
+                           0, ndest, op | blitmode, line_length);
 }
 
 /**************************************************************************
@@ -2917,8 +2775,6 @@ static void bestclock(long freq, int *nom, int *den, int *div)
        *den = 0;
        *div = 0;
 
-       DPRINTK("ENTER\n");
-
        if (freq < 8000)
                freq = 8000;
 
@@ -2960,12 +2816,6 @@ static void bestclock(long freq, int *nom, int *den, int *div)
                        }
                }
        }
-
-       DPRINTK("Best possible values for given frequency:\n");
-       DPRINTK("       freq: %ld kHz  nom: %d  den: %d  div: %d\n",
-               freq, *nom, *den, *div);
-
-       DPRINTK("EXIT\n");
 }
 
 /* -------------------------------------------------------------------------
@@ -2977,32 +2827,6 @@ static void bestclock(long freq, int *nom, int *den, int *div)
 
 #ifdef CIRRUSFB_DEBUG
 
-/**
- * cirrusfb_dbg_print_byte
- * @name: name associated with byte value to be displayed
- * @val: byte value to be displayed
- *
- * DESCRIPTION:
- * Display an indented string, along with a hexidecimal byte value, and
- * its decoded bits.  Bits 7 through 0 are listed in left-to-right
- * order.
- */
-
-static
-void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
-{
-       DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
-               name, val,
-               val & 0x80 ? '1' : '0',
-               val & 0x40 ? '1' : '0',
-               val & 0x20 ? '1' : '0',
-               val & 0x10 ? '1' : '0',
-               val & 0x08 ? '1' : '0',
-               val & 0x04 ? '1' : '0',
-               val & 0x02 ? '1' : '0',
-               val & 0x01 ? '1' : '0');
-}
-
 /**
  * cirrusfb_dbg_print_regs
  * @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3014,9 +2838,9 @@ void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
  * used at the given @base address to query the information.
  */
 
-static
-void cirrusfb_dbg_print_regs(caddr_t regbase,
-                            enum cirrusfb_dbg_reg_class reg_class, ...)
+static void cirrusfb_dbg_print_regs(struct fb_info *info,
+                                   caddr_t regbase,
+                                   enum cirrusfb_dbg_reg_class reg_class, ...)
 {
        va_list list;
        unsigned char val = 0;
@@ -3042,7 +2866,7 @@ void cirrusfb_dbg_print_regs(caddr_t regbase,
                        break;
                }
 
-               cirrusfb_dbg_print_byte(name, val);
+               dev_dbg(info->device, "%8s = 0x%02X\n", name, val);
 
                name = va_arg(list, char *);
        }
@@ -3050,18 +2874,6 @@ void cirrusfb_dbg_print_regs(caddr_t regbase,
        va_end(list);
 }
 
-/**
- * cirrusfb_dump
- * @cirrusfbinfo:
- *
- * DESCRIPTION:
- */
-
-static void cirrusfb_dump(void)
-{
-       cirrusfb_dbg_reg_dump(NULL);
-}
-
 /**
  * cirrusfb_dbg_reg_dump
  * @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3072,12 +2884,11 @@ static void cirrusfb_dump(void)
  * used at the given @base address to query the information.
  */
 
-static
-void cirrusfb_dbg_reg_dump(caddr_t regbase)
+static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase)
 {
-       DPRINTK("CIRRUSFB VGA CRTC register dump:\n");
+       dev_dbg(info->device, "VGA CRTC register dump:\n");
 
-       cirrusfb_dbg_print_regs(regbase, CRT,
+       cirrusfb_dbg_print_regs(info, regbase, CRT,
                           "CR00", 0x00,
                           "CR01", 0x01,
                           "CR02", 0x02,
@@ -3127,11 +2938,11 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase)
                           "CR3F", 0x3F,
                           NULL);
 
-       DPRINTK("\n");
+       dev_dbg(info->device, "\n");
 
-       DPRINTK("CIRRUSFB VGA SEQ register dump:\n");
+       dev_dbg(info->device, "VGA SEQ register dump:\n");
 
-       cirrusfb_dbg_print_regs(regbase, SEQ,
+       cirrusfb_dbg_print_regs(info, regbase, SEQ,
                           "SR00", 0x00,
                           "SR01", 0x01,
                           "SR02", 0x02,
@@ -3160,7 +2971,7 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase)
                           "SR1F", 0x1F,
                           NULL);
 
-       DPRINTK("\n");
+       dev_dbg(info->device, "\n");
 }
 
 #endif                         /* CIRRUSFB_DEBUG */
index 1657b9608b040d6b1a1dd0927a6e9cf6ba768f55..2cd500a304f234456c083baf920255a657c650f9 100644 (file)
@@ -2954,8 +2954,11 @@ static int fbcon_fb_unbind(int idx)
 
 static int fbcon_fb_unregistered(struct fb_info *info)
 {
-       int i, idx = info->node;
+       int i, idx;
 
+       if (!lock_fb_info(info))
+               return -ENODEV;
+       idx = info->node;
        for (i = first_fb_vc; i <= last_fb_vc; i++) {
                if (con2fb_map[i] == idx)
                        con2fb_map[i] = -1;
@@ -2979,13 +2982,14 @@ static int fbcon_fb_unregistered(struct fb_info *info)
                }
        }
 
-       if (!num_registered_fb)
-               unregister_con_driver(&fb_con);
-
-
        if (primary_device == idx)
                primary_device = -1;
 
+       unlock_fb_info(info);
+
+       if (!num_registered_fb)
+               unregister_con_driver(&fb_con);
+
        return 0;
 }
 
@@ -3021,9 +3025,13 @@ static inline void fbcon_select_primary(struct fb_info *info)
 
 static int fbcon_fb_registered(struct fb_info *info)
 {
-       int ret = 0, i, idx = info->node;
+       int ret = 0, i, idx;
 
+       if (!lock_fb_info(info))
+               return -ENODEV;
+       idx = info->node;
        fbcon_select_primary(info);
+       unlock_fb_info(info);
 
        if (info_idx == -1) {
                for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -3124,7 +3132,7 @@ static void fbcon_get_requirement(struct fb_info *info,
        }
 }
 
-static int fbcon_event_notify(struct notifier_block *self, 
+static int fbcon_event_notify(struct notifier_block *self,
                              unsigned long action, void *data)
 {
        struct fb_event *event = data;
@@ -3132,7 +3140,7 @@ static int fbcon_event_notify(struct notifier_block *self,
        struct fb_videomode *mode;
        struct fb_con2fbmap *con2fb;
        struct fb_blit_caps *caps;
-       int ret = 0;
+       int idx, ret = 0;
 
        /*
         * ignore all events except driver registration and deregistration
@@ -3144,23 +3152,54 @@ static int fbcon_event_notify(struct notifier_block *self,
 
        switch(action) {
        case FB_EVENT_SUSPEND:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_suspended(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_RESUME:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_resumed(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_MODE_CHANGE:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_modechanged(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_MODE_CHANGE_ALL:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_set_all_vcs(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_MODE_DELETE:
                mode = event->data;
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                ret = fbcon_mode_deleted(info, mode);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_FB_UNBIND:
-               ret = fbcon_fb_unbind(info->node);
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
+               idx = info->node;
+               unlock_fb_info(info);
+               ret = fbcon_fb_unbind(idx);
                break;
        case FB_EVENT_FB_REGISTERED:
                ret = fbcon_fb_registered(info);
@@ -3178,17 +3217,31 @@ static int fbcon_event_notify(struct notifier_block *self,
                con2fb->framebuffer = con2fb_map[con2fb->console - 1];
                break;
        case FB_EVENT_BLANK:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_fb_blanked(info, *(int *)event->data);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_NEW_MODELIST:
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_new_modelist(info);
+               unlock_fb_info(info);
                break;
        case FB_EVENT_GET_REQ:
                caps = event->data;
+               if (!lock_fb_info(info)) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                fbcon_get_requirement(info, caps);
+               unlock_fb_info(info);
                break;
        }
-
 done:
        return ret;
 }
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
deleted file mode 100644 (file)
index 9704b73..0000000
+++ /dev/null
@@ -1,1683 +0,0 @@
-/*
- * Frame buffer driver for Trident Cyberblade/i1 graphics core
- *
- * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de>
- *
- * CREDITS:
- *     tridentfb.c by Jani Monoses
- *     see files above for further credits
- *
- */
-
-#define CYBLAFB_DEBUG 0
-#define CYBLAFB_KD_GRAPHICS_QUIRK 1
-
-#define CYBLAFB_PIXMAPSIZE 8192
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <asm/types.h>
-#include <video/cyblafb.h>
-
-#define VERSION "0.62"
-
-struct cyblafb_par {
-       u32 pseudo_pal[16];
-       struct fb_ops ops;
-};
-
-static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
-       .id = "CyBla",
-       .type = FB_TYPE_PACKED_PIXELS,
-       .xpanstep = 1,
-       .ypanstep = 1,
-       .ywrapstep = 1,
-       .visual = FB_VISUAL_PSEUDOCOLOR,
-       .accel = FB_ACCEL_NONE,
-};
-
-static char *mode __devinitdata = NULL;
-static int bpp __devinitdata = 8;
-static int ref __devinitdata = 75;
-static int fp __devinitdata;
-static int crt __devinitdata;
-static int memsize __devinitdata;
-
-static int basestride;
-static int vesafb;
-static int nativex;
-static int center;
-static int stretch;
-static int pciwb = 1;
-static int pcirb = 1;
-static int pciwr = 1;
-static int pcirr = 1;
-static int disabled;
-static int verbosity;
-static int displaytype;
-
-static void __iomem *io_virt;  // iospace virtual memory address
-
-module_param(mode, charp, 0);
-module_param(bpp, int, 0);
-module_param(ref, int, 0);
-module_param(fp, int, 0);
-module_param(crt, int, 0);
-module_param(nativex, int, 0);
-module_param(center, int, 0);
-module_param(stretch, int, 0);
-module_param(pciwb, int, 0);
-module_param(pcirb, int, 0);
-module_param(pciwr, int, 0);
-module_param(pcirr, int, 0);
-module_param(memsize, int, 0);
-module_param(verbosity, int, 0);
-
-//=========================================
-//
-// Well, we have to fix the upper layers.
-// Until this has been done, we work around
-// the bugs.
-//
-//=========================================
-
-#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
-       if (disabled) { \
-               printk("********\n");\
-               dump_stack();\
-               return val;\
-       }
-
-#elif CYBLAFB_KD_GRAPHICS_QUIRK
-#define KD_GRAPHICS_RETURN(val)\
-       if (disabled) {\
-               return val;\
-       }
-#else
-#define KD_GRAPHICS_RETURN(val)
-#endif
-
-//=========================================
-//
-// Port access macros for memory mapped io
-//
-//=========================================
-
-#define out8(r, v) writeb(v, io_virt + r)
-#define out32(r, v) writel(v, io_virt + r)
-#define in8(r) readb(io_virt + r)
-#define in32(r) readl(io_virt + r)
-
-//======================================
-//
-// Hardware access inline functions
-//
-//======================================
-
-static inline u8 read3X4(u32 reg)
-{
-       out8(0x3D4, reg);
-       return in8(0x3D5);
-}
-
-static inline u8 read3C4(u32 reg)
-{
-       out8(0x3C4, reg);
-       return in8(0x3C5);
-}
-
-static inline u8 read3CE(u32 reg)
-{
-       out8(0x3CE, reg);
-       return in8(0x3CF);
-}
-
-static inline void write3X4(u32 reg, u8 val)
-{
-       out8(0x3D4, reg);
-       out8(0x3D5, val);
-}
-
-static inline void write3C4(u32 reg, u8 val)
-{
-       out8(0x3C4, reg);
-       out8(0x3C5, val);
-}
-
-static inline void write3CE(u32 reg, u8 val)
-{
-       out8(0x3CE, reg);
-       out8(0x3CF, val);
-}
-
-static inline void write3C0(u32 reg, u8 val)
-{
-       in8(0x3DA);             // read to reset index
-       out8(0x3C0, reg);
-       out8(0x3C0, val);
-}
-
-//=================================================
-//
-// Enable memory mapped io and unprotect registers
-//
-//=================================================
-
-static void enable_mmio(void)
-{
-       u8 tmp;
-
-       outb(0x0B, 0x3C4);
-       inb(0x3C5);             // Set NEW mode
-       outb(SR0E, 0x3C4);      // write enable a lot of extended ports
-       outb(0x80, 0x3C5);
-
-       outb(SR11, 0x3C4);      // write enable those extended ports that
-       outb(0x87, 0x3C5);      // are not affected by SR0E_New
-
-       outb(CR1E, 0x3d4);      // clear write protect bit for port 0x3c2
-       tmp = inb(0x3d5) & 0xBF;
-       outb(CR1E, 0x3d4);
-       outb(tmp, 0x3d5);
-
-       outb(CR39, 0x3D4);
-       outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
-}
-
-//=================================================
-//
-// Set pixel clock VCLK1
-// - multipliers set elswhere
-// - freq in units of 0.01 MHz
-//
-// Hardware bug: SR18 >= 250 is broken for the
-//              cyberblade/i1
-//
-//=================================================
-
-static void set_vclk(struct cyblafb_par *par, int freq)
-{
-       u32 m, n, k;
-       int f, fi, d, di;
-       u8 lo = 0, hi = 0;
-
-       d = 2000;
-       k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
-       for (m = 0; m < 64; m++)
-               for (n = 0; n < 250; n++) {
-                       fi = (int)(((5864727 * (n + 8)) /
-                                   ((m + 2) * (1 << k))) >> 12);
-                       if ((di = abs(fi - freq)) < d) {
-                               d = di;
-                               f = fi;
-                               lo = (u8) n;
-                               hi = (u8) ((k << 6) | m);
-                       }
-               }
-       write3C4(SR19, hi);
-       write3C4(SR18, lo);
-       if (verbosity > 0)
-               output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
-                      freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
-}
-
-//================================================
-//
-// Cyberblade specific Graphics Engine (GE) setup
-//
-//================================================
-
-static void cyblafb_setup_GE(int pitch, int bpp)
-{
-       KD_GRAPHICS_RETURN();
-
-       switch (bpp) {
-       case 8:
-               basestride = ((pitch >> 3) << 20) | (0 << 29);
-               break;
-       case 15:
-               basestride = ((pitch >> 3) << 20) | (5 << 29);
-               break;
-       case 16:
-               basestride = ((pitch >> 3) << 20) | (1 << 29);
-               break;
-       case 24:
-       case 32:
-               basestride = ((pitch >> 3) << 20) | (2 << 29);
-               break;
-       }
-
-       write3X4(CR36, 0x90);   // reset GE
-       write3X4(CR36, 0x80);   // enable GE
-       out32(GE24, 1 << 7);    // reset all GE pointers by toggling
-       out32(GE24, 0);         //   d7 of GE24
-       write3X4(CR2D, 0x00);   // GE Timinigs, no delays
-       out32(GE6C, 0);         // Pattern and Style, p 129, ok
-}
-
-//=====================================================================
-//
-// Cyberblade specific syncing
-//
-//   A timeout might be caused by disabled mmio.
-//   Cause:
-//     - bit CR39 & 1 == 0 upon return, X trident driver bug
-//     - kdm bug (KD_GRAPHICS not set on first switch)
-//     - kernel design flaw (it believes in the correctness
-//      of kdm/X
-//   First we try to sync ignoring that problem, as most of the
-//   time that will succeed immediately and the enable_mmio()
-//   would only degrade performance.
-//
-//=====================================================================
-
-static int cyblafb_sync(struct fb_info *info)
-{
-       u32 status, i = 100000;
-
-       KD_GRAPHICS_RETURN(0);
-
-       while (((status = in32(GE20)) & 0xFe800000) && i != 0)
-               i--;
-
-       if (i == 0) {
-               enable_mmio();
-               i = 1000000;
-               while (((status = in32(GE20)) & 0xFA800000) && i != 0)
-                       i--;
-               if (i == 0) {
-                       output("GE Timeout, status: %x\n", status);
-                       if (status & 0x80000000)
-                               output("Bresenham Engine : Busy\n");
-                       if (status & 0x40000000)
-                               output("Setup Engine     : Busy\n");
-                       if (status & 0x20000000)
-                               output("SP / DPE         : Busy\n");
-                       if (status & 0x10000000)
-                               output("Memory Interface : Busy\n");
-                       if (status & 0x08000000)
-                               output("Com Lst Proc     : Busy\n");
-                       if (status & 0x04000000)
-                               output("Block Write      : Busy\n");
-                       if (status & 0x02000000)
-                               output("Command Buffer   : Full\n");
-                       if (status & 0x01000000)
-                               output("RESERVED         : Busy\n");
-                       if (status & 0x00800000)
-                               output("PCI Write Buffer : Busy\n");
-                       cyblafb_setup_GE(info->var.xres,
-                                        info->var.bits_per_pixel);
-               }
-       }
-
-       return 0;
-}
-
-//==============================
-//
-// Cyberblade specific fillrect
-//
-//==============================
-
-static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
-{
-       u32 bpp = info->var.bits_per_pixel, col, desty, height;
-
-       KD_GRAPHICS_RETURN();
-
-       switch (bpp) {
-       default:
-       case 8:
-               col = fr->color;
-               col |= col << 8;
-               col |= col << 16;
-               break;
-       case 16:
-               col = ((u32 *) (info->pseudo_palette))[fr->color];
-               col |= col << 16;
-               break;
-       case 32:
-               col = ((u32 *) (info->pseudo_palette))[fr->color];
-               break;
-       }
-
-       desty = fr->dy;
-       height = fr->height;
-       while (height) {
-               out32(GEB8, basestride | ((desty * info->var.xres_virtual *
-                                          bpp) >> 6));
-               out32(GE60, col);
-               out32(GE48, fr->rop ? 0x66 : ROP_S);
-               out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
-               out32(GE08, point(fr->dx, 0));
-               out32(GE0C, point(fr->dx + fr->width - 1,
-                                 height > 4096 ? 4095 : height - 1));
-               if (likely(height <= 4096))
-                       return;
-               desty += 4096;
-               height -= 4096;
-       }
-}
-
-//================================================
-//
-// Cyberblade specific copyarea
-//
-// This function silently assumes that it never
-// will be called with width or height exceeding
-// 4096.
-//
-//================================================
-
-static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
-{
-       u32 s1, s2, d1, d2, direction;
-
-       KD_GRAPHICS_RETURN();
-
-       s1 = point(ca->sx, 0);
-       s2 = point(ca->sx + ca->width - 1, ca->height - 1);
-       d1 = point(ca->dx, 0);
-       d2 = point(ca->dx + ca->width - 1, ca->height - 1);
-
-       if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
-               direction = 0;
-       else
-               direction = 2;
-
-       out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
-                                  info->var.bits_per_pixel) >> 6));
-       out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
-                                  info->var.bits_per_pixel) >> 6));
-       out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
-       out32(GE00, direction ? s2 : s1);
-       out32(GE04, direction ? s1 : s2);
-       out32(GE08, direction ? d2 : d1);
-       out32(GE0C, direction ? d1 : d2);
-}
-
-//=======================================================================
-//
-// Cyberblade specific imageblit
-//
-// Accelerated for the most usual case, blitting 1 - bit deep
-// character images. Everything else is passed to the generic imageblit
-// unless it is so insane that it is better to printk an alert.
-//
-// Hardware bug: _Never_ blit across pixel column 2048, that will lock
-// the system. We split those blit requests into three blitting
-// operations.
-//
-//=======================================================================
-
-static void cyblafb_imageblit(struct fb_info *info,
-                             const struct fb_image *image)
-{
-       u32 fgcol, bgcol;
-       u32 *pd = (u32 *) image->data;
-       u32 bpp = info->var.bits_per_pixel;
-
-       KD_GRAPHICS_RETURN();
-
-       // Used only for drawing the penguine (image->depth > 1)
-       if (image->depth != 1) {
-               cfb_imageblit(info, image);
-               return;
-       }
-       // That should never happen, but it would be fatal
-       if (image->width == 0 || image->height == 0) {
-               output("imageblit: width/height 0 detected\n");
-               return;
-       }
-
-       if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
-           info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-               fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
-               bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
-       } else {
-               fgcol = image->fg_color;
-               bgcol = image->bg_color;
-       }
-
-       switch (bpp) {
-       case 8:
-               fgcol |= fgcol << 8;
-               bgcol |= bgcol << 8;
-       case 16:
-               fgcol |= fgcol << 16;
-               bgcol |= bgcol << 16;
-       default:
-               break;
-       }
-
-       out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
-                                  bpp) >> 6));
-       out32(GE60, fgcol);
-       out32(GE64, bgcol);
-
-       if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
-               u32 dds = ((image->width + 31) >> 5) * image->height;
-               out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-               out32(GE08, point(image->dx, 0));
-               out32(GE0C, point(image->dx + image->width - 1,
-                                 image->height - 1));
-               while (dds--)
-                       out32(GE9C, *pd++);
-       } else {
-               int i, j;
-               u32 ddstotal = (image->width + 31) >> 5;
-               u32 ddsleft = (2048 - image->dx + 31) >> 5;
-               u32 skipleft = ddstotal - ddsleft;
-
-               out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-               out32(GE08, point(image->dx, 0));
-               out32(GE0C, point(2048 - 1, image->height - 1));
-               for (i = 0; i < image->height; i++) {
-                       for (j = 0; j < ddsleft; j++)
-                               out32(GE9C, *pd++);
-                       pd += skipleft;
-               }
-
-               if (image->dx % 32) {
-                       out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-                       out32(GE08, point(2048, 0));
-                       if (image->width > ddsleft << 5)
-                               out32(GE0C, point(image->dx + (ddsleft << 5) -
-                                                 1, image->height - 1));
-                       else
-                               out32(GE0C, point(image->dx + image->width - 1,
-                                                 image->height - 1));
-                       pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
-                       for (i = 0; i < image->height; i++) {
-                               out32(GE9C, swab32(swab32(*pd) << ((32 -
-                                           (image->dx & 31)) & 31)));
-                               pd += ddstotal;
-                       }
-               }
-
-               if (skipleft) {
-                       out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
-                       out32(GE08, point(image->dx + (ddsleft << 5), 0));
-                       out32(GE0C, point(image->dx + image->width - 1,
-                                         image->height - 1));
-                       pd = (u32 *) image->data;
-                       for (i = 0; i < image->height; i++) {
-                               pd += ddsleft;
-                               for (j = 0; j < skipleft; j++)
-                                       out32(GE9C, *pd++);
-                       }
-               }
-       }
-}
-
-//==========================================================
-//
-// Check if video mode is acceptable. We change var->??? if
-// video mode is slightly off or return error otherwise.
-// info->??? must not be changed!
-//
-//==========================================================
-
-static int cyblafb_check_var(struct fb_var_screeninfo *var,
-                            struct fb_info *info)
-{
-       int bpp = var->bits_per_pixel;
-
-       //
-       // we try to support 8, 16, 24 and 32 bpp modes,
-       // default to 8
-       //
-       // there is a 24 bpp mode, but for now we change requests to 32 bpp
-       // (This is what tridentfb does ... will be changed in the future)
-       //
-       //
-       if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
-               bpp = 8;
-       if (bpp == 24)
-               bpp = var->bits_per_pixel = 32;
-
-       //
-       // interlaced modes are broken, fail if one is requested
-       //
-       if (var->vmode & FB_VMODE_INTERLACED)
-               return -EINVAL;
-
-       //
-       // fail if requested resolution is higher than physical
-       // flatpanel resolution
-       //
-       if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
-               return -EINVAL;
-
-       //
-       // we do not allow vclk to exceed 230 MHz. If the requested
-       // vclk is too high, we default to 200 MHz
-       //
-       if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
-               var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
-
-       //
-       // enforce (h|v)sync_len limits
-       //
-       var->hsync_len &= ~7;
-       if(var->hsync_len > 248)
-               var->hsync_len = 248;
-
-       var->vsync_len &= 15;
-
-       //
-       // Enforce horizontal and vertical hardware limits.
-       // 1600x1200 is mentioned as a maximum, but higher resolutions could
-       // work with slow refresh, small margins and short sync.
-       //
-       var->xres &= ~7;
-
-       if (((var->xres + var->left_margin + var->right_margin +
-                       var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
-                       ((var->yres + var->upper_margin + var->lower_margin +
-                       var->vsync_len) > 2047))
-               return -EINVAL;
-
-       if ((var->xres > 1600) || (var->yres > 1200))
-               output("Mode %dx%d exceeds documented limits.\n",
-                                          var->xres, var->yres);
-       //
-       // try to be smart about (x|y)res_virtual problems.
-       //
-       if (var->xres > var->xres_virtual)
-               var->xres_virtual = var->xres;
-       if (var->yres > var->yres_virtual)
-               var->yres_virtual = var->yres;
-
-       if (bpp == 8 || bpp == 16) {
-               if (var->xres_virtual > 4088)
-                       var->xres_virtual = 4088;
-       } else {
-               if (var->xres_virtual > 2040)
-                       var->xres_virtual = 2040;
-       }
-       var->xres_virtual &= ~7;
-       while (var->xres_virtual * var->yres_virtual * bpp / 8 >
-              info->fix.smem_len) {
-               if (var->yres_virtual > var->yres)
-                       var->yres_virtual--;
-               else if (var->xres_virtual > var->xres)
-                       var->xres_virtual -= 8;
-               else
-                       return -EINVAL;
-       }
-
-       switch (bpp) {
-       case 8:
-               var->red.offset = 0;
-               var->green.offset = 0;
-               var->blue.offset = 0;
-               var->red.length = 6;
-               var->green.length = 6;
-               var->blue.length = 6;
-               break;
-       case 16:
-               var->red.offset = 11;
-               var->green.offset = 5;
-               var->blue.offset = 0;
-               var->red.length = 5;
-               var->green.length = 6;
-               var->blue.length = 5;
-               break;
-       case 32:
-               var->red.offset = 16;
-               var->green.offset = 8;
-               var->blue.offset = 0;
-               var->red.length = 8;
-               var->green.length = 8;
-               var->blue.length = 8;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-//=====================================================================
-//
-// Pan the display
-//
-// The datasheets defines crt start address to be 20 bits wide and
-// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
-// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
-// it, so it is also safe to be used here. BTW: datasheet CR0E on page
-// 90 really is CR1E, the real CRE is documented on page 72.
-//
-// BUT:
-//
-// As of internal version 0.60 we do not use vga panning any longer.
-// Vga panning did not allow us the use of all available video memory
-// and thus prevented ywrap scrolling. We do use the "right view"
-// register now.
-//
-//
-//=====================================================================
-
-static int cyblafb_pan_display(struct fb_var_screeninfo *var,
-                              struct fb_info *info)
-{
-       KD_GRAPHICS_RETURN(0);
-
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-       out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
-                   var->xres_virtual)) * var->bits_per_pixel / 32));
-       return 0;
-}
-
-//============================================
-//
-// This will really help in case of a bug ...
-// dump most gaphics core registers.
-//
-//============================================
-
-static void regdump(struct cyblafb_par *par)
-{
-       int i;
-
-       if (verbosity < 2)
-               return;
-
-       printk("\n");
-       for (i = 0; i <= 0xff; i++) {
-               outb(i, 0x3d4);
-               printk("CR%02x=%02x ", i, inb(0x3d5));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-
-       outb(0x30, 0x3ce);
-       outb(inb(0x3cf) | 0x40, 0x3cf);
-       for (i = 0; i <= 0x1f; i++) {
-               if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
-                   || i == 0x16) {
-                       outb(i, 0x3d4);
-                       printk("CR%02x=%02x ", i, inb(0x3d5));
-               } else
-                       printk("------- ");
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-       outb(0x30, 0x3ce);
-       outb(inb(0x3cf) & 0xbf, 0x3cf);
-
-       printk("\n");
-       for (i = 0; i <= 0x7f; i++) {
-               outb(i, 0x3ce);
-               printk("GR%02x=%02x ", i, inb(0x3cf));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-
-       printk("\n");
-       for (i = 0; i <= 0xff; i++) {
-               outb(i, 0x3c4);
-               printk("SR%02x=%02x ", i, inb(0x3c5));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-
-       printk("\n");
-       for (i = 0; i <= 0x1F; i++) {
-               inb(0x3da);     // next access is index!
-               outb(i, 0x3c0);
-               printk("AR%02x=%02x ", i, inb(0x3c1));
-               if (i % 16 == 15)
-                       printk("\n");
-       }
-       printk("\n");
-
-       inb(0x3DA);             // reset internal flag to 3c0 index
-       outb(0x20, 0x3C0);      // enable attr
-
-       return;
-}
-
-//=======================================================================
-//
-// Save State
-//
-// This function is called while a switch to KD_TEXT is in progress,
-// before any of the other functions are called.
-//
-//=======================================================================
-
-static void cyblafb_save_state(struct fb_info *info)
-{
-       struct cyblafb_par *par = info->par;
-       if (verbosity > 0)
-               output("Switching to KD_TEXT\n");
-       disabled = 0;
-       regdump(par);
-       enable_mmio();
-       return;
-}
-
-//=======================================================================
-//
-// Restore State
-//
-// This function is called while a switch to KD_GRAPHICS is in progress,
-// We have to turn on vga style panning registers again because the
-// trident driver of X does not know about GE10.
-//
-//=======================================================================
-
-static void cyblafb_restore_state(struct fb_info *info)
-{
-       if (verbosity > 0)
-               output("Switching to KD_GRAPHICS\n");
-       out32(GE10, 0);
-       disabled = 1;
-       return;
-}
-
-//======================================
-//
-// Set hardware to requested video mode
-//
-//======================================
-
-static int cyblafb_set_par(struct fb_info *info)
-{
-       struct cyblafb_par *par = info->par;
-       u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
-           hblankend, preendfetch, vtotal, vdispend, vsyncstart,
-           vsyncend, vblankstart, vblankend;
-       struct fb_var_screeninfo *var = &info->var;
-       int bpp = var->bits_per_pixel;
-       int i;
-
-       KD_GRAPHICS_RETURN(0);
-
-       if (verbosity > 0)
-               output("Switching to new mode: "
-                      "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
-                      var->xres, var->yres, var->xres_virtual,
-                      var->yres_virtual, var->bits_per_pixel, var->pixclock,
-                      var->left_margin, var->right_margin, var->upper_margin,
-                      var->lower_margin, var->hsync_len, var->vsync_len);
-
-       htotal = (var->xres + var->left_margin + var->right_margin +
-                 var->hsync_len) / 8 - 5;
-       hdispend = var->xres / 8 - 1;
-       hsyncstart = (var->xres + var->right_margin) / 8;
-       hsyncend = var->hsync_len / 8;
-       hblankstart = hdispend + 1;
-       hblankend = htotal + 3; // should be htotal + 5, bios does it this way
-       preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
-
-       vtotal = var->yres + var->upper_margin + var->lower_margin +
-                                                       var->vsync_len - 2;
-       vdispend = var->yres - 1;
-       vsyncstart = var->yres + var->lower_margin;
-       vblankstart = var->yres;
-       vblankend = vtotal; // should be vtotal + 2, but bios does it this way
-       vsyncend = var->vsync_len;
-
-       enable_mmio();          // necessary! ... check X ...
-
-       write3X4(CR11, read3X4(CR11) & 0x7F);   // unlock cr00 .. cr07
-
-       write3CE(GR30, 8);
-
-       if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
-
-               // stretch or center ?
-
-               out8(0x3C2, 0xEB);
-
-               write3CE(GR30, read3CE(GR30) | 0x81);   // shadow mode on
-
-               if (center) {
-                       write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
-                       write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
-               } else if (stretch) {
-                       write3CE(GR5D, 0);
-                       write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
-                       write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
-               }
-
-       } else {
-               out8(0x3C2, 0x2B);
-               write3CE(GR30, 8);
-       }
-
-       //
-       // Setup CRxx regs
-       //
-
-       write3X4(CR00, htotal & 0xFF);
-       write3X4(CR01, hdispend & 0xFF);
-       write3X4(CR02, hblankstart & 0xFF);
-       write3X4(CR03, hblankend & 0x1F);
-       write3X4(CR04, hsyncstart & 0xFF);
-       write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
-       write3X4(CR06, vtotal & 0xFF);
-       write3X4(CR07, (vtotal & 0x100) >> 8 |
-                      (vdispend & 0x100) >> 7 |
-                      (vsyncstart & 0x100) >> 6 |
-                      (vblankstart & 0x100) >> 5 |
-                      0x10 |
-                      (vtotal & 0x200) >> 4 |
-                      (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
-       write3X4(CR08, 0);
-       write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 |      // FIX !!!
-                      ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
-       write3X4(CR0A, 0);      // Init to some reasonable default
-       write3X4(CR0B, 0);      // Init to some reasonable default
-       write3X4(CR0C, 0);      // Offset 0
-       write3X4(CR0D, 0);      // Offset 0
-       write3X4(CR0E, 0);      // Init to some reasonable default
-       write3X4(CR0F, 0);      // Init to some reasonable default
-       write3X4(CR10, vsyncstart & 0xFF);
-       write3X4(CR11, (vsyncend & 0x0F));
-       write3X4(CR12, vdispend & 0xFF);
-       write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
-       write3X4(CR14, 0x40);   // double word mode
-       write3X4(CR15, vblankstart & 0xFF);
-       write3X4(CR16, vblankend & 0xFF);
-       write3X4(CR17, 0xE3);
-       write3X4(CR18, 0xFF);
-       //       CR19: needed for interlaced modes ... ignore it for now
-       write3X4(CR1A, 0x07);   // Arbitration Control Counter 1
-       write3X4(CR1B, 0x07);   // Arbitration Control Counter 2
-       write3X4(CR1C, 0x07);   // Arbitration Control Counter 3
-       write3X4(CR1D, 0x00);   // Don't know, doesn't hurt ; -)
-       write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
-       //       CR1F: do not set, contains BIOS info about memsize
-       write3X4(CR20, 0x20);   // enabe wr buf, disable 16bit planar mode
-       write3X4(CR21, 0x20);   // enable linear memory access
-       //       CR22: RO cpu latch readback
-       //       CR23: ???
-       //       CR24: RO AR flag state
-       //       CR25: RAMDAC rw timing, pclk buffer tristate control ????
-       //       CR26: ???
-       write3X4(CR27, (vdispend & 0x400) >> 6 |
-                      (vsyncstart & 0x400) >> 5 |
-                      (vblankstart & 0x400) >> 4 |
-                      (vtotal & 0x400) >> 3 |
-                      0x8);
-       //       CR28: ???
-       write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
-                       bpp) / (4 * 16)) & 0x300) >> 4));
-       write3X4(CR2A, read3X4(CR2A) | 0x40);
-       write3X4(CR2B, (htotal & 0x100) >> 8 |
-                      (hdispend & 0x100) >> 7 |
-                      // (0x00 & 0x100) >> 6 |   hinterlace para bit 8 ???
-                      (hsyncstart & 0x100) >> 5 |
-                      (hblankstart & 0x100) >> 4);
-       //       CR2C: ???
-       //       CR2D: initialized in cyblafb_setup_GE()
-       write3X4(CR2F, 0x92);   // conservative, better signal quality
-       //       CR30: reserved
-       //       CR31: reserved
-       //       CR32: reserved
-       //       CR33: reserved
-       //       CR34: disabled in CR36
-       //       CR35: disabled in CR36
-       //       CR36: initialized in cyblafb_setup_GE
-       //       CR37: i2c, ignore for now
-       write3X4(CR38, (bpp == 8) ? 0x00 :      //
-                      (bpp == 16) ? 0x05 :     // highcolor
-                      (bpp == 24) ? 0x29 :     // packed 24bit truecolor
-                      (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
-       write3X4(CR39, 0x01 |   // MMIO enable
-                      (pcirb ? 0x02 : 0) |     // pci read burst enable
-                      (pciwb ? 0x04 : 0));     // pci write burst enable
-       write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
-                      (pcirr ? 0x40 : 0) |     // pci read retry enable
-                      (pciwr ? 0x80 : 0));     // pci write retry enable
-       write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
-                                           : 0);
-       write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
-       write3X4(CR58, 0x82);   // Bios does this .... don't know more
-       //
-       // Setup SRxx regs
-       //
-       write3C4(SR00, 3);
-       write3C4(SR01, 1);      //set char clock 8 dots wide
-       write3C4(SR02, 0x0F);   //enable 4 maps needed in chain4 mode
-       write3C4(SR03, 0);      //no character map select
-       write3C4(SR04, 0x0E);   //memory mode: ext mem, even, chain4
-
-       out8(0x3C4, 0x0b);
-       in8(0x3C5);             // Set NEW mode
-       write3C4(SR0D, 0x00);   // test ... check
-
-       set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
-                                       / info->var.pixclock);  //SR18, SR19
-
-       //
-       // Setup GRxx regs
-       //
-       write3CE(GR00, 0x00);   // test ... check
-       write3CE(GR01, 0x00);   // test ... check
-       write3CE(GR02, 0x00);   // test ... check
-       write3CE(GR03, 0x00);   // test ... check
-       write3CE(GR04, 0x00);   // test ... check
-       write3CE(GR05, 0x40);   // no CGA compat, allow 256 col
-       write3CE(GR06, 0x05);   // graphics mode
-       write3CE(GR07, 0x0F);   // planes?
-       write3CE(GR08, 0xFF);   // test ... check
-       write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
-       write3CE(GR20, 0xC0);   // test ... check
-       write3CE(GR2F, 0xA0);   // PCLK = VCLK, no skew,
-
-       //
-       // Setup ARxx regs
-       //
-       for (i = 0; i < 0x10; i++)      // set AR00 .. AR0f
-               write3C0(i, i);
-       write3C0(AR10, 0x41);   // graphics mode and support 256 color modes
-       write3C0(AR12, 0x0F);   // planes
-       write3C0(AR13, 0);      // horizontal pel panning
-       in8(0x3DA);             // reset internal flag to 3c0 index
-       out8(0x3C0, 0x20);      // enable attr
-
-       //
-       // Setup hidden RAMDAC command register
-       //
-       in8(0x3C8);             // these reads are
-       in8(0x3C6);             // necessary to
-       in8(0x3C6);             // unmask the RAMDAC
-       in8(0x3C6);             // command reg, otherwise
-       in8(0x3C6);             // we would write the pixelmask reg!
-       out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
-            (bpp == 15) ? 0x10 :       //
-            (bpp == 16) ? 0x30 :       // hicolor
-            (bpp == 24) ? 0xD0 :       // truecolor
-            (bpp == 32) ? 0xD0 : 0);   // truecolor
-       in8(0x3C8);
-
-       //
-       // GR31 is not mentioned in the datasheet
-       //
-       if (displaytype == DISPLAY_FP)
-               write3CE(GR31, (read3CE(GR31) & 0x8F) |
-                        ((info->var.yres > 1024) ? 0x50 :
-                         (info->var.yres > 768) ? 0x30 :
-                         (info->var.yres > 600) ? 0x20 :
-                         (info->var.yres > 480) ? 0x10 : 0));
-
-       info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
-                                     : FB_VISUAL_TRUECOLOR;
-       info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
-       info->cmap.len = (bpp == 8) ? 256 : 16;
-
-       //
-       // init acceleration engine
-       //
-       cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
-
-       //
-       // Set/clear flags to allow proper scroll mode selection.
-       //
-       if (var->xres == var->xres_virtual)
-               info->flags &= ~FBINFO_HWACCEL_XPAN;
-       else
-               info->flags |= FBINFO_HWACCEL_XPAN;
-
-       if (var->yres == var->yres_virtual)
-               info->flags &= ~FBINFO_HWACCEL_YPAN;
-       else
-               info->flags |= FBINFO_HWACCEL_YPAN;
-
-       if (info->fix.smem_len !=
-           var->xres_virtual * var->yres_virtual * bpp / 8)
-               info->flags &= ~FBINFO_HWACCEL_YWRAP;
-       else
-               info->flags |= FBINFO_HWACCEL_YWRAP;
-
-       regdump(par);
-
-       return 0;
-}
-
-//========================
-//
-// Set one color register
-//
-//========================
-
-static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                            unsigned blue, unsigned transp,
-                            struct fb_info *info)
-{
-       int bpp = info->var.bits_per_pixel;
-
-       KD_GRAPHICS_RETURN(0);
-
-       if (regno >= info->cmap.len)
-               return 1;
-
-       if (bpp == 8) {
-               out8(0x3C6, 0xFF);
-               out8(0x3C8, regno);
-               out8(0x3C9, red >> 10);
-               out8(0x3C9, green >> 10);
-               out8(0x3C9, blue >> 10);
-
-       } else if (regno < 16) {
-               if (bpp == 16)  // RGB 565
-                       ((u32 *) info->pseudo_palette)[regno] =
-                               (red & 0xF800) |
-                               ((green & 0xFC00) >> 5) |
-                               ((blue & 0xF800) >> 11);
-               else if (bpp == 32)     // ARGB 8888
-                       ((u32 *) info->pseudo_palette)[regno] =
-                               ((transp & 0xFF00) << 16) |
-                               ((red & 0xFF00) << 8) |
-                               ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
-       }
-
-       return 0;
-}
-
-//==========================================================
-//
-// Try blanking the screen. For flat panels it does nothing
-//
-//==========================================================
-
-static int cyblafb_blank(int blank_mode, struct fb_info *info)
-{
-       unsigned char PMCont, DPMSCont;
-
-       KD_GRAPHICS_RETURN(0);
-
-       if (displaytype == DISPLAY_FP)
-               return 0;
-
-       out8(0x83C8, 0x04);     // DPMS Control
-       PMCont = in8(0x83C6) & 0xFC;
-
-       DPMSCont = read3CE(GR23) & 0xFC;
-
-       switch (blank_mode) {
-       case FB_BLANK_UNBLANK:  // Screen: On, HSync: On, VSync: On
-       case FB_BLANK_NORMAL:   // Screen: Off, HSync: On, VSync: On
-               PMCont |= 0x03;
-               DPMSCont |= 0x00;
-               break;
-       case FB_BLANK_HSYNC_SUSPEND:    // Screen: Off, HSync: Off, VSync: On
-               PMCont |= 0x02;
-               DPMSCont |= 0x01;
-               break;
-       case FB_BLANK_VSYNC_SUSPEND:    // Screen: Off, HSync: On, VSync: Off
-               PMCont |= 0x02;
-               DPMSCont |= 0x02;
-               break;
-       case FB_BLANK_POWERDOWN:        // Screen: Off, HSync: Off, VSync: Off
-               PMCont |= 0x00;
-               DPMSCont |= 0x03;
-               break;
-       }
-
-       write3CE(GR23, DPMSCont);
-       out8(0x83C8, 4);
-       out8(0x83C6, PMCont);
-       //
-       // let fbcon do a softblank for us
-       //
-       return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
-}
-
-static struct fb_ops cyblafb_ops __devinitdata = {
-       .owner = THIS_MODULE,
-       .fb_setcolreg = cyblafb_setcolreg,
-       .fb_pan_display = cyblafb_pan_display,
-       .fb_blank = cyblafb_blank,
-       .fb_check_var = cyblafb_check_var,
-       .fb_set_par = cyblafb_set_par,
-       .fb_fillrect = cyblafb_fillrect,
-       .fb_copyarea = cyblafb_copyarea,
-       .fb_imageblit = cyblafb_imageblit,
-       .fb_sync = cyblafb_sync,
-       .fb_restore_state = cyblafb_restore_state,
-       .fb_save_state = cyblafb_save_state,
-};
-
-//==========================================================================
-//
-// getstartupmode() decides about the inital video mode
-//
-// There is no reason to use modedb, a lot of video modes there would
-// need altered timings to display correctly. So I decided that it is much
-// better to provide a limited optimized set of modes plus the option of
-// using the mode in effect at startup time (might be selected using the
-// vga=??? parameter). After that the user might use fbset to select any
-// mode he likes, check_var will not try to alter geometry parameters as
-// it would be necessary otherwise.
-//
-//==========================================================================
-
-static int __devinit getstartupmode(struct fb_info *info)
-{
-       u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
-           vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
-           cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
-           cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
-           cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
-
-       struct modus {
-               int xres; int vxres; int yres; int vyres;
-               int bpp; int pxclk;
-               int left_margin; int right_margin;
-               int upper_margin; int lower_margin;
-               int hsync_len; int vsync_len;
-       } modedb[5] = {
-               {
-               0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
-               640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
-               800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
-               1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
-               1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
-       };
-
-       outb(0x00, 0x3d4); cr00 = inb(0x3d5);
-       outb(0x01, 0x3d4); cr01 = inb(0x3d5);
-       outb(0x02, 0x3d4); cr02 = inb(0x3d5);
-       outb(0x03, 0x3d4); cr03 = inb(0x3d5);
-       outb(0x04, 0x3d4); cr04 = inb(0x3d5);
-       outb(0x05, 0x3d4); cr05 = inb(0x3d5);
-       outb(0x06, 0x3d4); cr06 = inb(0x3d5);
-       outb(0x07, 0x3d4); cr07 = inb(0x3d5);
-       outb(0x09, 0x3d4); cr09 = inb(0x3d5);
-       outb(0x10, 0x3d4); cr10 = inb(0x3d5);
-       outb(0x11, 0x3d4); cr11 = inb(0x3d5);
-       outb(0x12, 0x3d4); cr12 = inb(0x3d5);
-       outb(0x15, 0x3d4); cr15 = inb(0x3d5);
-       outb(0x16, 0x3d4); cr16 = inb(0x3d5);
-       outb(0x27, 0x3d4); cr27 = inb(0x3d5);
-       outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
-       outb(0x38, 0x3d4); cr38 = inb(0x3d5);
-
-       outb(0x0b, 0x3c4);
-       inb(0x3c5);
-
-       outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
-       outb(0x18, 0x3c4); sr18 = inb(0x3c5);
-       outb(0x19, 0x3c4); sr19 = inb(0x3c5);
-       outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
-
-       htotal = cr00 | (cr2b & 0x01) << 8;
-       hdispend = cr01 | (cr2b & 0x02) << 7;
-       hblankstart = cr02 | (cr2b & 0x10) << 4;
-       hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
-       hsyncstart = cr04 | (cr2b & 0x08) << 5;
-       hsyncend = cr05 & 0x1f;
-
-       modedb[0].xres = hblankstart * 8;
-       modedb[0].hsync_len = hsyncend * 8;
-       modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
-       modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
-           modedb[0].right_margin - modedb[0].hsync_len;
-
-       vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
-           | (cr27 & 0x80) << 3;
-       vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
-           | (cr27 & 0x10) << 6;
-       vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
-           | (cr27 & 0x20) << 5;
-       vsyncend = cr11 & 0x0f;
-       vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
-           | (cr27 & 0x40) << 4;
-       vblankend = cr16;
-
-       modedb[0].yres = vdispend + 1;
-       modedb[0].vsync_len = vsyncend;
-       modedb[0].lower_margin = vsyncstart - modedb[0].yres;
-       modedb[0].upper_margin = vtotal - modedb[0].yres -
-           modedb[0].lower_margin - modedb[0].vsync_len + 2;
-
-       tmp = cr38 & 0x3c;
-       modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
-           tmp == 8 ? 32 : 8;
-
-       fi = ((5864727 * (sr18 + 8)) /
-             (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
-       pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
-       tmp = sr0d & 0x06;
-       vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
-       modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
-
-       if (verbosity > 0)
-               output("detected startup mode: "
-                      "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
-                      modedb[0].xres, modedb[0].yres, modedb[0].xres,
-                      modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
-                      modedb[0].right_margin, modedb[0].upper_margin,
-                      modedb[0].lower_margin, modedb[0].hsync_len,
-                      modedb[0].vsync_len);
-
-       //
-       // We use this goto target in case of a failed check_var. No, I really
-       // do not want to do it in another way!
-       //
-
-      tryagain:
-
-       i = (mode == NULL) ? 0 :
-           !strncmp(mode, "640x480", 7) ? 1 :
-           !strncmp(mode, "800x600", 7) ? 2 :
-           !strncmp(mode, "1024x768", 8) ? 3 :
-           !strncmp(mode, "1280x1024", 9) ? 4 : 0;
-
-       ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
-
-       if (i == 0) {
-               info->var.pixclock = modedb[i].pxclk;
-               info->var.bits_per_pixel = modedb[i].bpp;
-       } else {
-               info->var.pixclock = (100000000 /
-                                     ((modedb[i].left_margin +
-                                       modedb[i].xres +
-                                       modedb[i].right_margin +
-                                       modedb[i].hsync_len) *
-                                      (modedb[i].upper_margin +
-                                       modedb[i].yres +
-                                       modedb[i].lower_margin +
-                                       modedb[i].vsync_len) * ref / 10000));
-               info->var.bits_per_pixel = bpp;
-       }
-
-       info->var.left_margin = modedb[i].left_margin;
-       info->var.right_margin = modedb[i].right_margin;
-       info->var.xres = modedb[i].xres;
-       if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
-               info->var.xres_virtual = modedb[i].vxres;
-       else
-               info->var.xres_virtual = modedb[i].xres;
-       info->var.xoffset = 0;
-       info->var.hsync_len = modedb[i].hsync_len;
-       info->var.upper_margin = modedb[i].upper_margin;
-       info->var.yres = modedb[i].yres;
-       info->var.yres_virtual = modedb[i].vyres;
-       info->var.yoffset = 0;
-       info->var.lower_margin = modedb[i].lower_margin;
-       info->var.vsync_len = modedb[i].vsync_len;
-       info->var.sync = 0;
-       info->var.vmode = FB_VMODE_NONINTERLACED;
-
-       if (cyblafb_check_var(&info->var, info)) {
-               // 640x480 - 8@75 should really never fail. One case would
-               // be fp == 1 and nativex < 640 ... give up then
-               if (i == 1 && bpp == 8 && ref == 75) {
-                       output("Can't find a valid mode :-(\n");
-                       return -EINVAL;
-               }
-               // Our detected mode is unlikely to fail. If it does,
-               // try 640x480 - 8@75 ...
-               if (i == 0) {
-                       mode = "640x480";
-                       bpp = 8;
-                       ref = 75;
-                       output("Detected mode failed check_var! "
-                              "Trying 640x480 - 8@75\n");
-                       goto tryagain;
-               }
-               // A specified video mode failed for some reason.
-               // Try the startup mode first
-               output("Specified mode '%s' failed check! "
-                      "Falling back to startup mode.\n", mode);
-               mode = NULL;
-               goto tryagain;
-       }
-
-       return 0;
-}
-
-//========================================================
-//
-// Detect activated memory size. Undefined values require
-// memsize parameter.
-//
-//========================================================
-
-static unsigned int __devinit get_memsize(void)
-{
-       unsigned char tmp;
-       unsigned int k;
-
-       if (memsize)
-               k = memsize * Kb;
-       else {
-               tmp = read3X4(CR1F) & 0x0F;
-               switch (tmp) {
-               case 0x03:
-                       k = 1 * 1024 * 1024;
-                       break;
-               case 0x07:
-                       k = 2 * 1024 * 1024;
-                       break;
-               case 0x0F:
-                       k = 4 * 1024 * 1024;
-                       break;
-               case 0x04:
-                       k = 8 * 1024 * 1024;
-                       break;
-               default:
-                       k = 1 * 1024 * 1024;
-                       output("Unknown memory size code %x in CR1F."
-                              " We default to 1 Mb for now, please"
-                              " do provide a memsize parameter!\n", tmp);
-               }
-       }
-
-       if (verbosity > 0)
-               output("framebuffer size = %d Kb\n", k / Kb);
-       return k;
-}
-
-//=========================================================
-//
-// Detect if a flat panel monitor connected to the special
-// interface is active. Override is possible by fp and crt
-// parameters.
-//
-//=========================================================
-
-static unsigned int __devinit get_displaytype(void)
-{
-       if (fp)
-               return DISPLAY_FP;
-       if (crt)
-               return DISPLAY_CRT;
-       return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
-}
-
-//=====================================
-//
-// Get native resolution of flat panel
-//
-//=====================================
-
-static int __devinit get_nativex(void)
-{
-       int x, y, tmp;
-
-       if (nativex)
-               return nativex;
-
-       tmp = (read3CE(GR52) >> 4) & 3;
-
-       switch (tmp) {
-       case 0: x = 1280; y = 1024;
-               break;
-       case 2: x = 1024; y = 768;
-               break;
-       case 3: x = 800;  y = 600;
-               break;
-       case 4: x = 1400; y = 1050;
-               break;
-       case 1:
-       default:
-               x = 640; y = 480;
-               break;
-       }
-
-       if (verbosity > 0)
-               output("%dx%d flat panel found\n", x, y);
-       return x;
-}
-
-static int __devinit cybla_pci_probe(struct pci_dev *dev,
-                                    const struct pci_device_id *id)
-{
-       struct fb_info *info;
-       struct cyblafb_par *par;
-
-       info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
-       if (!info)
-               goto errout_alloc_info;
-
-       info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
-       if (!info->pixmap.addr) {
-               output("allocation of pixmap buffer failed!\n");
-               goto errout_alloc_pixmap;
-       }
-       info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
-       info->pixmap.buf_align = 4;
-       info->pixmap.access_align = 32;
-       info->pixmap.flags = FB_PIXMAP_SYSTEM;
-       info->pixmap.scan_align = 4;
-
-       par = info->par;
-       par->ops = cyblafb_ops;
-
-       info->fix = cyblafb_fix;
-       info->fbops = &par->ops;
-       info->fix = cyblafb_fix;
-
-       if (pci_enable_device(dev)) {
-               output("could not enable device!\n");
-               goto errout_enable;
-       }
-       // might already be requested by vga console or vesafb,
-       // so we do care about success
-       if (!request_region(0x3c0, 0x20, "cyblafb")) {
-               output("region 0x3c0/0x20 already reserved\n");
-               vesafb |= 1;
-
-       }
-       //
-       // Graphics Engine Registers
-       //
-       if (!request_region(GEBase, 0x100, "cyblafb")) {
-               output("region %#x/0x100 already reserved\n", GEBase);
-               vesafb |= 2;
-       }
-
-       regdump(par);
-
-       enable_mmio();
-
-       // setup MMIO region
-       info->fix.mmio_start = pci_resource_start(dev, 1);
-       info->fix.mmio_len = 0x20000;
-
-       if (!request_mem_region(info->fix.mmio_start,
-                               info->fix.mmio_len, "cyblafb")) {
-               output("request_mem_region failed for mmio region!\n");
-               goto errout_mmio_reqmem;
-       }
-
-       io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
-
-       if (!io_virt) {
-               output("ioremap failed for mmio region\n");
-               goto errout_mmio_remap;
-       }
-       // setup framebuffer memory ... might already be requested
-       // by vesafb. Not to fail in case of an unsuccessful request
-       // is useful if both are loaded.
-       info->fix.smem_start = pci_resource_start(dev, 0);
-       info->fix.smem_len = get_memsize();
-
-       if (!request_mem_region(info->fix.smem_start,
-                               info->fix.smem_len, "cyblafb")) {
-               output("region %#lx/%#x already reserved\n",
-                      info->fix.smem_start, info->fix.smem_len);
-               vesafb |= 4;
-       }
-
-       info->screen_base = ioremap_nocache(info->fix.smem_start,
-                                           info->fix.smem_len);
-
-       if (!info->screen_base) {
-               output("ioremap failed for smem region\n");
-               goto errout_smem_remap;
-       }
-
-       displaytype = get_displaytype();
-
-       if (displaytype == DISPLAY_FP)
-               nativex = get_nativex();
-
-       info->flags = FBINFO_DEFAULT
-                   | FBINFO_HWACCEL_COPYAREA
-                   | FBINFO_HWACCEL_FILLRECT
-                   | FBINFO_HWACCEL_IMAGEBLIT
-                   | FBINFO_READS_FAST
-//                 | FBINFO_PARTIAL_PAN_OK
-                   | FBINFO_MISC_ALWAYS_SETPAR;
-
-       info->pseudo_palette = par->pseudo_pal;
-
-       if (getstartupmode(info))
-               goto errout_findmode;
-
-       fb_alloc_cmap(&info->cmap, 256, 0);
-
-       if (register_framebuffer(info)) {
-               output("Could not register CyBla framebuffer\n");
-               goto errout_register;
-       }
-
-       pci_set_drvdata(dev, info);
-
-       //
-       // normal exit and error paths
-       //
-
-       return 0;
-
-      errout_register:
-      errout_findmode:
-       iounmap(info->screen_base);
-      errout_smem_remap:
-       if (!(vesafb & 4))
-               release_mem_region(info->fix.smem_start, info->fix.smem_len);
-       iounmap(io_virt);
-      errout_mmio_remap:
-       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-      errout_mmio_reqmem:
-       if (!(vesafb & 1))
-               release_region(0x3c0, 32);
-      errout_enable:
-       kfree(info->pixmap.addr);
-      errout_alloc_pixmap:
-       framebuffer_release(info);
-      errout_alloc_info:
-       output("CyblaFB version %s aborting init.\n", VERSION);
-       return -ENODEV;
-}
-
-static void __devexit cybla_pci_remove(struct pci_dev *dev)
-{
-       struct fb_info *info = pci_get_drvdata(dev);
-
-       unregister_framebuffer(info);
-       iounmap(io_virt);
-       iounmap(info->screen_base);
-       if (!(vesafb & 4))
-               release_mem_region(info->fix.smem_start, info->fix.smem_len);
-       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-       fb_dealloc_cmap(&info->cmap);
-       if (!(vesafb & 2))
-               release_region(GEBase, 0x100);
-       if (!(vesafb & 1))
-               release_region(0x3c0, 32);
-       kfree(info->pixmap.addr);
-       framebuffer_release(info);
-       output("CyblaFB version %s normal exit.\n", VERSION);
-}
-
-//
-// List of boards that we are trying to support
-//
-static struct pci_device_id cybla_devices[] = {
-       {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, cybla_devices);
-
-static struct pci_driver cyblafb_pci_driver = {
-       .name = "cyblafb",
-       .id_table = cybla_devices,
-       .probe = cybla_pci_probe,
-       .remove = __devexit_p(cybla_pci_remove)
-};
-
-//=============================================================
-//
-// kernel command line example:
-//
-//     video=cyblafb:1280x1024, bpp=16, ref=50 ...
-//
-// modprobe command line example:
-//
-//     modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
-//
-//=============================================================
-
-static int __devinit cyblafb_init(void)
-{
-#ifndef MODULE
-       char *options = NULL;
-       char *opt;
-
-       if (fb_get_options("cyblafb", &options))
-               return -ENODEV;
-
-       if (options && *options)
-               while ((opt = strsep(&options, ",")) != NULL) {
-                       if (!*opt)
-                               continue;
-                       else if (!strncmp(opt, "bpp=", 4))
-                               bpp = simple_strtoul(opt + 4, NULL, 0);
-                       else if (!strncmp(opt, "ref=", 4))
-                               ref = simple_strtoul(opt + 4, NULL, 0);
-                       else if (!strncmp(opt, "fp", 2))
-                               displaytype = DISPLAY_FP;
-                       else if (!strncmp(opt, "crt", 3))
-                               displaytype = DISPLAY_CRT;
-                       else if (!strncmp(opt, "nativex=", 8))
-                               nativex = simple_strtoul(opt + 8, NULL, 0);
-                       else if (!strncmp(opt, "center", 6))
-                               center = 1;
-                       else if (!strncmp(opt, "stretch", 7))
-                               stretch = 1;
-                       else if (!strncmp(opt, "pciwb=", 6))
-                               pciwb = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "pcirb=", 6))
-                               pcirb = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "pciwr=", 6))
-                               pciwr = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "pcirr=", 6))
-                               pcirr = simple_strtoul(opt + 6, NULL, 0);
-                       else if (!strncmp(opt, "memsize=", 8))
-                               memsize = simple_strtoul(opt + 8, NULL, 0);
-                       else if (!strncmp(opt, "verbosity=", 10))
-                               verbosity = simple_strtoul(opt + 10, NULL, 0);
-                       else
-                               mode = opt;
-               }
-#endif
-       output("CyblaFB version %s initializing\n", VERSION);
-       return pci_register_driver(&cyblafb_pci_driver);
-}
-
-static void __exit cyblafb_exit(void)
-{
-       pci_unregister_driver(&cyblafb_pci_driver);
-}
-
-module_init(cyblafb_init);
-module_exit(cyblafb_exit);
-
-MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
-MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
-MODULE_LICENSE("GPL");
index daf9b81878a463a62bb81427f8e2e97c1978c2e3..0c5b9a9fd56f178cf0ad10bed907138a2b06fe3c 100644 (file)
@@ -129,6 +129,8 @@ static int set_system(const struct dmi_system_id *id)
                screen_info.lfb_width = info->width;
        if (screen_info.lfb_height == 0)
                screen_info.lfb_height = info->height;
+       if (screen_info.orig_video_isVGA == 0)
+               screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
 
        return 0;
 }
@@ -374,9 +376,10 @@ static int __init efifb_init(void)
        int ret;
        char *option = NULL;
 
+       dmi_check_system(dmi_system_table);
+
        if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
                return -ENODEV;
-       dmi_check_system(dmi_system_table);
 
        if (fb_get_options("efifb", &option))
                return -ENODEV;
index 082026546aee979e9bee1f2e8f4a440df02d20a6..0a7a6679ee6eb05e2be754ff816ba3547a0f7fdb 100644 (file)
@@ -85,8 +85,9 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
 
 /* vm_ops->page_mkwrite handler */
 static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
-                                 struct page *page)
+                                 struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct fb_info *info = vma->vm_private_data;
        struct fb_deferred_io *fbdefio = info->fbdefio;
        struct page *cur;
index cfd9dce1ce0b666627b6306e0eb693f669e154f5..2ac32e6b5953bb981e8bc57f9516584bc868d1c9 100644 (file)
 struct fb_info *registered_fb[FB_MAX] __read_mostly;
 int num_registered_fb __read_mostly;
 
+int lock_fb_info(struct fb_info *info)
+{
+       mutex_lock(&info->lock);
+       if (!info->fbops) {
+               mutex_unlock(&info->lock);
+               return 0;
+       }
+       return 1;
+}
+EXPORT_SYMBOL(lock_fb_info);
+
 /*
  * Helpers
  */
@@ -1086,13 +1097,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EINVAL;
                con2fb.framebuffer = -1;
                event.data = &con2fb;
-
-               if (!lock_fb_info(info))
-                       return -ENODEV;
                event.info = info;
                fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
-               unlock_fb_info(info);
-
                ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
                break;
        case FBIOPUT_CON2FBMAP:
@@ -1109,12 +1115,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        break;
                }
                event.data = &con2fb;
-               if (!lock_fb_info(info))
-                       return -ENODEV;
                event.info = info;
-               ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP,
-                                             &event);
-               unlock_fb_info(info);
+               ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
                break;
        case FBIOBLANK:
                if (!lock_fb_info(info))
index d9627b57eb4d27e12242116f2fc77c99516ab0dd..135ae18bfce84e7bdd0e307d7d470e8370919ca6 100644 (file)
@@ -362,6 +362,7 @@ int NVCommonSetup(struct fb_info *info)
        case 0x0186:
        case 0x0187:
        case 0x018D:
+       case 0x01D7:
        case 0x0228:
        case 0x0286:
        case 0x028C:
index f132aab8c5de2fbd57acd1ea1c5c3c934d85dd6c..c03f7f55c76d47199909dd89d6d520ac07f68f1f 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/mutex.h>
 #include <video/vga.h>
 
 #define NV_ARCH_04  0x04
@@ -99,7 +98,6 @@ struct nvidia_par {
        RIVA_HW_STATE initial_state;
        RIVA_HW_STATE *CurrentState;
        struct vgastate vgastate;
-       struct mutex open_lock;
        u32 pseudo_palette[16];
        struct pci_dev *pci_dev;
        u32 Architecture;
index 9dbb5a5a267b4ac5e060172748210981f251b1d3..efe10ff86d6365ceaf5ab6f4fb3a0425b8f82c78 100644 (file)
@@ -1004,15 +1004,12 @@ static int nvidiafb_open(struct fb_info *info, int user)
 {
        struct nvidia_par *par = info->par;
 
-       mutex_lock(&par->open_lock);
-
        if (!par->open_count) {
                save_vga_x86(par);
                nvidia_save_vga(par, &par->initial_state);
        }
 
        par->open_count++;
-       mutex_unlock(&par->open_lock);
        return 0;
 }
 
@@ -1021,8 +1018,6 @@ static int nvidiafb_release(struct fb_info *info, int user)
        struct nvidia_par *par = info->par;
        int err = 0;
 
-       mutex_lock(&par->open_lock);
-
        if (!par->open_count) {
                err = -EINVAL;
                goto done;
@@ -1035,7 +1030,6 @@ static int nvidiafb_release(struct fb_info *info, int user)
 
        par->open_count--;
 done:
-       mutex_unlock(&par->open_lock);
        return err;
 }
 
@@ -1300,7 +1294,6 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
 
        par = info->par;
        par->pci_dev = pd;
-       mutex_init(&par->open_lock);
        info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
 
        if (info->pixmap.addr == NULL)
index f24df0b54e1cad0ff54ab68d5439b99fd8ae03c0..8aa6e47202b943369cb23912b0f8c66ed613877a 100644 (file)
@@ -742,7 +742,7 @@ static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
                if (calc_reg_timing(sysclk, div) == 0)
                        break;
        }
-       if (div > max_clk_div)
+       if (div >= max_clk_div)
                goto err;
 
        *extif_mem_div = div;
@@ -752,7 +752,7 @@ static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
                        break;
        }
 
-       if (div > max_clk_div)
+       if (div >= max_clk_div)
                goto err;
 
        return 0;
index 1a49519dafa483b864c992dfb1f92b2f8e02505f..060d72fe57cb1f639861ae24cf10a6ed0babdb40 100644 (file)
@@ -338,7 +338,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 
        omapfb_rqueue_lock(fbdev);
        switch (blank) {
-       case VESA_NO_BLANKING:
+       case FB_BLANK_UNBLANK:
                if (fbdev->state == OMAPFB_SUSPENDED) {
                        if (fbdev->ctrl->resume)
                                fbdev->ctrl->resume();
@@ -349,7 +349,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                                do_update = 1;
                }
                break;
-       case VESA_POWERDOWN:
+       case FB_BLANK_POWERDOWN:
                if (fbdev->state == OMAPFB_ACTIVE) {
                        fbdev->panel->disable(fbdev->panel);
                        if (fbdev->ctrl->suspend)
@@ -1818,7 +1818,7 @@ static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
        struct omapfb_device *fbdev = platform_get_drvdata(pdev);
 
-       omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
+       omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]);
 
        return 0;
 }
@@ -1828,7 +1828,7 @@ static int omapfb_resume(struct platform_device *pdev)
 {
        struct omapfb_device *fbdev = platform_get_drvdata(pdev);
 
-       omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
+       omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]);
        return 0;
 }
 
index a7b01d2724b5110ce4365fa35e8c32c05c6b385c..0726aecf3b7e084c87f6abdc66ca44f4c16cb631 100644 (file)
 #define dbg(fmt, args...) do { } while (0)
 #endif
 
-static const int __devinitconst s1d13xxxfb_revisions[] = {
-       S1D13506_CHIP_REV,      /* Rev.4 on HP Jornada 7xx S1D13506 */
-       S1D13806_CHIP_REV,      /* Rev.7 on .. */
+/*
+ * List of card production ids
+ */
+static const int s1d13xxxfb_prod_ids[] = {
+       S1D13505_PROD_ID,
+       S1D13506_PROD_ID,
+       S1D13806_PROD_ID,
+};
+
+/*
+ * List of card strings
+ */
+static const char *s1d13xxxfb_prod_names[] = {
+       "S1D13505",
+       "S1D13506",
+       "S1D13806",
 };
 
 /*
@@ -377,7 +390,6 @@ s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-
 /* framebuffer information structures */
 
 static struct fb_ops s1d13xxxfb_fbops = {
@@ -544,7 +556,7 @@ s1d13xxxfb_probe(struct platform_device *pdev)
        struct s1d13xxxfb_pdata *pdata = NULL;
        int ret = 0;
        int i;
-       u8 revision;
+       u8 revision, prod_id;
 
        dbg("probe called: device is %p\n", pdev);
 
@@ -613,19 +625,31 @@ s1d13xxxfb_probe(struct platform_device *pdev)
                goto bail;
        }
 
-       revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
-
+       /* production id is top 6 bits */
+       prod_id = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
+       /* revision id is lower 2 bits */
+       revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) & 0x3;
        ret = -ENODEV;
 
-       for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) {
-               if (revision == s1d13xxxfb_revisions[i])
+       for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_prod_ids); i++) {
+               if (prod_id == s1d13xxxfb_prod_ids[i]) {
+                       /* looks like we got it in our list */
+                       default_par->prod_id = prod_id;
+                       default_par->revision = revision;
                        ret = 0;
+                       break;
+               }
        }
 
-       if (!ret)
+       if (!ret) {
+               printk(KERN_INFO PFX "chip production id %i = %s\n",
+                       prod_id, s1d13xxxfb_prod_names[i]);
                printk(KERN_INFO PFX "chip revision %i\n", revision);
-       else {
-               printk(KERN_INFO PFX "unknown chip revision %i\n", revision);
+       } else {
+               printk(KERN_INFO PFX
+                       "unknown chip production id %i, revision %i\n",
+                       prod_id, revision);
+               printk(KERN_INFO PFX "please contant maintainer\n");
                goto bail;
        }
 
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
new file mode 100644 (file)
index 0000000..5e9c630
--- /dev/null
@@ -0,0 +1,1036 @@
+/* linux/drivers/video/s3c-fb.c
+ *
+ * Copyright 2008 Openmoko Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * Samsung SoC Framebuffer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <mach/regs-fb.h>
+#include <plat/fb.h>
+
+/* This driver will export a number of framebuffer interfaces depending
+ * on the configuration passed in via the platform data. Each fb instance
+ * maps to a hardware window. Currently there is no support for runtime
+ * setting of the alpha-blending functions that each window has, so only
+ * window 0 is actually useful.
+ *
+ * Window 0 is treated specially, it is used for the basis of the LCD
+ * output timings and as the control for the output power-down state.
+*/
+
+/* note, some of the functions that get called are derived from including
+ * <mach/regs-fb.h> as they are specific to the architecture that the code
+ * is being built for.
+*/
+
+#ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
+#undef writel
+#define writel(v, r) do { \
+       printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
+       __raw_writel(v, r); } while(0)
+#endif /* FB_S3C_DEBUG_REGWRITE */
+
+struct s3c_fb;
+
+/**
+ * struct s3c_fb_win - per window private data for each framebuffer.
+ * @windata: The platform data supplied for the window configuration.
+ * @parent: The hardware that this window is part of.
+ * @fbinfo: Pointer pack to the framebuffer info for this window.
+ * @palette_buffer: Buffer/cache to hold palette entries.
+ * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
+ * @index: The window number of this window.
+ * @palette: The bitfields for changing r/g/b into a hardware palette entry.
+ */
+struct s3c_fb_win {
+       struct s3c_fb_pd_win    *windata;
+       struct s3c_fb           *parent;
+       struct fb_info          *fbinfo;
+       struct s3c_fb_palette    palette;
+
+       u32                     *palette_buffer;
+       u32                      pseudo_palette[16];
+       unsigned int             index;
+};
+
+/**
+ * struct s3c_fb - overall hardware state of the hardware
+ * @dev: The device that we bound to, for printing, etc.
+ * @regs_res: The resource we claimed for the IO registers.
+ * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
+ * @regs: The mapped hardware registers.
+ * @enabled: A bitmask of enabled hardware windows.
+ * @pdata: The platform configuration data passed with the device.
+ * @windows: The hardware windows that have been claimed.
+ */
+struct s3c_fb {
+       struct device           *dev;
+       struct resource         *regs_res;
+       struct clk              *bus_clk;
+       void __iomem            *regs;
+
+       unsigned char            enabled;
+
+       struct s3c_fb_platdata  *pdata;
+       struct s3c_fb_win       *windows[S3C_FB_MAX_WIN];
+};
+
+/**
+ * s3c_fb_win_has_palette() - determine if a mode has a palette
+ * @win: The window number being queried.
+ * @bpp: The number of bits per pixel to test.
+ *
+ * Work out if the given window supports palletised data at the specified bpp.
+ */
+static int s3c_fb_win_has_palette(unsigned int win, unsigned int bpp)
+{
+       return s3c_fb_win_pal_size(win) <= (1 << bpp);
+}
+
+/**
+ * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
+ * @var: The screen information to verify.
+ * @info: The framebuffer device.
+ *
+ * Framebuffer layer call to verify the given information and allow us to
+ * update various information depending on the hardware capabilities.
+ */
+static int s3c_fb_check_var(struct fb_var_screeninfo *var,
+                           struct fb_info *info)
+{
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb_pd_win *windata = win->windata;
+       struct s3c_fb *sfb = win->parent;
+
+       dev_dbg(sfb->dev, "checking parameters\n");
+
+       var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres);
+       var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres);
+
+       if (!s3c_fb_validate_win_bpp(win->index, var->bits_per_pixel)) {
+               dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
+                       win->index, var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       /* always ensure these are zero, for drop through cases below */
+       var->transp.offset = 0;
+       var->transp.length = 0;
+
+       switch (var->bits_per_pixel) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               if (!s3c_fb_win_has_palette(win->index, var->bits_per_pixel)) {
+                       /* non palletised, A:1,R:2,G:3,B:2 mode */
+                       var->red.offset         = 4;
+                       var->green.offset       = 2;
+                       var->blue.offset        = 0;
+                       var->red.length         = 5;
+                       var->green.length       = 3;
+                       var->blue.length        = 2;
+                       var->transp.offset      = 7;
+                       var->transp.length      = 1;
+               } else {
+                       var->red.offset = 0;
+                       var->red.length = var->bits_per_pixel;
+                       var->green      = var->red;
+                       var->blue       = var->red;
+               }
+               break;
+
+       case 19:
+               /* 666 with one bit alpha/transparency */
+               var->transp.offset      = 18;
+               var->transp.length      = 1;
+       case 18:
+               var->bits_per_pixel     = 32;
+
+               /* 666 format */
+               var->red.offset         = 12;
+               var->green.offset       = 6;
+               var->blue.offset        = 0;
+               var->red.length         = 6;
+               var->green.length       = 6;
+               var->blue.length        = 6;
+               break;
+
+       case 16:
+               /* 16 bpp, 565 format */
+               var->red.offset         = 11;
+               var->green.offset       = 5;
+               var->blue.offset        = 0;
+               var->red.length         = 5;
+               var->green.length       = 6;
+               var->blue.length        = 5;
+               break;
+
+       case 28:
+       case 25:
+               var->transp.length      = var->bits_per_pixel - 24;
+               var->transp.offset      = 24;
+               /* drop through */
+       case 24:
+               /* our 24bpp is unpacked, so 32bpp */
+               var->bits_per_pixel     = 32;
+       case 32:
+               var->red.offset         = 16;
+               var->red.length         = 8;
+               var->green.offset       = 8;
+               var->green.length       = 8;
+               var->blue.offset        = 0;
+               var->blue.length        = 8;
+               break;
+
+       default:
+               dev_err(sfb->dev, "invalid bpp\n");
+       }
+
+       dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
+       return 0;
+}
+
+/**
+ * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
+ * @sfb: The hardware state.
+ * @pixclock: The pixel clock wanted, in picoseconds.
+ *
+ * Given the specified pixel clock, work out the necessary divider to get
+ * close to the output frequency.
+ */
+static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
+{
+       unsigned long clk = clk_get_rate(sfb->bus_clk);
+       unsigned long long tmp;
+       unsigned int result;
+
+       tmp = (unsigned long long)clk;
+       tmp *= pixclk;
+
+       do_div(tmp, 1000000000UL);
+       result = (unsigned int)tmp / 1000;
+
+       dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
+               pixclk, clk, result, clk / result);
+
+       return result;
+}
+
+/**
+ * s3c_fb_align_word() - align pixel count to word boundary
+ * @bpp: The number of bits per pixel
+ * @pix: The value to be aligned.
+ *
+ * Align the given pixel count so that it will start on an 32bit word
+ * boundary.
+ */
+static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
+{
+       int pix_per_word;
+
+       if (bpp > 16)
+               return pix;
+
+       pix_per_word = (8 * 32) / bpp;
+       return ALIGN(pix, pix_per_word);
+}
+
+/**
+ * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
+ * @info: The framebuffer to change.
+ *
+ * Framebuffer layer request to set a new mode for the specified framebuffer
+ */
+static int s3c_fb_set_par(struct fb_info *info)
+{
+       struct fb_var_screeninfo *var = &info->var;
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb *sfb = win->parent;
+       void __iomem *regs = sfb->regs;
+       int win_no = win->index;
+       u32 data;
+       u32 pagewidth;
+       int clkdiv;
+
+       dev_dbg(sfb->dev, "setting framebuffer parameters\n");
+
+       switch (var->bits_per_pixel) {
+       case 32:
+       case 24:
+       case 16:
+       case 12:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
+       case 8:
+               if (s3c_fb_win_has_palette(win_no, 8))
+                       info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               else
+                       info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
+       case 1:
+               info->fix.visual = FB_VISUAL_MONO01;
+               break;
+       default:
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+       }
+
+       info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
+
+       /* disable the window whilst we update it */
+       writel(0, regs + WINCON(win_no));
+
+       /* use window 0 as the basis for the lcd output timings */
+
+       if (win_no == 0) {
+               clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
+
+               data = sfb->pdata->vidcon0;
+               data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+
+               if (clkdiv > 1)
+                       data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
+               else
+                       data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
+
+               /* write the timing data to the panel */
+
+               data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+               writel(data, regs + VIDCON0);
+
+               data = VIDTCON0_VBPD(var->upper_margin - 1) |
+                      VIDTCON0_VFPD(var->lower_margin - 1) |
+                      VIDTCON0_VSPW(var->vsync_len - 1);
+
+               writel(data, regs + VIDTCON0);
+
+               data = VIDTCON1_HBPD(var->left_margin - 1) |
+                      VIDTCON1_HFPD(var->right_margin - 1) |
+                      VIDTCON1_HSPW(var->hsync_len - 1);
+
+               writel(data, regs + VIDTCON1);
+
+               data = VIDTCON2_LINEVAL(var->yres - 1) |
+                      VIDTCON2_HOZVAL(var->xres - 1);
+               writel(data, regs + VIDTCON2);
+       }
+
+       /* write the buffer address */
+
+       writel(info->fix.smem_start, regs + VIDW_BUF_START(win_no));
+
+       data = info->fix.smem_start + info->fix.line_length * var->yres;
+       writel(data, regs + VIDW_BUF_END(win_no));
+
+       pagewidth = (var->xres * var->bits_per_pixel) >> 3;
+       data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
+              VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
+       writel(data, regs + VIDW_BUF_SIZE(win_no));
+
+       /* write 'OSD' registers to control position of framebuffer */
+
+       data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
+       writel(data, regs + VIDOSD_A(win_no));
+
+       data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
+                                                    var->xres - 1)) |
+              VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
+
+       writel(data, regs + VIDOSD_B(win_no));
+
+       data = var->xres * var->yres;
+       if (s3c_fb_has_osd_d(win_no)) {
+               writel(data, regs + VIDOSD_D(win_no));
+               writel(0, regs + VIDOSD_C(win_no));
+       } else
+               writel(data, regs + VIDOSD_C(win_no));
+
+       data = WINCONx_ENWIN;
+
+       /* note, since we have to round up the bits-per-pixel, we end up
+        * relying on the bitfield information for r/g/b/a to work out
+        * exactly which mode of operation is intended. */
+
+       switch (var->bits_per_pixel) {
+       case 1:
+               data |= WINCON0_BPPMODE_1BPP;
+               data |= WINCONx_BITSWP;
+               data |= WINCONx_BURSTLEN_4WORD;
+               break;
+       case 2:
+               data |= WINCON0_BPPMODE_2BPP;
+               data |= WINCONx_BITSWP;
+               data |= WINCONx_BURSTLEN_8WORD;
+               break;
+       case 4:
+               data |= WINCON0_BPPMODE_4BPP;
+               data |= WINCONx_BITSWP;
+               data |= WINCONx_BURSTLEN_8WORD;
+               break;
+       case 8:
+               if (var->transp.length != 0)
+                       data |= WINCON1_BPPMODE_8BPP_1232;
+               else
+                       data |= WINCON0_BPPMODE_8BPP_PALETTE;
+               data |= WINCONx_BURSTLEN_8WORD;
+               data |= WINCONx_BYTSWP;
+               break;
+       case 16:
+               if (var->transp.length != 0)
+                       data |= WINCON1_BPPMODE_16BPP_A1555;
+               else
+                       data |= WINCON0_BPPMODE_16BPP_565;
+               data |= WINCONx_HAWSWP;
+               data |= WINCONx_BURSTLEN_16WORD;
+               break;
+       case 24:
+       case 32:
+               if (var->red.length == 6) {
+                       if (var->transp.length != 0)
+                               data |= WINCON1_BPPMODE_19BPP_A1666;
+                       else
+                               data |= WINCON1_BPPMODE_18BPP_666;
+               } else if (var->transp.length != 0)
+                       data |= WINCON1_BPPMODE_25BPP_A1888;
+               else
+                       data |= WINCON0_BPPMODE_24BPP_888;
+
+               data |= WINCONx_BURSTLEN_16WORD;
+               break;
+       }
+
+       writel(data, regs + WINCON(win_no));
+       writel(0x0, regs + WINxMAP(win_no));
+
+       return 0;
+}
+
+/**
+ * s3c_fb_update_palette() - set or schedule a palette update.
+ * @sfb: The hardware information.
+ * @win: The window being updated.
+ * @reg: The palette index being changed.
+ * @value: The computed palette value.
+ *
+ * Change the value of a palette register, either by directly writing to
+ * the palette (this requires the palette RAM to be disconnected from the
+ * hardware whilst this is in progress) or schedule the update for later.
+ *
+ * At the moment, since we have no VSYNC interrupt support, we simply set
+ * the palette entry directly.
+ */
+static void s3c_fb_update_palette(struct s3c_fb *sfb,
+                                 struct s3c_fb_win *win,
+                                 unsigned int reg,
+                                 u32 value)
+{
+       void __iomem *palreg;
+       u32 palcon;
+
+       palreg = sfb->regs + s3c_fb_pal_reg(win->index, reg);
+
+       dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
+               __func__, win->index, reg, palreg, value);
+
+       win->palette_buffer[reg] = value;
+
+       palcon = readl(sfb->regs + WPALCON);
+       writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
+
+       if (s3c_fb_pal_is16(win->index))
+               writew(value, palreg);
+       else
+               writel(value, palreg);
+
+       writel(palcon, sfb->regs + WPALCON);
+}
+
+static inline unsigned int chan_to_field(unsigned int chan,
+                                        struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+/**
+ * s3c_fb_setcolreg() - framebuffer layer request to change palette.
+ * @regno: The palette index to change.
+ * @red: The red field for the palette data.
+ * @green: The green field for the palette data.
+ * @blue: The blue field for the palette data.
+ * @trans: The transparency (alpha) field for the palette data.
+ * @info: The framebuffer being changed.
+ */
+static int s3c_fb_setcolreg(unsigned regno,
+                           unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *info)
+{
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb *sfb = win->parent;
+       unsigned int val;
+
+       dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
+               __func__, win->index, regno, red, green, blue);
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               /* true-colour, use pseudo-palette */
+
+               if (regno < 16) {
+                       u32 *pal = info->pseudo_palette;
+
+                       val  = chan_to_field(red,   &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue,  &info->var.blue);
+
+                       pal[regno] = val;
+               }
+               break;
+
+       case FB_VISUAL_PSEUDOCOLOR:
+               if (regno < s3c_fb_win_pal_size(win->index)) {
+                       val  = chan_to_field(red, &win->palette.r);
+                       val |= chan_to_field(green, &win->palette.g);
+                       val |= chan_to_field(blue, &win->palette.b);
+
+                       s3c_fb_update_palette(sfb, win, regno, val);
+               }
+
+               break;
+
+       default:
+               return 1;       /* unknown type */
+       }
+
+       return 0;
+}
+
+/**
+ * s3c_fb_enable() - Set the state of the main LCD output
+ * @sfb: The main framebuffer state.
+ * @enable: The state to set.
+ */
+static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
+{
+       u32 vidcon0 = readl(sfb->regs + VIDCON0);
+
+       if (enable)
+               vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+       else {
+               /* see the note in the framebuffer datasheet about
+                * why you cannot take both of these bits down at the
+                * same time. */
+
+               if (!(vidcon0 & VIDCON0_ENVID))
+                       return;
+
+               vidcon0 |= VIDCON0_ENVID;
+               vidcon0 &= ~VIDCON0_ENVID_F;
+       }
+
+       writel(vidcon0, sfb->regs + VIDCON0);
+}
+
+/**
+ * s3c_fb_blank() - blank or unblank the given window
+ * @blank_mode: The blank state from FB_BLANK_*
+ * @info: The framebuffer to blank.
+ *
+ * Framebuffer layer request to change the power state.
+ */
+static int s3c_fb_blank(int blank_mode, struct fb_info *info)
+{
+       struct s3c_fb_win *win = info->par;
+       struct s3c_fb *sfb = win->parent;
+       unsigned int index = win->index;
+       u32 wincon;
+
+       dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
+
+       wincon = readl(sfb->regs + WINCON(index));
+
+       switch (blank_mode) {
+       case FB_BLANK_POWERDOWN:
+               wincon &= ~WINCONx_ENWIN;
+               sfb->enabled &= ~(1 << index);
+               /* fall through to FB_BLANK_NORMAL */
+
+       case FB_BLANK_NORMAL:
+               /* disable the DMA and display 0x0 (black) */
+               writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
+                      sfb->regs + WINxMAP(index));
+               break;
+
+       case FB_BLANK_UNBLANK:
+               writel(0x0, sfb->regs + WINxMAP(index));
+               wincon |= WINCONx_ENWIN;
+               sfb->enabled |= (1 << index);
+               break;
+
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       default:
+               return 1;
+       }
+
+       writel(wincon, sfb->regs + WINCON(index));
+
+       /* Check the enabled state to see if we need to be running the
+        * main LCD interface, as if there are no active windows then
+        * it is highly likely that we also do not need to output
+        * anything.
+        */
+
+       /* We could do something like the following code, but the current
+        * system of using framebuffer events means that we cannot make
+        * the distinction between just window 0 being inactive and all
+        * the windows being down.
+        *
+        * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
+       */
+
+       /* we're stuck with this until we can do something about overriding
+        * the power control using the blanking event for a single fb.
+        */
+       if (index == 0)
+               s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
+
+       return 0;
+}
+
+static struct fb_ops s3c_fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = s3c_fb_check_var,
+       .fb_set_par     = s3c_fb_set_par,
+       .fb_blank       = s3c_fb_blank,
+       .fb_setcolreg   = s3c_fb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+/**
+ * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
+ * @sfb: The base resources for the hardware.
+ * @win: The window to initialise memory for.
+ *
+ * Allocate memory for the given framebuffer.
+ */
+static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
+                                        struct s3c_fb_win *win)
+{
+       struct s3c_fb_pd_win *windata = win->windata;
+       unsigned int real_size, virt_size, size;
+       struct fb_info *fbi = win->fbinfo;
+       dma_addr_t map_dma;
+
+       dev_dbg(sfb->dev, "allocating memory for display\n");
+
+       real_size = windata->win_mode.xres * windata->win_mode.yres;
+       virt_size = windata->virtual_x * windata->virtual_y;
+
+       dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
+               real_size, windata->win_mode.xres, windata->win_mode.yres,
+               virt_size, windata->virtual_x, windata->virtual_y);
+
+       size = (real_size > virt_size) ? real_size : virt_size;
+       size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
+       size /= 8;
+
+       fbi->fix.smem_len = size;
+       size = PAGE_ALIGN(size);
+
+       dev_dbg(sfb->dev, "want %u bytes for window\n", size);
+
+       fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
+                                                 &map_dma, GFP_KERNEL);
+       if (!fbi->screen_base)
+               return -ENOMEM;
+
+       dev_dbg(sfb->dev, "mapped %x to %p\n",
+               (unsigned int)map_dma, fbi->screen_base);
+
+       memset(fbi->screen_base, 0x0, size);
+       fbi->fix.smem_start = map_dma;
+
+       return 0;
+}
+
+/**
+ * s3c_fb_free_memory() - free the display memory for the given window
+ * @sfb: The base resources for the hardware.
+ * @win: The window to free the display memory for.
+ *
+ * Free the display memory allocated by s3c_fb_alloc_memory().
+ */
+static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
+{
+       struct fb_info *fbi = win->fbinfo;
+
+       dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
+                             fbi->screen_base, fbi->fix.smem_start);
+}
+
+/**
+ * s3c_fb_release_win() - release resources for a framebuffer window.
+ * @win: The window to cleanup the resources for.
+ *
+ * Release the resources that where claimed for the hardware window,
+ * such as the framebuffer instance and any memory claimed for it.
+ */
+static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
+{
+       fb_dealloc_cmap(&win->fbinfo->cmap);
+       unregister_framebuffer(win->fbinfo);
+       s3c_fb_free_memory(sfb, win);
+}
+
+/**
+ * s3c_fb_probe_win() - register an hardware window
+ * @sfb: The base resources for the hardware
+ * @res: Pointer to where to place the resultant window.
+ *
+ * Allocate and do the basic initialisation for one of the hardware's graphics
+ * windows.
+ */
+static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
+                                     struct s3c_fb_win **res)
+{
+       struct fb_var_screeninfo *var;
+       struct fb_videomode *initmode;
+       struct s3c_fb_pd_win *windata;
+       struct s3c_fb_win *win;
+       struct fb_info *fbinfo;
+       int palette_size;
+       int ret;
+
+       dev_dbg(sfb->dev, "probing window %d\n", win_no);
+
+       palette_size = s3c_fb_win_pal_size(win_no);
+
+       fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
+                                  palette_size * sizeof(u32), sfb->dev);
+       if (!fbinfo) {
+               dev_err(sfb->dev, "failed to allocate framebuffer\n");
+               return -ENOENT;
+       }
+
+       windata = sfb->pdata->win[win_no];
+       initmode = &windata->win_mode;
+
+       WARN_ON(windata->max_bpp == 0);
+       WARN_ON(windata->win_mode.xres == 0);
+       WARN_ON(windata->win_mode.yres == 0);
+
+       win = fbinfo->par;
+       var = &fbinfo->var;
+       win->fbinfo = fbinfo;
+       win->parent = sfb;
+       win->windata = windata;
+       win->index = win_no;
+       win->palette_buffer = (u32 *)(win + 1);
+
+       ret = s3c_fb_alloc_memory(sfb, win);
+       if (ret) {
+               dev_err(sfb->dev, "failed to allocate display memory\n");
+               goto err_framebuffer;
+       }
+
+       /* setup the r/b/g positions for the window's palette */
+       s3c_fb_init_palette(win_no, &win->palette);
+
+       /* setup the initial video mode from the window */
+       fb_videomode_to_var(&fbinfo->var, initmode);
+
+       fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
+       fbinfo->fix.accel       = FB_ACCEL_NONE;
+       fbinfo->var.activate    = FB_ACTIVATE_NOW;
+       fbinfo->var.vmode       = FB_VMODE_NONINTERLACED;
+       fbinfo->var.bits_per_pixel = windata->default_bpp;
+       fbinfo->fbops           = &s3c_fb_ops;
+       fbinfo->flags           = FBINFO_FLAG_DEFAULT;
+       fbinfo->pseudo_palette  = &win->pseudo_palette;
+
+       /* prepare to actually start the framebuffer */
+
+       ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
+       if (ret < 0) {
+               dev_err(sfb->dev, "check_var failed on initial video params\n");
+               goto err_alloc_mem;
+       }
+
+       /* create initial colour map */
+
+       ret = fb_alloc_cmap(&fbinfo->cmap, s3c_fb_win_pal_size(win_no), 1);
+       if (ret == 0)
+               fb_set_cmap(&fbinfo->cmap, fbinfo);
+       else
+               dev_err(sfb->dev, "failed to allocate fb cmap\n");
+
+       s3c_fb_set_par(fbinfo);
+
+       dev_dbg(sfb->dev, "about to register framebuffer\n");
+
+       /* run the check_var and set_par on our configuration. */
+
+       ret = register_framebuffer(fbinfo);
+       if (ret < 0) {
+               dev_err(sfb->dev, "failed to register framebuffer\n");
+               goto err_alloc_mem;
+       }
+
+       *res = win;
+       dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
+
+       return 0;
+
+err_alloc_mem:
+       s3c_fb_free_memory(sfb, win);
+
+err_framebuffer:
+       unregister_framebuffer(fbinfo);
+       return ret;
+}
+
+/**
+ * s3c_fb_clear_win() - clear hardware window registers.
+ * @sfb: The base resources for the hardware.
+ * @win: The window to process.
+ *
+ * Reset the specific window registers to a known state.
+ */
+static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
+{
+       void __iomem *regs = sfb->regs;
+
+       writel(0, regs + WINCON(win));
+       writel(0xffffff, regs + WxKEYCONy(win, 0));
+       writel(0xffffff, regs + WxKEYCONy(win, 1));
+
+       writel(0, regs + VIDOSD_A(win));
+       writel(0, regs + VIDOSD_B(win));
+       writel(0, regs + VIDOSD_C(win));
+}
+
+static int __devinit s3c_fb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct s3c_fb_platdata *pd;
+       struct s3c_fb *sfb;
+       struct resource *res;
+       int win;
+       int ret = 0;
+
+       pd = pdev->dev.platform_data;
+       if (!pd) {
+               dev_err(dev, "no platform data specified\n");
+               return -EINVAL;
+       }
+
+       sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
+       if (!sfb) {
+               dev_err(dev, "no memory for framebuffers\n");
+               return -ENOMEM;
+       }
+
+       sfb->dev = dev;
+       sfb->pdata = pd;
+
+       sfb->bus_clk = clk_get(dev, "lcd");
+       if (IS_ERR(sfb->bus_clk)) {
+               dev_err(dev, "failed to get bus clock\n");
+               goto err_sfb;
+       }
+
+       clk_enable(sfb->bus_clk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "failed to find registers\n");
+               ret = -ENOENT;
+               goto err_clk;
+       }
+
+       sfb->regs_res = request_mem_region(res->start, resource_size(res),
+                                          dev_name(dev));
+       if (!sfb->regs_res) {
+               dev_err(dev, "failed to claim register region\n");
+               ret = -ENOENT;
+               goto err_clk;
+       }
+
+       sfb->regs = ioremap(res->start, resource_size(res));
+       if (!sfb->regs) {
+               dev_err(dev, "failed to map registers\n");
+               ret = -ENXIO;
+               goto err_req_region;
+       }
+
+       dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
+
+       /* setup gpio and output polarity controls */
+
+       pd->setup_gpio();
+
+       writel(pd->vidcon1, sfb->regs + VIDCON1);
+
+       /* zero all windows before we do anything */
+
+       for (win = 0; win < S3C_FB_MAX_WIN; win++)
+               s3c_fb_clear_win(sfb, win);
+
+       /* we have the register setup, start allocating framebuffers */
+
+       for (win = 0; win < S3C_FB_MAX_WIN; win++) {
+               if (!pd->win[win])
+                       continue;
+
+               ret = s3c_fb_probe_win(sfb, win, &sfb->windows[win]);
+               if (ret < 0) {
+                       dev_err(dev, "failed to create window %d\n", win);
+                       for (; win >= 0; win--)
+                               s3c_fb_release_win(sfb, sfb->windows[win]);
+                       goto err_ioremap;
+               }
+       }
+
+       platform_set_drvdata(pdev, sfb);
+
+       return 0;
+
+err_ioremap:
+       iounmap(sfb->regs);
+
+err_req_region:
+       release_resource(sfb->regs_res);
+       kfree(sfb->regs_res);
+
+err_clk:
+       clk_disable(sfb->bus_clk);
+       clk_put(sfb->bus_clk);
+
+err_sfb:
+       kfree(sfb);
+       return ret;
+}
+
+/**
+ * s3c_fb_remove() - Cleanup on module finalisation
+ * @pdev: The platform device we are bound to.
+ *
+ * Shutdown and then release all the resources that the driver allocated
+ * on initialisation.
+ */
+static int __devexit s3c_fb_remove(struct platform_device *pdev)
+{
+       struct s3c_fb *sfb = platform_get_drvdata(pdev);
+       int win;
+
+       for (win = 0; win <= S3C_FB_MAX_WIN; win++)
+               s3c_fb_release_win(sfb, sfb->windows[win]);
+
+       iounmap(sfb->regs);
+
+       clk_disable(sfb->bus_clk);
+       clk_put(sfb->bus_clk);
+
+       release_resource(sfb->regs_res);
+       kfree(sfb->regs_res);
+
+       kfree(sfb);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct s3c_fb *sfb = platform_get_drvdata(pdev);
+       struct s3c_fb_win *win;
+       int win_no;
+
+       for (win_no = S3C_FB_MAX_WIN; win_no >= 0; win_no--) {
+               win = sfb->windows[win_no];
+               if (!win)
+                       continue;
+
+               /* use the blank function to push into power-down */
+               s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
+       }
+
+       clk_disable(sfb->bus_clk);
+       return 0;
+}
+
+static int s3c_fb_resume(struct platform_device *pdev)
+{
+       struct s3c_fb *sfb = platform_get_drvdata(pdev);
+       struct s3c_fb_win *win;
+       int win_no;
+
+       clk_enable(sfb->bus_clk);
+
+       for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
+               win = sfb->windows[win_no];
+               if (!win)
+                       continue;
+
+               dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
+               s3c_fb_set_par(win->fbinfo);
+       }
+
+       return 0;
+}
+#else
+#define s3c_fb_suspend NULL
+#define s3c_fb_resume  NULL
+#endif
+
+static struct platform_driver s3c_fb_driver = {
+       .probe          = s3c_fb_probe,
+       .remove         = s3c_fb_remove,
+       .suspend        = s3c_fb_suspend,
+       .resume         = s3c_fb_resume,
+       .driver         = {
+               .name   = "s3c-fb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init s3c_fb_init(void)
+{
+       return platform_driver_register(&s3c_fb_driver);
+}
+
+static void __exit s3c_fb_cleanup(void)
+{
+       platform_driver_unregister(&s3c_fb_driver);
+}
+
+module_init(s3c_fb_init);
+module_exit(s3c_fb_cleanup);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-fb");
index f5252c2552fdd482731eef311f3f4ff14a70f03d..bba53714a7b13188796c72ace46b692a5b53cfea 100644 (file)
@@ -837,6 +837,8 @@ static int sgivwfb_remove(struct platform_device *dev)
                iounmap(par->regs);
                iounmap(info->screen_base);
                release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
+               fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
        }
        return 0;
 }
index df5336561d1304d4e35c586fead0d6942d9892cf..a439159204a8490fe79e2e0bebae3f9b47167481 100644 (file)
@@ -795,8 +795,9 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
     if (!retval || retval == 4)
        return -EINVAL;                 
 
-    /* This has to been done !!! */    
-    fb_alloc_cmap(&info->cmap, cmap_len, 0);
+    /* This has to be done! */
+    if (fb_alloc_cmap(&info->cmap, cmap_len, 0))
+       return -ENOMEM;
        
     /* 
      * The following is done in the case of having hardware with a static 
@@ -820,8 +821,10 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
      */
     /* xxxfb_set_par(info); */
 
-    if (register_framebuffer(info) < 0)
+    if (register_framebuffer(info) < 0) {
+       fb_dealloc_cmap(&info->cmap);
        return -EINVAL;
+    }
     printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
           info->fix.id);
     pci_set_drvdata(dev, info); /* or platform_set_drvdata(pdev, info) */
index dcd98793d5681e14e7521e1f9efcf92806fe4f8b..eb5d73a0670244cee172b1d31aa028a1a86ff8f4 100644 (file)
@@ -1525,7 +1525,10 @@ static int sm501fb_init_fb(struct fb_info *fb,
        }
 
        /* initialise and set the palette */
-       fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);
+       if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) {
+               dev_err(info->dev, "failed to allocate cmap memory\n");
+               return -ENOMEM;
+       }
        fb_set_cmap(&fb->cmap, fb);
 
        ret = (fb->fbops->fb_check_var)(&fb->var, fb);
index 5b11a00f49bc3708fbcc9d7b4866424c1539776f..609d0a521ca2df96d064efe7f71dcbd46fb21541 100644 (file)
@@ -1421,13 +1421,16 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
                goto fail;
        }
        
-       fb_alloc_cmap(&info->cmap, 256, 0);
+       if (fb_alloc_cmap(&info->cmap, 256, 0)) {
+               printk(KERN_ERR "sstfb: can't alloc cmap memory.\n");
+               goto fail;
+       }
 
        /* register fb */
        info->device = &pdev->dev;
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "sstfb: can't register framebuffer.\n");
-               goto fail;
+               goto fail_register;
        }
 
        sstfb_clear_screen(info);
@@ -1441,8 +1444,9 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
 
        return 0;
 
-fail:
+fail_register:
        fb_dealloc_cmap(&info->cmap);
+fail:
        iounmap(info->screen_base);
 fail_fb_remap:
        iounmap(par->mmio_vbase);
index 166481402412538fc2b778924524ff67ae3fe9a6..eabaad765aebcdf1e975c8d68108e098a330175d 100644 (file)
@@ -1262,24 +1262,25 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
        info->flags = FBINFO_DEFAULT;
        info->pseudo_palette = &fb->pseudo_palette;
 
-       /* This has to been done !!! */
-       fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
+       /* This has to be done !!! */
+       if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
+               goto out_err1;
        stifb_init_display(fb);
 
        if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
                printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
                                fix->smem_start, fix->smem_start+fix->smem_len);
-               goto out_err1;
+               goto out_err2;
        }
                
        if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
                printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
                                fix->mmio_start, fix->mmio_start+fix->mmio_len);
-               goto out_err2;
+               goto out_err3;
        }
 
        if (register_framebuffer(&fb->info) < 0)
-               goto out_err3;
+               goto out_err4;
 
        sti->info = info; /* save for unregister_framebuffer() */
 
@@ -1297,13 +1298,14 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
        return 0;
 
 
-out_err3:
+out_err4:
        release_mem_region(fix->mmio_start, fix->mmio_len);
-out_err2:
+out_err3:
        release_mem_region(fix->smem_start, fix->smem_len);
+out_err2:
+       fb_dealloc_cmap(&info->cmap);
 out_err1:
        iounmap(info->screen_base);
-       fb_dealloc_cmap(&info->cmap);
 out_err0:
        kfree(fb);
        return -ENXIO;
index c2ba51b7ea18af54dd9be3d0a6b25b90cf93edae..18b950706cad47f70ee83282a7cb7d905d902ef6 100644 (file)
@@ -349,11 +349,14 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev,
        if (err < 0) {
                printk(KERN_ERR "e3d: Could not register framebuffer %s\n",
                       pci_name(pdev));
-               goto err_unmap_fb;
+               goto err_free_cmap;
        }
 
        return 0;
 
+err_free_cmap:
+       fb_dealloc_cmap(&info->cmap);
+
 err_unmap_fb:
        iounmap(ep->fb_base);
 
@@ -389,6 +392,7 @@ static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
        pci_release_region(pdev, 0);
        pci_release_region(pdev, 1);
 
+       fb_dealloc_cmap(&info->cmap);
         framebuffer_release(info);
 
        pci_disable_device(pdev);
index 14bd3f3680b8e549d6662e4d5779b8b259886a05..ee64771fbe3dd0dee90f15664606901884b85245 100644 (file)
@@ -1393,6 +1393,7 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev)
        release_mem_region(pci_resource_start(pdev, 0),
                           pci_resource_len(pdev, 0));
        pci_set_drvdata(pdev, NULL);
+       fb_dealloc_cmap(&info->cmap);
        framebuffer_release(info);
 }
 
index 680642c089c9202b64f57f103e264b5ebc035609..a86046ff60ad527f7f10cf16a0451df33abc45a2 100644 (file)
@@ -1663,7 +1663,7 @@ tgafb_register(struct device *dev)
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "tgafb: Could not register framebuffer\n");
                ret = -EINVAL;
-               goto err1;
+               goto err2;
        }
 
        if (tga_bus_pci) {
@@ -1682,6 +1682,8 @@ tgafb_register(struct device *dev)
 
        return 0;
 
+ err2:
+       fb_dealloc_cmap(&info->cmap);
  err1:
        if (mem_base)
                iounmap(mem_base);
index 479b2e79ad68ea569882bf7ce7df7645d648a02d..03a9c35e9f552a951ff9ed6798536633d515e020 100644 (file)
@@ -2,7 +2,7 @@
  * Frame buffer driver for Trident TGUI, Blade and Image series
  *
  * Copyright 2001, 2002 - Jani Monoses   <jani@iv.ro>
- *
+ * Copyright 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
  *
  * CREDITS:(in order of appearance)
  *     skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
@@ -490,7 +490,6 @@ static void tgui_copy_rect(struct tridentfb_par *par,
 /*
  * Accel functions called by the upper layers
  */
-#ifdef CONFIG_FB_TRIDENT_ACCEL
 static void tridentfb_fillrect(struct fb_info *info,
                               const struct fb_fillrect *fr)
 {
@@ -565,11 +564,6 @@ static int tridentfb_sync(struct fb_info *info)
                par->wait_engine(par);
        return 0;
 }
-#else
-#define tridentfb_fillrect cfb_fillrect
-#define tridentfb_copyarea cfb_copyarea
-#define tridentfb_imageblit cfb_imageblit
-#endif /* CONFIG_FB_TRIDENT_ACCEL */
 
 /*
  * Hardware access functions
@@ -1333,9 +1327,7 @@ static struct fb_ops tridentfb_ops = {
        .fb_fillrect = tridentfb_fillrect,
        .fb_copyarea = tridentfb_copyarea,
        .fb_imageblit = tridentfb_imageblit,
-#ifdef CONFIG_FB_TRIDENT_ACCEL
        .fb_sync = tridentfb_sync,
-#endif
 };
 
 static int __devinit trident_pci_probe(struct pci_dev *dev,
@@ -1359,10 +1351,6 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
 
        chip_id = id->device;
 
-#ifndef CONFIG_FB_TRIDENT_ACCEL
-       noaccel = 1;
-#endif
-
        /* If PCI id is 0x9660 then further detect chip type */
 
        if (chip_id == TGUI9660) {
@@ -1490,6 +1478,9 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
        } else
                info->flags |= FBINFO_HWACCEL_DISABLED;
 
+       if (is_blade(chip_id) && chip_id != BLADE3D)
+               info->flags |= FBINFO_READS_FAST;
+
        info->pixmap.addr = kmalloc(4096, GFP_KERNEL);
        if (!info->pixmap.addr) {
                err = -ENOMEM;
@@ -1563,6 +1554,7 @@ static void __devexit trident_pci_remove(struct pci_dev *dev)
        release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
        pci_set_drvdata(dev, NULL);
        kfree(info->pixmap.addr);
+       fb_dealloc_cmap(&info->cmap);
        framebuffer_release(info);
 }
 
@@ -1663,4 +1655,5 @@ module_exit(tridentfb_exit);
 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("cyblafb");
 
index 74ae75899009fe3ad831c37ec14868d467b97ad7..0b370aebdbfd24d528cab7442d1983801b36b7c5 100644 (file)
@@ -189,7 +189,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
        uvfb_tasks[seq] = task;
        mutex_unlock(&uvfb_lock);
 
-       err = cn_netlink_send(m, 0, gfp_any());
+       err = cn_netlink_send(m, 0, GFP_KERNEL);
        if (err == -ESRCH) {
                /*
                 * Try to start the userspace helper if sending
@@ -850,14 +850,16 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
        if (vbemode) {
                for (i = 0; i < par->vbe_modes_cnt; i++) {
                        if (par->vbe_modes[i].mode_id == vbemode) {
+                               modeid = i;
+                               uvesafb_setup_var(&info->var, info,
+                                               &par->vbe_modes[modeid]);
                                fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-                                                       &info->var, info);
+                                               &info->var, info);
                                /*
                                 * With pixclock set to 0, the default BIOS
                                 * timings will be used in set_par().
                                 */
                                info->var.pixclock = 0;
-                               modeid = i;
                                goto gotmode;
                        }
                }
@@ -904,8 +906,11 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
                        fb_videomode_to_var(&info->var, mode);
                } else {
                        modeid = par->vbe_modes[0].mode_id;
+                       uvesafb_setup_var(&info->var, info,
+                                       &par->vbe_modes[modeid]);
                        fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-                                   &info->var, info);
+                                       &info->var, info);
+
                        goto gotmode;
                }
        }
@@ -917,9 +922,9 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
        if (modeid == -1)
                return -EINVAL;
 
-gotmode:
        uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]);
 
+gotmode:
        /*
         * If we are not VBE3.0+ compliant, we're done -- the BIOS will
         * ignore our timings anyway.
@@ -1552,7 +1557,7 @@ static void __devinit uvesafb_init_info(struct fb_info *info,
        }
 
        info->flags = FBINFO_FLAG_DEFAULT |
-                       (par->ypan) ? FBINFO_HWACCEL_YPAN : 0;
+                       (par->ypan ? FBINFO_HWACCEL_YPAN : 0);
 
        if (!par->ypan)
                info->fbops->fb_pan_display = NULL;
index 7b0cef9ca8f98d52fcc927050204f1ec874194b8..4bb9a0b18950028b21546eb443ac9f215bf97f8e 100644 (file)
@@ -119,7 +119,7 @@ static void set_valkyrie_clock(unsigned char *params);
 static int valkyrie_var_to_par(struct fb_var_screeninfo *var,
        struct fb_par_valkyrie *par, const struct fb_info *fb_info);
 
-static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p);
+static int valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p);
 static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix);
 static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p);
 
@@ -381,18 +381,22 @@ int __init valkyriefb_init(void)
 
        valkyrie_choose_mode(p);
        mac_vmode_to_var(default_vmode, default_cmode, &p->info.var);
-       valkyrie_init_info(&p->info, p);
+       err = valkyrie_init_info(&p->info, p);
+       if (err < 0)
+               goto out_free;
        valkyrie_init_fix(&p->info.fix, p);
        if (valkyriefb_set_par(&p->info))
                /* "can't happen" */
                printk(KERN_ERR "valkyriefb: can't set default video mode\n");
 
        if ((err = register_framebuffer(&p->info)) != 0)
-               goto out_free;
+               goto out_cmap_free;
 
        printk(KERN_INFO "fb%d: valkyrie frame buffer device\n", p->info.node);
        return 0;
 
+ out_cmap_free:
+       fb_dealloc_cmap(&p->info.cmap);
  out_free:
        if (p->frame_buffer)
                iounmap(p->frame_buffer);
@@ -538,14 +542,15 @@ static void valkyrie_par_to_fix(struct fb_par_valkyrie *par,
                /* ywrapstep, xpanstep, ypanstep */
 }
 
-static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
+static int __init valkyrie_init_info(struct fb_info *info,
+               struct fb_info_valkyrie *p)
 {
        info->fbops = &valkyriefb_ops;
        info->screen_base = p->frame_buffer + 0x1000;
        info->flags = FBINFO_DEFAULT;
        info->pseudo_palette = p->pseudo_palette;
-       fb_alloc_cmap(&info->cmap, 256, 0);
        info->par = &p->par;
+       return fb_alloc_cmap(&info->cmap, 256, 0);
 }
 
 
index e16322d157d0b9446a9e9cf6d0c2a99cc2898c7e..d6856f43d241df13d14ab43113c9472387ecbdef 100644 (file)
@@ -438,7 +438,7 @@ static int __init vesafb_probe(struct platform_device *dev)
        info->var = vesafb_defined;
        info->fix = vesafb_fix;
        info->flags = FBINFO_FLAG_DEFAULT |
-               (ypan) ? FBINFO_HWACCEL_YPAN : 0;
+               (ypan ? FBINFO_HWACCEL_YPAN : 0);
 
        if (!ypan)
                info->fbops->fb_pan_display = NULL;
index 93fe08d6c78f6f2a36b84c8977ad95c2781ff6f1..cc919ae465711e17cee1648b61bb679576ed3242 100644 (file)
@@ -543,6 +543,7 @@ static int vfb_remove(struct platform_device *dev)
        if (info) {
                unregister_framebuffer(info);
                rvfree(videomemory, videomemorysize);
+               fb_dealloc_cmap(&info->cmap);
                framebuffer_release(info);
        }
        return 0;
index 632523ff1fb765178421c483313303551df7bc51..45c54bfe99bb86f68b94be7dc73879d50b78d74d 100644 (file)
@@ -267,13 +267,17 @@ int viafb_wait_engine_idle(void)
        int loop = 0;
 
        while (!(readl(viaparinfo->io_virt + VIA_REG_STATUS) &
-                       VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP))
+                       VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
+               loop++;
                cpu_relax();
+       }
 
        while ((readl(viaparinfo->io_virt + VIA_REG_STATUS) &
                    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
-                   (loop++ < MAXLOOP))
+                   (loop < MAXLOOP)) {
+               loop++;
                cpu_relax();
+       }
 
        return loop >= MAXLOOP;
 }
index 37b433a08ce8fcaf893b47dcff8719ae4d4d6033..e327b84820d28fdb96c6eab1d74b2a08e78e67ab 100644 (file)
@@ -2059,25 +2059,21 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
        if (viafb_entry) {
                entry = create_proc_entry("dvp0", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dvp0_proc_read;
                        entry->write_proc = viafb_dvp0_proc_write;
                }
                entry = create_proc_entry("dvp1", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dvp1_proc_read;
                        entry->write_proc = viafb_dvp1_proc_write;
                }
                entry = create_proc_entry("dfph", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dfph_proc_read;
                        entry->write_proc = viafb_dfph_proc_write;
                }
                entry = create_proc_entry("dfpl", 0, *viafb_entry);
                if (entry) {
-                       entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dfpl_proc_read;
                        entry->write_proc = viafb_dfpl_proc_write;
                }
@@ -2086,7 +2082,6 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
                    viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
                        entry = create_proc_entry("vt1636", 0, *viafb_entry);
                        if (entry) {
-                               entry->owner = THIS_MODULE;
                                entry->read_proc = viafb_vt1636_proc_read;
                                entry->write_proc = viafb_vt1636_proc_write;
                        }
index 5777196bf6c9cc873ef07dd6e79eb10f1775379b..5c52369ab9bb81115376ec3e8b959908bdbe8d8f 100644 (file)
 
 #ifdef DEBUG
 /* For development, we want to crash whenever the ring is screwed. */
-#define BAD_RING(vq, fmt...)                   \
-       do { dev_err(&vq->vq.vdev->dev, fmt); BUG(); } while(0)
-#define START_USE(vq) \
-       do { if ((vq)->in_use) panic("in_use = %i\n", (vq)->in_use); (vq)->in_use = __LINE__; mb(); } while(0)
-#define END_USE(vq) \
-       do { BUG_ON(!(vq)->in_use); (vq)->in_use = 0; mb(); } while(0)
+#define BAD_RING(_vq, fmt...)                  \
+       do { dev_err(&(_vq)->vq.vdev->dev, fmt); BUG(); } while(0)
+/* Caller is supposed to guarantee no reentry. */
+#define START_USE(_vq)                                         \
+       do {                                                    \
+               if ((_vq)->in_use)                              \
+                       panic("in_use = %i\n", (_vq)->in_use);  \
+               (_vq)->in_use = __LINE__;                       \
+               mb();                                           \
+       } while(0)
+#define END_USE(_vq) \
+       do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
 #else
-#define BAD_RING(vq, fmt...)                   \
-       do { dev_err(&vq->vq.vdev->dev, fmt); (vq)->broken = true; } while(0)
+#define BAD_RING(_vq, fmt...)                  \
+       do { dev_err(&_vq->vq.vdev->dev, fmt); (_vq)->broken = true; } while(0)
 #define START_USE(vq)
 #define END_USE(vq)
 #endif
index 442bd8bbd4a5dcbed086cae48fed1350ba9e31b6..3ebe9726a9e55471ae9383fe262fc61de2727200 100644 (file)
@@ -69,7 +69,7 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)
                return w1_read_bit(dev);
        else {
                w1_write_bit(dev, 0);
-               return(0);
+               return 0;
        }
 }
 
@@ -184,17 +184,17 @@ static u8 w1_read_bit(struct w1_master *dev)
  */
 u8 w1_triplet(struct w1_master *dev, int bdir)
 {
-       if ( dev->bus_master->triplet )
-               return(dev->bus_master->triplet(dev->bus_master->data, bdir));
+       if (dev->bus_master->triplet)
+               return dev->bus_master->triplet(dev->bus_master->data, bdir);
        else {
                u8 id_bit   = w1_touch_bit(dev, 1);
                u8 comp_bit = w1_touch_bit(dev, 1);
                u8 retval;
 
-               if ( id_bit && comp_bit )
-                       return(0x03);  /* error */
+               if (id_bit && comp_bit)
+                       return 0x03;  /* error */
 
-               if ( !id_bit && !comp_bit ) {
+               if (!id_bit && !comp_bit) {
                        /* Both bits are valid, take the direction given */
                        retval = bdir ? 0x04 : 0;
                } else {
@@ -203,11 +203,11 @@ u8 w1_triplet(struct w1_master *dev, int bdir)
                        retval = id_bit ? 0x05 : 0x02;
                }
 
-               if ( dev->bus_master->touch_bit )
+               if (dev->bus_master->touch_bit)
                        w1_touch_bit(dev, bdir);
                else
                        w1_write_bit(dev, bdir);
-               return(retval);
+               return retval;
        }
 }
 
index 6cf155d6b350f1549aedca4dff0e3e6684a733d1..3137361ccbfe077eecfdfdaab61d4373224ed45c 100644 (file)
@@ -380,7 +380,7 @@ asm(".text                      \n\t"
  *     This function checks whether or not a SMBIOS/DMI record is
  *     the 64bit CRU info or not
  */
-static void __devinit dmi_find_cru(const struct dmi_header *dm)
+static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy)
 {
        struct smbios_cru64_info *smbios_cru64_ptr;
        unsigned long cru_physical_address;
@@ -403,7 +403,7 @@ static int __devinit detect_cru_service(void)
 {
        cru_rom_addr = NULL;
 
-       dmi_walk(dmi_find_cru);
+       dmi_walk(dmi_find_cru, NULL);
 
        /* if cru_rom_addr has been set then we found a CRU service */
        return ((cru_rom_addr != NULL) ? 0 : -ENODEV);
index 526187c8a12de73ccbab828eb815eac4c2abd52e..8ac9cddac5754fdbf8ef9df33550a47bfba318f4 100644 (file)
@@ -37,7 +37,7 @@ config XEN_COMPAT_XENFS
          The old xenstore userspace tools expect to find "xenbus"
          under /proc/xen, but "xenbus" is now found at the root of the
          xenfs filesystem.  Selecting this causes the kernel to create
-         the compatibilty mount point /proc/xen if it is running on
+         the compatibility mount point /proc/xen if it is running on
          a xen platform.
          If in doubt, say yes.
 
index 3ccd348d112d62036f4e63a038d23deca7ed67f7..0d61db1e7b49bc5f5fd095795e74001dadda1bc3 100644 (file)
@@ -39,12 +39,6 @@ static int xen_suspend(void *data)
 
        BUG_ON(!irqs_disabled());
 
-       err = device_power_down(PMSG_SUSPEND);
-       if (err) {
-               printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
-                      err);
-               return err;
-       }
        err = sysdev_suspend(PMSG_SUSPEND);
        if (err) {
                printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
@@ -69,7 +63,6 @@ static int xen_suspend(void *data)
        xen_mm_unpin_all();
 
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
 
        if (!*cancelled) {
                xen_irq_resume();
@@ -108,6 +101,12 @@ static void do_suspend(void)
        /* XXX use normal device tree? */
        xenbus_suspend();
 
+       err = device_power_down(PMSG_SUSPEND);
+       if (err) {
+               printk(KERN_ERR "device_power_down failed: %d\n", err);
+               goto resume_devices;
+       }
+
        err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
        if (err) {
                printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
@@ -120,6 +119,9 @@ static void do_suspend(void)
        } else
                xenbus_suspend_cancel();
 
+       device_power_up(PMSG_RESUME);
+
+resume_devices:
        device_resume(PMSG_RESUME);
 
        /* Make sure timer events get retriggered on all CPUs */
diff --git a/firmware/3com/3C359.bin.ihex b/firmware/3com/3C359.bin.ihex
new file mode 100644 (file)
index 0000000..781bac3
--- /dev/null
@@ -0,0 +1,1573 @@
+:10000000FE3A0000000000000000000000000000B8
+:1000100000000000000000000000000000000000E0
+:1000200000000000000000000000000000000000D0
+:1000300000000000000000000000000000000000C0
+:1000400000000000000030332F30322F39392031CA
+:10005000373A3133000000000000000000000000CB
+:1000600030313233343536373839414243444546EE
+:10007000000007FF0200FE9F0600007C48000070A1
+:100080008200FFFF8600FFFF8800FFFF9A00FFFF4E
+:10009000FFFF1100C000FFFFFFFF11223344556630
+:1000A00033434F4D20424142451140C000FFFFFF06
+:1000B000FF1122334455665374617274206F6620B9
+:1000C0004C4C43206672616D652E2020546F746124
+:1000D0006C20646174612073697A6520697320788B
+:1000E000787820202042414245E8D201833EF7340F
+:1000F000007521E84100833EF734007517E882005F
+:10010000833EF73400750DE8BF00833EF734007579
+:1001100003E84102C31EB800F08ED833F6B9008060
+:1001200033DBAD03D8E2FB1FB8000083FB00740390
+:10013000B82200A3F734C3FABA5600B0FFEE33C0BA
+:100140008EC033F6B9FF7F833EFF340074088D3EC6
+:100150003061D1EF2BCF268B1C26C704FFFF2683EF
+:100160003CFF751726C704000026833C00750C264B
+:10017000891C4646E2E0B80000EB03B82400A3F770
+:1001800034C3FAB4D79E733A753879367B349FB14D
+:1001900005D2EC732DB040D0E071277925D0E07303
+:1001A000217B1F32C0751B32E49E721674147812C4
+:1001B0007A109FD2EC720BD0E470077505B800007E
+:1001C000EB03B82600A3F734C3FABA5A0033C0EFE2
+:1001D000EFEFEFB000E656B000E654BA5200B801B7
+:1001E00001EFE8CA003C01757FE88300BA5200B80D
+:1001F0000202EFE8B9003C02756EE87A00BA5200DC
+:10020000B80404EFE8A8003C04755DE87100BA5238
+:1002100000B80808EFE897003C08754CE86800BA99
+:100220005200B81010EFE886003C10753BE85F0004
+:10023000BA5200B82020EFE875003C20752AE85635
+:1002400000BA5200B84040EFE864003C407519E83D
+:100250004D00BA5200B88080EFE853003C8075082A
+:10026000E84400B80000EB03B82800A3F734C3BA91
+:100270005A00B80080EFC3BA5A00B80180EFC3BA81
+:100280005A00B80280EFC3BA5A00B80380EFC3BA6D
+:100290005A00B80480EFC3BA5A00B80580EFC3BA59
+:1002A0005A00B80680EFC3BA5A00B80780EFC3B946
+:1002B000FFFFE458E4543C0075034975F7C3FA3274
+:1002C000C0E656E4563C007403E98200B0FFE656EF
+:1002D000E4563CFF7578BA5200B8FFFFEFED3CFFE3
+:1002E000756CB800FFEFED3C007563B0FFE654E4B9
+:1002F000543CFF755932C0E654E4543C00754FB08D
+:100300000FE650E450240F3C0F7543B000E650E474
+:1003100050240F3C0075378CC88EC0BE7000268BF1
+:1003200014268B5C02B80000EFED23C33D0000757E
+:100330001DB8FFFF23C3EF8BC8ED23C33BC1750E70
+:1003400083C60426833CFF75D5B80000EB03B82AAA
+:1003500000A3F734C3FA33C0BF0020B91700F3ABD2
+:10036000BF0030B91700F3ABBF0022B94000F3ABB8
+:10037000BF0032B94000F3ABFC1E8CC88ED833C02E
+:100380008EC0BE9200BF0020B91700F3A4BEA90022
+:10039000BF0022B94000F3A41FC706FB346400BAB3
+:1003A0000800B80F00EFE88201E89B01720DC70654
+:1003B000F7342C00C706F9340400C3BA0A0033C06E
+:1003C000EFE89801E8B501B81700BA9C00EFB80053
+:1003D00010BA9A00EFB81700A90100740140BA8C56
+:1003E00000EFB80018BA8600EFB80C00BA8200EF30
+:1003F000BA0200ED25F9FF0D0200EFBA060033C086
+:10040000EFBA0400B86000EFBA0000B81800EFBA05
+:100410008000B9FFFFEDA901007504E2F8EB3EBAD8
+:100420000A00EDA900407435A90020743033C0EFF4
+:1004300051B9C800E2FE591E061F268B0E023083FA
+:10044000F91775184949BE0220BF0630F3A61F23CD
+:10045000C9750AFF0EFB347412E94DFF1FB82C005A
+:10046000BB0000A3F734891EF934C3C706FB34640C
+:1004700000E8D300720DC706F7342C00C706F93424
+:100480000400C3E8D600E8F300B80300BA8200EF26
+:10049000B84080BA9800EFB80011BA9600EFB840A3
+:1004A00000A90100740140BA9200EFB80019BA8E99
+:1004B00000EFBA0200ED25F9FF0D0600EFBA0600C5
+:1004C00033C0EFBA0000B81800EFBA8000B9FFFFE0
+:1004D000EDA920007504E2F8EB43BA0A00EDA9008B
+:1004E00040743AA90020743533C0EF51B9C800E216
+:1004F000FE591E061F268B0E023283F940751D49D8
+:1005000049BE0222BF0632F3A61F23C9750FFF0E94
+:10051000FB347403E95AFFB80000EB0B1FB82C0042
+:10052000BB0200891EF934A3F734C3BA0200B80035
+:100530009CEFBA0000B80084EF33C0EFBA0A00EFB6
+:10054000BA0E0033C0EFC3BA0A00B9FFFFED2500B1
+:10055000603D00607404E2F5F8C3F9C3B000E656EC
+:10056000B800FFBA5200EFB9FFFFBA5800ED25EF0F
+:10057000007408BA5A0033C0EFE2EFC3BA8000ED4E
+:10058000BA8400EFBA8000EDC30000000000000054
+:10059000C606EC341533C08ED88EC01E8CC8BE4043
+:1005A00054BF60FE8ED8B91000F3A41FC706803672
+:1005B0001035C7068C3630358D063835A33035A357
+:1005C0003235053301A33435C70636355001C70629
+:1005D000843680FEC7068836C0FEC606C2FEFFC649
+:1005E00006933680C606923600C60680FE80C70691
+:1005F00082FE5450C70684FE2B4DE5CEA90200753D
+:1006000008C60681FE23E90500C60681FE22A1F781
+:1006100034A386FEB8483486E0A388FE8D064E34A7
+:1006200086E0A38AFEB8583486E0A38CFEB89C34DA
+:1006300086E0A38EFE8D06200386E0A390FE33C0E5
+:10064000BA7200EF33C0BA7400EFBA7600EFB88028
+:10065000FE86E0BA7200EFE8BF07BA0C01B840406E
+:10066000EFEDBA6A00B80300C1E0080D0300EFB96E
+:100670000A00E89400BA6A00B80300C1E008EFA1DC
+:100680003234A3A233C706A63304008D06A033C1BB
+:10069000E804CD39C7069036FFFFE9E300630D6635
+:1006A0000D660D8A0DE60E75122E0F030F500F60AA
+:1006B0000D600D600DED0FE912600D600D600D60B5
+:1006C0000D600D2210600D600D600D600DFE10605C
+:1006D0000D600D600D600D600D600DAF0F321037B5
+:1006E0000D600D600D600D600D600D600D600D60A2
+:1006F0000D600D600D600D600D600D600D600D6092
+:100700000D640E000F9509600A49BBFFFFBA6A002D
+:10071000EDA900207438803E80FE127531E84A0051
+:10072000A13234A3A233C706A63304008D06A0333A
+:10073000C1E804CD39E82200C706F3344600C706F5
+:10074000F534FFFFC7069036FFFF58E932004B83B0
+:10075000FB0075B983F90075B0C352BA6A00B803DB
+:1007600000C1E0080D0300EF5AC352BA6A00B80393
+:1007700000C1E008EF5AC3000000000000000000C4
+:10078000688007A19036CD358B3624022EFFA43524
+:100790000AFA8A2694368826E834C606943600FB80
+:1007A00022E47501C3F6C420747DF6C40874058084
+:1007B0000E9236048026E834D7C41E8436268B3742
+:1007C00081E6FF0083FE207605B001E9280053068C
+:1007D000D1E62EFF949D06075B268847023CFF74F6
+:1007E000073CFE7511E93B00F6069236087534F6B3
+:1007F00006923604742D80269236F3803E9536009C
+:10080000752126803F057513C60695360026807F24
+:1008100006007407268B4704A29536BA0C01B8402F
+:1008200040EFED8A26E834F6C4107503E95B00F664
+:10083000C4047405800E9236018026E834EBC43E71
+:100840008836268B3583E67F83FE12720826C645DE
+:100850000201E9240083C620D1E62EFF949D06C440
+:100860003E8836268845023CFF750EF60692360114
+:100870007414F606923602750D80269236FCBA0C78
+:1008800001B82020EFED8A26E834F6C408742280EF
+:1008900026E834F7800E923604F606923608741174
+:1008A00080269236F3BA0C01B84040EFED8A26E874
+:1008B00034F6C40474228026E834FB800E9236019C
+:1008C000F606923602751180269236FEBA0C01B8F1
+:1008D0002020EFED8A26E834F6C40174678026E80C
+:1008E00034FE803EE8FF007439803EE8FF04743235
+:1008F000803EE8FF017521E580A90007740ABA9ED1
+:1009000000B80002EFE9EFFFC606E8FF03BA0C01EA
+:10091000B80808EFEDE92800803EE8FF037406E917
+:100920001E00E90000BA1001B80202EFEDE5000D6B
+:100930001800E700E5820D0200E782C606E8FF0422
+:100940008A26E834F6C402740D8026E834FD802639
+:100950009236BFE84F0BFAA0E83408069436C60674
+:10096000E83400FBC3E8E70FC41E84362EFF1601EF
+:100970000726884702E97EFEE82D10C41E84362E25
+:10098000FF16030726884702E96BFE8E0626022E15
+:10099000FF160707C3C3833EF53400740FFF0EF341
+:1009A000347509E8C4FDC706F5340000F606933631
+:1009B000207430A1C2343B06E934A3E934742480A6
+:1009C0003E953600751DF706E63420007412A92006
+:1009D00000740D8326C234DF8326E934DFE9030087
+:1009E000E8DD09BA0601ED8BD081E200C0C1EA0E54
+:1009F00003167434C1E002110672347304FF0674E6
+:100A000034BA0201ED8BD081E200C0C1EA0E0316B8
+:100A10007034C1E00211066E347304FF067034C7EF
+:100A200006A6330400C706AA3300008D06A033C112
+:100A3000E804CD39C39509950965097809950995A3
+:100A4000099107950996098B0995099509950995C5
+:100A500009950995098BC08BC08BC08BC08BC0904A
+:100A6000F6069336207503E9CC008CC0408EC02674
+:100A70008B0E060086E926890E06008CC2C1E204B0
+:100A8000BE0E0026A10400D0E024C08AE0C0EC0421
+:100A90000AC426A2050026A10800A900C07403E923
+:100AA0009E0026F6061000807503E90A0026A016AF
+:100AB00000241F32E403F0803EEC3406725C803E7A
+:100AC00095360075668BFA33DB8EC326891D268822
+:100AD0005D045150C41E8C36B90F0033C0E82109A3
+:100AE00058590BDB7434FE0EE63A26C6078126C63B
+:100AF00047010026C64702FF26C747040000268993
+:100B00004F0A86F2268957062689770826C647099E
+:100B10000026C6470C02E88C09C3FF06EC338CC0E4
+:100B2000488EC0FAE89710FBE9EBFF8CC0488EC0F6
+:100B3000FAE88A10FBC38CC08EC0FAE88010FBC3B1
+:100B4000803E9536007503E9C200BF080026F60610
+:100B5000100080750503FEE90C0026A01600241F76
+:100B600032E403F003FEA095363C007503E99C00D7
+:100B70003C01740B3C0274143C03741DE98D00C6E7
+:100B800006963601E83C017227E98000C6069636D3
+:100B900002E88300721AE97300C606963601E8225D
+:100BA00001720DC606963602E86C007203E95C001D
+:100BB000530650C41E8C36B90B0033C0E8420858A7
+:100BC00026C6078226C64702FF8D06E0FE86C4269B
+:100BD000894706A0963626884708E8C808075B8339
+:100BE00026AD36FEA1AD36E704BA1001B88080EF1D
+:100BF000EDBA1001B80202EFED52BAE000B84110B0
+:100C0000EF5AB89C03CD39C6069536008CC0488E85
+:100C1000C0FAE8A90FFBC31E061F0633C08EC08BA7
+:100C2000F08D3E20F351B10A26837D0C01752A57C1
+:100C300026837D0E007406E82F00E90300E86607AE
+:100C40005F731633C08ED8268B4D128D75208D3E66
+:100C5000E0FEF3A459071FF9C3FEC9740781C7203A
+:100C600001E9C4FF59071FF8C35150535652573377
+:100C7000DB268A5D0E268B4D128D7D205A87D72666
+:100C80008A451487D74232FF80FF087508FECB22C1
+:100C9000DB75EA33DB23DB7406FEC7D0C8730C5068
+:100CA000268A053804587403E90A0049464723C9CF
+:100CB000740AE9D3FF5A5E5B5859F8C35A5E5B5811
+:100CC00059F9C31E061F0633C08EC086CD2BCE8BAE
+:100CD000F78BC133C9803CFF741680F90673093263
+:100CE000C94648742EE9EDFF3D6000730CE923000E
+:100CF000FEC14648741DE9DCFFB810008D3E183473
+:100D000032EDB106F3A67403E908004823C0740766
+:100D1000E9E9FF071FF8C38D36183433C08ED88D2C
+:100D20003EE0FEB81000B9060056F3A45E483D0050
+:100D30000075F3071FF9C3FF06E433C606EB340062
+:100D4000268B450686E0C1E80448068EC0FE06E60E
+:100D50003AFAE8690EFB07B0FFC30000000000008C
+:100D6000B001C3B000C3F6069336207503B004C3C8
+:100D70008B0E973681E18030268B4704257FCF0B81
+:100D8000C1A39736A3E634B000C3F60693362074A9
+:100D900003B003C3268B4708A39736A3E634268AFD
+:100DA0004720A2FD343C017506C706A13600002687
+:100DB0008A4721A2FE34268B470AA31834A358344D
+:100DC000268B470CA31A34A35A34268B470EA31C38
+:100DD00034A35C34C6062A34C0268B4714257FFF13
+:100DE00009062C34268B471625FFFE25FFFC090635
+:100DF0002E34C6060034C0268B4710A30234268B3F
+:100E00004712A304340653E8840A5B073D000075CB
+:100E100007800E923608B0FEC3B90001A1AC33338F
+:100E2000D2F7F9A3AE33914933D2F7E905003BA3DA
+:100E30004634BF003B893E4434BA6800B8E0E0EF76
+:100E4000A1AE33E762A1AE33BA0801EFA14434E7A3
+:100E500064A14434BA0A01EFB800012D04000D006A
+:100E600010E792C33D0000740A26894707E8833AD9
+:100E7000B007C3A1AE332689472BA1443426894746
+:100E80002DA146342689472F800E933620A188361F
+:100E900086E026894708A1843686E02689470AA18C
+:100EA000803686E02689470CB860FE86E0268947B2
+:100EB0000EA0A136268847108B36883626C64402F7
+:100EC000FFE59EA90008740CBA8400ED0D0800EF40
+:100ED000BA8E00EFE50225F9FFE702BA1001B80269
+:100EE00002EFEDB000C3F6069336207503B001C3E0
+:100EF000802693369FE88D0A800E923608B0FEC396
+:100F0000B000C3F6069336207503B004C3C6062AA4
+:100F100034C0268B4706257FFFA32C34268B470839
+:100F200025FFFE25FFFCA32E34CD52B000C3F606EC
+:100F30009336207503B004C3C6060034C0268B4721
+:100F400006A30234268B4708A30434CD52B000C355
+:100F5000F6069336207503B004C3578D7F0651B94A
+:100F6000070033C0F3AB598D7F06A17A34030639ED
+:100F700037268805A1953726884502A180340306C7
+:100F8000763426884507A1C63426884509A1D8337A
+:100F90002688450A33C0A37A34A33937A39537A3EB
+:100FA0008034A37634A3C634A3D8335FB000C3F62D
+:100FB000069336207503B004C3268B4F0483F906CD
+:100FC000741283F904740D83F900740883F90274B0
+:100FD00003B001C3890EE83A8326AB36F9090EAB9C
+:100FE00036E50225F9FF0BC1E702B000C3F6069310
+:100FF00036207503B004C3268B4F0480F9FF7408B4
+:1010000080F9007410B001C3830EAD3602A1AD3675
+:10101000E704E90A008326AD36FDA1AD36E704B04A
+:1010200000C3F6069336207503B004C3E8D504B0B8
+:1010300000C3F6069336807503B001C326837F068E
+:10104000057503E99D00268B5704268B47082681EA
+:101050007F0600807508ED2689470AE99D002683F2
+:101060007F06017504EFE9920026817F06018075F5
+:1010700009EFED2689470AE9810026837F0602757C
+:101080000726214704E9730026817F060280750C3C
+:1010900026214704ED2689470AE95F0026837F065B
+:1010A00003750726094704E9510026817F0603805E
+:1010B000750C26094704ED2689470AE93D00268379
+:1010C0007F0604750726314704E92F0026817F0635
+:1010D0000480750C26314704ED2689470AE91B0078
+:1010E000B001C3FA53268B4F080BC9740C8D1EE058
+:1010F000FEE852FF83C308E2F85BFBB000C3F606CC
+:10110000933680750AF6069336207503B001C38DB9
+:101110003EE0FEE500268905E50226894502A1ADEF
+:101120003626894504E50626894506E508268945CB
+:1011300008E50A2689450AE50E2689450CE5482674
+:1011400089450EE54A26894510E54C26894512A1B8
+:10115000B73626894514E55026894516E552268975
+:101160004518E5542689451AE5562689451CE55853
+:101170002689451EE56226894520E56426894522A3
+:10118000E56626894524E56826894526E56A268997
+:101190004528E56C2689452AE5702689452CE572A7
+:1011A0002689452EE57426894530E576268945321F
+:1011B000E57C26894534E57E26894536E580268905
+:1011C0004538E5822689453AE5862689453CE58805
+:1011D0002689453EE59A26894540E59E2689454271
+:1011E000E5CC26894544E5CE26894546E5D02689C5
+:1011F0004548E5D22689454ABA0001ED1106663414
+:101200007304FF0668342689454CBA0201EDC1E03B
+:101210000211066E347304FF0670342689454EBAF7
+:101220000401ED11066A347304FF066C3426894507
+:1012300050BA0601EDC1E002110672347304FF06D4
+:10124000743426894552BA0801ED26894554BA0AF4
+:1012500001ED26894556BA0C01ED26894558BA0E8E
+:1012600001ED01067A342689455EBA1001ED268922
+:10127000455CB000C3F6069336807407F6069336D5
+:10128000207503B001C326807F06007530803E952F
+:1012900036007452C6069536008326AD36FEA1ADE3
+:1012A00036E704BA1001B88080EFEDBA1001B80239
+:1012B00002EFEDBAE000B80010EFB000C3268B4794
+:1012C000043D000074203D0300771BBA1001B802F2
+:1012D00000EFBAE000B80110EF830EAD3601A1AD0A
+:1012E00036E704B000C3B006C3F606933680750334
+:1012F000B001C326837F0401740A26837F0402742D
+:1013000019B006C326837F060C77F626837F0A6012
+:1013100077EFE81000720BB046C3E84E007203B0DE
+:1013200046C3B000C351B10A8B3E20F326837D0C27
+:10133000027503E90E00FEC9740781C72001E9EBBD
+:10134000FF59F8C3578D7D0E8D7706B91200F3A4AF
+:101350008D7D208D36E0FE268B4D12F3A4FF060115
+:10136000355F26C7450C010059F9C351B10A8D3EBE
+:1013700020F38D36E0FE26837D0C01751B57E82592
+:10138000005F731433C0B92001F3AA26C7450C02CD
+:1013900000FF0E013559F9C3FEC9740781C720014A
+:1013A000E9D3FF59F8C351268B4D128D7D20F3A64A
+:1013B000740359F8C359F9C300000000000000008D
+:1013C000803EEC34067233FF06F03350C41E8C3678
+:1013D000B90F0033C0E82900588126C234DF7F816D
+:1013E00026E934DF7F0BDB741126C6078426C64747
+:1013F00002FF26894706E8AC00C3FF06EA33E9F599
+:10140000FF57268B3F03F9263B7F027416263B7F4E
+:10141000047C2A3D000075138D7F0803F9263B7F6D
+:10142000027C14FF06DE3333DB5FC3268B7F02268C
+:10143000893F03F9E9060026893F26290F26C705BB
+:10144000FFFF26873F26890D8D5D02508BFB83E9C8
+:101450000233C0F3AA58FE0EEC345FC38B7C023B10
+:101460003C742F833DFF750B8D7C08897C02833D86
+:10147000FF741E8A45023C81750C803EEB3400747B
+:101480000533C0E90B008B0D014C028D750283E919
+:1014900002C3803EEC3406720533C0E9F3FFFF0659
+:1014A000EE33E9BEFFF6069236407401C35756513B
+:1014B000528B368C36E8A4FF7503E91A00E91C004C
+:1014C000FE06EC34C43E8036F3A4800E923640BA59
+:1014D0000C01B88080EFED5A595E5FC3FF06E03320
+:1014E000803C81750CFF06E233C606EB3401E9CF80
+:1014F000FF803C847507FF06E633E9C3FFFF06E87B
+:1015000033E9BCFF8D3EE0FEA17234C706723400A1
+:10151000008905A17434C70674340000894502BAF5
+:101520000401ED894504C745060000A16E34C706D5
+:101530006E340000894508A17034C706703400007D
+:1015400089450ABA0001ED89450CC7450E000032F5
+:10155000E4BA0E01EC894510A17E34C7067E340042
+:1015600000894512A18C34C7068C340000894514CB
+:10157000A18A34C7068A340000894516A17C34C785
+:10158000067C340000894518A18834C706883400D9
+:101590000089451AA1CA33C706CA33000089451C11
+:1015A000A17834C7067834000089451EA1C634C727
+:1015B00006C6340000894520C3000000000000007A
+:1015C000FA33C08ED88EC0B8A001C1E8048ED08D89
+:1015D000268000E80001E810EB8B1EF7348B16F92B
+:1015E000348B36FF3433C0B9EFFF8D3E14002BCF60
+:1015F0002BCED1E9F3AB891EF7348916F93483FE7B
+:1016000000740CB9EFFFBF80FE2BCFD1E9F3ABB96B
+:10161000FFFF81E9003B83FE007403E91B00511EBC
+:10162000B800E08ED833F68D3E00D8B9000CF3A593
+:101630001F59BEFFFF81EE00D82BCE81E100FF894C
+:101640000EAC338D062002C1E804A332348ED036AE
+:10165000C7061E00801836C7062200FF7F36C70661
+:101660000A00FFFF36C7061C0080008D06A002C1DD
+:10167000E804A330348ED036C7061E00502836C783
+:10168000060A00FFFF36C7061C008000B8A001C193
+:10169000E804A33434A3F2338ED08D268000B80042
+:1016A00090E7028D3E70018BC7C1E804B903008941
+:1016B000450E894502C705FFFF83C710050100E2FB
+:1016C000EEE85B01E5CEA3B536E82100E84501A1CF
+:1016D00032348CCBCD370E58A900F0740733F6891D
+:1016E00036FF34C38D3630618936FF34C333C08B47
+:1016F000D08BF2B968002E80BCAC17807501EF83E7
+:10170000C20246E2F1B80200E750B95A0033FFC7FF
+:101710000565188C4D0283C704E2F433C08EC08C7B
+:10172000C88ED88D3E80008D369C17B90800E837EA
+:10173000008D3620218D3EC000B90D00E829008DB6
+:101740003E4001B90A00E81F00E84B0E33C08ED8B6
+:10175000C7064E376F17E748E74CB8409CE74AE5A5
+:101760004890B80070E748C3A583C702E2FAC3E512
+:101770004CC35051565752061E33C08ED8E558D12F
+:10178000E073118BF0D1E633C08ED88BB480008328
+:10179000C60BFFE61F075A5F5E5958CF581CE41C62
+:1017A0006C1C8E1AC01F401A441C6518808080FF74
+:1017B00080030280FFFFFFFFFFFFFFFFFFFFFFFF30
+:1017C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29
+:1017D0008003034380800280420302FF0301030170
+:1017E00001030203FFFFFFFFFFFFFFFF02030103EF
+:1017F00003FF0101FF01FF0101030303FFFFFFFFDF
+:10180000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8
+:10181000FFFFFF02B80F00E784B80FF8E782C3B9F3
+:101820000800890EE63A8D0620038BD0C1E804A398
+:1018300090018BC28BD8C1E8048EC005610026A33D
+:101840000000A1303426A3020083C314D1EB268903
+:101850001E080081C21006E2D926C7060000FFFF5D
+:101860008C069201C35051565752061E33C08ED873
+:10187000E75AFF06BE33BAD200EDCF0000000000E9
+:101880008CCBA13034CD37E906EDB83200C3E88CFB
+:1018900001FE06E234E8210175F0E8530E810EAF37
+:1018A0003600C0C706AD366000F706E63480007526
+:1018B0001AF706E63400087409C706AB360B00E9D0
+:1018C0000F00C706AB360300E90600C706AB3611AA
+:1018D0009CC706A9361800F706E6348000750DF798
+:1018E00006B53602007405830EA93620A1A936E795
+:1018F00000A1AB36E702F706E6348000742EE8F26A
+:101900002F33C00D4100E756A1B1360D0010E70896
+:10191000A1B336E70AA1AF36E706B84000E74E3379
+:10192000C0E70EC70626020000E92300C7064E37AF
+:101930003F208E06303426F7060A00008074072602
+:10194000810E08000080C606E03401B80000C3FE26
+:1019500006E134C606E03400A126020BC07401C3C0
+:10196000E80400B80000C3A1A936E7008B1EAB361F
+:1019700083E306E50225F9FF0BC30D1000E702A182
+:10198000AD36E704C3B80A00E784FE06E534C606B0
+:10199000E334018E06303426F7060A00004074074F
+:1019A00026810E08000040C3C7064E376F17FE069B
+:1019B000E434C606E33400C3C3F606183480750D5C
+:1019C000A118340B061A340B061C347501C3A12E62
+:1019D0003425FFFE8B16E73681E200010BC2A32EF1
+:1019E000348D161000BF0000B908008B850034EF5D
+:1019F00083C2108B850234EF83C2108B850434EFD1
+:101A000083C2E283C7064975E2B800008EC0BE00FB
+:101A100034BFB936B91800F3A5B80000C333C08E7F
+:101A2000C08D3EB033B90800F3AB8D3E3E34B903F0
+:101A300000F3ABC300000000000000000000000045
+:101A40005051565752061E33C08ED8E75AFF06BA79
+:101A500033E5560D2000E756BA7A00ED0826943695
+:101A600033C0B10832ED068EC08D3EE0FFF3AA8E82
+:101A700006323426810E0800000207E55625DFFFF6
+:101A8000E756E9F8FC00BD1B101BD91AF31A505198
+:101A9000565752061E33C08ED8E75AFF06B6335348
+:101AA0000651E580A3B4338BD88BC8251000A3ED75
+:101AB000340BC07414FF068034803EFE340074037F
+:101AC000E90600B88000E89D0483E303D1E32EFF1C
+:101AD00097861A59075BE9A4FCBA20008E063C34AD
+:101AE000833E3C34007503E9F000C7063C34000037
+:101AF000E92A00BA10008E063A34833E3A34007563
+:101B000003E9D5FFC7063A340000E81000E9C9FF31
+:101B1000BA10008E063A34C7063A34000026A114E3
+:101B20000026A30C0026A1160026A30E0026C6063A
+:101B30000A0000C1EA0223D1741CBA200026C7069D
+:101B40000E00EA05260B160C002689160C00FF066F
+:101B50008634FF06DC3326A10C00A9003774162654
+:101B6000C6060A0002A900307404FF067A34FF0694
+:101B7000DA33E94900C0EC0783168A340024073CB5
+:101B8000077504FF068C34FF067E34A130348CC305
+:101B90008EC08EDB26830E0800408CD82687061662
+:101BA0000026833E1400FF740A8EC0268C1E00009F
+:101BB000E90500268C1E140033C08ED8C3C38CC028
+:101BC000870692013DFFFF740D8ED88C060000330E
+:101BD000C08ED8E904008C069001E80100C306839A
+:101BE0003E9001FF7429833E3A34007511BA860095
+:101BF000E81E008C063A34833E9001FF7411833E48
+:101C00003C3400750ABA8800E806008C063C3407AC
+:101C1000C3A190018EC026A10800EF26A1000026D6
+:101C2000C7060000FFFFA390013DFFFF7503A392CD
+:101C300001833EED3400740BB81000E784C706ED55
+:101C4000340000C35051565752061E33C08ED8E799
+:101C50005AFF06BC33E925FB5051565752061E3336
+:101C6000C08ED8E75AFF06B033E911FB50515657E2
+:101C700052061E33C08ED8E75AFF06B43306FF065D
+:101C80007634803EFE3400740407E9F0FAB8800030
+:101C9000E8D30207E9E6FA000000000000000000B7
+:101CA000C61D081D911E5D1E731E891E911EA81D56
+:101CB000911E911EAF1EAF1E151D151D911E991F61
+:101CC000000000000000000000040000000200000E
+:101CD00000010010000100400000000000010000B1
+:101CE00007E999FA5051565752061E33C08ED8E76D
+:101CF0005AFF06B2330668F61CE506A3B2338BF032
+:101D000083E61E2EFFA4A01CE50CA980007406E843
+:101D1000A401E506C353E50C8BD8A9010074148314
+:101D20003EE03A00740D8E063834E8BF06C706E080
+:101D30003A0000E5000D1800E700E5020D1100E78C
+:101D4000028BC35BA901007401C38BD0B80008E704
+:101D5000848BC28E06383426A30C008BD0C1E003DE
+:101D60008316883400FF067C3426833E06000A75FD
+:101D7000218BC22540183D4000740C3D00107512A7
+:101D800026FE0E0A00740BF706EF3420007503E9F7
+:101D90005A068CC0268E06020026830E08002026D6
+:101DA000A3120026A31000C3FF06C433E50CA9014B
+:101DB000007501C3A9F0077401C3FF06D433E50021
+:101DC0000D1800E700C3FF06CA33803EA036087531
+:101DD000148E06303426F7060A00000874072681A0
+:101DE0000E08000008E58225FDFFE782E50C50E5BE
+:101DF00080250007A3E43AE58C250080A3E23A5849
+:101E0000A902007525833EE23A00751E833EE43A3E
+:101E1000007517E5080D000425FF04E708E86A01CE
+:101E2000E5820D0200E782E92100E81A06803EE81B
+:101E3000FF00740A803EE8FF047403E90D00C60643
+:101E4000E8FF01BA0C01B80808EFED803E9F3606A6
+:101E50007505830E993640B80001E90901FF06CCEB
+:101E6000338126AF36FFF7A1AF36E706FF06C6344B
+:101E7000E91E00FF06CE33FF0695378126AF36FFF9
+:101E8000EFA1AF36E706E90800FF06D033FF067A78
+:101E900034FF06D233D1E68E0630342E8B84C01C3C
+:101EA00026090608002E8B84C21C09066637C3E586
+:101EB0000CA98000745650E8F00058A9000175077D
+:101EC000FF06C633E90800FF067834FF06C833E58D
+:101ED0008225FDFFE782E86E05BA1001ED803EE83D
+:101EE000FF00740A803EE8FF047403E91D00C60683
+:101EF000E8FF01BA0C01B80808EFEDE90D00C606CD
+:101F0000E8FF03BA0C01B80808EFEDC3A90100749B
+:101F10001CE82C00833EE03A00740F068E0638342D
+:101F2000E8C904C706E03A000007E95D008BD08EDF
+:101F300006383426A30C00E8060068691DE94A004B
+:101F4000A90004740AB80004FF06D833E91700A9F1
+:101F50000001740AFF063937B80001E90800A9102A
+:101F600000B81000741D090666378CC08E06303428
+:101F700026F7060A000001740726810E08000001FA
+:101F80008EC0C3FF06C233E9F8FFE5000D1800E775
+:101F900000E5020D1100E702C358E943FDE5080D15
+:101FA000000425FF04E708E9E0FFE50EA900087535
+:101FB00001C3E9F5FF000000000000000000000080
+:101FC0005051565752061E33C08ED8E75AFF06B8F6
+:101FD00033E548065357FF164E375F5B833E80015B
+:101FE000FF74588E06800126FF0E0800754D26A14D
+:101FF0000000A3800126C7060000FFFF8CC0268ECC
+:1020000006020026810E080080008BD02687061A63
+:102010000026833E1800FF740A8EC0268916000031
+:10202000E905002689161800833E8001FF740C8E96
+:1020300006800126833E08000074B307E93EF7E5F9
+:102040004C90E502A90020740D25FFDF0D0100E78B
+:10205000020D0020E702E50A8BD8A3F43325C3570D
+:102060000D0010E70AF7069B3600807437F7C300AF
+:10207000807406F7C30008745D8126C2347FFFC7F1
+:102080000635370500B88003CD3981269B36FF7FA2
+:10209000C7060F370400F7069B3640007506C706D3
+:1020A0000F370300F7069B360020742AF7C3000899
+:1020B0007424803E9D36067C1DFF069434830E6694
+:1020C00037208E06303426F7060A000001740726F2
+:1020D000810E08000001F7C30020753BF7069A3710
+:1020E0008000740BFF06893733C0E70EE90400FF58
+:1020F000063B37F7069B360020741C80269E36FF71
+:1021000075158E06303426F7060A00000874072677
+:10211000810E08000008C3C300000000000000009A
+:1021200002230223022302230323DD220223FD21B3
+:102130000223A424F32402238D227A23022397244A
+:102140001B247524022302238E25FB8E067E01FBB1
+:1021500026833E0000FF74F2268E060000FA268BCE
+:102160001E080026231E0A0074E58CC08ED0268B24
+:102170002602008C16F23322FF756A26A11C008A03
+:10218000E38ADC22D8750DD0E824F80AC075F2B0D5
+:1021900080E9EDFFD0E824F80AC07502B08032E48F
+:1021A00026A31C00F7C3080075472E8A9FC5252E5D
+:1021B0008BBFC52680C310268E1D268C1E06008B65
+:1021C000160000C7060000FFFF26891583FAFF7579
+:1021D0000A2E8B97CD26262116080033C08ED826CE
+:1021E000891E0400C38ADFB7002E8A9FC525E9E057
+:1021F000FF2683260800F783C310E9DEFF60061E72
+:102200006887256A001F8E06F2338B0E3434390E30
+:10221000F233740E26810E0A00000226810E080099
+:1022200000022689260200A3F2338ED08D2680007C
+:10223000368926020036891E200036C706080000AF
+:1022400000B90400BE00002E8BBCC52636C705FFB2
+:10225000FF36C74502FFFF83C602E2EB8E067E0112
+:10226000368B0E22008CC026833E0000FF268E0691
+:1022700000007407263B0E22007DEA368C06000023
+:102280008EC0268C160000FB36FF2E1E00061E6830
+:102290008B256A001F2609360800F7C600FF740167
+:1022A000C356522E8BB4C52581E6FF002E8BB4C5D4
+:1022B000268CC28EC026C7060000FFFF8EC2268372
+:1022C0003CFF740F8BD0268754028EC226A30000D9
+:1022D000E90700268944022689045A5EC3061E685F
+:1022E0008B256A001F8E06F23326A30A0026892654
+:1022F0000200A134348ED08D2680008C16F233E992
+:102300004DFECF501E525333C08ED826833E04005C
+:10231000FF26C706040000007403E91A00833EE6A6
+:102320003A027613FF06D6338CC08E063234BE4096
+:1023300000683A23E95EFFE884F85B5A1F58CFE84B
+:10234000E10026C606180010268A1E2900881E1BDA
+:102350003726C7060C00FF7F26A10E00E79C26A1AA
+:102360000800E79AE50080FB0874090D18ACE70047
+:10237000071F58CF0D1800E9F4FF501E0633C08E1A
+:10238000D8833EA1360075B7268B3606002EFF9403
+:10239000DC23071F58CFE88A00E5000D1800E7008E
+:1023A000E84900C353F706EF342000752DE58C256E
+:1023B00000708BD8E58C2500703BC374058BD8E981
+:1023C000F2FF3D00307510E50225EFFFE702C7067A
+:1023D000E03AFFFFE90300E812005BC3A323962362
+:1023E000A423A4239623A4239623962326A029007E
+:1023F000A21B3726C7060C00FF7F26A10E00E79C14
+:1024000026A10800E79AE50025FF53268B36060033
+:1024100083E60E2E0B84AD25E700C3061E688B25D0
+:102420006A001F830EEF3420830E9B3608E50025DB
+:10243000EFFF0D0800E700E500A910007501C3E5F6
+:1024400000A9100075F9C350535156061E33C08EB3
+:10245000D8B80500E784E5080D000425FF04E70867
+:10246000E5000D1800E700E5020D1100E7021F0767
+:102470005E595B58C3501E33C08ED8C706EF340078
+:102480000083269B36F7E5000D1800E700E5020DF6
+:102490001100E7021F58CF60061E6887256A001FDB
+:1024A000E816F5C3061E688B256A001F8EC02683BA
+:1024B0003E0A00007403E8430026C7060A00FFFF37
+:1024C000268B1606008E1E8E018CD88BCA833E008A
+:1024D00000FF8E1E0000740A2B16080073EB290EF5
+:1024E000080026890E0800268C1E00008ED88C0657
+:1024F0000000C360061E6887256A001F8EC08BC857
+:102500008E1E8E0126C7060A0000008CD8833E006E
+:1025100000FF74253B0E00008E1E000075ED8ED866
+:1025200026A10000A300003DFFFF74568ED826A10F
+:10253000080001060800E94900268E1E0200BE18A8
+:1025400000833CFF743C390C74198E1CBE00008360
+:102550003E0000FF742C390E000074078E1E000030
+:10256000E9ECFF26A10000890433C98ED93DFFFFA5
+:10257000751083FE18750B268E1E0200812608003A
+:102580007FFF33C08ED8C31F0761CF1F07CF600600
+:102590001E6887256A001FE506251E003D1E007582
+:1025A000F6B90800E558E75A23C0E0F8C300000078
+:1025B000000000000000AC000000A8008C02040035
+:1025C0000008102000FF0E0C0C0A0A0A0A0808086E
+:1025D0000808080808060606060606060606060691
+:1025E00006060606060404040404040404040404A1
+:1025F000040404040404040404040404040404049B
+:1026000004040404040202020202020202020202A0
+:10261000020202020202020202020202020202029A
+:10262000020202020202020202020202020202028A
+:10263000020202020202020202020202020202027A
+:102640000202020202000000000000000000000080
+:10265000000000000000000000000000000000007A
+:10266000000000000000000000000000000000006A
+:10267000000000000000000000000000000000005A
+:10268000000000000000000000000000000000004A
+:10269000000000000000000000000000000000003A
+:1026A000000000000000000000000000000000002A
+:1026B000000000000000000000000000000000001A
+:1026C00000000000001800140010000C00FF7FFF45
+:1026D000BFFFDFFFEFFFF7FFFBFFFDFFFE7FFFBF49
+:1026E000FFDFFFEFFFF7FFFBFFFDFFFEFF00000036
+:1026F000803EE234017603E9A500B80000E74EB958
+:102700002800E2FEC606453702BF3F282E8B45084B
+:10271000E74EB92800E2FE2E8B1DC706B3364011E6
+:10272000C706B1362700C70646370200C706483736
+:102730006400F706B5360200751C2E0B5D0281267B
+:10274000B336FFFEC706B1369C00C7064637080001
+:10275000C70648379001891EB736891EFE33BE2052
+:10276000008BC3E74EB92800E2FE2E8B4504E74EEE
+:10277000B92800E2FEE54E8BCB2E2345062E234DD5
+:10278000063AC174364E75D9803E453700740BC683
+:1027900006453700BF2F28E972FFC606453701F707
+:1027A00006B53602007414E5CE25FDFFE7CEE843FA
+:1027B00000E5CE0D0200E7CEE83900803EE23401AC
+:1027C0007601C3B8EA05E78CFAE812F4FB8D06D06F
+:1027D000398BD8C1E804A338348EC0A1303426A385
+:1027E000020026C7060000FFFF83C318D1EB26892D
+:1027F0001E0800C3E5020D0040E702E5000D0400DD
+:10280000E700B80000E70AE50AA900807514E508AA
+:102810000D0010E708E50A0D0008B90500E70AE217
+:10282000FCC3E5080D0010B90500E708E2FCC3048D
+:102830000C2000010C7EFF000C0200100040000C78
+:10284000C6010000C0F7FF00C002001000400000F9
+:1028500033C08ED88D3E72498D36B037B914008B97
+:102860001E3034895C022E8B45028944062E8B056E
+:1028700089440483C70483C610E2E8C6069E360E68
+:10288000E8FD26688328A1AA02CD35833EA1360043
+:102890007403E93B2733FF8E06A6028B36A4022E73
+:1028A000FFA42E30830E993604C70637370100C6C1
+:1028B00006CA3401E97D19803EA0360874E68026F8
+:1028C0009E36FF751AF7069B3600207412F7069B9A
+:1028D000360300750A830E663710C606A03608E96F
+:1028E000FB01803E9E360275CEC606A03606E9EC98
+:1028F00001C3E9E80126C7060A00000026FF2604F6
+:1029000000A1D1362639061A007522A1D336263900
+:10291000061C007518A1D5362639061E00750E2630
+:10292000F7060C0040007405830E663740810EAF39
+:10293000360010A1AF36E706803E9D36027506CD03
+:1029400034E9A21AC3F7069B361000755426F60622
+:102950000A00FF754C26A0190024C03C4075118068
+:102960003E953600743B26C7060400FFFFE93100A0
+:10297000E8F104F7069B360300742F8BD8B87D036B
+:10298000CD3A8BC3C606A03606F7069B3602007505
+:1029900005C606A03604810E9B36800083269B3632
+:1029A000FCE92301E8871DE933015026A10C00252D
+:1029B00007003D07007503E984003D05007503E944
+:1029C0007C00833EE83A047475833EE83A02746EF4
+:1029D000F706E63418807503E96A00F706E6340066
+:1029E00080743526803E290002752D5156578D364C
+:1029F0003E348D3E2000B90600F3A65F5E59744553
+:102A000026A12000A33E3426A12200A3403426A103
+:102A10002400A34234E92600F706E6340800740BCC
+:102A200026803E1900007403E91300F706E634100F
+:102A300000741226A02800C0E80422C0740726C72C
+:102A4000060400FFFF5823C07403E957FF81269B4B
+:102A500036FFFE83FE067F2426A120003B06D136EA
+:102A6000751A26A122003B06D336751026A1240034
+:102A70003B06D5367506810E9B36000126A1200047
+:102A8000257FFFA3B83426A12200A3BA3426A124AF
+:102A900000A3BC348BC686C4A3C034D1E680FC0935
+:102AA0007403E8AA1C8BC62EFFA4304926A10C0093
+:102AB0003DFF7F740F26FF2604008E063834E8366B
+:102AC00006CD50C3E91600CD34E91100CD34893666
+:102AD0003D37A19D36A33F37C606A0360CE88E00D1
+:102AE000A19F3622E47532F7064C370100752AF6AD
+:102AF000069D3680740788269E36E931003A069D89
+:102B000036A39D3674288BF02EFFA40D2B4429EE9E
+:102B1000421944CD442F455A453A269E367501C385
+:102B200032C086C48BF0A29E362EFFA420498B2E85
+:102B3000993623ED7501C3BF0100BE000085FD7508
+:102B40001A46D1E7E9F6FF2A0029002800270025C8
+:102B50000005000700260006002000F7D7213E9957
+:102B600036D1E62E8BB4472BE94FFFE956FF80267E
+:102B70009E36FF7517F7064C370100750FF6069D58
+:102B800036807408F7066637FFFF7507C706663795
+:102B90000000C3F70641370100750BB87F03CD393C
+:102BA000C7064137010033F6B80040850666377422
+:102BB0002180BC5437FF7404FE84543780BC9634A3
+:102BC000FF7404FE84963431066637833E66370010
+:102BD000740546D1E873D4C3A1F433A90088740BFB
+:102BE000A9001075098B1E4337FFE3E9D700C7061C
+:102BF00035370500C70643371E2CF706F4330008A7
+:102C00007406C7064337102CB88003CD39E9CDFED2
+:102C1000A9000874D9FF0E353775EDE96600A900E3
+:102C20000875CBFF0E353775DF810EC234C000F654
+:102C3000069D36807448810E9B360080F7069B36D1
+:102C40000100741EB87D03CD3A810E9B368000834F
+:102C5000269B36FEC7060F370200C606A03604E9DB
+:102C60007BFE803EA036047507833E0F3701750555
+:102C7000C606A03606C7060F370200E95FFEBE0291
+:102C800000E94AFE80269E36FF753AF6069D36809C
+:102C9000742DF7069B360020752BC606A03606FF5E
+:102CA000069434830E6637208E06303426F7060AE3
+:102CB000000001740726810E08000001E90600BE2D
+:102CC0000400E909FE810EAF360008A1AF36E70621
+:102CD000E50AA90080740E8126AF36FFF7A1AF3652
+:102CE000E706E909FFE9F5FDC70641370000830E55
+:102CF000993602E9E7FD80269E36FF751DF7069B93
+:102D00003600407505830E993608830E993620816A
+:102D1000269B36FFBFB88503CD39E9C0FD803E9EB6
+:102D200036067407803E9E360A7534F6069D368058
+:102D30007506BE0700E996FDC606A03604833E0F61
+:102D40003702741BC7060F370400803E9E36067597
+:102D50000EF7069B3640007506C7060F370300E9DD
+:102D60007BFD803E9D36047512810EC2340040FF0B
+:102D7000069234C606A03606E962FDBE0500E94D9E
+:102D8000FDF6069D36807519830EC23404BE06001A
+:102D9000E93BFD80269E36FF75C5FF063137E90009
+:102DA000008326C234BFC606A03606E92FFDE50A19
+:102DB0005025C3BFE70A5880269E36FF750DA9002F
+:102DC000407508C606A03606E912FDB88303CD3962
+:102DD000C3B87C03CD39F706F43300107509C70674
+:102DE00033370200E9F6FCFF0E33377403E9EDFCDC
+:102DF000FF068E34E8F719830EC23408BE0300E9DB
+:102E0000CCFC0000000000000000000400040405E9
+:102E1000040404000300030300000000000000009D
+:102E20000004000808050808080003000303000068
+:102E3000020404040400000800000A1400001A0040
+:102E40001C001E2000000441060B08C2FFE704031B
+:102E500006040405040604870403060404854EA240
+:102E600004CF04CDC706A2370000C706A63700006E
+:102E700026A12000257FFFA3F53626A12200A3F777
+:102E80003626A12400A3F936E83B198BF0268B0ED9
+:102E90000E002BC883E90EB8018083F9047C51260B
+:102EA0008A542888161C3740268B6C2686CD3BCD4D
+:102EB00086CD890EA43775384032FF268A5C29807A
+:102EC000FB15772580FB0A742080FB01741BB80476
+:102ED000802E3A97022E74072E3A97182E751133CA
+:102EE000C080FB09754F8BF3C326C7060400FFFFA4
+:102EF0005052A1A43786C4263B0626007C32268188
+:102F00003E260000047E298D742A268B1422D2745A
+:102F10001F80E6BF80FE097517C706A23701008033
+:102F2000FA04750C268B4402A3033786C4A3D0345D
+:102F30005A58E9B1FFBD72372E8A872E2E22C074EF
+:102F40001605442E8BF82E8B053E89460083C5025C
+:102F500083C70222E47DEF8D742A83E9047503E9B7
+:102F6000A100268B1422D27503E97C00C706A63780
+:102F70000100BF72378B0583C70280E6BF80E43F44
+:102F800080FE09752280FA04755EC706A23701002B
+:102F9000268B4402A3033786C4A3D03486C4C70655
+:102FA000A6370000E947003BFD7E15268B04A840AC
+:102FB0007406B80780E938FF32C0268B04E92E007A
+:102FC0003AF475B1C745FE000080FE22750D3AD077
+:102FD0007716C706A6370000E913003AD07509C76F
+:102FE00006A6370000E90600B80580E902FF32F6C0
+:102FF00003F22BCAB8058023C97603E964FF740382
+:10300000E9EDFE33C0BF72378B1547473BFD7F1B91
+:10301000F6C6807416F706A63701007406B8088055
+:10302000E9C3FEF6C64074E0B80780E9B8FE7D4209
+:10303000A34544294429B728E228EE2BF228F52895
+:103040000129AC2A4429442944294429442900005F
+:10305000733600000336C535833545350735D23420
+:1030600045340000000000000000000000000000E7
+:103070000000A6380000E03800000000000000005A
+:103080000000000000000000000000000000000040
+:10309000F2330000A6336033FD32BC3277323C326B
+:1030A000FB316A310A31E0E0101010E0E0E0E000AE
+:1030B0000000000000000000000000000000000010
+:1030C000000000000000E000E0E0E0E0E0E0E0E020
+:1030D000E033FF26F6061A0080741B2680261A00AD
+:1030E0007F268B3E260083E71F740B26800E200070
+:1030F0008026013E0E00C3602E8B84A63026A318C6
+:1031000000D1E62EFF94503061C326C7060400C4E8
+:103110002A26C7060E00160026C706060006002649
+:10312000C606190000E8BF05E8980526C706260070
+:10313000000826C60628004026C60629002ABF2AFF
+:103140000026C6050426C645012AA1933733DBA90C
+:1031500040007502B301A900107402B788A90008E5
+:10316000740380CF4426895D02C3830EC2342026B7
+:10317000C70604006B2B26C7060E00300026C706C4
+:1031800006000A0026C7060A00040026C606190023
+:1031900000E86905E82C0526C7062600002226C699
+:1031A0000628006026C606290029BF2A0026C60573
+:1031B0000826C645012D8D7D02BE5437B90300F3A4
+:1031C000A526C6050826C645012E8D7D02BE5A37A6
+:1031D000B90300F3A5E8D405E86405B90600BE54B8
+:1031E000378D2E2C00268B4600290483C60283C50A
+:1031F0000283F90475024545E2EBC326C7060400C5
+:10320000C42A26C7060E00240026C70606000600AC
+:1032100026C606190000E8E404E8A70426C7062627
+:1032200000001626C60628006026C606290028BF0C
+:103230002A00E85B06E87405E80405C326C706040F
+:1032400000C42A26C7060E001A0026C70606000676
+:103250000026C606190000E8A304E8660426C7068F
+:103260002600000C26C60628006026C60629002770
+:10327000BF2A00E82105C326C7060400C42A26C7C2
+:10328000060E00200026C70606000A0026C7060A0A
+:1032900000040026C606190000E84B04E8240426B2
+:1032A000C7062600001226C60628004026C60629A4
+:1032B0000026BF2A00E8F404E88404C326C70604F5
+:1032C00000C42A26C7060E00340026C706060006DC
+:1032D0000026C606190000E80D04E8E60326C70626
+:1032E0002600002626C60628004026C606290025F8
+:1032F000BF2A00E8B604E84604E8FA04C326C70675
+:103300000400C42A26C7060E003800A1A237500BBD
+:10331000C0750726C7060E00340026C7060600063D
+:103320000026C606190000E89903E8A4FD26C74553
+:1033300026002A580BC0750626C745260026A11C64
+:1033400037C1E0042688452826C645292483C72A94
+:10335000E82904E8A004E82205E8F803E80904C322
+:1033600026C7060400C42A26C7060E00320026C758
+:10337000060600060026C606190000E84503E850C8
+:10338000FD26C745260024A11C37C1E00426884538
+:103390002826C645292383C72AE8E003E86C04E809
+:1033A0008A04E89C04C326C7060400C42A26C7066C
+:1033B0000E00340026C7060600060026C6061900C1
+:1033C00000E8FF02E80AFD26C745260026A11C37B3
+:1033D000C1E0042688452826C645292283C72AE855
+:1033E0009A03E8C703E85703E8F803E87804E88A93
+:1033F00004C326C7060400744526C7060E003E0017
+:1034000026C7060600060026C7060A00040026C6D0
+:1034100006190000E8FC02E8A902833E8D37037517
+:10342000019026C7062600003026C6062800502632
+:10343000C606290020BF2A00E8D003E80103E8B54A
+:1034400003E89F03C326C70604006143B9F0008365
+:10345000E90226890E0E0026C7060600020026C6CF
+:103460000619000026C7061A00000026C7061C0021
+:10347000000026C7061E000000E8470283E90E860A
+:10348000CD26890E260086CD26C60628000026C633
+:1034900006290008BF2A0083E90426890D26C645AF
+:1034A00001268D7D0283E902BB0100B830304B75E7
+:1034B00017BB0A008AC4268805B03180C40180FC8D
+:1034C0003A750AB461E90500268805040147497583
+:1034D000DDC326C7060400044526C7060E001200F9
+:1034E00026C7060600060026C606190001E8E50103
+:1034F000E8D00126C7062600000426C606280000DC
+:1035000026C606290007C326C7060400C42A26C704
+:10351000060E00200026C7060600060026C606196D
+:103520000006E80402E89B0126C7062600001226D2
+:10353000C60628000026C606290006BF2A00E86B3A
+:1035400002E8FB01C326C7060400C42A26C7060EEC
+:1035500000200026C7060600060026C6061900053C
+:10356000E8C601E85D0126C7062600001226C60649
+:1035700028000026C606290005BF2A00E82D02E81B
+:10358000BD01C3FF06823426C70604003D4126C79D
+:10359000060E00200026C70606000E0026C60619E5
+:1035A0000004E88401E81B0126C706260000122655
+:1035B000C60628000026C606290004BF2A00E8EB3C
+:1035C00001E87B01C326C7060400674226C7060E32
+:1035D00000200026C7060600080026C606190003BC
+:1035E000E84601E8DD0026C7062600001226C606CA
+:1035F00028000026C606290003BF2A00E8AD01E81E
+:103600003D01C3FF06843426C7060400674226C76F
+:10361000060E00240026C7060600080026C6061966
+:103620000002E80401E89B0026C7062600001626D3
+:10363000C60628000026C606290002BF2A0026C6A4
+:10364000050426C6450101A10F3786E0F6066F374F
+:1036500001750F3906CC3474098BD8B88903CD397C
+:103660008BC3A3CC34268945028D7D04E83D01E857
+:10367000CD00C326C7060400C42A26C7060E001CB8
+:1036800000A1A237500BC0750726C7060E00180010
+:1036900026C7060600060026C606190000E8230015
+:1036A000E82EFA26C74526000E580BC0750626C719
+:1036B0004526000A26C645290083C72AE8BD00E83A
+:1036C000FF00C3565751B90300BED136BF2000F3E7
+:1036D000A5595F5EC3565751B90300BED136BF1A14
+:1036E00000F3A5595F5EC326C7061A00C00026C7AF
+:1036F000061C00000026C7061E000010C326C706D1
+:103700001A00C00026C7061C00000026C7061E00BF
+:103710000008C326C7061A00C00026C7061C000002
+:103720000026C7061E000002C326C7061A00C000F6
+:1037300026C7061C00FFFF26C7061E00FFFFC32684
+:10374000C6050826C64501028D7D02BE0537B903B0
+:1037500000F3A5C326C6050426C6450106A10D37FC
+:10376000268945028D7D04C326C6050426C645016B
+:1037700007A10B372689450283C704C3A1A2370BD3
+:10378000C0741326C6050426C6450109A1033726C1
+:1037900089450283C704C326C6050826C64501021B
+:1037A0008D7D02BE0537B90300F3A5C326C6050605
+:1037B00026C645010B8D7D02BEEF36B90200F3A58A
+:1037C000C326C6050626C6450120A16837268945B9
+:1037D00002A16A3726886505C1E00426884504836E
+:1037E000C706C326C6050426C645012126C74502CD
+:1037F000000083C704C326C6051426C64501228DD2
+:103800007D02BE1F37B90900F3A5C326C6050C26E5
+:10381000C64501238D7D021E0E1F8D364054B9030F
+:1038200000F3A533C0B90200F3AB1FC326C60508D9
+:1038300026C64501288D7D02BED136B90300F3A509
+:10384000C326C6050826C6450129A1C23486E0263E
+:10385000894502A19B362689450426884506268887
+:1038600045078D7D08C326C6050626C645012B8D56
+:103870007D02BEBB36B90200F3A5C326C6050626E7
+:10388000C645012C8D7D02BEE536B90200F3A5C305
+:1038900026C6050426C6450130A1373786E02689AD
+:1038A00045028D7D04C326C7060E001E0026C706EE
+:1038B0000600020026C606190000E86CFEE803FEBA
+:1038C00026C7062600001026C60628003026C60693
+:1038D000290011BF2A00E83500E84500E85500C37B
+:1038E00026C7060E00120026C7060600020026C6DE
+:1038F00006190000E832FEE8C9FD26C706260000CA
+:103900000426C60628003026C606290013C326C68C
+:10391000050426C645010C26C74502000183C704DD
+:10392000C326C6050426C645010E26C74502000269
+:1039300083C704C326C6050426C645012126C745FC
+:1039400002000083C704C300000000000000000064
+:10395000B339C939833AB339B339B3391C3A1C3A4C
+:10396000A3B634A1E936A31137A3D234A1EB36A311
+:103970001337A3D434A1ED36A31537A3D634A10150
+:1039800037A3CE34A1F736A31737A3DC34A1F93619
+:10399000A31937A3DE34F7069B360200750C33C03B
+:1039A000A09E368BF02EFFA45039E90F01BE070010
+:1039B000E919F1F6069D368074F3C606A03602C6F4
+:1039C000066E3708C606703702B88803CD39F6068A
+:1039D0006F3701754AA1D1363A06E93675413A2664
+:1039E000EA36753BA1D3363A06EB3675323A26EC09
+:1039F00036752CA1D5363A06ED3675233A26EE36C5
+:103A0000751DC606703702FE0E6E37750FB8880337
+:103A1000CD3A830E9B3612C606A0360CE9A8F0A15B
+:103A20000537263B0620007540A10737263B0622B6
+:103A3000007536A10937263B062400752CA09E365A
+:103A40003C02750826F6061800087547C6066E374C
+:103A500008FE0E7037751CC606703702E5020D01B0
+:103A60000425EFFFE702E95EF0C606703702C606DE
+:103A70006E3708E50225FFFB0D010025EFFFE70289
+:103A8000E944F0F7069B360001742526F606180077
+:103A90000875ED81269B367FFFB88903CD3AB8843F
+:103AA00003CD3AC606A036068326C234AFE917F026
+:103AB000A101373A260F377FC7E9F7FE83269B36E9
+:103AC000ECE82A0D810E9B368000BBFF7FCD53C6EC
+:103AD00006A03602E9F0EF830E9B3611C606A0362B
+:103AE0000CE9F9EF443B2C3BC72A6B3B443BC72A0C
+:103AF000C72AC72AA3B634810EC2340020F7064174
+:103B0000370100741B8CC3C70641370000B87F0320
+:103B1000CD3A33C08EC0BF5437B90600F3AB8EC365
+:103B200033C0A09E368BF02EFFA4E43AF7069B36F6
+:103B3000000175218326C234BFA1A936E700A19BED
+:103B400036E90900A19B3681269B36FFDFA90020BC
+:103B50007506E96E00E96FEF830E993604C70637E4
+:103B6000370100C606CA3401E95800830E9B36406F
+:103B7000E85800A105373B06E9367537A107373B02
+:103B800006EB36752EA109373B06ED367525FE0E80
+:103B90007137751CB88703CD3A830E993610A15042
+:103BA00037C7065037000009069936C606A0360802
+:103BB000E914EF830E993604C70637370300C606AB
+:103BC000CA3403C606A0360AE9FCEEA1D136263B6C
+:103BD0000620007515A1D336263B0622007512A1DA
+:103BE000D536263B062400750FC38D362000E90B21
+:103BF000008D362200E904008D36240083C402F7CC
+:103C000006E63401007415263A047708720E263A47
+:103C100064017208C606A03606E9ABEEE87C0A8CA1
+:103C2000C03DFFFF741B26C60618001026C70604F9
+:103C300000493C26C70606000C00CD50B94E00E2F4
+:103C4000FEC606A0360AE994EEE97BEE8F3C063DFF
+:103C5000063D063DD23CEA3C063D063DA3B6348116
+:103C600026C234AFDFC7064C370000B88A03CD3A0E
+:103C7000803E9D3604750C803E9E36067405C60651
+:103C80009F360633C0A09E368BF02EFFA44C3CF727
+:103C9000069B360020750E81269B36FFBFB88B032E
+:103CA000CD3AE95400F7069B3600017403E917EE9C
+:103CB000C70637370200C606CA3402830E99360497
+:103CC000830E503704F6069D3680752AE81F0BE9EF
+:103CD0002700F7069B36000175D3C7063737020069
+:103CE000C606CA3402830E993604C606A03600F60C
+:103CF000069D36807403E8DE0A81269B367CFFBB76
+:103D0000FFFFCD53CD54E9BEEDA3B634E8AD01B805
+:103D10008603CD39C7064C3700008126C234AFDF99
+:103D2000F6069D36807434F7069B3600207456F7ED
+:103D3000069B3600017427E83501721CBE004085E1
+:103D400036C23475080936C234FF069234E88B0156
+:103D50007306810E99368000E96CEDE9B500C7065F
+:103D600037370200C606CA3402830E993604830E22
+:103D7000503704803E9E36087403E85A0AE8EF0084
+:103D800072D6E9C8FF803E9E360A7512C606A03676
+:103D900000F7069B3608007402CD54E8390A8126E4
+:103DA0009B36FFBFE8C80072AFB88B03CD39E99CE2
+:103DB000FFF6069E36FF7558A3B634E8FE0081264E
+:103DC000C234FFBFF6069D36807448F7069B360066
+:103DD000207422F7069B3600407508E89100723087
+:103DE000E9220026A10C00A960007524810E663727
+:103DF0000008E9D2ECC7064C370000E871007210E9
+:103E0000B88B03CD39E8D3007306810E9936800054
+:103E1000E9B4EC803E9D3604750C803E9E360674F7
+:103E200046C6069F3606F7069B360001740C803E98
+:103E30009D36087505C6069F360AE8320072D1E83D
+:103E40009900803E9D36087513810E99368000F7E3
+:103E5000069B3600207508B88B03CD39E968ECC69F
+:103E6000069F360AE960ECB88603CD3AE958EC269D
+:103E7000A10C00A9600074088126C234FFBFF9C3F9
+:103E8000F7069B3600407413810E66370008E84A37
+:103E9000007306810E99368000F9C3810E9B3600AF
+:103EA0004080266F37FE81269B367FFFC606A036F0
+:103EB00000F8C3810E99360001E921EC26A120000B
+:103EC000A3FB36A3AA3426A12200A3FD36A3AC345B
+:103ED00026A12400A3FF36A3AE34C3A10537263B99
+:103EE0000620007519A10737263B062200750FA191
+:103EF0000937263B0624007505E80200F8C3511E69
+:103F0000068BC78D362000BF0537B903001E061F7C
+:103F100007F3A58BF88D362000BFA034B90300F35A
+:103F2000A5071F598BF8A10737A3A634A10937A30A
+:103F3000A834F9C3C606B63401E98BEBE887088BD1
+:103F4000F00512002629060E00268B442A263A0682
+:103F50000E00755B26832E0E000280FC277550260E
+:103F60008B442CA9FFFF75478BFE33C026F6453CDA
+:103F7000807406268A453A241F03F826807D450969
+:103F8000752D8CC28E0638348EDA8B0E0E00268983
+:103F90000E0E008D742CBF1800F3A433C08ED826EB
+:103FA000C7060400B53F26C70606000600CD50B878
+:103FB0000680E9EFE926A10C00A39337830E99361A
+:103FC00001E900EB26803E1C00FF752F26803E1E77
+:103FD00000FF752726F7060C004000751BA1D1369F
+:103FE00026A31A00A1D33626A31C00A1D53626A3EA
+:103FF0001E00B80A80E83607E9E2EAFF069034BE00
+:104000000A00C606B63401F6069D36807505830E95
+:10401000C23401E9B6EA803E9D360A750F26A10C2E
+:10402000002507003D04007503E87900A1F33686FA
+:10403000E0E71EA3E33681260B37000381260D3708
+:104040007B7F830E0D3748E81E0026A10C00250754
+:10405000003D0400740926F7060C0020007506B820
+:104060000100E93FE9E95FEAC70641370000B87F90
+:1040700003CD3AA11D37A3C43486E0687F031FA394
+:10408000060033C08ED8A10B37A3B234A10D37A3DD
+:10409000B434A1F336A3C834A1EF36A39C34A1F104
+:1040A00036A39E34C3800E9D3680BE0000E8B40760
+:1040B000B87B03CD3AB87C03CD39C706333702004D
+:1040C000A1E536E72EA1E736E73EB88203CD3AF701
+:1040D000069B3600207503E8FD06A1D336A3EF3614
+:1040E000A39C34A1D536A3F136A39E34C3F6069D16
+:1040F00036807431BE2200E91700F6069D368074C2
+:1041000024BE2300E90A00F6069D36807417BE24FB
+:104110000056E8A8058CC03DFFFF5E7405E8D7EFA8
+:10412000CD50E91FE8E99FE9000000000000000011
+:10413000B88403CD3AB88A03CD39E9F700803EA0B0
+:104140003608752EA9D007752CA1B1360D0004E7ED
+:1041500008E50025FF73E700B88A03CD3AE8C306F7
+:1041600033C0E70EE50A25C317E70ACD54C606A0FB
+:104170003600E968E9BE0400E93FE983269B36BFC3
+:10418000C606713703B88603CD3AB88803CD3AB86E
+:104190008303CD3AB88703CD39810EC2340020E9BC
+:1041A0009200E84906B88703CD39BBFF7FCD53B8ED
+:1041B0008403CD3AB88803CD3AB88B03CD3AB8839F
+:1041C00003CD3AB88603CD3AB88503CD3AC3E500AE
+:1041D00025FF53E700830EC234408326C234EFE844
+:1041E0000C06BBFF7FCD53B88A03CD3AB88503CD0B
+:1041F0003AB88603CD3AB88303CD3AB88703CD3AAF
+:10420000B88B03CD3AB88403CD3AB88903CD3AC30D
+:10421000830EC23450E81804E8D305F6066F370160
+:104220007512B88903CD39833E0F37007506C7066E
+:104230000F370400A19D3680FC087405B88403CDB7
+:1042400039E5020D010825EFFFE702A19D3686E062
+:1042500032E48BF0D1EE33C00D20000906AD36A15B
+:10426000AD36E704E953E8E95AE833C0A01B37D17B
+:10427000E03A06A0367503E9BAFFE960E8C70641EF
+:10428000370000E8C1E1E86A0633C00D4100E75697
+:10429000A1B1360D0010E708E50225F9FF0D030076
+:1042A000E702A1B336E70AA1AF36E706A1AD36E7CC
+:1042B00004E87C03E89F03C7061D3700C8C7060B48
+:1042C000370003C7060D377B7F33C0A39936A39B06
+:1042D00036A39D36A39F36A34C37A3F336A3EF3600
+:1042E000A3F136E882FDC6069F3602E9EFE7E50254
+:1042F0000D018825EFFF0D00400D0004E702E8F2F4
+:1043000005E50A0D4000E70A33C0A38137A38537CE
+:10431000A38337A38737A38937E5000D0084E7001F
+:10432000B88C03CD39B88000CD35C706AA02FFFF8F
+:10433000E50025FF7BE700810E9A378000B87E03F9
+:10434000CD3933C0E70EBE08008E063834E8A7ED3D
+:104350008326EF34DFFF068137CD50830EEF342004
+:10436000C3F7069A378000743DA9D0077410A900DE
+:1043700004741233C0E70EFF068737E9D2FFFF0649
+:104380008537E9CBFFFF068337E9C4FF83269A37D9
+:104390007FA18937030687373D05007F01C3BBFF37
+:1043A0007FCD53E90000E50225FFFB25EFFF0D015E
+:1043B00000E702A183373B0646377F2AA185373BBA
+:1043C0000648377C21A18937030687373D05007FE2
+:1043D00015C6069F3604E50225FFF70D010025EFFF
+:1043E000FFE702E9F7E6BE0100F7069B360300741B
+:1043F0000A83269B36FC830EC23404E9D0E6B87BE0
+:1044000003CD39E5020D016025EFFFE702C706F194
+:10441000342003B88E03CD39C38126C2347FFF8098
+:104420000E6F3701F7069B36030074D2B87B03CDBD
+:104430003AB87D03CD3983269B36EF33C0B08AA2CC
+:104440009F36A29D36C7064C370100C7060F3704BA
+:1044500000F7069B3640007506C7060F370300B805
+:104460008D03CD39E800D5E5020D014025EFFF8B26
+:10447000D8B87C03CD39C706333702008BC30D0093
+:104480002025F9FF0B06E83AE702C3FF0EF1347569
+:1044900001C3E54EA901007512E500A900047505E8
+:1044A0000D0004E700B88E03CD39C3E500A9000470
+:1044B00074F325FFFBE700E9EBFFC606A036048393
+:1044C000269B36FC810E9B368000E910E6B88E03F1
+:1044D000CD3ACD54810EAF360018A1AF36E706B8FD
+:1044E0007B03CD39A1D336A38F37A1D536A391371E
+:1044F000C7068B370200C7068D370200830E993638
+:1045000040E9D9E5803E9F36067515A9D00775ECC0
+:10451000250018750EFF0E8B3775E1C6069F36080D
+:10452000E9BAE5FF0E8D3775D3BE0800E99FE5B8FF
+:104530007B03CD39F7069B3600207408C6069F36EC
+:104540000AE90D00F7069B360040740BB88B03CDCB
+:1045500039810E99368000E983E5B87B03CD39C7F0
+:10456000068B370400C7068D370400810E9936008C
+:1045700002E969E5F6069D3680751BA9D00775EB43
+:10458000A90018750CFF0E8D3775E0E817FBE94C94
+:10459000E5B88203CD39C3FF0E8B3775CEBE090057
+:1045A000E92BE5C7063D370000C7069B360000E84B
+:1045B0003C028126AF36FFE7A1AF36E70681269B96
+:1045C00036FF7FE5020D010025EFFF25FFDFE70243
+:1045D000BBFF7FCD5333C0A39D36A39F36E8500069
+:1045E000E87300B88103CD39C3F7069B3603007426
+:1045F0000DC6069F3602C606A03600E9DFE4830E2C
+:104600009B3610C70699360000E8E702E5560D0212
+:1046100000E756C706A80200008B363D37E8440283
+:10462000C606A0360EE9B5E4000000000000000058
+:1046300006B88A03CD3AB88503CD3AB88603CD3A99
+:10464000B88303CD3AB88703CD3AB88B03CD3AB8D7
+:104650008803CD3A07C306B88803CD3AB87B03CDAB
+:104660003AB88203CD3AB87F03CD3AB87C03CD3A4D
+:10467000B87E03CD3AB88003CD3AB88103CD3AB8BD
+:104680008403CD3AB88903CD3AB87D03CD3AB88DCD
+:1046900003CD3AC7064137000007C3068E063834FB
+:1046A0001F8B0E0E0026890E0E00BE1800BF1800CC
+:1046B000F3A4061E07CD340733C08ED8C326F606F2
+:1046C000200080744433C026A02600241F8BF026CF
+:1046D0008B5C28891E6A37068E0638341FC0E304B7
+:1046E00026885C288BC6B90600BE2000BF1A00F3DE
+:1046F000A48BC883C706F3A426812626001F802624
+:10470000813626000080E9A9FF268B1E2800891E1D
+:104710006A37068E0638341FC0E30426881E280038
+:10472000B90600BE2000BF1A00F3A4E984FF86C4C6
+:10473000A36837E887FFF7066A370F007410803EDA
+:104740009E36007509BE0000E8ACE9CD50C3C350E9
+:10475000560633C026F606200080740626A02600E2
+:10476000241F8BF0268B5C2686FB83EB04744F831F
+:10477000C62A8CC08ED8B9070033C08EC0BF72372E
+:10478000F3AB33C98A0C80F9007503E930003BD9DB
+:104790007303E929002BD98A4401253F0074193D90
+:1047A0000B007D14D1E08BF82E8BBD5C498D74021B
+:1047B00083E902F3A4E9020003F123DB75C433C0EB
+:1047C0008ED8075E58C333C026F6062000807406D4
+:1047D00026A02600241FC3E50A25C3BFE70AB88622
+:1047E00003CD39B88303CD3981269B367CDFB8856C
+:1047F00003CD3AE50225FFF30D010025EFFFE702A7
+:10480000E50025FF53E700A1E73625FFFEA3E736C5
+:10481000E73E83269936CF810EAF360010A1AF3622
+:10482000E706C3E5020D010C25EFFFE702A1E7361D
+:104830000D0001E73EA3E736810E9B360020830E74
+:1048400099362081269B367CBF810EAF360010A1A1
+:10485000AF36E706B88603CD39B88503CD39B883BE
+:1048600003CD3AC30BF67549068E063234803EE01E
+:104870003401751B26893606008E06323426F7066B
+:104880000A000020740726810E0800002007C3805C
+:104890003EE33401751926893606008E0632342629
+:1048A000F7060A000010740726810E0800001007A2
+:1048B000C3E9B4FF50515733C0B906008EC0BFD111
+:1048C00036F3AE5F740C26F6060000C07504F85986
+:1048D00058C3F9E9F9FF8B050B45020B4504C35298
+:1048E00050E506251E003D1E0075F6B80180E75A0A
+:1048F000585AC3E8E9FF50E50225FF7F0D01002566
+:10490000EFFFE7020D0080E702A1AD36E704A1AF9B
+:1049100036E70658C3000000000000000000000059
+:104920002E2BCE4110427B413041A241AF4544295C
+:10493000C72AC72A6039F43A5C3C093DB13D343F8F
+:10494000C72A3C3FC72AC43F16401640ED40FA40F4
+:104950000741C72AC72AC72AC72AD65200000137EB
+:10496000E936F336EF361D370D370B379C370337F3
+:10497000FB36622D4006D12DF401BA4440068C432B
+:104980006400E82CC800D82B0500E9455000974585
+:10499000FA00AE2D04016A420200F62CBC02932DEF
+:1049A000DC051D2D6400A12D1400D73A0807812DC8
+:1049B0006400B33E020030436400C52CF4018B4414
+:1049C00002000000000000000000000000000000E5
+:1049D000803EFD3402740CE82005C706A1360000B5
+:1049E000E99AF8FF06C033E810058B363D37E873C7
+:1049F000FEC3CD34E9E805C706A3360000C706416B
+:104A0000370000E8EDFE33C00D4100E756A1B13696
+:104A10000D0010E708A1B336E70AA1AF36E706A1FB
+:104A2000AD36E704E82B09C7061D3700C8C7060BDB
+:104A3000370003C7060D377B7F33C0A39B36A39D8A
+:104A400036C7064C370100C6069E36FFC706053737
+:104A50000000C70607370000C70609370000A3F3A8
+:104A600036A3EF36A3F136E8FEF5E50225F9FF0D92
+:104A700003000D008825EFFF0D00400D0004E70244
+:104A8000B88F03CD39B88000CD35C706AA02FFFF25
+:104A9000A1A936A3A7360D00A40D0008E700A3A91D
+:104AA00036C706A3360100C706A5360C00833EA50F
+:104AB00036007509C7063D370500E913FFFF0EA54F
+:104AC00036BE1100E82205B89003CD39C3833EA35A
+:104AD000360174D9C3B89003CD3A26A02B00268B9B
+:104AE0001E2C00CD34833EA336017403E9F0043C50
+:104AF0000F751E81FB0002751826A12000A3053743
+:104B000026A12200A3073726A12400A30937E9091B
+:104B100000C7063D370100E9B6FEC706A33602000E
+:104B2000C6069E36FFE8CBFDE81CD933C0A3853707
+:104B3000A38337A38737A38937B89103CD39B880CA
+:104B400000CD35C706AA02FFFFE50025FF53E700A9
+:104B5000810E9A378000B89203CD3933C0E70EBE7C
+:104B600008008E063834E88EE526C70604007D4B23
+:104B70008326EF34DFCD50830EEF3420C3F7069A3F
+:104B80003780007432A9D007740CA90004740E3366
+:104B9000C0E70EE9DAFFFF068537E9D3FFFF06839A
+:104BA00037E9CCFFC7063D370100E936FE83269A78
+:104BB000377FBBFF7FCD53E5000D00ACE700E5027A
+:104BC00025FFFB25EFFF25FFF70D0100E702A1837D
+:104BD000373B0646377FCDA185373B0648377CC437
+:104BE000C706A3360300BE1300E8FD03B89303CD48
+:104BF00039B89403CD39B89603CD39B89503CD397A
+:104C0000BE0600E8E303E9D603833EA3360374013E
+:104C1000C3BE1300E8D203B89403CD39C3B89403DC
+:104C2000CD3A26A02B00268B1E2C00CD34833EA32C
+:104C300036037403E9A8033C0D753E83FB00753908
+:104C4000E5020D0020E702B89303CD3AC706A3366C
+:104C50000400BE0000E80CFCC6069D3680C6069E19
+:104C60003600C70633370200B89A03CD39E8FC0096
+:104C7000C7064C370000E96603C7063D370800E960
+:104C800061FD833EA336037509C7063D370500E97C
+:104C900051FDE94A03833EA336047412833EA336D2
+:104CA00005740BCD34C7063D370700E935FDC7064F
+:104CB000A3360600C6069E36FFB89A03CD3AB899C9
+:104CC00003CD3AB89603CD3AB89703CD39B89803D7
+:104CD000CD39B89B03CD39E918FDCD34833EA336D9
+:104CE000047718833EA336037508F7069B36000148
+:104CF0007509C7063D370100E9E8FCE9E102CD345A
+:104D0000833EA336027709C7063D370100E9D3FC8D
+:104D1000833EA336047705B89603CD39E9C00283F4
+:104D20003EA33603751026A10C00250700503D0454
+:104D3000007503E83600A1F33686E0E71EA3E336EC
+:104D400081260B37000381260D377B7F830E0D37BD
+:104D500048E814F3583D0400740926F7060C0020B7
+:104D6000007506B80100E97A02E986FCA1E536E79C
+:104D70002EA1E736E73EA1D336A39C34A1D536A3B6
+:104D80009E34C326803E1C00FF752F26803E1E00E9
+:104D9000FF752726F7060C004000751BA1D13626AB
+:104DA000A31A00A1D33626A31C00A1D53626A31E24
+:104DB00000B80A80E92C02E938FCFF069034BE0AEC
+:104DC00000C606B63401F6069D36807505830EC210
+:104DD0003401CD34E90CFC833EA336037509C706C4
+:104DE0003D370500E9FCFBE5020D03000D00880DD1
+:104DF00000400D0004E702C706A3360500C6069E64
+:104E000036FFBE0200E8E101B88903CD3AB89A0343
+:104E1000CD3AB89903CD39B89703CD39B89803CDB9
+:104E200039E9BB01833EA33603740A833EA33604EB
+:104E30007403E9AA01BE0600E8AE01B89503CD39B6
+:104E4000E99C01833EA336057403E99201BE02008A
+:104E5000E89601B89903CD39E98401C7060F3705F3
+:104E600000E97B01E50225FFDFE702C706A336075D
+:104E700000C7060F370500E96501E8D504C6069DA1
+:104E80003600C7069B360000C7060F370500C70669
+:104E9000A8020000C7064C370100E50225F9FF0D06
+:104EA00003000D008825EFFF0D00400D0004E70210
+:104EB000E967FCB89A03CD39F706F4330010750999
+:104EC000C70633370200E91601FF0E33377403E9D2
+:104ED0000D01FF068E34830EC23408C7063D37032A
+:104EE00000E9FFFAC35250BAE000B80010EF585A78
+:104EF000C3C7063D370000E9E9FAFAE85404B88070
+:104F0000038EC026C7060400D82BB87F038EC026A8
+:104F1000C7060400E82C33C08EC0A1A736A3A9366B
+:104F2000A1A936E700A1AB36E702C70605370000A6
+:104F3000C70607370000C70609370000C6069D36BA
+:104F400000C6069E36FFC7069B360000C706A3367E
+:104F50000000C7060F370000C706A8020000C706FA
+:104F60004C3701008126AF36FFE7A1AF36E706BB1D
+:104F7000FF7FCD53E87CF9E5560D0200E756FBC3F1
+:104F80008D3EC0538D36F038B90E008B1E303489FB
+:104F90005C022E8B45028944062E8B0589440483CE
+:104FA000C70483C610E2E8B880038EC026C7060493
+:104FB00000E251B87F038EC026C7060400B2523308
+:104FC000C08EC0C706A1360100C7060F370500C353
+:104FD00033FF8E06A6028B36A4022EFFA4A053E850
+:104FE0008CDBC3E848F7E9F6FF8E063834E807E1C2
+:104FF00026C7060400DF4FCD50C326C7060A0000AF
+:105000000026FF260400CD34E9D4FFA1D13626398D
+:10501000061A007522A1D3362639061C007518A180
+:10502000D5362639061E00750E26F7060C00400000
+:105030007405830E663740810EAF360010A1AF367F
+:10504000E706833EA336027505CD34E956FB833E61
+:10505000A3360074B1833EA3360577AA26F6060A66
+:1050600000FF75A2E8FDDD50F6069336207503E9D2
+:105070008C0026A10C002507003D07007503E9768A
+:10508000003D05007503E96E00F706E634188075EB
+:1050900003E96A00F706E6340080743526803E296D
+:1050A0000002752D5156578D363E348D3E2000B985
+:1050B0000600F3A65F5E59754526A12000A33E3485
+:1050C00026A12200A3403426A12400A34234E926CD
+:1050D00000F706E6340800740B26803E19000074C1
+:1050E00003E91300F706E6341000741226A0280026
+:1050F000C0E80422C0740726C7060400FFFF582337
+:10510000C07403E9DDFE81269B36FFFE26A1200048
+:105110003B06D136751A26A122003B06D336751000
+:1051200026A124003B06D5367506810E9B3600016C
+:1051300026A12000257FFFA3B83426A12200A3BA10
+:105140003426A12400A3BC348BC686C4A3C034D1AA
+:10515000E680FC097403E8F6F5A105370B0607376E
+:105160000B060937743E26A120003B06053775174C
+:1051700026A122003B060737750D26A124003B0619
+:1051800009377503E91D0026A02800240F3C03748D
+:105190001B3C00750F833EA336047410F7069B3644
+:1051A000000174082EFF94F853E933FECD34C7068E
+:1051B0003D370100E92CF8833EA336057410833E89
+:1051C000A336017E0983EE162EFF942454C3CD34FA
+:1051D000C326A10C003DFF7F740526FF260400E9CD
+:1051E000FDFDA1F433A90088740BA9001075098B8B
+:1051F0001E4337FFE3E99700C70635370500C706AA
+:1052000043372852F706F43300087406C7064337BD
+:105210001A52B88003CD39E9C5FDA9000874D9FF39
+:105220000E353775EDE93000A9000875CBFF0E3556
+:105230003775DF810EC234C000F6069D3680740FCC
+:10524000810E9B360080C7060F370200E990FDC72C
+:10525000063D370200E98BF780269E36FF7530F653
+:10526000069D36807420FF069434830E6637208EA8
+:1052700006303426F7060A000001740726810E085E
+:10528000000001E90900C7063D370400E954F78131
+:105290000EAF360008A1AF36E706E50AA900807414
+:1052A0000E8126AF36FFF7A1AF36E706E949FFE9E1
+:1052B0002DFDC70641370000BE2900E82BFDE91E81
+:1052C000FDCD34833EA336047709C7063D37010080
+:1052D000E910F7E909FDCD34C3C7069B360000E8A5
+:1052E0000CF58126AF36FFE7A1AF36E70681269B96
+:1052F00036FF7FE5020D010025EFFF25FFDFE70206
+:10530000BBFF7FCD5333C0A39D36A39F36E820F368
+:10531000E843F3830E9B3610C70699360000E8D2A7
+:10532000F5E5560D0200E756C706A8020000BE00CC
+:1053300000E830F5C606A0360EB89C03CD39B8801B
+:1053400000CD35C706AA02FFFFC706A1360100E956
+:10535000A5F606B88F03CD3AB89003CD3AB89103BD
+:10536000CD3AB89203CD3AB89303CD3AB89403CD71
+:105370003AB89503CD3AB89603CD3AB89703CD3AEB
+:10538000B89803CD3AB89903CD3AB89A03CD3AB854
+:105390009B03CD3AB87F03CD3AB88003CD3A07C31B
+:1053A000F749F14EDF4FDF4FDF4FDF4FF851DF4F4F
+:1053B000FA4F0B50D151DF4FDF4FDF4FDF4FDF4F41
+:1053C000E44E0600CD4A0400E44E1900AD4BFA004D
+:1053D000824C0807094C1400244E6400D74DF40198
+:1053E000644EBC027A4EE803434E0200B34EF40111
+:1053F0005B4EF401E54E140006500650954CC15228
+:10540000C152FE4CDA4C0650065006500650B751B9
+:10541000B751B751B751B751B7510650D54A065099
+:105420001D4C0650834D1F4D1F4DED40FA40074166
+:1054300037372E3737202079792F79792F797920CE
+:1054400030312E3930202030322F31372F3939206A
+:10545000000000000000000000000000000000004C
+:10546000000000000000000000000000000000003C
+:10547000000000000000000000000000000000002C
+:10548000000000000000000000000000000000001C
+:10549000000000000000000000000000000000000C
+:1054A00000000000000000000000000000000000FC
+:1054B00000000000000000000000000000000000EC
+:1054C00000000000000000000000000000000000DC
+:1054D00000000000000000000000000000000000CC
+:1054E00000000000000000000000000000000000BC
+:1054F00000000000000000000000000000000000AC
+:10550000000000000000000000000000000000009B
+:10551000000000000000000000000000000000008B
+:10552000000000000000000000000000000000007B
+:10553000000000000000000000000000000000006B
+:10554000000000000000000000000000000000005B
+:10555000000000000000000000000000000000004B
+:10556000000000000000000000000000000000003B
+:10557000000000000000000000000000000000002B
+:10558000000000000000000000000000000000001B
+:10559000000000000000000000000000000000000B
+:1055A00000000000000000000000000000000000FB
+:1055B00000000000000000000000000000000000EB
+:1055C00000000000000000000000000000000000DB
+:1055D00000000000000000000000000000000000CB
+:1055E00000000000000000000000000000000000BB
+:1055F00000000000000000000000000000000000AB
+:10560000000000000000000000000000000000009A
+:10561000000000000000000000000000000000008A
+:10562000000000000000000000000000000000007A
+:10563000000000000000000000000000000000006A
+:10564000000000000000000000000000000000005A
+:10565000000000000000000000000000000000004A
+:10566000000000000000000000000000000000003A
+:10567000000000000000000000000000000000002A
+:10568000000000000000000000000000000000001A
+:10569000000000000000000000000000000000000A
+:1056A00000000000000000000000000000000000FA
+:1056B00000000000000000000000000000000000EA
+:1056C00000000000000000000000000000000000DA
+:1056D00000000000000000000000000000000000CA
+:1056E00000000000000000000000000000000000BA
+:1056F00000000000000000000000000000000000AA
+:105700000000000000000000000000000000000099
+:105710000000000000000000000000000000000089
+:105720000000000000000000000000000000000079
+:105730000000000000000000000000000000000069
+:105740000000000000000000000000000000000059
+:105750000000000000000000000000000000000049
+:105760000000000000000000000000000000000039
+:105770000000000000000000000000000000000029
+:105780000000000000000000000000000000000019
+:105790000000000000000000000000000000000009
+:1057A00000000000000000000000000000000000F9
+:1057B00000000000000000000000000000000000E9
+:1057C00000000000000000000000000000000000D9
+:1057D00000000000000000000000000000000000C9
+:1057E00000000000000000000000000000000000B9
+:1057F00000000000000000000000000000000000A9
+:105800000000000000000000000000000000000098
+:105810000000000000000000000000000000000088
+:105820000000000000000000000000000000000078
+:105830000000000000000000000000000000000068
+:105840000000000000000000000000000000000058
+:105850000000000000000000000000000000000048
+:105860000000000000000000000000000000000038
+:105870000000000000000000000000000000000028
+:105880000000000000000000000000000000000018
+:105890000000000000000000000000000000000008
+:1058A00000000000000000000000000000000000F8
+:1058B00000000000000000000000000000000000E8
+:1058C00000000000000000000000000000000000D8
+:1058D00000000000000000000000000000000000C8
+:1058E00000000000000000000000000000000000B8
+:1058F00000000000000000000000000000000000A8
+:105900000000000000000000000000000000000097
+:105910000000000000000000000000000000000087
+:105920000000000000000000000000000000000077
+:105930000000000000000000000000000000000067
+:105940000000000000000000000000000000000057
+:105950000000000000000000000000000000000047
+:105960000000000000000000000000000000000037
+:105970000000000000000000000000000000000027
+:105980000000000000000000000000000000000017
+:105990000000000000000000000000000000000007
+:1059A00000000000000000000000000000000000F7
+:1059B00000000000000000000000000000000000E7
+:1059C00000000000000000000000000000000000D7
+:1059D00000000000000000000000000000000000C7
+:1059E00000000000000000000000000000000000B7
+:1059F00000000000000000000000000000000000A7
+:105A00000000000000000000000000000000000096
+:105A10000000000000000000000000000000000086
+:105A20000000000000000000000000000000000076
+:105A30000000000000000000000000000000000066
+:105A40000000000000000000000000000000000056
+:105A50000000000000000000000000000000000046
+:105A60000000000000000000000000000000000036
+:105A70000000000000000000000000000000000026
+:105A80000000000000000000000000000000000016
+:105A90000000000000000000000000000000000006
+:105AA00000000000000000000000000000000000F6
+:105AB00000000000000000000000000000000000E6
+:105AC00000000000000000000000000000000000D6
+:105AD00000000000000000000000000000000000C6
+:105AE00000000000000000000000000000000000B6
+:105AF00000000000000000000000000000000000A6
+:105B00000000000000000000000000000000000095
+:105B10000000000000000000000000000000000085
+:105B20000000000000000000000000000000000075
+:105B30000000000000000000000000000000000065
+:105B40000000000000000000000000000000000055
+:105B50000000000000000000000000000000000045
+:105B60000000000000000000000000000000000035
+:105B70000000000000000000000000000000000025
+:105B80000000000000000000000000000000000015
+:105B90000000000000000000000000000000000005
+:105BA00000000000000000000000000000000000F5
+:105BB00000000000000000000000000000000000E5
+:105BC00000000000000000000000000000000000D5
+:105BD00000000000000000000000000000000000C5
+:105BE00000000000000000000000000000000000B5
+:105BF00000000000000000000000000000000000A5
+:105C00000000000000000000000000000000000094
+:105C10000000000000000000000000000000000084
+:105C20000000000000000000000000000000000074
+:105C30000000000000000000000000000000000064
+:105C40000000000000000000000000000000000054
+:105C50000000000000000000000000000000000044
+:105C60000000000000000000000000000000000034
+:105C70000000000000000000000000000000000024
+:105C80000000000000000000000000000000000014
+:105C90000000000000000000000000000000000004
+:105CA00000000000000000000000000000000000F4
+:105CB00000000000000000000000000000000000E4
+:105CC00000000000000000000000000000000000D4
+:105CD00000000000000000000000000000000000C4
+:105CE00000000000000000000000000000000000B4
+:105CF00000000000000000000000000000000000A4
+:105D00000000000000000000000000000000000093
+:105D10000000000000000000000000000000000083
+:105D20000000000000000000000000000000000073
+:105D30000000000000000000000000000000000063
+:105D40000000000000000000000000000000000053
+:105D50000000000000000000000000000000000043
+:105D60000000000000000000000000000000000033
+:105D70000000000000000000000000000000000023
+:105D80000000000000000000000000000000000013
+:105D90000000000000000000000000000000000003
+:105DA00000000000000000000000000000000000F3
+:105DB00000000000000000000000000000000000E3
+:105DC00000000000000000000000000000000000D3
+:105DD00000000000000000000000000000000000C3
+:105DE00000000000000000000000000000000000B3
+:105DF00000000000000000000000000000000000A3
+:105E00000000000000000000000000000000000092
+:105E10000000000000000000000000000000000082
+:105E20000000000000000000000000000000000072
+:105E30000000000000000000000000000000000062
+:105E40000000000000000000000000000000000052
+:105E50000000000000000000000000000000000042
+:105E60000000000000000000000000000000000032
+:105E70000000000000000000000000000000000022
+:105E80000000000000000000000000000000000012
+:105E90000000000000000000000000000000000002
+:105EA00000000000000000000000000000000000F2
+:105EB00000000000000000000000000000000000E2
+:105EC00000000000000000000000000000000000D2
+:105ED00000000000000000000000000000000000C2
+:105EE00000000000000000000000000000000000B2
+:105EF00000000000000000000000000000000000A2
+:105F00000000000000000000000000000000000091
+:105F10000000000000000000000000000000000081
+:105F20000000000000000000000000000000000071
+:105F30000000000000000000000000000000000061
+:105F40000000000000000000000000000000000051
+:105F50000000000000000000000000000000000041
+:105F60000000000000000000000000000000000031
+:105F70000000000000000000000000000000000021
+:105F80000000000000000000000000000000000011
+:105F90000000000000000000000000000000000001
+:105FA00000000000000000000000000000000000F1
+:105FB00000000000000000000000000000000000E1
+:105FC00000000000000000000000000000000000D1
+:105FD00000000000000000000000000000000000C1
+:105FE00000000000000000000000000000000000B1
+:105FF00000000000000000000000000000000000A1
+:106000000000000000000000000000000000000090
+:106010000000000000000000000000000000000080
+:106020000000000000000000000000000000000070
+:106030000000000000000000000000000000000060
+:106040000000000000000000000000000000000050
+:106050000000000000000000000000000000000040
+:106060000000000000000000000000000000000030
+:106070000000000000000000000000000000000020
+:106080000000000000000000000000000000000010
+:106090000000000000000000000000000000000000
+:1060A00000000000000000000000000000000000F0
+:1060B00000000000000000000000000000000000E0
+:1060C00000000000000000000000000000000000D0
+:1060D00000000000000000000000000000000000C0
+:1060E00000000000000000000000000000000000B0
+:1060F00000000000000000000000000000000000A0
+:10610000000000000000000000000000000000008F
+:10611000000000000000000000000000000000007F
+:1061200090EAC01500000000000000000000130607
+:00000001FF
+/*
+ * The firmware this driver downloads into the tokenring card is a
+ * separate program and is not GPL'd source code, even though the Linux
+ * side driver and the routine that loads this data into the card are.
+ *
+ * This firmware is licensed to you strictly for use in conjunction
+ * with the use of 3Com 3C359 TokenRing adapters. There is no
+ * waranty expressed or implied about its fitness for any purpose.
+ */
+
+/* 3c359_microcode.mac: 3Com 3C359 Tokenring microcode.
+ *
+ * Notes:
+ *  - Loaded from xl_init upon adapter initialization.
+ *
+ * Available from 3Com as part of their standard 3C359 driver.
+ */
index c6af61b4e51e4448272a88cdee6daac956fa2a51..baf5ae45642d99752a45f8244c1b78b6743d9b88 100644 (file)
@@ -26,6 +26,7 @@ fw-shipped- += acenic/tg1.bin
 else
 acenic-objs := acenic/tg1.bin acenic/tg2.bin
 endif
+fw-shipped-$(CONFIG_3C359) += 3com/3C359.bin
 fw-shipped-$(CONFIG_ACENIC) += $(acenic-objs)
 fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \
                                         adaptec/starfire_tx.bin
@@ -39,6 +40,7 @@ fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
 fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
 fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
                             e100/d102e_ucode.bin
+fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin
 fw-shipped-$(CONFIG_SMCTR) += tr_smctr.bin
 fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp
 fw-shipped-$(CONFIG_SND_MAESTRO3) += ess/maestro3_assp_kernel.fw \
@@ -91,6 +93,7 @@ fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda/keyspan_pda.fw
 fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
 fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
 fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
+fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
 
 fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
 
index 00b6e3c0905d09aa41d5670cdcd4e0ae4bba1362..3814d7d426650f574e079730738978d01496b72f 100644 (file)
@@ -493,3 +493,53 @@ Licence:
 Found in hex form in kernel source.
 
 --------------------------------------------------------------------------
+
+Driver: YAM - YAM driver for AX.25
+
+File: yam/1200.bin
+File: yam/9600.bin
+
+Licence:
+ * (C) F6FBB 1998
+
+Found in hex form in kernel source.
+
+--------------------------------------------------------------------------
+
+Driver: 3C359 - 3Com 3C359 Token Link Velocity XL adapter
+
+File: 3com/3C359.bin
+
+Licence:
+/*
+ * The firmware this driver downloads into the tokenring card is a
+ * separate program and is not GPL'd source code, even though the Linux
+ * side driver and the routine that loads this data into the card are.
+ *
+ * This firmware is licensed to you strictly for use in conjunction
+ * with the use of 3Com 3C359 TokenRing adapters. There is no
+ * waranty expressed or implied about its fitness for any purpose.
+ */
+/* 3c359_microcode.mac: 3Com 3C359 Tokenring microcode.
+ *
+ * Notes:
+ *  - Loaded from xl_init upon adapter initialization.
+ *
+ * Available from 3Com as part of their standard 3C359 driver.
+ */
+
+Found in hex form in kernel source.
+
+--------------------------------------------------------------------------
+
+Driver: PCMCIA_SMC91C92 - SMC 91Cxx PCMCIA
+
+File: ositech/Xilinx7OD.bin
+
+Licence: Allegedly GPL, but no source visible. Marked:
+    This file contains the firmware of Seven of Diamonds from OSITECH.
+    (Special thanks to Kevin MacPherson of OSITECH)
+
+Found in hex form in kernel source.
+
+--------------------------------------------------------------------------
diff --git a/firmware/ositech/Xilinx7OD.bin.ihex b/firmware/ositech/Xilinx7OD.bin.ihex
new file mode 100644 (file)
index 0000000..03e8085
--- /dev/null
@@ -0,0 +1,177 @@
+:10000000FF04A036F3ECFFFFFFDFFBFFF3FFFFFF72
+:10001000EF3FFFF7FFFFFFFFEF7FFEFFCEFEFEFE8D
+:10002000FEDEBDDDFDFFFDCFF7BF7FFF7F3FFEBFE3
+:10003000FFFFFFBCFFFFBDB57F7FBFBF7FFFEFFFAF
+:10004000FFFFFBFFF7F7FFFFFFFFFEDEFEFEFADE1E
+:10005000BDFDEDFDFDCFEFEFEFEFC7DFDFDFDFDF52
+:10006000FF7EFEFD7D6DEEFE7CFBF4FBCFDBDFFF54
+:10007000FFBB7FFF7FFFF7FF9EBF3BBFBF7F7F7F41
+:100080007E6FDFEFF5F6FDF6F5EDEBFFEFEFEF7EC0
+:100090007F7F6F7FFFFEFEFEFEFEEFBFFFFFFFFFD5
+:1000A000FFFFFFFFFFFFBC1F1FEEFFBCB7FFDFFF1F
+:1000B000DFEF3BE3D3FFFBFFFFDFFFFFFFBABF2D07
+:1000C000DBBDFDDBDFFAFBFFEFFBDBF3FFDFFD7FDB
+:1000D000EFFBFFFFBEBF27BAFEFBDFFFF6FFFFEF20
+:1000E000FBDBF3D99A3FFFAFBFFFFFBE3F37BD96A3
+:1000F000FFFFFFFFFFFFAEFBF3F3EBFFFFFFFFFF91
+:10010000FFF7FABCAEFEBEFEBB7FFDFF7FEFF7FB45
+:10011000BBD7F77FFFF7FFFFF7BCEDFDBD9D7D7BF4
+:10012000FB7B7BFBAFFFFEFDFDFEFEFFFFFFFFF74E
+:10013000AAB9BF8FBFDFFF7FFFFF7FCFFBEBCBEB0A
+:10014000EEFFFFD7FFFFFF3E333F1C7CFCFFFFFFAE
+:10015000FFFFCFD3F3E3F3FBFFFFFFFFFFEBFE3522
+:100160003F3DFDFDFFFFFFBFFFEF6FE3E3E3EFFF69
+:10017000FFDFFFFFF7FE3E5EFEFFFFFFFFFDFFFF1D
+:10018000AFCFF2CBCF8EFFFFFFFFFFFDFC3E1F9EE8
+:10019000ADFDFFFFBFFFFFEFFFB3F7E7F7FAFFFF8C
+:1001A000FFFFFFEEEBABAF9FE37FFFDEFF7FEEFFD6
+:1001B000FFFB3AFAFFF277FFFFF7FEFFFEBDAEDE70
+:1001C0007D7DFDFFBFEEFFFDFFDBFBFFF7EFFBFFDC
+:1001D000FFFEFF2DAFB9FD79FBFAFFBFEFFFFF91E7
+:1001E000FAFBDFF7F7FFFFFFFCCF37BFBFFF7F7FD3
+:1001F000FFFFFFAFFFFFF3FBFBFFF5EFFFFFF7FA9A
+:10020000FFFFEEFAFEFB55DDFF7FAFFEFFFBFBF5C8
+:10021000FFF7EFFFFFFFBEBDBDBDBD7D7B7B7B7BE1
+:10022000FBAEFFFDFEFFFFFFFFFFFFFFF7DAB76149
+:10023000FFB959F373F3DF7F6FDFEFF7EBEBD7FF16
+:10024000D7FFFFF7FE7FFB3E3873F67FFCFFFFCF43
+:10025000FFB7FBB3B367FFE7FDFFEFF67FB7BCF572
+:100260007BF6F7F5FFFFEFFFF7FFF7CEE7FF9FFF06
+:10027000FFF5FE7DFF5FFFFFFFFFFFFFFFEFFFF6D4
+:10028000CBDBEEFEFFDFFFFFFFFE7FBE1E3EFEFF6D
+:100290007DFEFFFFEFBFE7FFE3E3FFDFE7FFFFFFC9
+:1002A000B8EFB72FEEFFDFFFBFFF7FEFEBBFA3D3AA
+:1002B000FF7FFFFFFFFFF7BEFD3FCFFDFBFFFFFF0F
+:1002C000FFFFAFFBBFBBBFDBFDFBFFFFFFFF3EFE42
+:1002D0003FBABAFEFFFFFFEFFFEFC37FB29BFFFF06
+:1002E000FFFFFEFFFF3CFF3F3CFFFEFFFFFFFFFF66
+:1002F000AFF3FEF3E3EBFFFFFFFBFFF79AFEAF9ECA
+:10030000BEFEFFDFFFFF7BEFF7BFFBFBFBFFFF7FC7
+:10031000FFFFFFBCBDFDBDDD7D7B7B7B7BFBAEFFBF
+:10032000FFFFFEFEFFFDFFFFFFF79AFF9FFFAFEF0E
+:10033000FFFFFFFF7FCFF3FFEBFFEBFFFFBFFFFFF1
+:10034000EFFEFF37FCBFFFFFFFFFFFFFCFEFFDF327
+:10035000FFEEFEFFFFFFFFFF6EFD2FFDFFFDFFFF26
+:10036000FFFFFFEFCFFFF3BF69FFFFFFFFFFFFFEC0
+:10037000FB9FFFBFFDFFFFFFFFFFEF87FEDAEFCF21
+:10038000FFFFFFFFFFFFFEEFBFEFEFFDFFFFFFFFF0
+:10039000FFEFFDFF7BFFEBFEFFFFFFFFEBF8FFEF43
+:1003A000AFFFFFBDFFFFFF7FEE7FEFFFBBFFBFFB98
+:1003B000FFFFFFF7F6FBBDFDDDF5FFFFFFFFFFAF22
+:1003C000FF5FF5DFFF7FFFFFFFFFFFF6F3FFDEFEBE
+:1003D000EFFDFFFFFFFFEFFFDEDF5FDFFDFFFFFF52
+:1003E000FFFFFEFFFFFEFEFFFDFFFFFFFFAFFFFF72
+:1003F000EFEDFFDFFFFFFBFFFFDABDBEAEFE7FFDCF
+:10040000DFFFFF7FEFFFFBFBFB7FF7FFFFFFFFF748
+:10041000BCFDBDBDBDFD7B7B7B7BFBAEFFFFFDFF60
+:10042000FFFFFDFFFFFFFFFA9FBFBFCF7FFFFFFF73
+:10043000FFFFAFFFEBEBEBFFD7FEFFFFBFE7FEBF1A
+:100440007FFCFFFFEDFFFFFFFF4FFFFBFBFFFFDD2B
+:10045000FFFFFFFFFFFEBDDF9DFDDFB9FFFFFFFFD9
+:10046000EFFFFBEFEBFFDEFFFFFFFFFFF69FFFFC61
+:10047000FEFBFDFFFFFFFFEFDFFACDCFBF9FFFFFCA
+:10048000FFFFF7FEBFFFDFEF5FFFFFFFFF7F6FFFA5
+:10049000BBFDFFFFFFFFFFFFFFFF7EFF5FFFBFBF53
+:1004A000F9FFFFFF7F6E7BFFEFFDEBDFFFFFFFFF3D
+:1004B000F7B63EFCFDBF7EFBFFFFFFF7EFF7F3F75C
+:1004C000FFFBFFFFFFFFFFFF6E3579FFBFFCFFFF64
+:1004D000FFFFFFEFFB53DFFFEBBFFFFFFFFFFFBCA3
+:1004E000FFFFFFBFFFFDFFFFFFFFAFF5FFF7FFFBC4
+:1004F000FFFFFFFFFFFFBAAAEEFE3F7DFDFFFFFFFC
+:100500007FAF77FBFBFFFBF7FFFFFFFFF7BEBDBD34
+:10051000BDBDFD7B7B7B7BFBAEFFEFFFFFFFFFFCE9
+:10052000FFFFFFFF9AD9B8FFFF79FFFFFFFFFFCF63
+:10053000FBFFEBFFEBD7FFFFFFFFE7DEF8FBFE3F24
+:10054000FBFDFFFFFFFFCFADBFFAFF73DFFFFFFF34
+:10055000FFFF3AF5B7FC3FF9FDFFFFFF7FEFF3FF29
+:10056000BFFEF39FFEFFFFFFF73EFFFFFFBFFFFF52
+:10057000FFFFFFFFAFD3FEDBFFDBDFFFFFFFFFFF70
+:100580003EFFBFFF7FFFFDFFFFFFFF8FF3FFEDFF8C
+:10059000F7FBFFFFFFFFEFF63CFEFFFFFFFFFFFF54
+:1005A000FF9FEFEFD1FFFFFFFFFFFFFFFFFF7EBFCA
+:1005B000FDFFFFFFFFFFFFFFBBEFDFF1FFFFFFFFCF
+:1005C000FFFFFFFFFFEE3EFEFFFFFFFFFFFFFFBF4E
+:1005D000EFFDC3FFFFFFFFFFFFFFBFFFFC3EFEFF7E
+:1005E000FFFFFFFFFFFFFF2EEFF3FFFFFFFFFFFF08
+:1005F000FFFFF7BABEFEFFFFFFFFFFFFFF7FAFFB6E
+:10060000FBFDFFFFFFFEFFFFFFF2D6EDBDBDBD7D91
+:100610007B7B7B7BFBAFDFFFFFFFFFFFFFFFFFFF6E
+:10062000FF92BFFFFFFFFFFFFFFFFF7FAFEBEBFF7F
+:10063000FFFFFFFFFFFFFFE7FE2EFEFFFFFFFFFFB5
+:10064000FFFFFF4FEFF3FFFFFFFFFFFFFFFFFFFE87
+:100650003CFEFFFFFFFFFFFFFFFFEFCEC3FDFFFFED
+:10066000FFFFFFFFFFFFFE5DFFFFFFFFFFFFFFFF3D
+:10067000FFEFCFEBFFFFFFFFFFFFFFFFF7EE3EFFB8
+:10068000FFFFFFFFFFFFFF7FEFDFE2FFFFFFFBFF4B
+:10069000FFFFFFFFF6BEFCFFFFFFFFFFFFFF7FEE48
+:1006A0005FE6FFFFFFFFFFFFFFFFFF3E7DFFFFFF56
+:1006B000FFFFFFFFFFFFEFF3FBFFFFFFFFFFFFFF6A
+:1006C000BFF736BEFEFFFFFFFFFFFFFFFFEFD3F6D2
+:1006D000FEFFFFFFFFFFFFFFFFFC7FEEFFFFFFFFBF
+:1006E000FFFFFFFFAFEFEBFFFFFFFFFFFFFFFFFF8E
+:1006F000BABEFEFFFFFFFFFFFFFFFFEEFBFAFFFFAB
+:10070000FFFFFFFFFFFFF7D6FDBDBDBD7D7B7B7B00
+:100710007BFBAEFF7EFFFFFFFFFFFFFFFFF7BABFD0
+:10072000FFFFFFFFFFFFFFFF7FEFEB6BFFFFFFFF11
+:10073000FFFFFFFFF7FEBEFEFFFFFFFFFFFFFFFF14
+:100740004FEFF7FFFFFFFFFFFFFFFFEF3E6EFCFFE6
+:10075000FFFFFFFFFFFFFFEFC3C9FFFFFFFFFFFF2B
+:10076000FFFFFF3EBFFFFFFFFFFFFFFFFFFFEFFBAE
+:10077000D5FFFFFFFFFFFFFFFFFFFEFEFEFFFFFFB6
+:10078000FFFFFFFFFF6FEFFBFFFFFFFBFFFFFFFF21
+:10079000FFF6DFFFFFFFFFFFFFFF7FFEEFFFFFFF23
+:1007A000FFFFFFFFFFFFE7FFFEFFF7FFFFFFFFFF7A
+:1007B000FF7FFAEFBFFFFFFFFFFFFFFFFFE7FFFE37
+:1007C000FFFFFFFFFFFFFFFF7FFEEFBFFFFFFFFF0A
+:1007D000FFFFFFFFA7FFFCF7FFFFFFFFFFFFFF7F0C
+:1007E000FEAEFFFFFDFFFFFFFFFFFFE7F7FAFFFD94
+:1007F000FFFFFFFFFFFFFF7FAFFFFFFFFFFFFFFFD9
+:10080000FFFFFFF7BEBDBDBDBD7D7B7B7B7BFBAF2F
+:100810007FFFFFFFFFFFFFFFFFFFFFCAFFFFFFFF9D
+:10082000FFFFFFFFFF7F6FFFFFFFFFFFFFFFFFFFE8
+:10083000FFE7FEFFFFFFFFFFFFFFFFFFFFCFFEFF12
+:10084000FFFFFFFFFFFFFFFFFFFEDFFFFFFFFFFFD9
+:10085000FFFFFFFFEFFFFEFFFFFFFFFFFFFFFFFFB9
+:10086000FEFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFA9
+:10087000FFFFFFFFFFFFF7FEFFFFFFFFFFFFFFFF91
+:10088000FFFFEFFFFEFFFFFFFBFFFFFFFFE7F2FCB5
+:10089000EFFFFFFFFFFFFFFF7FAEEFFFFFFFFFFF59
+:1008A000FFFFFFFFF77EFDFFFFFFFFFFFFFFFFFFE3
+:1008B000EFFFFEFFFFFFBFFFFFFFBFFFFEFEFFFFDB
+:1008C000FFFFFFFFFFFFDFEFDDFEFFFFFFFFFFFF8B
+:1008D000FFFFFFFEFEFFFFFFFFFFFFFFFFFFAFEF8A
+:1008E000FFFFFFFFFFFFFFFFFFFFBAFEFFFFFFFF5E
+:1008F000FFFFFFFFFFEFFAFEFFFFFFFFFFFFFFFF1E
+:10090000F69CBDBDBDBD7D7B7B7B7BFBAEFFFFFF52
+:10091000FFFFFFFFFFFFFFF77AFFFFFFFFDFFFFF94
+:10092000FFFF6FEFF7FFFFFFDFFFFFFFFFFFF7FEA8
+:10093000FEFFFFFFDFFFFFFFFFFFCFEBFFFFFFFF2C
+:10094000FFFFFFFFFFEF9EFCFFFFFFFFFFFFFFFF2B
+:10095000FFEFEFFFFFFFFFFFFFFFFFFFFFFEFFFFC8
+:10096000FFFFFFFFFFFFFF7FEFCBFFFFFFFFFFFD5D
+:10097000FFFFFFFFBEFDFFFFFFFFFFFFFFFFFFEFDA
+:10098000EFFFFFFFDFFFFFFFFFFFFFF8FFFFFFFFAE
+:10099000BFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFB7
+:1009A000FFFFFEFFFFFFFFFFFFFFFFFFFBAF7FFF2C
+:1009B000FFFFDFFFFFFFFFFFFFFEEFFFFFFFFFFF78
+:1009C000FFFFFFFFEFFFFFFFFFFFFFFFFFFFBFFF87
+:1009D000FEFFFFFFFFFFFFFFFFFFFFAEFFFFFFFF79
+:1009E000FFFFFFFFFFFFF7FAFFFFFFFFFFFFFFFF24
+:1009F000FF7FEFFFFFFFFFFFFFFFFFFFFFF7BCBD24
+:100A0000BDBDBD7D7B7B7B7BFBAFFFFFFFFFFFFFA2
+:100A1000FFFFFFFFF7FAFFFFFFFFFFFFFFFFFF7F73
+:100A2000AF7FFFFFFFFFFFFFFFFFFFEFFEFFFFFFB7
+:100A3000FFFFFFFFFFFFFFCFFFFFFFFFFFFFFFFFF6
+:100A4000FFFFFFFEFFFFFFFFFFFFFBFFFFFFEFFFCB
+:100A5000FFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFA7
+:100A6000FFFFFFFFFFEFFFFFFFFFFFFFBFFFFFFFE6
+:100A7000FFFCFFFFFFFFFFFFFFFFFFFFEFFFFFFF99
+:100A8000FFFFFBFFFFFFFFEFFEFF9F9F9F3F3F3FEB
+:100A90003F3FFFEFDFDFDFDFCFB7BFBFBFBFFFBC31
+:100AA000B99DBDBD7D7B7B7B7BFBEFD7F5F3F1D1A2
+:100AB00065E3E3E3A3FFFE7FFEDEDEFFBDBDBDBD5C
+:100AC000DFEFFBF7F3F3F3E7E7E7E7E7FBFEFFFF13
+:0A0AD000FFFFFFFFFFFFFFFFFFFF26
+:00000001FF
+This file contains the firmware of Seven of Diamonds from OSITECH.
+(Special thanks to Kevin MacPherson of OSITECH)
diff --git a/firmware/yam/1200.bin.ihex b/firmware/yam/1200.bin.ihex
new file mode 100644 (file)
index 0000000..9d34e56
--- /dev/null
@@ -0,0 +1,342 @@
+:10000000FFF200A5ADFFFE9FFFEFF3CBFFDBFCF29D
+:10001000FFF6FF3CBFFDBFDF6E3F6FF17DB4FDBF5C
+:10002000DF6F3F6FF70BFFDBFDF2FFF6FFFFFFFF18
+:10003000F0CFFFFFFFFEFFFFDFFFFFFFEFFFFFFF40
+:10004000FDFFFFFFFEFFFFFFFFFFF1FFFFFFFFBF11
+:10005000FFFFF7FFFFFBFFFFFFFCFFFEFFFFFFF0CF
+:100060005FFFFFFFFEFFFFFFFFFFFFFFFFFFFFFF41
+:10007000FFFFFFFFFFF7FFFFFFF1FFFFFE7FBFFF67
+:10008000FFFFFFFFFFFFFFFFF7FFFBFFFFFFF09FFB
+:10009000FFFFFFFEFFFDFFFFFFFFDFFFFFFFF7FF9B
+:1000A000FFFFFBFFFBFFFFFFF0FFFFFFFFFFFFFF77
+:1000B000F7FFFFFBFFFFFFFEFFFFFFEFFFF05FFF1C
+:1000C000FFFFFEFFFFEFFFFFFBFFFFFFFFFFFFFF55
+:1000D000FFBFFFFFDFF7FFF1FFFFFFFFFFFFFFFFA6
+:1000E000FFFFFFFFFFFBFEFFFFFFFFFFF0FFFFFF34
+:1000F000FFFEFFFFFFFFFFFFFFFFFFFFFFFFFFEB25
+:10010000FFFFFFFDFFBFF1FFFFFFFFDFFFFFFFFB73
+:10011000FFFFFFFFFFFFFFFFFFFFFFF06FFFFFFF8E
+:10012000FEFFFFFFFFFFFFFFFFFFDFFFFFFFFFFF00
+:10013000FFFFF7FFFFF1FFFFF7BFE7FFFFFFFFFB49
+:10014000FFFFFFFFFFFF77FFFFFFF0FFFFFFFFFE57
+:10015000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF
+:10016000FFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFAD
+:10017000FFFFFFFFFFFFFFFFFFF01FFFFFFFFEDBA3
+:10018000FFFFF5A5FD4B6EEF3332DDD34AD692FE6D
+:10019000B33FBDF1FADBFEF7F696BDBDFFBDFFED47
+:1001A0007F6B7FFBDFFEFBFE90CFFFFFFFFEBEEF0E
+:1001B000FFFFDB5FF6FFF68FFDA5DDFFFFFFFF6FA3
+:1001C0007FDBF1FCBFFF6FFFEFFC5B5DDADFF4FF6D
+:1001D000F2FFFDBFFFFFFFD01FFFFFFFFEFFFFFF8E
+:1001E000FFFBEFB7FC33FFFBFF046AF33C36FFF085
+:1001F0000FF10FFFFFFFF315720FF16FFFFE943F3A
+:10020000FFFFFF7BFFFFF0FFFFFFFFFEFFFFFFF0A1
+:10021000F7EFB7FC33FFFFFF046AF33C36FFF00F44
+:10022000F10FFFFFFFF315738FF26FFFFE943FFF97
+:10023000FFFF7D9FFFF00FFFFFFFFEFFFFFFFF9E11
+:10024000FFFCEFD3FBFF7FF55FFE59FFFFFFFCF1E3
+:10025000FE7FFFFFFA17FFE7EFEFFFFF3FF1FFFF22
+:10026000FFFFFFFFF0FFFFFFFFFEF5FFBFFFFCEA10
+:10027000FFF0FFFFBFF93FB1EFFFD7FFFBFFF0FF3C
+:10028000FFF3FFDFFF7BFFFDFFF6FFBFFFFFBFFFB9
+:10029000FFFFDAF0FFFFFFFFFEF2C00100000202E5
+:1002A0000202004040401000000020000001000059
+:1002B000000000001900040400000000000000100D
+:1002C000003CF0AFFFFFFFFEFDBFFFFFFBFFFDFFA8
+:1002D000FF7FFFFFBFFFEFFFFFFDFFFFF1FFDFFF2E
+:1002E000FFFFFFFFFFBFFEFFFFFEFFFFFFFFFFDF80
+:1002F000DBF06FFFFFFFFEF0BFDFFF7FFFFFFFFFC1
+:10030000DFDFFFEFFF9EEFFFFF7FFFF1EFFFFFFF5C
+:10031000F7FABFFFFFFE47EFFFBDF6FFFFDFF5F087
+:10032000F0EFFFFFFFFEF8300000000400010208BC
+:1003300016000000800001020080010C0200000194
+:100340000000200000060020001000140004C1F08E
+:100350002FFFFFFFFEFFFFFFFFFFFFFFFBFFFF7F02
+:10036000ECFFFFFAFFBFFF6FFFE1FFFFFFFFBDFEE6
+:1003700046FFEF7FCDDFFFFFFDFFBDFF7F7FF04F2B
+:10038000FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7E
+:10039000FFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFF7B
+:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFF00FFF5C
+:1003B000FFFFFEFFFFFFFDA4BCCD6D6B6F5BDC3369
+:1003C0005AF6F7F6B33FBDC1FA5AF6F6B6F7FFBDD7
+:1003D000BB3CCECF34EF33BBCCFFFFFFF04FFFFF72
+:1003E000FFFEBFFFFFFFDBFFF6D6FFFDFDBFFFAD4A
+:1003F000BFF97F6FFCDBF1FDBFFF6FFFFFDADBFCB6
+:10040000DBFF768FF6FFCDABFEFBFFD0FFFFFFFFDC
+:10041000FEFF9FFFF420AF6D0BC17BFFFFFFCBFF03
+:100420003FF0EF7F0FF1C33CFFFFFFFFFFFFF80B33
+:100430001D6A64056B9901FFFDEFF02FFFFFFFFEC2
+:10044000FFFFFFF4002FCC0BC37FFFFFFF0ADFBFCE
+:10045000FD7FFFFFF1C3BFFFFFFFFFFFFFF04A0E6D
+:10046000966402979910FFFFFFF0DFFFFFFFFEFF8A
+:10047000FFFFFE84F9D527F17FFFF8EBDFF3CF3FD5
+:100480001FFFF711FFCFFFFE67FFFFFFFFC4FFFF56
+:10049000B3A1FFF9E0FFFFFFF0EFFFFFFFFEF5FF65
+:1004A000FFFB7FE0FFC7FE7F3FFFFD778D7F0FFFE4
+:1004B000C3FFF1BF8FCFFFFFDD7BFFF6FAF7FF40F1
+:1004C0009FF97FD8FFFFFAF01FFFFFFFFEF1C0008A
+:1004D00000030000000000000000400010000010B9
+:1004E00000010010202000001000040105000000A1
+:1004F00000404000003CF01FFFFFFFFEFDBFFFFF7C
+:10050000FFFFFE7F7FFFEFFFFFDFFFFFDFFFEFF764
+:10051000F1FFFFFFFFDFFFFFF7FFFFFFFCFDFF7FA6
+:100520007EFFFFFFDBF06FFFFFFFFEF0BBFFFFFF73
+:10053000FFFFFEEBFD6FFFF7FEF57FFFFF7FBFB113
+:10054000FFFF9FBFFBFFFEFFFEFFF7EBDFBF5FDD9F
+:10055000FFDBFDD0F06FFFFFFFFEF8302000420010
+:100560000000301804080921828002000800010000
+:1005700000000C2010001100448400202084800022
+:100580000000C1F0DFFFFFFFFEFFF7FFFBDDF9FF1B
+:10059000DAFFDCDDFCFBFFBFFB3ED796FE61F7FF19
+:1005A0007FFF3FFDFFDFCFF7DFF7BFFDFFFEEFEF80
+:1005B000FEFFF07FFFFFFFFEFFFFFFFFFFFFFFFFDC
+:1005C000FFFFFFFFFFFFFFFFFFFFFFFFF1FFFFFF49
+:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B
+:1005E000FFF02FFFFFFFFEFFFFFFF3BDFD4B74CFBA
+:1005F000735BCB3BDFFEF7FED375ACA1FBDFFEF7F1
+:100600007696B524BDA5AD492F692B525BBDFFFF82
+:10061000F0CFFFFFFFFEBFFFFFFFDBFFF6FEFFCCCB
+:10062000A7FBADFF7F6FFF6D7FDBF1FDBFFF6FFFAE
+:100630006FFFDBFFDBFFF697F6FFB5B5FFFFFFD0DF
+:10064000EFFFFFFFFEFFFFFFFDA5BC43FC7C03E7C0
+:10065000FFFF20FFFFFFCCFD7DF1FFFFFFFFD5591E
+:10066000BA56666AAD9AA99A97A5AABBFFFFF00F82
+:10067000FFFFFFFEFEFBFFFDF7FD43FFFD6BE7FF06
+:10068000FFDFFFFFFFFFFF3FF1FFFFFFFFD559B582
+:10069000A6666AAD9AA9996B5AAAFFFFB7F03FFF09
+:1006A000FFFFFEFFFFFFFE9CF7FDD241FFFFF27F41
+:1006B0008FFFFF3DF3FF17F1FFFFFFFFFF7FDFFC21
+:1006C0008F38FFEF23FFFBF7C8FFFFFFF09FFFFF0F
+:1006D000FFFEF57FFFFDFFE4FFEBFFCFBFFAFFABAF
+:1006E000EFFFFBFFF3FD61FFFFFFFFFAFFFBFD0DD7
+:1006F000FFFEFF437FFEBFD0FDFFFAF03FFFFFFF8D
+:10070000FEF3C0000000020002010060C0400000D3
+:100710000000340400010000000000000008880010
+:100720000003000040004000003CF03FFFFFFFFEE0
+:10073000FD3FFFFFFFFFFFFF7F7FBFFFFFFFFFFFCB
+:10074000FFFFFFF7F1FFFFFFFFFFF7FFFFFFFDFFD9
+:10075000FFFFFFFEFE5FFFFFCBF0DFFFFFFFFEF0BE
+:10076000FFFFFDFFEFE3DEEED9C593FFFFFEFEFFC7
+:10077000FBEEFEF1FFFFFFFFFFFDFFBFF7FFFF7F77
+:10078000AFBDDFDFFBF3F3F0F0AFFFFFFFFEF834A8
+:10079000000661001801A0051700200528200000B0
+:1007A0000500410000400009000120868208400346
+:1007B000803070081402C1F0CFFFFFFFFEFFFFFF83
+:1007C000FFFFBDEFFBFFFFFB9C7FEFDFFFBFEBDE1B
+:1007D000FFC17FFFFB7FFFFFFF5FFFFFFFDFBFEF7B
+:1007E0003FF78FEF7FFFF07FFFFFFFFEFFFFFFFF71
+:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09
+:10080000F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06
+:10081000FFFFFFFFFFF03FFFFFFFFEFFFFFFFFBDFA
+:10082000DFEF7D6D2B5A5DD2DFF692B6B2B3ACA18D
+:10083000FBDFFEF1EEF5F6BC6BBD7DAF1AEF5F6B33
+:10084000C6FFFFFFF05FFFFFFFFEBFFFFFFFDBFF05
+:10085000F6FFF6B7FDADFDBFF36FFF6FFFDBD1FD18
+:10086000BFFF6FF56BBC5B3CDAEF16AF16FFCDAB8D
+:10087000FF6FFFD0FFFFFFFFFEFFFFFFFCBFFFFF8B
+:10088000FF6C0310C1F3FFF33AF3CAFFAFF1FFFFB0
+:10089000FFFFD996A665A6666A9569696A5A5AFFE6
+:1008A000FF5FF01FFFFFFFFEFFFFFFFFBFFFFFFF28
+:1008B000EA0F50C3F37FFFF3F3C3FFAFF1FFFFFF76
+:1008C000FFD996A665A6666A9569696A5A5AFFFFB6
+:1008D000FFF03FFFFFFFFEFFFFFFFFD7FFFF5FC1FE
+:1008E0003FF75EF5CE9E5F3F17FFF3E1FFFFFFFF8F
+:1008F000D8FFFAFE67FFFEBF5AFFFFAFF5FFFFFF0D
+:10090000F02FFFFFFFFEF5FFFFFDFFF7FFFD4E3D60
+:100910003FE70BBF8FF9FFEBE3FFE1FFFFFCFFC7F2
+:100920009FFF3E39E5FFCF9BF9FFFFC5FFFFFAF0C0
+:100930005FFFFFFFFEF3C00000000000000040006A
+:100940000000006000000000000100000020002006
+:10095000000110080000000000000000003CF04F03
+:10096000FFFFFFFEFDBFFFFFFFFFFFFFFEFFFFBF1B
+:100970003FFFFFBFFFFFFFFBF1FFFFFFFFF7FFF7A9
+:10098000FFEDFFFBFEFF7FFF7FDFFFFFDDF03FFF9F
+:10099000FFFFFEF0FFFFF3FFF7FFFE5FFFF7FFFF34
+:1009A000DFFFFFFFF7FE7BF1FFFDFDFFDFDFFF7DD8
+:1009B00073F9FFC37EFEFFEFD7FFCFD0F06FFFFFCD
+:1009C000FFFEF83000004004000141200004000256
+:1009D000D50900028002010000000A04000700019E
+:1009E000500180026140410C1408C1F09FFFFFFFDD
+:1009F000FEFFFFFFFEFFFFFFFEDFCB5FFEEFFFFE10
+:100A0000FF3FFF7FFDC1FFFF7FFFDFFDFCFDF7EE36
+:100A1000FFFF4EFFDFCFDBEBFFFFF01FFFFFFFFE0F
+:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6
+:100A3000FFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFD4
+:100A4000FFFFFFFFFFFFFFFFFFF02FFFFFFFFE7F16
+:100A5000FFFFFFFDFFFFFFFFFFFFFFFFDFFFFFFFC8
+:100A6000F7FBFFF1FFFFFFFFFFFFFFFFFFFFFFFFB0
+:100A7000FFFF7FFFFFFF7FFFF01FFFFFFFFEDDFF98
+:100A8000FFFFA5FF6F6BE96FDACAFBDDEEF7F6B289
+:100A9000B3A4A15B5BF6D7F4F77BBDBDADCFEF7F11
+:100AA0006B7F3BDFDBFFFF30CFFFFFFFFEBFFFFFB2
+:100AB000FFFFFFF6FE96FFFDB5FDBFAD7FFF6FFFA9
+:100AC000DED1ADADE9FFF1ECEFDE3FCBFFF6FF325B
+:100AD000FFC5BDFFFFFFD0BFFFFFFFFEFEFBFFF422
+:100AE00028BFFFFDFBD3FFFF42FFFFFFEAB3FCC3BC
+:100AF000C1FF33FFC0156B70FFF0F24FFFFC3E9754
+:100B00003CFFFFFDEFF0BFFFFFFFFEFFFFFFFE78A2
+:100B1000BFFFFDF3EF55FF7EFFFFFFEAB3FCC3C14C
+:100B2000FF33FFC0156FFF0FF0F00FFFFC3D6BC3ED
+:100B3000FFFFFEF7F0CFFFFFFFFEFFFFFFFFFCFF11
+:100B4000FF23F87FFF4EFFFFFFFBF917FFF6F1FFD2
+:100B5000CFEFFFFF13DFE62FC7FFFFE7C1FDFFFE6B
+:100B6000FFFFFFF04FFFFFFFFEF5FFFFFFFEAEFFB1
+:100B7000FF7F3B3FFC7FFCEFFFFCE27BFFF1FDEDE5
+:100B8000EFFFFF3573FFFFFEFAFFFFFFFEBFFFFF22
+:100B9000FFFAF08FFFFFFFFEF1C000000000000031
+:100BA000000000800000400000000C0401404000F4
+:100BB00000302804000800000001000100000000CF
+:100BC00038F00FFFFFFFFEFDBFFFFFFFFFFBFF7FC2
+:100BD000FFFF9FFFFFFFFFFFFFFFFFF1FFDFDFFFD3
+:100BE000FFFFFFEDFFFDFFFFFFFFFFBFBFFFFFC3E5
+:100BF000F03FFFFFFFFEF0BFFDFFBFFFFFFDFFFF68
+:100C0000FFFFFFFD7BFF7FFFBDFFF1EFFFFFFDDF7C
+:100C1000FDFBFFFFBFBEFFCD7FFCF7F76FBFD8F036
+:100C2000EFFFFFFFFEF830000000040000A000000E
+:100C3000C0000020340000000C810020A42000101F
+:100C400008044808004093001000381820C1F03F05
+:100C5000FFFFFFFEFFFBFFFFB9DFFEB3FFFFE7FD76
+:100C6000FFFF3BFF7FFFBFFFC1FFFCFFFF3F77FEA2
+:100C7000FECFFFBFFDBFFFFEEDF2FDF7FFF02FFF40
+:100C8000FFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFF75
+:100C9000FFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFF72
+:100CA000FFFFFFFFFFFFFFFFFFFFFFFFF0BFFFFFA3
+:100CB000FFFEFFFFFFF3ADCFEF70C9733BDF5B4A71
+:100CC000F6B7FED7F5BCC133CAD6B76EF7FBBDC5C4
+:100CD00024CF6F2F4D2BBA5AFFFFFFF0AFFFFFFF5E
+:100CE000FEBFFFFFFFFFF6F6D7FFFFADBDFFFFFF23
+:100CF000EFF77FFC5BB1FDBD756FEF6AFD5BFBDB62
+:100D00003ABF8E9FFFBFFDFF6FFFD06FFFFFFFFE5B
+:100D1000FFBBFFF03FFFFFFDFB7FDEFFFF5AD6BFAB
+:100D2000D82ABFBFF1E5FFCCC0A970FFF33C3CFD62
+:100D300057FD980300C3FFFFFFF0AFFFFFFFFEFF6B
+:100D4000FFFFFF3DBFFFFDFBFFDBFFFF0FFC3FD8B9
+:100D50002ABFBFF1EFFFCCC096BEFFF33FFFFD57A8
+:100D6000FD990FFFC3FFFFFFF04FFFFFFFFEFFFFE7
+:100D7000FFF1E7FFFFF38E7BFFA8FFDF7F8E787325
+:100D8000FFF15162FFFC4BFFF3FF7ECFF9FFFDFF48
+:100D9000FF7FFFE0FFFFFFF04FFFFFFFFEF5FFFFCC
+:100DA000FBFDAEFFFCFE6F3FF8FD77AFFE37FE7B2D
+:100DB000FFB18CFFEFFDF8E7BFFFF1FE3EF7FE95B8
+:100DC0003EBFFFFFFFFAF0BFFFFFFFFEF1C00000D4
+:100DD0000104000000008002000010001000100854
+:100DE0004180100000081084000C040261000081A2
+:100DF000000000003DF07FFFFFFFFEFDBFFFFFFF93
+:100E0000FFFF7FFFFEFDBFFFFFFFFFFFFFFFFFF1C3
+:100E10007FBFF77FEFFFEFFFF7FDFFFFFD7FFFBE17
+:100E2000DFFFFFD9F0BFFFFFFFFEF0BBFF7FFBFF3F
+:100E3000FBFFBFFFF37FFBFDEB7FDFFAFFDEF0ED93
+:100E4000FFB1F7F91FB55BFE7EF7BEFD7F5FB5F71B
+:100E5000FFFFD0F04FFFFFFFFEF830010007420117
+:100E6000006A185080000002400101200101241492
+:100E700021100208070800401080580084801810D4
+:100E800040C1F0BFFFFFFFFEFFFFFFF7FFDBB7F33F
+:100E9000DF7CF874FFFF6F7D3F7EEC7FC1F5FFCFF5
+:100EA0006F9FF9DFBEE5E7FFD7F3DDFBFFFCFFBF78
+:100EB000FFF0FFFFFFFFFEFFFFFFFFFFFFFFFFFF52
+:100EC000FFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFF40
+:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22
+:100EE000F02FFFFFFFFED7FFFFFFB4CFEF776F7349
+:100EF0003A4A3ACBD4F72ED6BDBDA13BDFD6F7EEAA
+:100F0000D335BDFBBDCEEB2B4D2FBBDAFFFFFEB0C3
+:100F10005FFFFFFFFEBFFFFFFFDF5F36AF3FEDB7B5
+:100F2000F5FDF32BEF77FFFBDAB1BDA377697F4FB8
+:100F3000FFDBFA5BFFF2FEFF96FFFFFEDFFFD0AFA5
+:100F4000FFFFFFFEFFFFFFFD8FFD406F9E835A0FE7
+:100F5000FAC3FFFFFCE97FF301D000FEBFCD3FF0F5
+:100F6000EFFCC50C3FFD680BFFFFFFFEDFF0FFFF4E
+:100F7000FFFFFEFFBBFFFD85FFD46F9FC35A0FFF2E
+:100F8000FFFFFFFCE97FF301F0FBC2BFFC0037EF7E
+:100F9000FCCDBC3FFF0CBFFFFFFFFFFFF05FFFFF7B
+:100FA000FFFEFFFFFFFFD9F7D1B77E7FF1E4FDFF22
+:100FB000FBFBFF5FFF7FB1BC0F67EBB83FFFE2FFBA
+:100FC000E9FFFDE3FF3F9FC2FFFFFFF09FFFFFFF31
+:100FD000FEF57FFFF03FBCFFD5F5CE3FFEFFFE6D77
+:100FE000FFF1BF7BFFF1FDFF4FFF87FFAEFFB1F8C1
+:100FF000FEFFFF7801B9FFFFFFFAF02FFFFFFFFEB2
+:10100000F3C00000000402130200804000901000B2
+:1010100010000200012080121000400800040000AF
+:1010200002000140008000003CF0EFFFFFFFFEFDEA
+:101030001FFFFFFF7FFFFFFFFF7FFF7FF7DFF7FF50
+:10104000F7FBEBD1FFFFFFFFEFF7FFFFFBFFFEFF1B
+:10105000FF7EFFFBFFFFFFDBF0FFFFFFFFFEF0FF68
+:10106000FFB7EBF7DFFFFEF56BE7EDF73EECFF5464
+:10107000EF6FF1F5AF6FF6FDFFDD7BFFEFBF7FFF99
+:10108000FFF7FFF35FF7D0F0CFFFFFFFFEF8300070
+:1010900080400400812C0424000201C802000224C4
+:1010A0000001B442DC4402159002034839100224C6
+:1010B000A0BA000040C1F0BFFFFFFFFEFFFFFFFF2F
+:1010C000FEFCF7F0EEB65DFDF5FFDBF77F7FBEFFC0
+:1010D000C1FEBFFAFA5FFFADFFEFFF7FDF7FFEBF0C
+:1010E000B794BFFFFFF09FFFFFFFFEFFFFFFFFFF73
+:1010F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10E
+:10110000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF
+:10111000FFFFFFFFF08FFFFFFFFED7FFFFFBB5FFD5
+:10112000EF7CEB2B525B3BDAD4F33696B5BDF1FB8B
+:10113000DAEEF6FED335BDDFADCFEF7ECD6BBBDF94
+:10114000FFFFFDB0EFFFFFFFFEBFFFFFFFD35FF626
+:10115000FFF6FFFDADFDFF7FEFFF6F7FDBF1A5A386
+:101160007F6F6B4FFFDBFBCBFFF6FFF4D7FDBFFEBE
+:10117000DFFFD0CFFFFFFFFEFFFFFFF7DFFFFFFF27
+:101180003F7FFCE5FF20FEFFFFDF7FFFF17FFFFEDB
+:10119000FFF07C3D4FF3C33FFFFF6FC3FF0FFFFF27
+:1011A000AFF02FFFFFFFFEFFFFFBB7E00FFFFF2BAE
+:1011B000FF7DBFFFDFFFFFF89F7FFFF155FFFFFFC0
+:1011C000FD7C3CFFF3C33FFFFFEFC3FFDFFFFFFFEB
+:1011D000F09FFFFFFFFEFFFFFFFFEFFFFF9FBF7FBF
+:1011E000F919478EE79F3F17FFFC81C17EF3D9F9BC
+:1011F00073DFF47FFAFFFFFFFB7F77C7FFFFFFF08E
+:101200002FFFFFFFFEF5F7FFFBFFF73FFCBF3E3F61
+:10121000ECFF81AFFE4FF3BBFFF07EFF6FFF87FF58
+:10122000BBFFD5FCFF7FFC6FFFEFE7FFFFFAF03F4E
+:10123000FFFFFFFEF3C00000000000000000008080
+:101240000030106020000800012080001000040021
+:101250000000000000020080400008203CF06FFF0A
+:10126000FFFFFEF5BFFFFFFEFFFFFFFF7FFE3FFF1B
+:10127000FFFFFFFFEFFFFFF1DFDFFFFFFF7FDFFF7C
+:10128000FDBDFFFFFFFBDFFFFFFFFF5BF0FFFFFF89
+:10129000FFFEF0BFBFBFFFF7FBFFFEEEFAFFFFFF51
+:1012A0003D3BFFFFFEFBF1FFBF7BFFFFEFFFBFFFFB
+:1012B000FFFFFFFFFEFFF7EFFFFBD0F0DFFFFFFFB9
+:1012C000FEF83000000000000B10050100080002CD
+:1012D000010100001001C8080000000042020000E7
+:1012E000008002000040248000C1F03FFFFFFFFEAD
+:1012F000FFFFFFFFF7FDF7FAEFEEF9FDFFF7FEBF87
+:101300001FFD9EFDD1EFFFF77F9FFFEFFFF6FFFE72
+:10131000FE7BFFBDFF7EFFFFFFF03FFFFFFFFEFFF5
+:10132000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD
+:10133000FFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFFCB
+:10134000FFFFFFFFFFFFFFFFF0AFFFFFFFFEFFFF0D
+:10135000FFF7FFFFFFFF7FFFFFFFDFFDFFFFDFFF67
+:10136000FF5FF1BFFFFFFFFFFFFFFFFFFFFFFFFF7B
+:10137000FFFFFFFFFFFFFFF0DFFFFFFFFEFFEFFFBD
+:10138000F7FFFFFFFFFFFFFFFF3FFBFFFFEFFBFD4F
+:10139000FFF1FFFFFBFFFFFFFFFFFFFFFFFFFFFF6F
+:1013A000FFFFFFFFFFFFF02FFFFFFFFEF7FFFFFF35
+:1013B000FFFFFFFFFDFFFFFFFFFFFF7FFFFFE7FFD7
+:1013C000F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B
+:1013D000FFFFFFFFFFF0FFFFFFFFFEFFFFFFFFFF2D
+:1013E000FFFFFFFFFFFFFFFFFFFFCFFFFBFFFBF153
+:1013F000FFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFF01
+:10140000FFFFFFFFF02FFFFFFFFEFFFFFFFFFFFFCC
+:10141000FFFFFFFFFFFFFFFF7BFFFFFF7FFFF1FFEE
+:10142000FFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFEC
+:10143000FFFFFFF07FFFFFFFFEFFFFFFEFFFFFFF5C
+:10144000FFFFFFFFFFFFFFDF57FFFEBFFBF1FFFFC7
+:10145000FDF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFA6
+:10146000D7FFF07FFFFFFFFEFFFFFFF7DBFFDBFD96
+:10147000F6FFF6FF3CBCBCBFDF6FEF2FF13CBFBCFB
+:10148000BFDF6FFF6FF7DBFFDBFDF6FFF6FFFFFF50
+:1014900001E2EFFFFFFFFEFFFFFFFFFFFFFFFFFF88
+:1014A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C
+:0614B000FFFFFFFFFFFF3C
+:00000001FF
+/*
+ *
+ * File yam1k2b5.mcs converted to h format by mcs2h
+ *
+ * (C) F6FBB 1998
+ *
+ * Tue Aug 25 20:24:08 1998
+ *
+ */
diff --git a/firmware/yam/9600.bin.ihex b/firmware/yam/9600.bin.ihex
new file mode 100644 (file)
index 0000000..817a34b
--- /dev/null
@@ -0,0 +1,342 @@
+:10000000FFF200A5ADFFFE9FFFEFFBCBFFDBFEF293
+:10001000FFF6FF9CBFFDBFEF2E3F6FF1FDB4FDBFAC
+:10002000FF6FFF6FFF0BFFDBFFF2FFF6FFFFFFFF2E
+:10003000F06FFFFFFFFEFFFDDFFFFFFFF7FFFFFF9A
+:10004000FBFFFFF7FFFFFFFEFF7FF1FFFEFFBFBFDC
+:10005000FFFFFFFFFFF7FFFFFFFEFFFEFFFFFFF0C9
+:10006000EFFFFFFFFEFFFFFFFFFFFFBFFFFFFFF7F9
+:10007000FFFFF7EFFFFFFFFFFFF1FFFFFF7EFFFF37
+:10008000FFFFFFFFDFFFFFFFFFFFFDFFFFFFF0DFD1
+:10009000FFFFFFFEFFFFDFFFFFFFFFFFFFFFFFFF91
+:1000A000FFFFEFFFF3FBFEFFF1FFFDFFFFFFFFFF91
+:1000B000FFFFFFFFFFFFFFFEFFFFFFDFFFF07FFF00
+:1000C000FFFFFEFFFFEFFFFFFFFFFFFFFFFFFFFF51
+:1000D000FFFFDFFFFFFFF7F1FFFFFFDFFFFFFFFF86
+:1000E000FFFFFFFFFFFFFFFEFFFFFFFFF00FFFFF20
+:1000F000FFFEFFFFFFFFFFFFFFFFFFFFFFFF7FFF91
+:10010000FFFFFFFFFFFFF1FFFFFFFFFFFFFFFFF517
+:10011000FFFFFFFFFFFFFFFFFFFFFFF02FFFFFFFCE
+:10012000FEFFFFFFFFFFFFFBFFFFFFEFFF7FFFEF84
+:10013000FFEFFF7FEFF1FFEFFF7FFFFFFFFFFFFF0D
+:10014000FFFFFFFFFFFEFFFFFFFFF09FFFFFFFFE30
+:10015000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF
+:10016000FFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFAD
+:10017000FFFFFFFFFFFFFFFFFFF0BFFFFFFFFEFFDF
+:10018000FFFFFFBDFFEF7FEF7FFBDFD35AFED7D628
+:10019000F77FBDF1BB5DD6F7FE96FFBDAFADBFEFFC
+:1001A0007F6B7FFBD6FEF7FF10EFFFFFFFFEBEEF7A
+:1001B000FFFFDBFFF6FFF6FFFDBFFDBFFF7FFF7F09
+:1001C000DFDBF1FD35FF6FFF6FFFDBFFCBFFF6FFDE
+:1001D000F2FDFDBFFFFFFFD0EFFFFFFFFEFFFFFFC0
+:1001E000FFFFFFFFFFFFFFFFFFFF55FFCCC03FFFFB
+:1001F000FFF124F0FFFFCFEF3FFFF0FFFFFFFC3FD9
+:10020000FFFFFFFFFFFFF0CFFFFFFFFEFFFFFFFF3E
+:10021000FFFFFFFFFFFFFFFFFF55FFCCC03FFFFFCA
+:10022000F100F0FFFFCFDFFFFFF0FFFFFFFC3FFF1C
+:10023000FFFF7DFFFFF0FFFFFFFFFEFFFFFFFFFF60
+:10024000FFFFFFFFFFFFFFFFDFFE7FDFFFFFFFF18D
+:10025000FFCFFFF3FF97FFFF8FE7FFFFFC71FFFF6B
+:10026000FFFFFFFFF0EFFFFFFFFEF5FFBFFFFFFF08
+:10027000FFFFFFFFFFFFE3F7EFFFFFFC7BFFF13F17
+:10028000FFEFFFCFE3E3FFFFFFFF3FFFFFFFBFFFF6
+:10029000BFFFDAF07FFFFFFFFEF2C00000000000AA
+:1002A000000000000000000000000000000100004D
+:1002B000000000000000000100000200000000003B
+:1002C000013CF0AFFFFFFFFEFDBFFFFFFFFFFFFFA1
+:1002D000FFFFFFFFFFDBFFFFFFFFFFFFF1FF9FFFC0
+:1002E000FFFFF7FFEFFFFFFFFFFFFFFFFFFFFFFF36
+:1002F000DBF07FFFFFFFFEF0BBDFFFFFFFFFFFFF35
+:10030000FFFFFFFFFFFFFFEFFBDFBFF1FEFDF7FF8A
+:10031000FFFFFFFFFEFFFFFFFFFFFFFFFF77FDF285
+:10032000F01FFFFFFFFEF838000000000000000390
+:100330000000000200900000000C010000042400F6
+:100340004001000000400000000002000001C0F079
+:100350004FFFFFFFFEFFFFFFFFFFFFFFFFFFFFFF5E
+:10036000FFFFBFFFFF6FFFDFFFD1FFFEFFFFFFFFBC
+:10037000FFFFDFFFFBFFFBEFFFFFEEFFFF7FF0DF85
+:10038000FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7E
+:10039000FFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFF7B
+:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFF08FFFDC
+:1003B000FFFFFEFFFFFFF5ADFF692AED6BFBDF3AA4
+:1003C000DCF496EEB33D35C1BBDDFEF6FED6B5AD31
+:1003D000BFA5AD492F4F2BDA5FFFFFFFF02FFFFFC7
+:1003E000FFFEBFFFFFFB5BF7F6FFF6FFFDBFFDA5BE
+:1003F000F36FF36EFA7BD1FDB5776FE96FFFDBFB2F
+:10040000DBDFF6FFF6FFFD3FFEF7FFD04FFFFFFFFC
+:10041000FEFF9FFFFF0FFFC03F9C03FFFF8BA5FE6A
+:10042000803EC2BFACB124FFFFFFFFFFFF0FFFA361
+:10043000FFFD6BFFFFF0A5FFFFFFF0AFFFFFFFFE2B
+:10044000FFFFFFFF0FFFC03FD46BFFFFDBFFFE8608
+:10045000BFC2BF30A124FFFFFFFFCCFF0FFFA3FFF0
+:10046000056BFFFFF0A5FFFFFFF07FFFFFFFFEFF23
+:10047000FFFFFBC7FFC4FFFF7FFFECFE7FDFD8B9A4
+:1004800047FC36C1DFFFFFF9FFF3FFF7FFFCFFFD7D
+:100490003FFFFFFF3FFFFFFFF07FFFFFFFFEF5FF86
+:1004A000FFFFFFFEFFFF7EBD3FFF2BFE2FF5A3FCEE
+:1004B0005BFE619F7FEFFFFFA7FBFFFFFAFEFF33AD
+:1004C000F1FFBFFFFFFFFAF07FFFFFFFFEF1C0006B
+:1004D0000000000000000000000000400030240484
+:1004E000000100804000080000000201010002003D
+:1004F00000000000013DF02FFFFFFFFEFDBDFFFDEE
+:10050000FFFFFFFFFFFBFFFF7FF6EFBFF7FF73EB80
+:10051000F1FFFFFFDFFFFFFFFFFFF9FFFDFEFFFF22
+:10052000FFFFFFFFD9F0DFFFFFFFFEF0BF7FFFFF00
+:10053000FF7FFFFFDEFFFFEFDDDE77F2FBEDE7F190
+:1005400073FDFDDFFF7DBEDFFFFBFFEFFFEFFFFF72
+:10055000FFFFFFD0F0BFFFFFFFFEF83020020022B8
+:1005600040C0000000080002410212002187810003
+:100570000080040B2801B000820040000000000051
+:100580000000C1F0DFFFFFFFFEFFFFFFFFFFFDFFE9
+:10059000F7FFFE7FED79FFDEEB7F74F7F7E1F9FF00
+:1005A000F65F7FFFFFFFD7DBEFFFBBFFFFFFCCFF57
+:1005B000FFFFF0CFFFFFFFFEFFFFFFFFFFFFFFFF8B
+:1005C000FFFFFFFFFFFFFFFFFFFFFFFFF1FFFFFF49
+:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B
+:1005E000FFF00FFFFFFFFEFFFFFFFD3DCD497F6FD7
+:1005F0002BBA5CD2DAF6F33EF7FFBDF1FADFFEF775
+:10060000CCF6BBA5B3ADBF6F7D6F6BDBDFBDFFFE6F
+:10061000B05FFFFFFFFEBFFFFFFBDB57F6FE9FD57E
+:10062000B7FFAFE53FFFFF6FFFDBF1FDBFFF6F6976
+:100630006CDFDADFCBFFF6FF76FDFDBFFFFFFFD0FB
+:100640003FFFFFFFFEFFFFFFFFFDBD0803894F5A7D
+:100650000FF0FFF8BFFFFFFFFFF15AFFFFFFFFF3AF
+:10066000FAA0F0F2BFFFFFFFFFFFFFFFFFFFF0FF69
+:10067000FFFFFFFEFFFFFFFFFCFD006BFFFF5A0FB8
+:10068000F0FFFFFFFFFFFFFFF15AFFFFFFFFB3F592
+:1006900050F0F0FFFFFFD7FFFFFFFFFFFFF07FFFEE
+:1006A000FFFFFEFFFFFFFDBCFFE4E771FFF9C4F4AD
+:1006B0007F7FCFFFFFFFFFF1FFFFFFFBF773BF144B
+:1006C000FFE6FFFFE17DFFFFE7FFFFFFF03FFFFFDA
+:1006D000FFFEF5FFFFFED2FAFFC4F45CBFFAFFFF96
+:1006E000EC7EBFFFFFFFF1FFFFEFFFFF6BDBFFDFE4
+:1006F000F9FBBFFFF1FFBFFFFFFFFBF0BFFFFFFFF5
+:10070000FEF3C00002000000008200000000800034
+:10071000000000400001000000010820000000006F
+:100720000100010000800200013CF05FFFFFFFFEBE
+:10073000FDBFFFFFFFDFFFFFFFFF7FFFDFFFEFFFDB
+:10074000FFFFFFFFF1FFFFFFFFFFF7FFFBFFFDFFD5
+:10075000FFFFFFFFFFFDFFFFC3F0AFFFFFFFFEF056
+:10076000FFDFFFFFF723FFFFFDFFEFFFFE7F7DF7BA
+:10077000FEFF7F71FFFB7FFFFFFF6EFDF7FDFFBFF9
+:10078000FFBFF9FDFFDFEFF0F0AFFFFFFFFEF83036
+:10079000400100830000000C060804262600000625
+:1007A0000300010000000004007008800020012008
+:1007B000000200300000C1F05FFFFFFFFEFFFFFFFF
+:1007C000FFFF7B3FF7FFD7FEFEFBFE3BFEBDFF2F8B
+:1007D000FF71FFFB7FE7FFF9EFFFD7FAFFB7BBFE23
+:1007E000FFFF74FFF7FFF0CFFFFFFFFEFFFFFFFFEC
+:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09
+:10080000F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06
+:10081000FFFFFFFFFFF08FFFFFFFFEFFFFFFFFB5B2
+:10082000BD6F7CEB7FFBDBD34BEED6F6B7FDACA107
+:10083000FBDFFEF7F496BDB4C5A5AF6F694F7FBA75
+:10084000DBFFFFFFF03FFFFFFFFEBFFFFFFFDBFF10
+:10085000F6FFF6FFBDBFA5BFFF7D7FEFFFFBF1FDFC
+:10086000BFFF6FFF6B7ADBFFDBDFF6FEB6FDFDBF80
+:10087000FEF7FFD0EFFFFFFFFEFFFFFFFFF42FFFAC
+:10088000FC436BFFFFFF0DFFFC333FF05FF1FFFF09
+:10089000FFFFF9DEF04CFE77AFFFFFEFFFF0FFDB6D
+:1008A000FF5FF0EFFFFFFFFEFFFEF7FFF02FFFFD02
+:1008B000437FFFFFF10FFFFC333FFFAFF1FFFFFF6F
+:1008C000FFF6D7FFBCFDBDFFFFFFFFFFF0FFFFFFFF
+:1008D000FFF0EFFFFFFFFEFFFFFFFFFCFFFFFBF15D
+:1008E000BFFFF9FDCFF270FF1F9FF3F1FFFFFFFF86
+:1008F000FCF7FF139FFCFFFF84F7FFFF47FFFFFF9D
+:10090000F0BFFFFFFFFEF5FFFFFFF1FCFFFEFE79EA
+:100910003FFF1D46CFFFCFFC7BFFF1FFFFFFFFED49
+:10092000F3ABFFCBFFF8FFFCF5FFBFFFFFFFFAF0D3
+:100930008FFFFFFFFEF3C200000000000000010077
+:10094000000020002000000408010000000000203A
+:100950000C0000040100010000800000013CF07F59
+:10096000FFFFFFFEFDBFFFFFFDFEFFFFFFFFFEFFDE
+:10097000DFFFFFF7FFFFFFEFF1FFFFFFFFFFFFEBE1
+:10098000FFDFFFFFFBF77FFFFEFFFFBFDBF0FFFF97
+:10099000FFFFFEF0FFFFFFFFFFDFFFFFFF7FF7FF1F
+:1009A000BFBFCFFFFFFF3EF17FFFFFEFFFFFFFFE67
+:1009B000FFFDFFBFBDFEFFFBF7DFFBD0F09FFFFF9A
+:1009C000FFFEF8302000400180C030000020001001
+:1009D00050882000001301000000000000100000FB
+:1009E00000000180080000A00010C1F0EFFFFFFF31
+:1009F000FEFDEF7FFFFFBFFFF7FFEFFBFD77EFBFD0
+:100A0000F77FFFFFBFD17FFFFFF7FFFFFFFFAFFFC4
+:100A1000DFF7FBFFFDFFFCFFFDFFF0FFFFFFFFFE29
+:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6
+:100A3000FFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFD4
+:100A4000FFFFFFFFFFFFFFFFFFF05FFFFFFFFEFF66
+:100A5000FFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFC6
+:100A6000FFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFFA4
+:100A7000FFFFFFFFFFFFFFFFE03FFFFFFFFEDDFF88
+:100A8000FFFFA5FD6F7D6D7F52DF5A4BEEB6EEF294
+:100A9000BBACA15B4DD6F7FEB2BD35B5B5DD6F7F02
+:100AA000E95F52DFBDFFFFF0DFFFFFFFFEBFFFFF8B
+:100AB000FFDBFEF6FFF6FFFDBFFDB5BFF97F6FFF61
+:100AC000DBF1FDBFFF6FFF697FDBFFD3FFF6FEF2B7
+:100AD000FFADBFFFFFFFD0DFFFFFFFFEFFFFFFF512
+:100AE000300FFFFFFD6BCAFFF00FD6BFCF3FFFFFF8
+:100AF000F1FFFFFFCAFEBFFFF005AF0FFFFCF0CF15
+:100B0000F0FFFFFFFFF0EFFFFFFFFEFFFFFFF530FD
+:100B10000FFFFFFC3FCAFF0F0FD6BFFFFFF55FF1CE
+:100B2000FF8BFFC3FFFFFFFFFFFF0FFFFCF0CFF0C6
+:100B3000FFFFFFFFF03FFFFFFFFEFFFFFFFFCFFFC5
+:100B4000FFBF9F3FFEFCFF4FFFFFFFFFFFF7F1FFDF
+:100B5000DFFE7E3F9FF4FC7FFCFFFF3FFF3FFE3F39
+:100B6000FFFFFFF04FFFFFFFFEF5FFFFFBFFFEFF64
+:100B7000FFFFFFBFFBFFF8EDFF8FFFBBFFB1F3EF00
+:100B80008FF7FFFFDBFFFFFFEFBFFD79BFBFFFFF69
+:100B9000FFFBF0DFFFFFFFFEF3C0000000040000DA
+:100BA000000000000000008000040808010100901F
+:100BB000000000040008000000000800040000011C
+:100BC0003CF0DFFFFFFFFEFDBFFFFFFFFFFFFFFF6A
+:100BD000FFFFFFFF9FFFAFDFFFFFFFF1FFFFFFFF03
+:100BE000BFEFFFFFFFEDFFFFFFEFFFBFFFFFFFC303
+:100BF000F03FFFFFFFFEF0FFFDFFFFFFFBFFBBFF2E
+:100C0000FFFF7FF6FF7FFBFDEDFFF1FFFE7FFFFFA4
+:100C1000FF5FFFF7FF7EFFFDFFEFFFFFFFEFF0F04D
+:100C20008FFFFFFFFEF83080000400004002000349
+:100C300000050420000001D0008100200404000011
+:100C4000810408801000C0000000200008C1F06F7F
+:100C5000FFFFFFFEFFFF7FFFFFFFFFF3FDFFEDFC48
+:100C6000FFFF9FFBFDFFFFFFF1FFFF7FFB3EFF9FAD
+:100C7000FFFFFFFFFDF9FFFFFFFDFFFFFFF06FFF2D
+:100C8000FFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFF75
+:100C9000FFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFF72
+:100CA000FFFFFFFFFFFFFFFFFFFFFFFFF0CFFFFF93
+:100CB000FFFEFFFFFFFDBDFFEF7CEB7FFBDBFADC00
+:100CC000EEF7F6D7F52DA1BBDDEEF754F7FB2CB50B
+:100CD000B4BD6B6FEF6FBBDFFFFFFFF01FFFFFFFC8
+:100CE000FEBFFFFFFFFBFFF6FFF6FFFDBFFFBFEFFD
+:100CF0006FFF6FFADBF1C5BDF56FFF6FCADBFFDB7E
+:100D0000FBF697F6FFFDBFFEF7FFD09FFFFFFFFE4C
+:100D1000FFFFFFFFFFFFFFFF8B7FFFFFE763FFFF8B
+:100D2000FFFC77DFF1DBFFD6A83FFFFF082FF0FFC6
+:100D3000C3FFEBFFFFFFFFFF5FF0EFFFFFFFFEFFD3
+:100D4000FFFFFFFFFFFFFF8BFFFFFFFFFFFFFFFF27
+:100D5000FCFFCFF1DBFFD6A83FFFFF082FF0FFC35A
+:100D6000FFEBFFFFFFFFFFFFF05FFFFFFFFEFFFF57
+:100D7000FFFFFFFFFFFFF5BFFFCAFF9FFFFAB9E7C5
+:100D80009FF381FFFFFC73D7FFFF77FFFDFFFCFFA1
+:100D9000FFFFFFCFFFFFFFF01FFFFFFFFEF5FFFF8D
+:100DA000FFF7DEFFFE7EFFBFFFBFF1B3FFFFE3FBF8
+:100DB000FFE11F7FFFF878FFFB1EFFF7FEE7FFFF55
+:100DC000FFBFFFFFFFFAF04FFFFFFFFEF3C0000081
+:100DD00000000000000000000000500000000400BF
+:100DE00001804040200000080000000003000000D7
+:100DF000800000013CF0AFFFFFFFFEFDBFFFFBFFE7
+:100E0000FFFFFFFFFFFEFFFFFFFFFFFFFFEFF7F119
+:100E1000FDFFFFFFDFFFEFFFFFFFFFFFFFFF7FFF94
+:100E2000FFFFFFDBF08FFFFFFFFEF0FFDFFFFF7F25
+:100E3000FFFFFFBED7FFEDBD7EBFFEF67FBF71FF98
+:100E4000FFDAFFF9FFBF7FFEFF6F7FFFFFFFFFFFAE
+:100E50007FFFD0F0CFFFFFFFFEF830420000000020
+:100E600080C100009000C400001220432281840051
+:100E700000140001000880000200020004020000CB
+:100E800010C1F01FFFFFFFFEFFFFFDFFFFDDFEFFB4
+:100E9000B676E5BCF9F7AF5FBFFCDFCFF1FFEF79C6
+:100EA000FFBDFFEFFFFFF76F5FFFFFFDEFEFBFFF3E
+:100EB000FFF09FFFFFFFFEFFFFFFFFFFFFFFFFFFB2
+:100EC000FFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFF40
+:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22
+:100EE000F0FFFFFFFFFEDBFFFFFD2DFF692AEF771D
+:100EF000BBDD5ADFF6F6D6F77DBDD1B24AD6B2BE1B
+:100F000097F5BDB3ADFFEF7F696BFBDFFFFFFFF030
+:100F10002FFFFFFFFEBFFFFFFFDBFFF6FE9FD4BFEB
+:100F2000EDAFFF6B6FF7FFDDDB31FDBFFF6F7FFFC5
+:100F3000FFDBFFCBDFF6FFF6FFFDBFFEF7FFD08F35
+:100F4000FFFFFFFEFFFFFFFD1FFF462F9FFFFFFF7D
+:100F5000A5FFFFFFDFB7FFFFF1FFFFFFF7E96ABF64
+:100F6000FFFFFDFFFFFD5557FFFFFFFFAFF04FFFF6
+:100F7000FFFFFEFEDFFFFD1FFF462F9FFFFFFFA5C8
+:100F8000FFFFFFC037FFFFF1998EDC7FE96ABFFFEB
+:100F9000F00FFFFFFD5557FFFFFFFFFFF00FFFFFB3
+:100FA000FFFEFFFFFFFF07FFC0BEFFFFCFEF9FFF6A
+:100FB000FFFBFFE7FFFFA1E3CE3C583FF3FFFDEF50
+:100FC000F9FFFFF7F17FFFCBFFFFFFF02FFFFFFFE0
+:100FD000FEF57FFFF0FFFEFFC475E7B9FFFFFFEFEF
+:100FE000FFC7373BFFF0139E0FF4FFFEFBFFFFF937
+:100FF000FCFFFFFFFFBFFFFFFFFAF0EFFFFFFFFE69
+:10100000F3C0010000020002220000C040004000C6
+:101010000408040A0101102020000004080804004C
+:1010200000000000010000013CF0CFFFFFFFFEFDCB
+:101030003FFFFFFFFFFFFF7FFF7FFF7FFFCF9DFF92
+:10104000FFF7FDF1FFFFFFEEBFFFFFFFFFFEFFFF1A
+:10105000FFFFFFFFFFFFFFDBF06FFFFFFFFEF0FF73
+:10106000FFFFF7F7FFFFFEBFF7FFFF5BFFBFF7FFD5
+:10107000FD7F71FDFFEDF7FEEFFFFF7FFFFFFFFF3D
+:10108000FFFFEFFF7FFFD0F0FFFFFFFFFEF8301103
+:10109000004860408260246000CC008004010000B1
+:1010A00014010C0400300000000808000100C20018
+:1010B0000002008000C1F05FFFFFFFFEFFFFFFFFA7
+:1010C000F77BFFF3EBBFFFF7FFFFFFE75D3FFFF6A7
+:1010D000D1FDFFEBF73DFFFFFF5FFF7F7FF3FFFFDA
+:1010E000EFFDBFFFFFF05FFFFFFFFEFFFFFFFFFF12
+:1010F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10E
+:10110000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF
+:10111000FFFFFFFFF0DFFFFFFFFEFFFFFFF5B5DF83
+:101120006F7D697FFBDF525FF6F7FEF6F3BDB1DA44
+:10113000CDFEF6EED2BDA5AFBDFF6F7CEB2BFADA8C
+:10114000FFFEDFF04FFFFFFFFEBFFFFFFFDBFFF6FD
+:10115000FFF6FFBDBFCDBFEB6FF76FDFDB51FDBD0E
+:10116000FF6FFF6FFB5BFFDBFFF6FEF6FDFDBFFED3
+:10117000F7FFD0FFFFFFFFFEFFFFFFFA50FFFFFF6B
+:10118000F06FFFFFF096FFFFC62BFFFFF1FCFFFFA4
+:10119000F7DBC3FF00FFFFFFFFFFC14FC3FFFFFFF0
+:1011A000AFF09FFFFFFFFEFFFFFFF5A0FFFFFFF087
+:1011B0006FFFFFF096FFFFC62BFFFFF15AFFFFFF07
+:1011C000F3C3FF00FFFFFFFFFFC14FC3FFFFFFFFA0
+:1011D000F0CFFFFFFFFEFFFFFFFFFCFFFF9FF07F51
+:1011E000FFF9FC4FF3FF27EBFFFC81FC7FFE7BFF49
+:1011F000F7FF127FFFFFFFFF18FFFFFFFFFFFFF06A
+:101200007FFFFFFFFEF5FFFFFFDFFEFFFC7E7FBFDE
+:10121000FFFFAFEFFFDFDFFBFFF1C3FE6FF1CF3F5B
+:10122000FBFFFFCFFEFFFFFE7FBFFFFFBFFAF0DF38
+:10123000FFFFFFFEF3C000000100000000010000FE
+:10124000200001001000000001000200000000006A
+:101250000000000200008000028000023CF02FFF2E
+:10126000FFFFFEFDBFFFFBFDFFFFFFFFFFFFFFFFD7
+:10127000FFFFFFFFFFFFF5F1FF7FFFFFFFFFEFFF26
+:10128000FFFFFFFFFEFFFFFFFFFFFFDBF02FFFFF72
+:10129000FFFEF0FFFFFFFBFFBFFFFFFFFFF7BFFBFE
+:1012A000FFFFFFDFF7FFF1F7BFFBFFFFFF7FDEFF71
+:1012B000FFFFFFFFFFEDF7FFFF7FD0F03FFFFFFFD6
+:1012C000FEF830000000004000000000E000008058
+:1012D0002001019200010100E01C6020300808009C
+:1012E000000000000000008000C1F06FFFFFFFFE63
+:1012F000FFFFFFFFFFDBFEFFFFDFFFFC7FFBBFFF0A
+:10130000FFFFFFFFF1F6FFF77E3FFF7FFFFFFFF7D5
+:10131000FFFFFFEDFFDFFFB7FFF03FFFFFFFFEFF27
+:10132000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD
+:10133000FFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFFCB
+:10134000FFFFFFFFFFFFFFFFF0FFFFFFFFFEFFFFBD
+:10135000FFFFFFFFDFFFFFFFDFFFFFFFFFBFFFDF3D
+:1013600057EFF1FDFE7FFFFFFFFFFFFFFFDFFBFFFA
+:10137000FFFFFFFFFFFFFFF07FFFFFFFFEFFFFFF0D
+:10138000FFFFFF7FFFFFFFFFFFFFFFFFFBFFDFFF11
+:10139000FFF1FDFF7FBFFFFFFFFFFFFFFFFFFFFF2D
+:1013A000FFFEFFFFFFFFF09FFFFFFFFEF7FDFFFFC8
+:1013B000FFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFF7D
+:1013C000F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B
+:1013D000FFFFFFFFFFF06FFFFFFFFEFFFFFFFFFFBD
+:1013E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11B
+:1013F000FFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+:10140000FFFFFFFFF0CFFFFFFFFEFFFFFFFFFFFF2C
+:10141000FFFBFFFFFFFEFFFFFB6FFFFEBFFFF1FFC4
+:10142000F7FFFF7FFFFFFFFFFFFFFFFFFFFFFFFD56
+:10143000FFFFFFF0EFFFFFFFFEFFFFFFFFFFFFFFDC
+:10144000FBFFFFFFFEFFFFFF57FFFDBFFFF1FFEFB9
+:10145000FEFFBFFFFFFFFFFFFFFFFFFFFFFFFEFFDE
+:10146000DEFFF0CFFFFFFFFEFFFFFFF7DBFFDBFD3F
+:10147000F6FFF6FF3CBCBCBFDF6FE72FF13CBFFDC2
+:10148000BFDF6FFF6FF7DBFFDBFDF6FFF6FFFFFF50
+:101490000201DFFFFFFFFEFFFFFFFFFFFFFFFFFF78
+:1014A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C
+:0614B000FFFFFFFFFFFF3C
+:00000001FF
+/*
+ *
+ * File yam111.mcs converted to h format by mcs2h
+ *
+ * (C) F6FBB 1998
+ *
+ * Tue Aug 25 20:23:03 1998
+ *
+ */
index cef8b18ceaa367b56ffcf8145cb2f24af8de7389..86b203fc3c56af2b41e0118dd3cc3bddd8a002d4 100644 (file)
@@ -66,6 +66,13 @@ config GENERIC_ACL
        bool
        select FS_POSIX_ACL
 
+menu "Caches"
+
+source "fs/fscache/Kconfig"
+source "fs/cachefiles/Kconfig"
+
+endmenu
+
 if BLOCK
 menu "CD-ROM/DVD Filesystems"
 
@@ -169,6 +176,8 @@ source "fs/romfs/Kconfig"
 source "fs/sysv/Kconfig"
 source "fs/ufs/Kconfig"
 
+source "fs/exofs/Kconfig"
+
 endif # MISC_FILESYSTEMS
 
 menuconfig NETWORK_FILESYSTEMS
index 6e82a307bcd436c6d131b67f120c4324ad34aafe..70b2aed87133328997e0754737f7ea49a499b21b 100644 (file)
@@ -11,7 +11,7 @@ obj-y :=      open.o read_write.o file_table.o super.o \
                attr.o bad_inode.o file.o filesystems.o namespace.o \
                seq_file.o xattr.o libfs.o fs-writeback.o \
                pnode.o drop_caches.o splice.o sync.o utimes.o \
-               stack.o
+               stack.o fs_struct.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=       buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
@@ -63,6 +63,7 @@ obj-$(CONFIG_PROFILING)               += dcookies.o
 obj-$(CONFIG_DLM)              += dlm/
  
 # Do not add any filesystems before this line
+obj-$(CONFIG_FSCACHE)          += fscache/
 obj-$(CONFIG_REISERFS_FS)      += reiserfs/
 obj-$(CONFIG_EXT3_FS)          += ext3/ # Before ext2 so root fs can be ext3
 obj-$(CONFIG_EXT2_FS)          += ext2/
@@ -116,7 +117,9 @@ obj-$(CONFIG_AFS_FS)                += afs/
 obj-$(CONFIG_BEFS_FS)          += befs/
 obj-$(CONFIG_HOSTFS)           += hostfs/
 obj-$(CONFIG_HPPFS)            += hppfs/
+obj-$(CONFIG_CACHEFILES)       += cachefiles/
 obj-$(CONFIG_DEBUG_FS)         += debugfs/
 obj-$(CONFIG_OCFS2_FS)         += ocfs2/
 obj-$(CONFIG_BTRFS_FS)         += btrfs/
 obj-$(CONFIG_GFS2_FS)           += gfs2/
+obj-$(CONFIG_EXOFS_FS)          += exofs/
index 7f83a46f2b7e45502e7c761775f96498280a32e5..dd9becca4241bd20a01706e3e18cb9c47109cbe1 100644 (file)
@@ -219,16 +219,20 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data)
 
 static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct adfs_sb_info *asb = ADFS_SB(dentry->d_sb);
+       struct super_block *sb = dentry->d_sb;
+       struct adfs_sb_info *sbi = ADFS_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type    = ADFS_SUPER_MAGIC;
-       buf->f_namelen = asb->s_namelen;
-       buf->f_bsize   = dentry->d_sb->s_blocksize;
-       buf->f_blocks  = asb->s_size;
-       buf->f_files   = asb->s_ids_per_zone * asb->s_map_size;
+       buf->f_namelen = sbi->s_namelen;
+       buf->f_bsize   = sb->s_blocksize;
+       buf->f_blocks  = sbi->s_size;
+       buf->f_files   = sbi->s_ids_per_zone * sbi->s_map_size;
        buf->f_bavail  =
-       buf->f_bfree   = adfs_map_free(dentry->d_sb);
+       buf->f_bfree   = adfs_map_free(sb);
        buf->f_ffree   = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        return 0;
 }
index a19d64b582aac0e2882610b3a5839d88e0bd329d..5ce695e707fe1054617a6a1664579eceb78b3790 100644 (file)
@@ -533,6 +533,7 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        int              free;
+       u64              id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",AFFS_SB(sb)->s_partition_size,
             AFFS_SB(sb)->s_reserved);
@@ -543,6 +544,9 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_blocks  = AFFS_SB(sb)->s_partition_size - AFFS_SB(sb)->s_reserved;
        buf->f_bfree   = free;
        buf->f_bavail  = free;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
+       buf->f_namelen = 30;
        return 0;
 }
 
index e7b522fe15e167c1ee53b0a6c0011b472e145a14..5c4e61d3c77250728076fb8940f0cd4cc27d7d72 100644 (file)
@@ -19,3 +19,11 @@ config AFS_DEBUG
          See <file:Documentation/filesystems/afs.txt> for more information.
 
          If unsure, say N.
+
+config AFS_FSCACHE
+       bool "Provide AFS client caching support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       depends on AFS_FS=m && FSCACHE || AFS_FS=y && FSCACHE=y
+       help
+         Say Y here if you want AFS data to be cached locally on disk through
+         the generic filesystem cache manager
index a66671082cfbb98d37277e73e3255c70d8415946..4f64b95d57bd1ff7af9c781eac506787dc3b4c9f 100644 (file)
@@ -2,7 +2,10 @@
 # Makefile for Red Hat Linux AFS client.
 #
 
+afs-cache-$(CONFIG_AFS_FSCACHE) := cache.o
+
 kafs-objs := \
+       $(afs-cache-y) \
        callback.o \
        cell.o \
        cmservice.o \
index de0d7de69edc4764b98f3d2ff098225e0e18e5fe..e2b1d3f165191444e96f3eebfbeb909aa07f5db1 100644 (file)
@@ -1,6 +1,6 @@
 /* AFS caching stuff
  *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_cell_cache_match(void *target,
-                                               const void *entry);
-static void afs_cell_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_cache_cell_index_def = {
-       .name                   = "cell_ix",
-       .data_size              = sizeof(struct afs_cache_cell),
-       .keys[0]                = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
-       .match                  = afs_cell_cache_match,
-       .update                 = afs_cell_cache_update,
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include "internal.h"
+
+static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
+                                      void *buffer, uint16_t buflen);
+static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
+                                      void *buffer, uint16_t buflen);
+static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
+                                                     const void *buffer,
+                                                     uint16_t buflen);
+
+static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t buflen);
+static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t buflen);
+static enum fscache_checkaux afs_vlocation_cache_check_aux(
+       void *cookie_netfs_data, const void *buffer, uint16_t buflen);
+
+static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
+                                        void *buffer, uint16_t buflen);
+
+static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
+                                       void *buffer, uint16_t buflen);
+static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
+                                    uint64_t *size);
+static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
+                                       void *buffer, uint16_t buflen);
+static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
+                                                      const void *buffer,
+                                                      uint16_t buflen);
+static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
+
+struct fscache_netfs afs_cache_netfs = {
+       .name                   = "afs",
+       .version                = 0,
+};
+
+struct fscache_cookie_def afs_cell_cache_index_def = {
+       .name           = "AFS.cell",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key        = afs_cell_cache_get_key,
+       .get_aux        = afs_cell_cache_get_aux,
+       .check_aux      = afs_cell_cache_check_aux,
+};
+
+struct fscache_cookie_def afs_vlocation_cache_index_def = {
+       .name                   = "AFS.vldb",
+       .type                   = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key                = afs_vlocation_cache_get_key,
+       .get_aux                = afs_vlocation_cache_get_aux,
+       .check_aux              = afs_vlocation_cache_check_aux,
+};
+
+struct fscache_cookie_def afs_volume_cache_index_def = {
+       .name           = "AFS.volume",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key        = afs_volume_cache_get_key,
+};
+
+struct fscache_cookie_def afs_vnode_cache_index_def = {
+       .name                   = "AFS.vnode",
+       .type                   = FSCACHE_COOKIE_TYPE_DATAFILE,
+       .get_key                = afs_vnode_cache_get_key,
+       .get_attr               = afs_vnode_cache_get_attr,
+       .get_aux                = afs_vnode_cache_get_aux,
+       .check_aux              = afs_vnode_cache_check_aux,
+       .now_uncached           = afs_vnode_cache_now_uncached,
 };
-#endif
 
 /*
- * match a cell record obtained from the cache
+ * set the key for the index entry
  */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_cell_cache_match(void *target,
-                                               const void *entry)
+static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
+                                      void *buffer, uint16_t bufmax)
 {
-       const struct afs_cache_cell *ccell = entry;
-       struct afs_cell *cell = target;
+       const struct afs_cell *cell = cookie_netfs_data;
+       uint16_t klen;
 
-       _enter("{%s},{%s}", ccell->name, cell->name);
+       _enter("%p,%p,%u", cell, buffer, bufmax);
 
-       if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) {
-               _leave(" = SUCCESS");
-               return CACHEFS_MATCH_SUCCESS;
-       }
+       klen = strlen(cell->name);
+       if (klen > bufmax)
+               return 0;
 
-       _leave(" = FAILED");
-       return CACHEFS_MATCH_FAILED;
+       memcpy(buffer, cell->name, klen);
+       return klen;
 }
-#endif
 
 /*
- * update a cell record in the cache
+ * provide new auxilliary cache data
  */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_cell_cache_update(void *source, void *entry)
+static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
+                                      void *buffer, uint16_t bufmax)
 {
-       struct afs_cache_cell *ccell = entry;
-       struct afs_cell *cell = source;
+       const struct afs_cell *cell = cookie_netfs_data;
+       uint16_t dlen;
 
-       _enter("%p,%p", source, entry);
+       _enter("%p,%p,%u", cell, buffer, bufmax);
 
-       strncpy(ccell->name, cell->name, sizeof(ccell->name));
+       dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
+       dlen = min(dlen, bufmax);
+       dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
 
-       memcpy(ccell->vl_servers,
-              cell->vl_addrs,
-              min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs)));
+       memcpy(buffer, cell->vl_addrs, dlen);
+       return dlen;
+}
 
+/*
+ * check that the auxilliary data indicates that the entry is still valid
+ */
+static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
+                                                     const void *buffer,
+                                                     uint16_t buflen)
+{
+       _leave(" = OKAY");
+       return FSCACHE_CHECKAUX_OKAY;
 }
-#endif
-
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vlocation_cache_match(void *target,
-                                                    const void *entry);
-static void afs_vlocation_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_vlocation_cache_index_def = {
-       .name           = "vldb",
-       .data_size      = sizeof(struct afs_cache_vlocation),
-       .keys[0]        = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
-       .match          = afs_vlocation_cache_match,
-       .update         = afs_vlocation_cache_update,
-};
-#endif
 
+/*****************************************************************************/
 /*
- * match a VLDB record stored in the cache
- * - may also load target from entry
+ * set the key for the index entry
  */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vlocation_cache_match(void *target,
-                                                    const void *entry)
+static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t bufmax)
 {
-       const struct afs_cache_vlocation *vldb = entry;
-       struct afs_vlocation *vlocation = target;
+       const struct afs_vlocation *vlocation = cookie_netfs_data;
+       uint16_t klen;
+
+       _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
+
+       klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name));
+       if (klen > bufmax)
+               return 0;
 
-       _enter("{%s},{%s}", vlocation->vldb.name, vldb->name);
+       memcpy(buffer, vlocation->vldb.name, klen);
 
-       if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0
-           ) {
-               if (!vlocation->valid ||
-                   vlocation->vldb.rtime == vldb->rtime
+       _leave(" = %u", klen);
+       return klen;
+}
+
+/*
+ * provide new auxilliary cache data
+ */
+static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t bufmax)
+{
+       const struct afs_vlocation *vlocation = cookie_netfs_data;
+       uint16_t dlen;
+
+       _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
+
+       dlen = sizeof(struct afs_cache_vlocation);
+       dlen -= offsetof(struct afs_cache_vlocation, nservers);
+       if (dlen > bufmax)
+               return 0;
+
+       memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen);
+
+       _leave(" = %u", dlen);
+       return dlen;
+}
+
+/*
+ * check that the auxilliary data indicates that the entry is still valid
+ */
+static
+enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data,
+                                                   const void *buffer,
+                                                   uint16_t buflen)
+{
+       const struct afs_cache_vlocation *cvldb;
+       struct afs_vlocation *vlocation = cookie_netfs_data;
+       uint16_t dlen;
+
+       _enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen);
+
+       /* check the size of the data is what we're expecting */
+       dlen = sizeof(struct afs_cache_vlocation);
+       dlen -= offsetof(struct afs_cache_vlocation, nservers);
+       if (dlen != buflen)
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       cvldb = container_of(buffer, struct afs_cache_vlocation, nservers);
+
+       /* if what's on disk is more valid than what's in memory, then use the
+        * VL record from the cache */
+       if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) {
+               memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen);
+               vlocation->valid = 1;
+               _leave(" = SUCCESS [c->m]");
+               return FSCACHE_CHECKAUX_OKAY;
+       }
+
+       /* need to update the cache if the cached info differs */
+       if (memcmp(&vlocation->vldb, buffer, dlen) != 0) {
+               /* delete if the volume IDs for this name differ */
+               if (memcmp(&vlocation->vldb.vid, &cvldb->vid,
+                          sizeof(cvldb->vid)) != 0
                    ) {
-                       vlocation->vldb = *vldb;
-                       vlocation->valid = 1;
-                       _leave(" = SUCCESS [c->m]");
-                       return CACHEFS_MATCH_SUCCESS;
-               } else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {
-                       /* delete if VIDs for this name differ */
-                       if (memcmp(&vlocation->vldb.vid,
-                                  &vldb->vid,
-                                  sizeof(vldb->vid)) != 0) {
-                               _leave(" = DELETE");
-                               return CACHEFS_MATCH_SUCCESS_DELETE;
-                       }
-
-                       _leave(" = UPDATE");
-                       return CACHEFS_MATCH_SUCCESS_UPDATE;
-               } else {
-                       _leave(" = SUCCESS");
-                       return CACHEFS_MATCH_SUCCESS;
+                       _leave(" = OBSOLETE");
+                       return FSCACHE_CHECKAUX_OBSOLETE;
                }
+
+               _leave(" = UPDATE");
+               return FSCACHE_CHECKAUX_NEEDS_UPDATE;
        }
 
-       _leave(" = FAILED");
-       return CACHEFS_MATCH_FAILED;
+       _leave(" = OKAY");
+       return FSCACHE_CHECKAUX_OKAY;
 }
-#endif
 
+/*****************************************************************************/
 /*
- * update a VLDB record stored in the cache
+ * set the key for the volume index entry
  */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_vlocation_cache_update(void *source, void *entry)
+static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
+                                       void *buffer, uint16_t bufmax)
 {
-       struct afs_cache_vlocation *vldb = entry;
-       struct afs_vlocation *vlocation = source;
+       const struct afs_volume *volume = cookie_netfs_data;
+       uint16_t klen;
+
+       _enter("{%u},%p,%u", volume->type, buffer, bufmax);
+
+       klen = sizeof(volume->type);
+       if (klen > bufmax)
+               return 0;
 
-       _enter("");
+       memcpy(buffer, &volume->type, sizeof(volume->type));
+
+       _leave(" = %u", klen);
+       return klen;
 
-       *vldb = vlocation->vldb;
 }
-#endif
-
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_volume_cache_match(void *target,
-                                                 const void *entry);
-static void afs_volume_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_volume_cache_index_def = {
-       .name           = "volume",
-       .data_size      = sizeof(struct afs_cache_vhash),
-       .keys[0]        = { CACHEFS_INDEX_KEYS_BIN, 1 },
-       .keys[1]        = { CACHEFS_INDEX_KEYS_BIN, 1 },
-       .match          = afs_volume_cache_match,
-       .update         = afs_volume_cache_update,
-};
-#endif
 
+/*****************************************************************************/
 /*
- * match a volume hash record stored in the cache
+ * set the key for the index entry
  */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_volume_cache_match(void *target,
-                                                 const void *entry)
+static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
+                                       void *buffer, uint16_t bufmax)
 {
-       const struct afs_cache_vhash *vhash = entry;
-       struct afs_volume *volume = target;
+       const struct afs_vnode *vnode = cookie_netfs_data;
+       uint16_t klen;
 
-       _enter("{%u},{%u}", volume->type, vhash->vtype);
+       _enter("{%x,%x,%llx},%p,%u",
+              vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
+              buffer, bufmax);
 
-       if (volume->type == vhash->vtype) {
-               _leave(" = SUCCESS");
-               return CACHEFS_MATCH_SUCCESS;
-       }
+       klen = sizeof(vnode->fid.vnode);
+       if (klen > bufmax)
+               return 0;
+
+       memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode));
 
-       _leave(" = FAILED");
-       return CACHEFS_MATCH_FAILED;
+       _leave(" = %u", klen);
+       return klen;
 }
-#endif
 
 /*
- * update a volume hash record stored in the cache
+ * provide updated file attributes
  */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_volume_cache_update(void *source, void *entry)
+static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
+                                    uint64_t *size)
 {
-       struct afs_cache_vhash *vhash = entry;
-       struct afs_volume *volume = source;
+       const struct afs_vnode *vnode = cookie_netfs_data;
 
-       _enter("");
+       _enter("{%x,%x,%llx},",
+              vnode->fid.vnode, vnode->fid.unique,
+              vnode->status.data_version);
 
-       vhash->vtype = volume->type;
+       *size = vnode->status.size;
 }
-#endif
-
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vnode_cache_match(void *target,
-                                                const void *entry);
-static void afs_vnode_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_vnode_cache_index_def = {
-       .name           = "vnode",
-       .data_size      = sizeof(struct afs_cache_vnode),
-       .keys[0]        = { CACHEFS_INDEX_KEYS_BIN, 4 },
-       .match          = afs_vnode_cache_match,
-       .update         = afs_vnode_cache_update,
-};
-#endif
 
 /*
- * match a vnode record stored in the cache
+ * provide new auxilliary cache data
+ */
+static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
+                                       void *buffer, uint16_t bufmax)
+{
+       const struct afs_vnode *vnode = cookie_netfs_data;
+       uint16_t dlen;
+
+       _enter("{%x,%x,%Lx},%p,%u",
+              vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
+              buffer, bufmax);
+
+       dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
+       if (dlen > bufmax)
+               return 0;
+
+       memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique));
+       buffer += sizeof(vnode->fid.unique);
+       memcpy(buffer, &vnode->status.data_version,
+              sizeof(vnode->status.data_version));
+
+       _leave(" = %u", dlen);
+       return dlen;
+}
+
+/*
+ * check that the auxilliary data indicates that the entry is still valid
  */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vnode_cache_match(void *target,
-                                                const void *entry)
+static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
+                                                      const void *buffer,
+                                                      uint16_t buflen)
 {
-       const struct afs_cache_vnode *cvnode = entry;
-       struct afs_vnode *vnode = target;
-
-       _enter("{%x,%x,%Lx},{%x,%x,%Lx}",
-              vnode->fid.vnode,
-              vnode->fid.unique,
-              vnode->status.version,
-              cvnode->vnode_id,
-              cvnode->vnode_unique,
-              cvnode->data_version);
-
-       if (vnode->fid.vnode != cvnode->vnode_id) {
-               _leave(" = FAILED");
-               return CACHEFS_MATCH_FAILED;
+       struct afs_vnode *vnode = cookie_netfs_data;
+       uint16_t dlen;
+
+       _enter("{%x,%x,%llx},%p,%u",
+              vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
+              buffer, buflen);
+
+       /* check the size of the data is what we're expecting */
+       dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
+       if (dlen != buflen) {
+               _leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen);
+               return FSCACHE_CHECKAUX_OBSOLETE;
        }
 
-       if (vnode->fid.unique != cvnode->vnode_unique ||
-           vnode->status.version != cvnode->data_version) {
-               _leave(" = DELETE");
-               return CACHEFS_MATCH_SUCCESS_DELETE;
+       if (memcmp(buffer,
+                  &vnode->fid.unique,
+                  sizeof(vnode->fid.unique)
+                  ) != 0) {
+               unsigned unique;
+
+               memcpy(&unique, buffer, sizeof(unique));
+
+               _leave(" = OBSOLETE [uniq %x != %x]",
+                      unique, vnode->fid.unique);
+               return FSCACHE_CHECKAUX_OBSOLETE;
+       }
+
+       if (memcmp(buffer + sizeof(vnode->fid.unique),
+                  &vnode->status.data_version,
+                  sizeof(vnode->status.data_version)
+                  ) != 0) {
+               afs_dataversion_t version;
+
+               memcpy(&version, buffer + sizeof(vnode->fid.unique),
+                      sizeof(version));
+
+               _leave(" = OBSOLETE [vers %llx != %llx]",
+                      version, vnode->status.data_version);
+               return FSCACHE_CHECKAUX_OBSOLETE;
        }
 
        _leave(" = SUCCESS");
-       return CACHEFS_MATCH_SUCCESS;
+       return FSCACHE_CHECKAUX_OKAY;
 }
-#endif
 
 /*
- * update a vnode record stored in the cache
+ * indication the cookie is no longer uncached
+ * - this function is called when the backing store currently caching a cookie
+ *   is removed
+ * - the netfs should use this to clean up any markers indicating cached pages
+ * - this is mandatory for any object that may have data
  */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_vnode_cache_update(void *source, void *entry)
+static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
 {
-       struct afs_cache_vnode *cvnode = entry;
-       struct afs_vnode *vnode = source;
+       struct afs_vnode *vnode = cookie_netfs_data;
+       struct pagevec pvec;
+       pgoff_t first;
+       int loop, nr_pages;
+
+       _enter("{%x,%x,%Lx}",
+              vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version);
+
+       pagevec_init(&pvec, 0);
+       first = 0;
+
+       for (;;) {
+               /* grab a bunch of pages to clean */
+               nr_pages = pagevec_lookup(&pvec, vnode->vfs_inode.i_mapping,
+                                         first,
+                                         PAGEVEC_SIZE - pagevec_count(&pvec));
+               if (!nr_pages)
+                       break;
 
-       _enter("");
+               for (loop = 0; loop < nr_pages; loop++)
+                       ClearPageFsCache(pvec.pages[loop]);
+
+               first = pvec.pages[nr_pages - 1]->index + 1;
+
+               pvec.nr = nr_pages;
+               pagevec_release(&pvec);
+               cond_resched();
+       }
 
-       cvnode->vnode_id        = vnode->fid.vnode;
-       cvnode->vnode_unique    = vnode->fid.unique;
-       cvnode->data_version    = vnode->status.version;
+       _leave("");
 }
-#endif
index 36a3642cf90ecdf7e9034f4c40b1b9b41805d989..5c4f6b499e90104a5c3184989090cf948a0b57fd 100644 (file)
@@ -1,6 +1,6 @@
 /* AFS local cache management interface
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -9,15 +9,4 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifndef AFS_CACHE_H
-#define AFS_CACHE_H
-
-#undef AFS_CACHING_SUPPORT
-
-#include <linux/mm.h>
-#ifdef AFS_CACHING_SUPPORT
-#include <linux/cachefs.h>
-#endif
-#include "types.h"
-
-#endif /* AFS_CACHE_H */
+#include <linux/fscache.h>
index 5e1df14e16b188d9a47501a28c48ce65a4be4c5b..e19c13f059ed5fa8ec0bcac9f0ce80377476b26c 100644 (file)
@@ -147,12 +147,11 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
        if (ret < 0)
                goto error;
 
-#ifdef AFS_CACHING_SUPPORT
-       /* put it up for caching */
-       cachefs_acquire_cookie(afs_cache_netfs.primary_index,
-                              &afs_vlocation_cache_index_def,
-                              cell,
-                              &cell->cache);
+#ifdef CONFIG_AFS_FSCACHE
+       /* put it up for caching (this never returns an error) */
+       cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index,
+                                            &afs_cell_cache_index_def,
+                                            cell);
 #endif
 
        /* add to the cell lists */
@@ -362,10 +361,9 @@ static void afs_cell_destroy(struct afs_cell *cell)
        list_del_init(&cell->proc_link);
        up_write(&afs_proc_cells_sem);
 
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_relinquish_cookie(cell->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_relinquish_cookie(cell->cache, 0);
 #endif
-
        key_put(cell->anonymous_key);
        kfree(cell);
 
index a3901769a96c4231b3b6c0cf88b9d3e6746f7468..7a1d942ef68d469b778678482f880afac446bfa9 100644 (file)
@@ -23,6 +23,9 @@ static void afs_invalidatepage(struct page *page, unsigned long offset);
 static int afs_releasepage(struct page *page, gfp_t gfp_flags);
 static int afs_launder_page(struct page *page);
 
+static int afs_readpages(struct file *filp, struct address_space *mapping,
+                        struct list_head *pages, unsigned nr_pages);
+
 const struct file_operations afs_file_operations = {
        .open           = afs_open,
        .release        = afs_release,
@@ -46,6 +49,7 @@ const struct inode_operations afs_file_inode_operations = {
 
 const struct address_space_operations afs_fs_aops = {
        .readpage       = afs_readpage,
+       .readpages      = afs_readpages,
        .set_page_dirty = afs_set_page_dirty,
        .launder_page   = afs_launder_page,
        .releasepage    = afs_releasepage,
@@ -101,37 +105,18 @@ int afs_release(struct inode *inode, struct file *file)
 /*
  * deal with notification that a page was read from the cache
  */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_readpage_read_complete(void *cookie_data,
-                                      struct page *page,
-                                      void *data,
-                                      int error)
+static void afs_file_readpage_read_complete(struct page *page,
+                                           void *data,
+                                           int error)
 {
-       _enter("%p,%p,%p,%d", cookie_data, page, data, error);
+       _enter("%p,%p,%d", page, data, error);
 
-       if (error)
-               SetPageError(page);
-       else
+       /* if the read completes with an error, we just unlock the page and let
+        * the VM reissue the readpage */
+       if (!error)
                SetPageUptodate(page);
        unlock_page(page);
-
 }
-#endif
-
-/*
- * deal with notification that a page was written to the cache
- */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_readpage_write_complete(void *cookie_data,
-                                       struct page *page,
-                                       void *data,
-                                       int error)
-{
-       _enter("%p,%p,%p,%d", cookie_data, page, data, error);
-
-       unlock_page(page);
-}
-#endif
 
 /*
  * AFS read page from file, directory or symlink
@@ -161,9 +146,9 @@ static int afs_readpage(struct file *file, struct page *page)
        if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
                goto error;
 
-#ifdef AFS_CACHING_SUPPORT
        /* is it cached? */
-       ret = cachefs_read_or_alloc_page(vnode->cache,
+#ifdef CONFIG_AFS_FSCACHE
+       ret = fscache_read_or_alloc_page(vnode->cache,
                                         page,
                                         afs_file_readpage_read_complete,
                                         NULL,
@@ -171,20 +156,21 @@ static int afs_readpage(struct file *file, struct page *page)
 #else
        ret = -ENOBUFS;
 #endif
-
        switch (ret) {
-               /* read BIO submitted and wb-journal entry found */
-       case 1:
-               BUG(); // TODO - handle wb-journal match
-
                /* read BIO submitted (page in cache) */
        case 0:
                break;
 
-               /* no page available in cache */
-       case -ENOBUFS:
+               /* page not yet cached */
        case -ENODATA:
+               _debug("cache said ENODATA");
+               goto go_on;
+
+               /* page will not be cached */
+       case -ENOBUFS:
+               _debug("cache said ENOBUFS");
        default:
+       go_on:
                offset = page->index << PAGE_CACHE_SHIFT;
                len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
 
@@ -198,27 +184,25 @@ static int afs_readpage(struct file *file, struct page *page)
                                set_bit(AFS_VNODE_DELETED, &vnode->flags);
                                ret = -ESTALE;
                        }
-#ifdef AFS_CACHING_SUPPORT
-                       cachefs_uncache_page(vnode->cache, page);
+
+#ifdef CONFIG_AFS_FSCACHE
+                       fscache_uncache_page(vnode->cache, page);
 #endif
+                       BUG_ON(PageFsCache(page));
                        goto error;
                }
 
                SetPageUptodate(page);
 
-#ifdef AFS_CACHING_SUPPORT
-               if (cachefs_write_page(vnode->cache,
-                                      page,
-                                      afs_file_readpage_write_complete,
-                                      NULL,
-                                      GFP_KERNEL) != 0
-                   ) {
-                       cachefs_uncache_page(vnode->cache, page);
-                       unlock_page(page);
+               /* send the page to the cache */
+#ifdef CONFIG_AFS_FSCACHE
+               if (PageFsCache(page) &&
+                   fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) {
+                       fscache_uncache_page(vnode->cache, page);
+                       BUG_ON(PageFsCache(page));
                }
-#else
-               unlock_page(page);
 #endif
+               unlock_page(page);
        }
 
        _leave(" = 0");
@@ -232,34 +216,59 @@ error:
 }
 
 /*
- * invalidate part or all of a page
+ * read a set of pages
  */
-static void afs_invalidatepage(struct page *page, unsigned long offset)
+static int afs_readpages(struct file *file, struct address_space *mapping,
+                        struct list_head *pages, unsigned nr_pages)
 {
-       int ret = 1;
+       struct afs_vnode *vnode;
+       int ret = 0;
 
-       _enter("{%lu},%lu", page->index, offset);
+       _enter(",{%lu},,%d", mapping->host->i_ino, nr_pages);
 
-       BUG_ON(!PageLocked(page));
+       vnode = AFS_FS_I(mapping->host);
+       if (vnode->flags & AFS_VNODE_DELETED) {
+               _leave(" = -ESTALE");
+               return -ESTALE;
+       }
 
-       if (PagePrivate(page)) {
-               /* We release buffers only if the entire page is being
-                * invalidated.
-                * The get_block cached value has been unconditionally
-                * invalidated, so real IO is not possible anymore.
-                */
-               if (offset == 0) {
-                       BUG_ON(!PageLocked(page));
-
-                       ret = 0;
-                       if (!PageWriteback(page))
-                               ret = page->mapping->a_ops->releasepage(page,
-                                                                       0);
-                       /* possibly should BUG_ON(!ret); - neilb */
-               }
+       /* attempt to read as many of the pages as possible */
+#ifdef CONFIG_AFS_FSCACHE
+       ret = fscache_read_or_alloc_pages(vnode->cache,
+                                         mapping,
+                                         pages,
+                                         &nr_pages,
+                                         afs_file_readpage_read_complete,
+                                         NULL,
+                                         mapping_gfp_mask(mapping));
+#else
+       ret = -ENOBUFS;
+#endif
+
+       switch (ret) {
+               /* all pages are being read from the cache */
+       case 0:
+               BUG_ON(!list_empty(pages));
+               BUG_ON(nr_pages != 0);
+               _leave(" = 0 [reading all]");
+               return 0;
+
+               /* there were pages that couldn't be read from the cache */
+       case -ENODATA:
+       case -ENOBUFS:
+               break;
+
+               /* other error */
+       default:
+               _leave(" = %d", ret);
+               return ret;
        }
 
-       _leave(" = %d", ret);
+       /* load the missing pages from the network */
+       ret = read_cache_pages(mapping, pages, (void *) afs_readpage, file);
+
+       _leave(" = %d [netting]", ret);
+       return ret;
 }
 
 /*
@@ -273,25 +282,82 @@ static int afs_launder_page(struct page *page)
 }
 
 /*
- * release a page and cleanup its private data
+ * invalidate part or all of a page
+ * - release a page and clean up its private data if offset is 0 (indicating
+ *   the entire page)
+ */
+static void afs_invalidatepage(struct page *page, unsigned long offset)
+{
+       struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
+
+       _enter("{%lu},%lu", page->index, offset);
+
+       BUG_ON(!PageLocked(page));
+
+       /* we clean up only if the entire page is being invalidated */
+       if (offset == 0) {
+#ifdef CONFIG_AFS_FSCACHE
+               if (PageFsCache(page)) {
+                       struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+                       fscache_wait_on_page_write(vnode->cache, page);
+                       fscache_uncache_page(vnode->cache, page);
+                       ClearPageFsCache(page);
+               }
+#endif
+
+               if (PagePrivate(page)) {
+                       if (wb && !PageWriteback(page)) {
+                               set_page_private(page, 0);
+                               afs_put_writeback(wb);
+                       }
+
+                       if (!page_private(page))
+                               ClearPagePrivate(page);
+               }
+       }
+
+       _leave("");
+}
+
+/*
+ * release a page and clean up its private state if it's not busy
+ * - return true if the page can now be released, false if not
  */
 static int afs_releasepage(struct page *page, gfp_t gfp_flags)
 {
+       struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
        struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
-       struct afs_writeback *wb;
 
        _enter("{{%x:%u}[%lu],%lx},%x",
               vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
               gfp_flags);
 
+       /* deny if page is being written to the cache and the caller hasn't
+        * elected to wait */
+#ifdef CONFIG_AFS_FSCACHE
+       if (PageFsCache(page)) {
+               if (fscache_check_page_write(vnode->cache, page)) {
+                       if (!(gfp_flags & __GFP_WAIT)) {
+                               _leave(" = F [cache busy]");
+                               return 0;
+                       }
+                       fscache_wait_on_page_write(vnode->cache, page);
+               }
+
+               fscache_uncache_page(vnode->cache, page);
+               ClearPageFsCache(page);
+       }
+#endif
+
        if (PagePrivate(page)) {
-               wb = (struct afs_writeback *) page_private(page);
-               ASSERT(wb != NULL);
-               set_page_private(page, 0);
+               if (wb) {
+                       set_page_private(page, 0);
+                       afs_put_writeback(wb);
+               }
                ClearPagePrivate(page);
-               afs_put_writeback(wb);
        }
 
-       _leave(" = 0");
-       return 0;
+       /* indicate that the page can be released */
+       _leave(" = T");
+       return 1;
 }
index bb47217f6a18478abd4d35215f4fdda1135845a4..c048f06587512c93535e7ca1221d6d7b3ee77f02 100644 (file)
@@ -61,6 +61,11 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
                return -EBADMSG;
        }
 
+#ifdef CONFIG_AFS_FSCACHE
+       if (vnode->status.size != inode->i_size)
+               fscache_attr_changed(vnode->cache);
+#endif
+
        inode->i_nlink          = vnode->status.nlink;
        inode->i_uid            = vnode->status.owner;
        inode->i_gid            = 0;
@@ -149,15 +154,6 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
                return inode;
        }
 
-#ifdef AFS_CACHING_SUPPORT
-       /* set up caching before reading the status, as fetch-status reads the
-        * first page of symlinks to see if they're really mntpts */
-       cachefs_acquire_cookie(vnode->volume->cache,
-                              NULL,
-                              vnode,
-                              &vnode->cache);
-#endif
-
        if (!status) {
                /* it's a remotely extant inode */
                set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
@@ -183,6 +179,15 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
                }
        }
 
+       /* set up caching before mapping the status, as map-status reads the
+        * first page of symlinks to see if they're really mountpoints */
+       inode->i_size = vnode->status.size;
+#ifdef CONFIG_AFS_FSCACHE
+       vnode->cache = fscache_acquire_cookie(vnode->volume->cache,
+                                             &afs_vnode_cache_index_def,
+                                             vnode);
+#endif
+
        ret = afs_inode_map_status(vnode, key);
        if (ret < 0)
                goto bad_inode;
@@ -196,6 +201,10 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
 
        /* failure */
 bad_inode:
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_relinquish_cookie(vnode->cache, 0);
+       vnode->cache = NULL;
+#endif
        iget_failed(inode);
        _leave(" = %d [bad]", ret);
        return ERR_PTR(ret);
@@ -340,8 +349,8 @@ void afs_clear_inode(struct inode *inode)
        ASSERT(list_empty(&vnode->writebacks));
        ASSERT(!vnode->cb_promised);
 
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_relinquish_cookie(vnode->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_relinquish_cookie(vnode->cache, 0);
        vnode->cache = NULL;
 #endif
 
index 67f259d99cd6f11afae3b9296b74f0f5bdde3065..106be66dafd2ca7edc9388dac55d8a218ab52dc6 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "afs.h"
 #include "afs_vl.h"
+#include "cache.h"
 
 #define AFS_CELL_MAX_ADDRS 15
 
@@ -193,8 +194,8 @@ struct afs_cell {
        struct key              *anonymous_key; /* anonymous user key for this cell */
        struct list_head        proc_link;      /* /proc cell list link */
        struct proc_dir_entry   *proc_dir;      /* /proc dir for this cell */
-#ifdef AFS_CACHING_SUPPORT
-       struct cachefs_cookie   *cache;         /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+       struct fscache_cookie   *cache;         /* caching cookie */
 #endif
 
        /* server record management */
@@ -249,8 +250,8 @@ struct afs_vlocation {
        struct list_head        grave;          /* link in master graveyard list */
        struct list_head        update;         /* link in master update list */
        struct afs_cell         *cell;          /* cell to which volume belongs */
-#ifdef AFS_CACHING_SUPPORT
-       struct cachefs_cookie   *cache;         /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+       struct fscache_cookie   *cache;         /* caching cookie */
 #endif
        struct afs_cache_vlocation vldb;        /* volume information DB record */
        struct afs_volume       *vols[3];       /* volume access record pointer (index by type) */
@@ -302,8 +303,8 @@ struct afs_volume {
        atomic_t                usage;
        struct afs_cell         *cell;          /* cell to which belongs (unrefd ptr) */
        struct afs_vlocation    *vlocation;     /* volume location */
-#ifdef AFS_CACHING_SUPPORT
-       struct cachefs_cookie   *cache;         /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+       struct fscache_cookie   *cache;         /* caching cookie */
 #endif
        afs_volid_t             vid;            /* volume ID */
        afs_voltype_t           type;           /* type of volume */
@@ -333,8 +334,8 @@ struct afs_vnode {
        struct afs_server       *server;        /* server currently supplying this file */
        struct afs_fid          fid;            /* the file identifier for this inode */
        struct afs_file_status  status;         /* AFS status info for this file */
-#ifdef AFS_CACHING_SUPPORT
-       struct cachefs_cookie   *cache;         /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+       struct fscache_cookie   *cache;         /* caching cookie */
 #endif
        struct afs_permits      *permits;       /* cache of permits so far obtained */
        struct mutex            permits_lock;   /* lock for altering permits list */
@@ -427,6 +428,22 @@ struct afs_uuid {
 };
 
 /*****************************************************************************/
+/*
+ * cache.c
+ */
+#ifdef CONFIG_AFS_FSCACHE
+extern struct fscache_netfs afs_cache_netfs;
+extern struct fscache_cookie_def afs_cell_cache_index_def;
+extern struct fscache_cookie_def afs_vlocation_cache_index_def;
+extern struct fscache_cookie_def afs_volume_cache_index_def;
+extern struct fscache_cookie_def afs_vnode_cache_index_def;
+#else
+#define afs_cell_cache_index_def       (*(struct fscache_cookie_def *) NULL)
+#define afs_vlocation_cache_index_def  (*(struct fscache_cookie_def *) NULL)
+#define afs_volume_cache_index_def     (*(struct fscache_cookie_def *) NULL)
+#define afs_vnode_cache_index_def      (*(struct fscache_cookie_def *) NULL)
+#endif
+
 /*
  * callback.c
  */
@@ -446,9 +463,6 @@ extern void afs_callback_update_kill(void);
  */
 extern struct rw_semaphore afs_proc_cells_sem;
 extern struct list_head afs_proc_cells;
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_cache_cell_index_def;
-#endif
 
 #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
 extern int afs_cell_init(char *);
@@ -554,9 +568,6 @@ extern void afs_clear_inode(struct inode *);
  * main.c
  */
 extern struct afs_uuid afs_uuid;
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_netfs afs_cache_netfs;
-#endif
 
 /*
  * misc.c
@@ -637,10 +648,6 @@ extern int afs_get_MAC_address(u8 *, size_t);
 /*
  * vlclient.c
  */
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_vlocation_cache_index_def;
-#endif
-
 extern int afs_vl_get_entry_by_name(struct in_addr *, struct key *,
                                    const char *, struct afs_cache_vlocation *,
                                    const struct afs_wait_mode *);
@@ -664,12 +671,6 @@ extern void afs_vlocation_purge(void);
 /*
  * vnode.c
  */
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_vnode_cache_index_def;
-#endif
-
-extern struct afs_timer_ops afs_vnode_cb_timed_out_ops;
-
 static inline struct afs_vnode *AFS_FS_I(struct inode *inode)
 {
        return container_of(inode, struct afs_vnode, vfs_inode);
@@ -711,10 +712,6 @@ extern int afs_vnode_release_lock(struct afs_vnode *, struct key *);
 /*
  * volume.c
  */
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_volume_cache_index_def;
-#endif
-
 #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0)
 
 extern void afs_put_volume(struct afs_volume *);
index 2d3e5d4fb9f781b7b360fea9bf3c2896b0771504..66d54d348c55f2c232bd362f1b432ab242d4256b 100644 (file)
@@ -1,6 +1,6 @@
 /* AFS client file system
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002,5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -29,18 +29,6 @@ static char *rootcell;
 module_param(rootcell, charp, 0);
 MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
 
-#ifdef AFS_CACHING_SUPPORT
-static struct cachefs_netfs_operations afs_cache_ops = {
-       .get_page_cookie        = afs_cache_get_page_cookie,
-};
-
-struct cachefs_netfs afs_cache_netfs = {
-       .name                   = "afs",
-       .version                = 0,
-       .ops                    = &afs_cache_ops,
-};
-#endif
-
 struct afs_uuid afs_uuid;
 
 /*
@@ -104,10 +92,9 @@ static int __init afs_init(void)
        if (ret < 0)
                return ret;
 
-#ifdef AFS_CACHING_SUPPORT
+#ifdef CONFIG_AFS_FSCACHE
        /* we want to be able to cache */
-       ret = cachefs_register_netfs(&afs_cache_netfs,
-                                    &afs_cache_cell_index_def);
+       ret = fscache_register_netfs(&afs_cache_netfs);
        if (ret < 0)
                goto error_cache;
 #endif
@@ -142,8 +129,8 @@ error_fs:
 error_open_socket:
 error_vl_update_init:
 error_cell_init:
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_unregister_netfs(&afs_cache_netfs);
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_unregister_netfs(&afs_cache_netfs);
 error_cache:
 #endif
        afs_callback_update_kill();
@@ -175,8 +162,8 @@ static void __exit afs_exit(void)
        afs_vlocation_purge();
        flush_scheduled_work();
        afs_cell_purge();
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_unregister_netfs(&afs_cache_netfs);
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_unregister_netfs(&afs_cache_netfs);
 #endif
        afs_proc_cleanup();
        rcu_barrier();
index 78db4953a80047847b2d6098ca0c8bf4b30a76ef..2b9e2d03a3902d686940339ce349f88e9af51324 100644 (file)
@@ -173,9 +173,9 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
        if (PageError(page))
                goto error;
 
-       buf = kmap(page);
+       buf = kmap_atomic(page, KM_USER0);
        memcpy(devname, buf, size);
-       kunmap(page);
+       kunmap_atomic(buf, KM_USER0);
        page_cache_release(page);
        page = NULL;
 
index 7578c1ab9e0be9ec3260c4cce41b78287f213bce..8630615e57fe512ca9c7a10472ce5f959f317234 100644 (file)
@@ -146,7 +146,6 @@ int afs_proc_init(void)
        proc_afs = proc_mkdir("fs/afs", NULL);
        if (!proc_afs)
                goto error_dir;
-       proc_afs->owner = THIS_MODULE;
 
        p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops);
        if (!p)
index 849fc3160cb5b372c2626545f926ce185c22762b..ec2a7431e458b52c89795f6ba9c01a2efe8aa254 100644 (file)
@@ -281,9 +281,8 @@ static void afs_vlocation_apply_update(struct afs_vlocation *vl,
 
        vl->vldb = *vldb;
 
-#ifdef AFS_CACHING_SUPPORT
-       /* update volume entry in local cache */
-       cachefs_update_cookie(vl->cache);
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_update_cookie(vl->cache);
 #endif
 }
 
@@ -304,11 +303,9 @@ static int afs_vlocation_fill_in_record(struct afs_vlocation *vl,
        memset(&vldb, 0, sizeof(vldb));
 
        /* see if we have an in-cache copy (will set vl->valid if there is) */
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_acquire_cookie(cell->cache,
-                              &afs_volume_cache_index_def,
-                              vlocation,
-                              &vl->cache);
+#ifdef CONFIG_AFS_FSCACHE
+       vl->cache = fscache_acquire_cookie(vl->cell->cache,
+                                          &afs_vlocation_cache_index_def, vl);
 #endif
 
        if (vl->valid) {
@@ -420,6 +417,11 @@ fill_in_record:
        spin_unlock(&vl->lock);
        wake_up(&vl->waitq);
 
+       /* update volume entry in local cache */
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_update_cookie(vl->cache);
+#endif
+
        /* schedule for regular updates */
        afs_vlocation_queue_for_updates(vl);
        goto success;
@@ -465,7 +467,7 @@ found_in_memory:
        spin_unlock(&vl->lock);
 
 success:
-       _leave(" = %p",vl);
+       _leave(" = %p", vl);
        return vl;
 
 error_abandon:
@@ -523,10 +525,9 @@ static void afs_vlocation_destroy(struct afs_vlocation *vl)
 {
        _enter("%p", vl);
 
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_relinquish_cookie(vl->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_relinquish_cookie(vl->cache, 0);
 #endif
-
        afs_put_cell(vl->cell);
        kfree(vl);
 }
index 8bab0e3437f9384507721cb68e93245c4c154ff6..a353e69e2391bc5f8bb3dd2970f19aeade9ea7e8 100644 (file)
@@ -124,13 +124,11 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
        }
 
        /* attach the cache and volume location */
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_acquire_cookie(vlocation->cache,
-                              &afs_vnode_cache_index_def,
-                              volume,
-                              &volume->cache);
+#ifdef CONFIG_AFS_FSCACHE
+       volume->cache = fscache_acquire_cookie(vlocation->cache,
+                                              &afs_volume_cache_index_def,
+                                              volume);
 #endif
-
        afs_get_vlocation(vlocation);
        volume->vlocation = vlocation;
 
@@ -194,8 +192,8 @@ void afs_put_volume(struct afs_volume *volume)
        up_write(&vlocation->cell->vl_sem);
 
        /* finish cleaning up the volume */
-#ifdef AFS_CACHING_SUPPORT
-       cachefs_relinquish_cookie(volume->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_relinquish_cookie(volume->cache, 0);
 #endif
        afs_put_vlocation(vlocation);
 
index 3fb36d433621dd2bb71edcc757dbe22390ff2640..c2e7a7ff008054ad63fb8ae33677b96b359bd90f 100644 (file)
@@ -780,3 +780,24 @@ int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
        _leave(" = %d", ret);
        return ret;
 }
+
+/*
+ * notification that a previously read-only page is about to become writable
+ * - if it returns an error, the caller will deliver a bus error signal
+ */
+int afs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+       struct afs_vnode *vnode = AFS_FS_I(vma->vm_file->f_mapping->host);
+
+       _enter("{{%x:%u}},{%lx}",
+              vnode->fid.vid, vnode->fid.vnode, page->index);
+
+       /* wait for the page to be written to the cache before we allow it to
+        * be modified */
+#ifdef CONFIG_AFS_FSCACHE
+       fscache_wait_on_page_write(vnode->cache, page);
+#endif
+
+       _leave(" = 0");
+       return 0;
+}
index a76803108d06fe58ce8b2a99d24bdae9f3e5004f..b7ff33c63101545c17410c220a2e6c0f5ab51994 100644 (file)
@@ -186,6 +186,8 @@ int autofs4_expire_wait(struct dentry *dentry);
 int autofs4_expire_run(struct super_block *, struct vfsmount *,
                        struct autofs_sb_info *,
                        struct autofs_packet_expire __user *);
+int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
+                           struct autofs_sb_info *sbi, int when);
 int autofs4_expire_multi(struct super_block *, struct vfsmount *,
                        struct autofs_sb_info *, int __user *);
 struct dentry *autofs4_expire_direct(struct super_block *sb,
index 025e105bffea984495c1861aa00e731d979b6c4a..9e5ae8a4f5c867bf1ddb81525cd260028d8d3c9e 100644 (file)
@@ -525,40 +525,13 @@ static int autofs_dev_ioctl_expire(struct file *fp,
                                   struct autofs_sb_info *sbi,
                                   struct autofs_dev_ioctl *param)
 {
-       struct dentry *dentry;
        struct vfsmount *mnt;
-       int err = -EAGAIN;
        int how;
 
        how = param->expire.how;
        mnt = fp->f_path.mnt;
 
-       if (autofs_type_trigger(sbi->type))
-               dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how);
-       else
-               dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how);
-
-       if (dentry) {
-               struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-               /*
-                * This is synchronous because it makes the daemon a
-                * little easier
-               */
-               err = autofs4_wait(sbi, dentry, NFY_EXPIRE);
-
-               spin_lock(&sbi->fs_lock);
-               if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
-                       ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
-                       sbi->sb->s_root->d_mounted++;
-               }
-               ino->flags &= ~AUTOFS_INF_EXPIRING;
-               complete_all(&ino->expire_complete);
-               spin_unlock(&sbi->fs_lock);
-               dput(dentry);
-       }
-
-       return err;
+       return autofs4_do_expire_multi(sbi->sb, mnt, sbi, how);
 }
 
 /* Check if autofs mount point is in use */
index e3bd50776f9e4f9997d21940c11cd99acd855263..75f7ddacf7d6d0575577e6172185fdc32d5f12ee 100644 (file)
@@ -478,22 +478,16 @@ int autofs4_expire_run(struct super_block *sb,
        return ret;
 }
 
-/* Call repeatedly until it returns -EAGAIN, meaning there's nothing
-   more to be done */
-int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
-                       struct autofs_sb_info *sbi, int __user *arg)
+int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
+                           struct autofs_sb_info *sbi, int when)
 {
        struct dentry *dentry;
        int ret = -EAGAIN;
-       int do_now = 0;
-
-       if (arg && get_user(do_now, arg))
-               return -EFAULT;
 
        if (autofs_type_trigger(sbi->type))
-               dentry = autofs4_expire_direct(sb, mnt, sbi, do_now);
+               dentry = autofs4_expire_direct(sb, mnt, sbi, when);
        else
-               dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now);
+               dentry = autofs4_expire_indirect(sb, mnt, sbi, when);
 
        if (dentry) {
                struct autofs_info *ino = autofs4_dentry_ino(dentry);
@@ -516,3 +510,16 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
        return ret;
 }
 
+/* Call repeatedly until it returns -EAGAIN, meaning there's nothing
+   more to be done */
+int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
+                       struct autofs_sb_info *sbi, int __user *arg)
+{
+       int do_now = 0;
+
+       if (arg && get_user(do_now, arg))
+               return -EFAULT;
+
+       return autofs4_do_expire_multi(sb, mnt, sbi, do_now);
+}
+
index 74b1469a950452ba86f661b79c1390d03c464857..e383bf0334f173c8c0a381ef2b2c50964931c62c 100644 (file)
@@ -485,22 +485,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
        DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
                 current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);
 
-       expiring = autofs4_lookup_expiring(sbi, dentry->d_parent, &dentry->d_name);
-       if (expiring) {
-               /*
-                * If we are racing with expire the request might not
-                * be quite complete but the directory has been removed
-                * so it must have been successful, so just wait for it.
-                */
-               ino = autofs4_dentry_ino(expiring);
-               autofs4_expire_wait(expiring);
-               spin_lock(&sbi->lookup_lock);
-               if (!list_empty(&ino->expiring))
-                       list_del_init(&ino->expiring);
-               spin_unlock(&sbi->lookup_lock);
-               dput(expiring);
-       }
-
        unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name);
        if (unhashed)
                dentry = unhashed;
@@ -538,14 +522,31 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
        }
 
        if (!oz_mode) {
+               mutex_unlock(&dir->i_mutex);
+               expiring = autofs4_lookup_expiring(sbi,
+                                                  dentry->d_parent,
+                                                  &dentry->d_name);
+               if (expiring) {
+                       /*
+                        * If we are racing with expire the request might not
+                        * be quite complete but the directory has been removed
+                        * so it must have been successful, so just wait for it.
+                        */
+                       ino = autofs4_dentry_ino(expiring);
+                       autofs4_expire_wait(expiring);
+                       spin_lock(&sbi->lookup_lock);
+                       if (!list_empty(&ino->expiring))
+                               list_del_init(&ino->expiring);
+                       spin_unlock(&sbi->lookup_lock);
+                       dput(expiring);
+               }
+
                spin_lock(&dentry->d_lock);
                dentry->d_flags |= DCACHE_AUTOFS_PENDING;
                spin_unlock(&dentry->d_lock);
-               if (dentry->d_op && dentry->d_op->d_revalidate) {
-                       mutex_unlock(&dir->i_mutex);
+               if (dentry->d_op && dentry->d_op->d_revalidate)
                        (dentry->d_op->d_revalidate)(dentry, nd);
-                       mutex_lock(&dir->i_mutex);
-               }
+               mutex_lock(&dir->i_mutex);
        }
 
        /*
index d06cb023ad028a000a2f41db1208fa46991d7f47..76afd0d6b86c93e44ffb1cdf6d67616b57086822 100644 (file)
@@ -900,6 +900,7 @@ static int
 befs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        befs_debug(sb, "---> befs_statfs()");
 
@@ -910,6 +911,8 @@ befs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = buf->f_bfree;
        buf->f_files = 0;       /* UNKNOWN */
        buf->f_ffree = 0;       /* UNKNOWN */
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = BEFS_NAME_LEN;
 
        befs_debug(sb, "<--- befs_statfs()");
index 33b7235f853b2d46a7a685d805163d57ee0ef505..40381df348697263027536cd182e4b1294052bd7 100644 (file)
@@ -12,8 +12,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/errno.h>
 #include <linux/binfmts.h>
 #include <linux/string.h>
 #include <linux/file.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
-#include <linux/shm.h>
 #include <linux/personality.h>
 #include <linux/elfcore.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
-#include <linux/smp.h>
 #include <linux/compiler.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/security.h>
-#include <linux/syscalls.h>
 #include <linux/random.h>
 #include <linux/elf.h>
 #include <linux/utsname.h>
@@ -576,7 +569,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        unsigned long error;
        struct elf_phdr *elf_ppnt, *elf_phdata;
        unsigned long elf_bss, elf_brk;
-       int elf_exec_fileno;
        int retval, i;
        unsigned int size;
        unsigned long elf_entry;
@@ -631,12 +623,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto out_free_ph;
        }
 
-       retval = get_unused_fd();
-       if (retval < 0)
-               goto out_free_ph;
-       get_file(bprm->file);
-       fd_install(elf_exec_fileno = retval, bprm->file);
-
        elf_ppnt = elf_phdata;
        elf_bss = 0;
        elf_brk = 0;
@@ -655,13 +641,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                        retval = -ENOEXEC;
                        if (elf_ppnt->p_filesz > PATH_MAX || 
                            elf_ppnt->p_filesz < 2)
-                               goto out_free_file;
+                               goto out_free_ph;
 
                        retval = -ENOMEM;
                        elf_interpreter = kmalloc(elf_ppnt->p_filesz,
                                                  GFP_KERNEL);
                        if (!elf_interpreter)
-                               goto out_free_file;
+                               goto out_free_ph;
 
                        retval = kernel_read(bprm->file, elf_ppnt->p_offset,
                                             elf_interpreter,
@@ -956,8 +942,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 
        kfree(elf_phdata);
 
-       sys_close(elf_exec_fileno);
-
        set_binfmt(&elf_format);
 
 #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
@@ -1028,8 +1012,6 @@ out_free_dentry:
                fput(interpreter);
 out_free_interp:
        kfree(elf_interpreter);
-out_free_file:
-       sys_close(elf_exec_fileno);
 out_free_ph:
        kfree(elf_phdata);
        goto out;
index f3e72c5c19f56ec0deee0614e1a625df511a58e0..70cfc4b84ae0995a1d7c66d21ecd833a36b02e74 100644 (file)
@@ -972,9 +972,12 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(
                        params->elfhdr_addr = seg->addr;
 
                /* clear any space allocated but not loaded */
-               if (phdr->p_filesz < phdr->p_memsz)
-                       clear_user((void *) (seg->addr + phdr->p_filesz),
-                                  phdr->p_memsz - phdr->p_filesz);
+               if (phdr->p_filesz < phdr->p_memsz) {
+                       ret = clear_user((void *) (seg->addr + phdr->p_filesz),
+                                        phdr->p_memsz - phdr->p_filesz);
+                       if (ret)
+                               return ret;
+               }
 
                if (mm) {
                        if (phdr->p_flags & PF_X) {
@@ -1014,7 +1017,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
        struct elf32_fdpic_loadseg *seg;
        struct elf32_phdr *phdr;
        unsigned long load_addr, delta_vaddr;
-       int loop, dvset;
+       int loop, dvset, ret;
 
        load_addr = params->load_addr;
        delta_vaddr = 0;
@@ -1114,7 +1117,9 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
                 * PT_LOAD */
                if (prot & PROT_WRITE && disp > 0) {
                        kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp);
-                       clear_user((void __user *) maddr, disp);
+                       ret = clear_user((void __user *) maddr, disp);
+                       if (ret)
+                               return ret;
                        maddr += disp;
                }
 
@@ -1149,15 +1154,19 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
                if (prot & PROT_WRITE && excess1 > 0) {
                        kdebug("clear[%d] ad=%lx sz=%lx",
                               loop, maddr + phdr->p_filesz, excess1);
-                       clear_user((void __user *) maddr + phdr->p_filesz,
-                                  excess1);
+                       ret = clear_user((void __user *) maddr + phdr->p_filesz,
+                                        excess1);
+                       if (ret)
+                               return ret;
                }
 
 #else
                if (excess > 0) {
                        kdebug("clear[%d] ad=%lx sz=%lx",
                               loop, maddr + phdr->p_filesz, excess);
-                       clear_user((void *) maddr + phdr->p_filesz, excess);
+                       ret = clear_user((void *) maddr + phdr->p_filesz, excess);
+                       if (ret)
+                               return ret;
                }
 #endif
 
index 08644a61616e1e7bb6cacb655de0ad06387d3ada..eff74b9c9e77cf8f0b933adb2addcc9aac899a46 100644 (file)
@@ -188,7 +188,6 @@ out:
 static int
 load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
-       int som_exec_fileno;
        int retval;
        unsigned int size;
        unsigned long som_entry;
@@ -220,12 +219,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                goto out_free;
        }
 
-       retval = get_unused_fd();
-       if (retval < 0)
-               goto out_free;
-       get_file(bprm->file);
-       fd_install(som_exec_fileno = retval, bprm->file);
-
        /* Flush all traces of the currently running executable */
        retval = flush_old_exec(bprm);
        if (retval)
index a040cde7f6fd567f68a7c28504f9f25d6a274146..e0c9e545bbfa3834443af51e4e8dfbfc42735426 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1420,8 +1420,7 @@ static void bio_pair_end_2(struct bio *bi, int err)
 }
 
 /*
- * split a bio - only worry about a bio with a single page
- * in it's iovec
+ * split a bio - only worry about a bio with a single page in its iovec
  */
 struct bio_pair *bio_split(struct bio *bi, int first_sectors)
 {
index 8c3c6899ccf33f433969e1b48b045a6a896b55ef..f45dbc18dd175891950ddb84fffa2bc6ce0df117 100644 (file)
@@ -204,6 +204,7 @@ int fsync_bdev(struct block_device *bdev)
        }
        return sync_blockdev(bdev);
 }
+EXPORT_SYMBOL(fsync_bdev);
 
 /**
  * freeze_bdev  --  lock a filesystem and force it into a consistent state
index d2cf5a54a4b816d308ed7c452892fae27e009db1..9adf5e4f7e967b09045e8444c80dd819d72f3031 100644 (file)
@@ -8,7 +8,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
           ref-cache.o export.o tree-log.o acl.o free-space-cache.o zlib.o \
-          compression.o
+          compression.o delayed-ref.o
 else
 
 # Normal Makefile
index 1d53b62dbba51aa61896c8e78ab50b6544e5c267..7fdd184a528d11caa58ddb37f8d59d07de17a517 100644 (file)
@@ -256,7 +256,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
                }
 
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
 
        if (IS_POSIXACL(dir) && acl) {
index c84ca1f5259a5408f538d8254f939677567924a4..51bfdfc8fcdac00b5f13599bed87922563a38f07 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/freezer.h>
-#include <linux/ftrace.h>
 #include "async-thread.h"
 
 #define WORK_QUEUED_BIT 0
@@ -195,6 +194,9 @@ again_locked:
                                if (!list_empty(&worker->pending))
                                        continue;
 
+                               if (kthread_should_stop())
+                                       break;
+
                                /* still no more work?, sleep for real */
                                spin_lock_irq(&worker->lock);
                                set_current_state(TASK_INTERRUPTIBLE);
@@ -208,7 +210,8 @@ again_locked:
                                worker->working = 0;
                                spin_unlock_irq(&worker->lock);
 
-                               schedule();
+                               if (!kthread_should_stop())
+                                       schedule();
                        }
                        __set_current_state(TASK_RUNNING);
                }
index 72677ce2b74fc87b1ff6a277906492389085f687..b30986f00b9d7eebb9bfd50c93e86a9a34f329be 100644 (file)
@@ -66,6 +66,12 @@ struct btrfs_inode {
         */
        struct list_head delalloc_inodes;
 
+       /*
+        * list for tracking inodes that must be sent to disk before a
+        * rename or truncate commit
+        */
+       struct list_head ordered_operations;
+
        /* the space_info for where this inode's data allocations are done */
        struct btrfs_space_info *space_info;
 
@@ -86,12 +92,6 @@ struct btrfs_inode {
         */
        u64 logged_trans;
 
-       /*
-        * trans that last made a change that should be fully fsync'd.  This
-        * gets reset to zero each time the inode is logged
-        */
-       u64 log_dirty_trans;
-
        /* total number of bytes pending delalloc, used by stat to calc the
         * real block usage of the file
         */
@@ -121,6 +121,25 @@ struct btrfs_inode {
        /* the start of block group preferred for allocations. */
        u64 block_group;
 
+       /* the fsync log has some corner cases that mean we have to check
+        * directories to see if any unlinks have been done before
+        * the directory was logged.  See tree-log.c for all the
+        * details
+        */
+       u64 last_unlink_trans;
+
+       /*
+        * ordered_data_close is set by truncate when a file that used
+        * to have good data has been truncated to zero.  When it is set
+        * the btrfs file release call will add this inode to the
+        * ordered operations list so that we make sure to flush out any
+        * new data the application may have written before commit.
+        *
+        * yes, its silly to have a single bitflag, but we might grow more
+        * of these.
+        */
+       unsigned ordered_data_close:1;
+
        struct inode vfs_inode;
 };
 
index 37f31b5529aa0abe62a4e30ec7170c69c443eb0a..e5b2533b691a3040f108d517efea04ccfdcc6117 100644 (file)
@@ -254,18 +254,13 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
  * empty_size -- a hint that you plan on doing more cow.  This is the size in
  * bytes the allocator should try to find free next to the block it returns.
  * This is just a hint and may be ignored by the allocator.
- *
- * prealloc_dest -- if you have already reserved a destination for the cow,
- * this uses that block instead of allocating a new one.
- * btrfs_alloc_reserved_extent is used to finish the allocation.
  */
 static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct extent_buffer *buf,
                             struct extent_buffer *parent, int parent_slot,
                             struct extent_buffer **cow_ret,
-                            u64 search_start, u64 empty_size,
-                            u64 prealloc_dest)
+                            u64 search_start, u64 empty_size)
 {
        u64 parent_start;
        struct extent_buffer *cow;
@@ -291,26 +286,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        level = btrfs_header_level(buf);
        nritems = btrfs_header_nritems(buf);
 
-       if (prealloc_dest) {
-               struct btrfs_key ins;
-
-               ins.objectid = prealloc_dest;
-               ins.offset = buf->len;
-               ins.type = BTRFS_EXTENT_ITEM_KEY;
-
-               ret = btrfs_alloc_reserved_extent(trans, root, parent_start,
-                                                 root->root_key.objectid,
-                                                 trans->transid, level, &ins);
-               BUG_ON(ret);
-               cow = btrfs_init_new_buffer(trans, root, prealloc_dest,
-                                           buf->len, level);
-       } else {
-               cow = btrfs_alloc_free_block(trans, root, buf->len,
-                                            parent_start,
-                                            root->root_key.objectid,
-                                            trans->transid, level,
-                                            search_start, empty_size);
-       }
+       cow = btrfs_alloc_free_block(trans, root, buf->len,
+                                    parent_start, root->root_key.objectid,
+                                    trans->transid, level,
+                                    search_start, empty_size);
        if (IS_ERR(cow))
                return PTR_ERR(cow);
 
@@ -413,7 +392,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
                    struct btrfs_root *root, struct extent_buffer *buf,
                    struct extent_buffer *parent, int parent_slot,
-                   struct extent_buffer **cow_ret, u64 prealloc_dest)
+                   struct extent_buffer **cow_ret)
 {
        u64 search_start;
        int ret;
@@ -436,7 +415,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
            btrfs_header_owner(buf) == root->root_key.objectid &&
            !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
                *cow_ret = buf;
-               WARN_ON(prealloc_dest);
                return 0;
        }
 
@@ -447,8 +425,7 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
        btrfs_set_lock_blocking(buf);
 
        ret = __btrfs_cow_block(trans, root, buf, parent,
-                                parent_slot, cow_ret, search_start, 0,
-                                prealloc_dest);
+                                parent_slot, cow_ret, search_start, 0);
        return ret;
 }
 
@@ -617,7 +594,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                err = __btrfs_cow_block(trans, root, cur, parent, i,
                                        &cur, search_start,
                                        min(16 * blocksize,
-                                           (end_slot - i) * blocksize), 0);
+                                           (end_slot - i) * blocksize));
                if (err) {
                        btrfs_tree_unlock(cur);
                        free_extent_buffer(cur);
@@ -937,7 +914,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                BUG_ON(!child);
                btrfs_tree_lock(child);
                btrfs_set_lock_blocking(child);
-               ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0);
+               ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
                BUG_ON(ret);
 
                spin_lock(&root->node_lock);
@@ -945,6 +922,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                spin_unlock(&root->node_lock);
 
                ret = btrfs_update_extent_ref(trans, root, child->start,
+                                             child->len,
                                              mid->start, child->start,
                                              root->root_key.objectid,
                                              trans->transid, level - 1);
@@ -971,6 +949,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
            BTRFS_NODEPTRS_PER_BLOCK(root) / 4)
                return 0;
 
+       if (trans->transaction->delayed_refs.flushing &&
+           btrfs_header_nritems(mid) > 2)
+               return 0;
+
        if (btrfs_header_nritems(mid) < 2)
                err_on_enospc = 1;
 
@@ -979,7 +961,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_lock(left);
                btrfs_set_lock_blocking(left);
                wret = btrfs_cow_block(trans, root, left,
-                                      parent, pslot - 1, &left, 0);
+                                      parent, pslot - 1, &left);
                if (wret) {
                        ret = wret;
                        goto enospc;
@@ -990,7 +972,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_lock(right);
                btrfs_set_lock_blocking(right);
                wret = btrfs_cow_block(trans, root, right,
-                                      parent, pslot + 1, &right, 0);
+                                      parent, pslot + 1, &right);
                if (wret) {
                        ret = wret;
                        goto enospc;
@@ -1171,7 +1153,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
                        wret = 1;
                } else {
                        ret = btrfs_cow_block(trans, root, left, parent,
-                                             pslot - 1, &left, 0);
+                                             pslot - 1, &left);
                        if (ret)
                                wret = 1;
                        else {
@@ -1222,7 +1204,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
                } else {
                        ret = btrfs_cow_block(trans, root, right,
                                              parent, pslot + 1,
-                                             &right, 0);
+                                             &right);
                        if (ret)
                                wret = 1;
                        else {
@@ -1262,9 +1244,9 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
  * readahead one full node of leaves, finding things that are close
  * to the block in 'slot', and triggering ra on them.
  */
-static noinline void reada_for_search(struct btrfs_root *root,
-                                     struct btrfs_path *path,
-                                     int level, int slot, u64 objectid)
+static void reada_for_search(struct btrfs_root *root,
+                            struct btrfs_path *path,
+                            int level, int slot, u64 objectid)
 {
        struct extent_buffer *node;
        struct btrfs_disk_key disk_key;
@@ -1464,6 +1446,117 @@ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
        }
 }
 
+/*
+ * helper function for btrfs_search_slot.  The goal is to find a block
+ * in cache without setting the path to blocking.  If we find the block
+ * we return zero and the path is unchanged.
+ *
+ * If we can't find the block, we set the path blocking and do some
+ * reada.  -EAGAIN is returned and the search must be repeated.
+ */
+static int
+read_block_for_search(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *root, struct btrfs_path *p,
+                      struct extent_buffer **eb_ret, int level, int slot,
+                      struct btrfs_key *key)
+{
+       u64 blocknr;
+       u64 gen;
+       u32 blocksize;
+       struct extent_buffer *b = *eb_ret;
+       struct extent_buffer *tmp;
+
+       blocknr = btrfs_node_blockptr(b, slot);
+       gen = btrfs_node_ptr_generation(b, slot);
+       blocksize = btrfs_level_size(root, level - 1);
+
+       tmp = btrfs_find_tree_block(root, blocknr, blocksize);
+       if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
+               *eb_ret = tmp;
+               return 0;
+       }
+
+       /*
+        * reduce lock contention at high levels
+        * of the btree by dropping locks before
+        * we read.
+        */
+       btrfs_release_path(NULL, p);
+       if (tmp)
+               free_extent_buffer(tmp);
+       if (p->reada)
+               reada_for_search(root, p, level, slot, key->objectid);
+
+       tmp = read_tree_block(root, blocknr, blocksize, gen);
+       if (tmp)
+               free_extent_buffer(tmp);
+       return -EAGAIN;
+}
+
+/*
+ * helper function for btrfs_search_slot.  This does all of the checks
+ * for node-level blocks and does any balancing required based on
+ * the ins_len.
+ *
+ * If no extra work was required, zero is returned.  If we had to
+ * drop the path, -EAGAIN is returned and btrfs_search_slot must
+ * start over
+ */
+static int
+setup_nodes_for_search(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *root, struct btrfs_path *p,
+                      struct extent_buffer *b, int level, int ins_len)
+{
+       int ret;
+       if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >=
+           BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
+               int sret;
+
+               sret = reada_for_balance(root, p, level);
+               if (sret)
+                       goto again;
+
+               btrfs_set_path_blocking(p);
+               sret = split_node(trans, root, p, level);
+               btrfs_clear_path_blocking(p, NULL);
+
+               BUG_ON(sret > 0);
+               if (sret) {
+                       ret = sret;
+                       goto done;
+               }
+               b = p->nodes[level];
+       } else if (ins_len < 0 && btrfs_header_nritems(b) <
+                  BTRFS_NODEPTRS_PER_BLOCK(root) / 4) {
+               int sret;
+
+               sret = reada_for_balance(root, p, level);
+               if (sret)
+                       goto again;
+
+               btrfs_set_path_blocking(p);
+               sret = balance_level(trans, root, p, level);
+               btrfs_clear_path_blocking(p, NULL);
+
+               if (sret) {
+                       ret = sret;
+                       goto done;
+               }
+               b = p->nodes[level];
+               if (!b) {
+                       btrfs_release_path(NULL, p);
+                       goto again;
+               }
+               BUG_ON(btrfs_header_nritems(b) == 1);
+       }
+       return 0;
+
+again:
+       ret = -EAGAIN;
+done:
+       return ret;
+}
+
 /*
  * look for key in the tree.  path is filled in with nodes along the way
  * if key is found, we return zero and you can find the item in the leaf
@@ -1482,17 +1575,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      ins_len, int cow)
 {
        struct extent_buffer *b;
-       struct extent_buffer *tmp;
        int slot;
        int ret;
        int level;
-       int should_reada = p->reada;
        int lowest_unlock = 1;
-       int blocksize;
        u8 lowest_level = 0;
-       u64 blocknr;
-       u64 gen;
-       struct btrfs_key prealloc_block;
 
        lowest_level = p->lowest_level;
        WARN_ON(lowest_level && ins_len > 0);
@@ -1501,8 +1588,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        if (ins_len < 0)
                lowest_unlock = 2;
 
-       prealloc_block.objectid = 0;
-
 again:
        if (p->skip_locking)
                b = btrfs_root_node(root);
@@ -1523,50 +1608,21 @@ again:
                if (cow) {
                        int wret;
 
-                       /* is a cow on this block not required */
+                       /*
+                        * if we don't really need to cow this block
+                        * then we don't want to set the path blocking,
+                        * so we test it here
+                        */
                        if (btrfs_header_generation(b) == trans->transid &&
                            btrfs_header_owner(b) == root->root_key.objectid &&
                            !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) {
                                goto cow_done;
                        }
-
-                       /* ok, we have to cow, is our old prealloc the right
-                        * size?
-                        */
-                       if (prealloc_block.objectid &&
-                           prealloc_block.offset != b->len) {
-                               btrfs_release_path(root, p);
-                               btrfs_free_reserved_extent(root,
-                                          prealloc_block.objectid,
-                                          prealloc_block.offset);
-                               prealloc_block.objectid = 0;
-                               goto again;
-                       }
-
-                       /*
-                        * for higher level blocks, try not to allocate blocks
-                        * with the block and the parent locks held.
-                        */
-                       if (level > 0 && !prealloc_block.objectid) {
-                               u32 size = b->len;
-                               u64 hint = b->start;
-
-                               btrfs_release_path(root, p);
-                               ret = btrfs_reserve_extent(trans, root,
-                                                          size, size, 0,
-                                                          hint, (u64)-1,
-                                                          &prealloc_block, 0);
-                               BUG_ON(ret);
-                               goto again;
-                       }
-
                        btrfs_set_path_blocking(p);
 
                        wret = btrfs_cow_block(trans, root, b,
                                               p->nodes[level + 1],
-                                              p->slots[level + 1],
-                                              &b, prealloc_block.objectid);
-                       prealloc_block.objectid = 0;
+                                              p->slots[level + 1], &b);
                        if (wret) {
                                free_extent_buffer(b);
                                ret = wret;
@@ -1611,51 +1667,15 @@ cow_done:
                        if (ret && slot > 0)
                                slot -= 1;
                        p->slots[level] = slot;
-                       if ((p->search_for_split || ins_len > 0) &&
-                           btrfs_header_nritems(b) >=
-                           BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
-                               int sret;
-
-                               sret = reada_for_balance(root, p, level);
-                               if (sret)
-                                       goto again;
-
-                               btrfs_set_path_blocking(p);
-                               sret = split_node(trans, root, p, level);
-                               btrfs_clear_path_blocking(p, NULL);
-
-                               BUG_ON(sret > 0);
-                               if (sret) {
-                                       ret = sret;
-                                       goto done;
-                               }
-                               b = p->nodes[level];
-                               slot = p->slots[level];
-                       } else if (ins_len < 0 &&
-                                  btrfs_header_nritems(b) <
-                                  BTRFS_NODEPTRS_PER_BLOCK(root) / 4) {
-                               int sret;
-
-                               sret = reada_for_balance(root, p, level);
-                               if (sret)
-                                       goto again;
-
-                               btrfs_set_path_blocking(p);
-                               sret = balance_level(trans, root, p, level);
-                               btrfs_clear_path_blocking(p, NULL);
+                       ret = setup_nodes_for_search(trans, root, p, b, level,
+                                                    ins_len);
+                       if (ret == -EAGAIN)
+                               goto again;
+                       else if (ret)
+                               goto done;
+                       b = p->nodes[level];
+                       slot = p->slots[level];
 
-                               if (sret) {
-                                       ret = sret;
-                                       goto done;
-                               }
-                               b = p->nodes[level];
-                               if (!b) {
-                                       btrfs_release_path(NULL, p);
-                                       goto again;
-                               }
-                               slot = p->slots[level];
-                               BUG_ON(btrfs_header_nritems(b) == 1);
-                       }
                        unlock_up(p, level, lowest_unlock);
 
                        /* this is only true while dropping a snapshot */
@@ -1664,44 +1684,11 @@ cow_done:
                                goto done;
                        }
 
-                       blocknr = btrfs_node_blockptr(b, slot);
-                       gen = btrfs_node_ptr_generation(b, slot);
-                       blocksize = btrfs_level_size(root, level - 1);
+                       ret = read_block_for_search(trans, root, p,
+                                                   &b, level, slot, key);
+                       if (ret == -EAGAIN)
+                               goto again;
 
-                       tmp = btrfs_find_tree_block(root, blocknr, blocksize);
-                       if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
-                               b = tmp;
-                       } else {
-                               /*
-                                * reduce lock contention at high levels
-                                * of the btree by dropping locks before
-                                * we read.
-                                */
-                               if (level > 0) {
-                                       btrfs_release_path(NULL, p);
-                                       if (tmp)
-                                               free_extent_buffer(tmp);
-                                       if (should_reada)
-                                               reada_for_search(root, p,
-                                                                level, slot,
-                                                                key->objectid);
-
-                                       tmp = read_tree_block(root, blocknr,
-                                                        blocksize, gen);
-                                       if (tmp)
-                                               free_extent_buffer(tmp);
-                                       goto again;
-                               } else {
-                                       btrfs_set_path_blocking(p);
-                                       if (tmp)
-                                               free_extent_buffer(tmp);
-                                       if (should_reada)
-                                               reada_for_search(root, p,
-                                                                level, slot,
-                                                                key->objectid);
-                                       b = read_node_slot(root, b, slot);
-                               }
-                       }
                        if (!p->skip_locking) {
                                int lret;
 
@@ -1742,12 +1729,8 @@ done:
         * we don't really know what they plan on doing with the path
         * from here on, so for now just mark it as blocking
         */
-       btrfs_set_path_blocking(p);
-       if (prealloc_block.objectid) {
-               btrfs_free_reserved_extent(root,
-                          prealloc_block.objectid,
-                          prealloc_block.offset);
-       }
+       if (!p->leave_spinning)
+               btrfs_set_path_blocking(p);
        return ret;
 }
 
@@ -1768,7 +1751,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
        int ret;
 
        eb = btrfs_lock_root_node(root);
-       ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb, 0);
+       ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb);
        BUG_ON(ret);
 
        btrfs_set_lock_blocking(eb);
@@ -1826,7 +1809,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
                        }
 
                        ret = btrfs_cow_block(trans, root, eb, parent, slot,
-                                             &eb, 0);
+                                             &eb);
                        BUG_ON(ret);
 
                        if (root->root_key.objectid ==
@@ -2139,7 +2122,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
        spin_unlock(&root->node_lock);
 
        ret = btrfs_update_extent_ref(trans, root, lower->start,
-                                     lower->start, c->start,
+                                     lower->len, lower->start, c->start,
                                      root->root_key.objectid,
                                      trans->transid, level - 1);
        BUG_ON(ret);
@@ -2174,8 +2157,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
        BUG_ON(!path->nodes[level]);
        lower = path->nodes[level];
        nritems = btrfs_header_nritems(lower);
-       if (slot > nritems)
-               BUG();
+       BUG_ON(slot > nritems);
        if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root))
                BUG();
        if (slot != nritems) {
@@ -2221,7 +2203,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
                ret = insert_new_root(trans, root, path, level + 1);
                if (ret)
                        return ret;
-       } else {
+       } else if (!trans->transaction->delayed_refs.flushing) {
                ret = push_nodes_for_insert(trans, root, path, level);
                c = path->nodes[level];
                if (!ret && btrfs_header_nritems(c) <
@@ -2329,66 +2311,27 @@ noinline int btrfs_leaf_free_space(struct btrfs_root *root,
        return ret;
 }
 
-/*
- * push some data in the path leaf to the right, trying to free up at
- * least data_size bytes.  returns zero if the push worked, nonzero otherwise
- *
- * returns 1 if the push failed because the other node didn't have enough
- * room, 0 if everything worked out and < 0 if there were major errors.
- */
-static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
-                          *root, struct btrfs_path *path, int data_size,
-                          int empty)
+static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
+                                     struct btrfs_root *root,
+                                     struct btrfs_path *path,
+                                     int data_size, int empty,
+                                     struct extent_buffer *right,
+                                     int free_space, u32 left_nritems)
 {
        struct extent_buffer *left = path->nodes[0];
-       struct extent_buffer *right;
-       struct extent_buffer *upper;
+       struct extent_buffer *upper = path->nodes[1];
        struct btrfs_disk_key disk_key;
        int slot;
        u32 i;
-       int free_space;
        int push_space = 0;
        int push_items = 0;
        struct btrfs_item *item;
-       u32 left_nritems;
        u32 nr;
        u32 right_nritems;
        u32 data_end;
        u32 this_item_size;
        int ret;
 
-       slot = path->slots[1];
-       if (!path->nodes[1])
-               return 1;
-
-       upper = path->nodes[1];
-       if (slot >= btrfs_header_nritems(upper) - 1)
-               return 1;
-
-       btrfs_assert_tree_locked(path->nodes[1]);
-
-       right = read_node_slot(root, upper, slot + 1);
-       btrfs_tree_lock(right);
-       btrfs_set_lock_blocking(right);
-
-       free_space = btrfs_leaf_free_space(root, right);
-       if (free_space < data_size)
-               goto out_unlock;
-
-       /* cow and double check */
-       ret = btrfs_cow_block(trans, root, right, upper,
-                             slot + 1, &right, 0);
-       if (ret)
-               goto out_unlock;
-
-       free_space = btrfs_leaf_free_space(root, right);
-       if (free_space < data_size)
-               goto out_unlock;
-
-       left_nritems = btrfs_header_nritems(left);
-       if (left_nritems == 0)
-               goto out_unlock;
-
        if (empty)
                nr = 0;
        else
@@ -2397,6 +2340,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
        if (path->slots[0] >= left_nritems)
                push_space += data_size;
 
+       slot = path->slots[1];
        i = left_nritems - 1;
        while (i >= nr) {
                item = btrfs_item_nr(left, i);
@@ -2527,25 +2471,83 @@ out_unlock:
        return 1;
 }
 
+/*
+ * push some data in the path leaf to the right, trying to free up at
+ * least data_size bytes.  returns zero if the push worked, nonzero otherwise
+ *
+ * returns 1 if the push failed because the other node didn't have enough
+ * room, 0 if everything worked out and < 0 if there were major errors.
+ */
+static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
+                          *root, struct btrfs_path *path, int data_size,
+                          int empty)
+{
+       struct extent_buffer *left = path->nodes[0];
+       struct extent_buffer *right;
+       struct extent_buffer *upper;
+       int slot;
+       int free_space;
+       u32 left_nritems;
+       int ret;
+
+       if (!path->nodes[1])
+               return 1;
+
+       slot = path->slots[1];
+       upper = path->nodes[1];
+       if (slot >= btrfs_header_nritems(upper) - 1)
+               return 1;
+
+       btrfs_assert_tree_locked(path->nodes[1]);
+
+       right = read_node_slot(root, upper, slot + 1);
+       btrfs_tree_lock(right);
+       btrfs_set_lock_blocking(right);
+
+       free_space = btrfs_leaf_free_space(root, right);
+       if (free_space < data_size)
+               goto out_unlock;
+
+       /* cow and double check */
+       ret = btrfs_cow_block(trans, root, right, upper,
+                             slot + 1, &right);
+       if (ret)
+               goto out_unlock;
+
+       free_space = btrfs_leaf_free_space(root, right);
+       if (free_space < data_size)
+               goto out_unlock;
+
+       left_nritems = btrfs_header_nritems(left);
+       if (left_nritems == 0)
+               goto out_unlock;
+
+       return __push_leaf_right(trans, root, path, data_size, empty,
+                               right, free_space, left_nritems);
+out_unlock:
+       btrfs_tree_unlock(right);
+       free_extent_buffer(right);
+       return 1;
+}
+
 /*
  * push some data in the path leaf to the left, trying to free up at
  * least data_size bytes.  returns zero if the push worked, nonzero otherwise
  */
-static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
-                         *root, struct btrfs_path *path, int data_size,
-                         int empty)
+static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
+                                    struct btrfs_root *root,
+                                    struct btrfs_path *path, int data_size,
+                                    int empty, struct extent_buffer *left,
+                                    int free_space, int right_nritems)
 {
        struct btrfs_disk_key disk_key;
        struct extent_buffer *right = path->nodes[0];
-       struct extent_buffer *left;
        int slot;
        int i;
-       int free_space;
        int push_space = 0;
        int push_items = 0;
        struct btrfs_item *item;
        u32 old_left_nritems;
-       u32 right_nritems;
        u32 nr;
        int ret = 0;
        int wret;
@@ -2553,41 +2555,6 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        u32 old_left_item_size;
 
        slot = path->slots[1];
-       if (slot == 0)
-               return 1;
-       if (!path->nodes[1])
-               return 1;
-
-       right_nritems = btrfs_header_nritems(right);
-       if (right_nritems == 0)
-               return 1;
-
-       btrfs_assert_tree_locked(path->nodes[1]);
-
-       left = read_node_slot(root, path->nodes[1], slot - 1);
-       btrfs_tree_lock(left);
-       btrfs_set_lock_blocking(left);
-
-       free_space = btrfs_leaf_free_space(root, left);
-       if (free_space < data_size) {
-               ret = 1;
-               goto out;
-       }
-
-       /* cow and double check */
-       ret = btrfs_cow_block(trans, root, left,
-                             path->nodes[1], slot - 1, &left, 0);
-       if (ret) {
-               /* we hit -ENOSPC, but it isn't fatal here */
-               ret = 1;
-               goto out;
-       }
-
-       free_space = btrfs_leaf_free_space(root, left);
-       if (free_space < data_size) {
-               ret = 1;
-               goto out;
-       }
 
        if (empty)
                nr = right_nritems;
@@ -2755,10 +2722,158 @@ out:
 }
 
 /*
- * split the path's leaf in two, making sure there is at least data_size
- * available for the resulting leaf level of the path.
- *
- * returns 0 if all went well and < 0 on failure.
+ * push some data in the path leaf to the left, trying to free up at
+ * least data_size bytes.  returns zero if the push worked, nonzero otherwise
+ */
+static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
+                         *root, struct btrfs_path *path, int data_size,
+                         int empty)
+{
+       struct extent_buffer *right = path->nodes[0];
+       struct extent_buffer *left;
+       int slot;
+       int free_space;
+       u32 right_nritems;
+       int ret = 0;
+
+       slot = path->slots[1];
+       if (slot == 0)
+               return 1;
+       if (!path->nodes[1])
+               return 1;
+
+       right_nritems = btrfs_header_nritems(right);
+       if (right_nritems == 0)
+               return 1;
+
+       btrfs_assert_tree_locked(path->nodes[1]);
+
+       left = read_node_slot(root, path->nodes[1], slot - 1);
+       btrfs_tree_lock(left);
+       btrfs_set_lock_blocking(left);
+
+       free_space = btrfs_leaf_free_space(root, left);
+       if (free_space < data_size) {
+               ret = 1;
+               goto out;
+       }
+
+       /* cow and double check */
+       ret = btrfs_cow_block(trans, root, left,
+                             path->nodes[1], slot - 1, &left);
+       if (ret) {
+               /* we hit -ENOSPC, but it isn't fatal here */
+               ret = 1;
+               goto out;
+       }
+
+       free_space = btrfs_leaf_free_space(root, left);
+       if (free_space < data_size) {
+               ret = 1;
+               goto out;
+       }
+
+       return __push_leaf_left(trans, root, path, data_size,
+                              empty, left, free_space, right_nritems);
+out:
+       btrfs_tree_unlock(left);
+       free_extent_buffer(left);
+       return ret;
+}
+
+/*
+ * split the path's leaf in two, making sure there is at least data_size
+ * available for the resulting leaf level of the path.
+ *
+ * returns 0 if all went well and < 0 on failure.
+ */
+static noinline int copy_for_split(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              struct btrfs_path *path,
+                              struct extent_buffer *l,
+                              struct extent_buffer *right,
+                              int slot, int mid, int nritems)
+{
+       int data_copy_size;
+       int rt_data_off;
+       int i;
+       int ret = 0;
+       int wret;
+       struct btrfs_disk_key disk_key;
+
+       nritems = nritems - mid;
+       btrfs_set_header_nritems(right, nritems);
+       data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l);
+
+       copy_extent_buffer(right, l, btrfs_item_nr_offset(0),
+                          btrfs_item_nr_offset(mid),
+                          nritems * sizeof(struct btrfs_item));
+
+       copy_extent_buffer(right, l,
+                    btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
+                    data_copy_size, btrfs_leaf_data(l) +
+                    leaf_data_end(root, l), data_copy_size);
+
+       rt_data_off = BTRFS_LEAF_DATA_SIZE(root) -
+                     btrfs_item_end_nr(l, mid);
+
+       for (i = 0; i < nritems; i++) {
+               struct btrfs_item *item = btrfs_item_nr(right, i);
+               u32 ioff;
+
+               if (!right->map_token) {
+                       map_extent_buffer(right, (unsigned long)item,
+                                       sizeof(struct btrfs_item),
+                                       &right->map_token, &right->kaddr,
+                                       &right->map_start, &right->map_len,
+                                       KM_USER1);
+               }
+
+               ioff = btrfs_item_offset(right, item);
+               btrfs_set_item_offset(right, item, ioff + rt_data_off);
+       }
+
+       if (right->map_token) {
+               unmap_extent_buffer(right, right->map_token, KM_USER1);
+               right->map_token = NULL;
+       }
+
+       btrfs_set_header_nritems(l, mid);
+       ret = 0;
+       btrfs_item_key(right, &disk_key, 0);
+       wret = insert_ptr(trans, root, path, &disk_key, right->start,
+                         path->slots[1] + 1, 1);
+       if (wret)
+               ret = wret;
+
+       btrfs_mark_buffer_dirty(right);
+       btrfs_mark_buffer_dirty(l);
+       BUG_ON(path->slots[0] != slot);
+
+       ret = btrfs_update_ref(trans, root, l, right, 0, nritems);
+       BUG_ON(ret);
+
+       if (mid <= slot) {
+               btrfs_tree_unlock(path->nodes[0]);
+               free_extent_buffer(path->nodes[0]);
+               path->nodes[0] = right;
+               path->slots[0] -= mid;
+               path->slots[1] += 1;
+       } else {
+               btrfs_tree_unlock(right);
+               free_extent_buffer(right);
+       }
+
+       BUG_ON(path->slots[0] < 0);
+
+       return ret;
+}
+
+/*
+ * split the path's leaf in two, making sure there is at least data_size
+ * available for the resulting leaf level of the path.
+ *
+ * returns 0 if all went well and < 0 on failure.
  */
 static noinline int split_leaf(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
@@ -2771,17 +2886,14 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
        int mid;
        int slot;
        struct extent_buffer *right;
-       int data_copy_size;
-       int rt_data_off;
-       int i;
        int ret = 0;
        int wret;
        int double_split;
        int num_doubles = 0;
-       struct btrfs_disk_key disk_key;
 
        /* first try to make some room by pushing left and right */
-       if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
+       if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY &&
+           !trans->transaction->delayed_refs.flushing) {
                wret = push_leaf_right(trans, root, path, data_size, 0);
                if (wret < 0)
                        return wret;
@@ -2830,11 +2942,14 @@ again:
        write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
                            (unsigned long)btrfs_header_chunk_tree_uuid(right),
                            BTRFS_UUID_SIZE);
+
        if (mid <= slot) {
                if (nritems == 1 ||
                    leaf_space_used(l, mid, nritems - mid) + data_size >
                        BTRFS_LEAF_DATA_SIZE(root)) {
                        if (slot >= nritems) {
+                               struct btrfs_disk_key disk_key;
+
                                btrfs_cpu_key_to_disk(&disk_key, ins_key);
                                btrfs_set_header_nritems(right, 0);
                                wret = insert_ptr(trans, root, path,
@@ -2862,6 +2977,8 @@ again:
                if (leaf_space_used(l, 0, mid) + data_size >
                        BTRFS_LEAF_DATA_SIZE(root)) {
                        if (!extend && data_size && slot == 0) {
+                               struct btrfs_disk_key disk_key;
+
                                btrfs_cpu_key_to_disk(&disk_key, ins_key);
                                btrfs_set_header_nritems(right, 0);
                                wret = insert_ptr(trans, root, path,
@@ -2894,76 +3011,16 @@ again:
                        }
                }
        }
-       nritems = nritems - mid;
-       btrfs_set_header_nritems(right, nritems);
-       data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l);
-
-       copy_extent_buffer(right, l, btrfs_item_nr_offset(0),
-                          btrfs_item_nr_offset(mid),
-                          nritems * sizeof(struct btrfs_item));
-
-       copy_extent_buffer(right, l,
-                    btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
-                    data_copy_size, btrfs_leaf_data(l) +
-                    leaf_data_end(root, l), data_copy_size);
-
-       rt_data_off = BTRFS_LEAF_DATA_SIZE(root) -
-                     btrfs_item_end_nr(l, mid);
-
-       for (i = 0; i < nritems; i++) {
-               struct btrfs_item *item = btrfs_item_nr(right, i);
-               u32 ioff;
-
-               if (!right->map_token) {
-                       map_extent_buffer(right, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &right->map_token, &right->kaddr,
-                                       &right->map_start, &right->map_len,
-                                       KM_USER1);
-               }
-
-               ioff = btrfs_item_offset(right, item);
-               btrfs_set_item_offset(right, item, ioff + rt_data_off);
-       }
-
-       if (right->map_token) {
-               unmap_extent_buffer(right, right->map_token, KM_USER1);
-               right->map_token = NULL;
-       }
 
-       btrfs_set_header_nritems(l, mid);
-       ret = 0;
-       btrfs_item_key(right, &disk_key, 0);
-       wret = insert_ptr(trans, root, path, &disk_key, right->start,
-                         path->slots[1] + 1, 1);
-       if (wret)
-               ret = wret;
-
-       btrfs_mark_buffer_dirty(right);
-       btrfs_mark_buffer_dirty(l);
-       BUG_ON(path->slots[0] != slot);
-
-       ret = btrfs_update_ref(trans, root, l, right, 0, nritems);
+       ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems);
        BUG_ON(ret);
 
-       if (mid <= slot) {
-               btrfs_tree_unlock(path->nodes[0]);
-               free_extent_buffer(path->nodes[0]);
-               path->nodes[0] = right;
-               path->slots[0] -= mid;
-               path->slots[1] += 1;
-       } else {
-               btrfs_tree_unlock(right);
-               free_extent_buffer(right);
-       }
-
-       BUG_ON(path->slots[0] < 0);
-
        if (double_split) {
                BUG_ON(num_doubles != 0);
                num_doubles++;
                goto again;
        }
+
        return ret;
 }
 
@@ -3021,26 +3078,27 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
                return -EAGAIN;
        }
 
+       btrfs_set_path_blocking(path);
        ret = split_leaf(trans, root, &orig_key, path,
                         sizeof(struct btrfs_item), 1);
        path->keep_locks = 0;
        BUG_ON(ret);
 
+       btrfs_unlock_up_safe(path, 1);
+       leaf = path->nodes[0];
+       BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
+
+split:
        /*
         * make sure any changes to the path from split_leaf leave it
         * in a blocking state
         */
        btrfs_set_path_blocking(path);
 
-       leaf = path->nodes[0];
-       BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
-
-split:
        item = btrfs_item_nr(leaf, path->slots[0]);
        orig_offset = btrfs_item_offset(leaf, item);
        item_size = btrfs_item_size(leaf, item);
 
-
        buf = kmalloc(item_size, GFP_NOFS);
        read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
                            path->slots[0]), item_size);
@@ -3445,39 +3503,27 @@ out:
 }
 
 /*
- * Given a key and some data, insert items into the tree.
- * This does all the path init required, making room in the tree if needed.
+ * this is a helper for btrfs_insert_empty_items, the main goal here is
+ * to save stack depth by doing the bulk of the work in a function
+ * that doesn't call btrfs_search_slot
  */
-int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root,
-                           struct btrfs_path *path,
-                           struct btrfs_key *cpu_key, u32 *data_size,
-                           int nr)
+static noinline_for_stack int
+setup_items_for_insert(struct btrfs_trans_handle *trans,
+                     struct btrfs_root *root, struct btrfs_path *path,
+                     struct btrfs_key *cpu_key, u32 *data_size,
+                     u32 total_data, u32 total_size, int nr)
 {
-       struct extent_buffer *leaf;
        struct btrfs_item *item;
-       int ret = 0;
-       int slot;
-       int slot_orig;
        int i;
        u32 nritems;
-       u32 total_size = 0;
-       u32 total_data = 0;
        unsigned int data_end;
        struct btrfs_disk_key disk_key;
+       int ret;
+       struct extent_buffer *leaf;
+       int slot;
 
-       for (i = 0; i < nr; i++)
-               total_data += data_size[i];
-
-       total_size = total_data + (nr * sizeof(struct btrfs_item));
-       ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1);
-       if (ret == 0)
-               return -EEXIST;
-       if (ret < 0)
-               goto out;
-
-       slot_orig = path->slots[0];
        leaf = path->nodes[0];
+       slot = path->slots[0];
 
        nritems = btrfs_header_nritems(leaf);
        data_end = leaf_data_end(root, leaf);
@@ -3489,9 +3535,6 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
                BUG();
        }
 
-       slot = path->slots[0];
-       BUG_ON(slot < 0);
-
        if (slot != nritems) {
                unsigned int old_data = btrfs_item_end_nr(leaf, slot);
 
@@ -3547,21 +3590,60 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
                data_end -= data_size[i];
                btrfs_set_item_size(leaf, item, data_size[i]);
        }
+
        btrfs_set_header_nritems(leaf, nritems + nr);
-       btrfs_mark_buffer_dirty(leaf);
 
        ret = 0;
        if (slot == 0) {
+               struct btrfs_disk_key disk_key;
                btrfs_cpu_key_to_disk(&disk_key, cpu_key);
                ret = fixup_low_keys(trans, root, path, &disk_key, 1);
        }
+       btrfs_unlock_up_safe(path, 1);
+       btrfs_mark_buffer_dirty(leaf);
 
        if (btrfs_leaf_free_space(root, leaf) < 0) {
                btrfs_print_leaf(root, leaf);
                BUG();
        }
+       return ret;
+}
+
+/*
+ * Given a key and some data, insert items into the tree.
+ * This does all the path init required, making room in the tree if needed.
+ */
+int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root,
+                           struct btrfs_path *path,
+                           struct btrfs_key *cpu_key, u32 *data_size,
+                           int nr)
+{
+       struct extent_buffer *leaf;
+       int ret = 0;
+       int slot;
+       int i;
+       u32 total_size = 0;
+       u32 total_data = 0;
+
+       for (i = 0; i < nr; i++)
+               total_data += data_size[i];
+
+       total_size = total_data + (nr * sizeof(struct btrfs_item));
+       ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1);
+       if (ret == 0)
+               return -EEXIST;
+       if (ret < 0)
+               goto out;
+
+       leaf = path->nodes[0];
+       slot = path->slots[0];
+       BUG_ON(slot < 0);
+
+       ret = setup_items_for_insert(trans, root, path, cpu_key, data_size,
+                              total_data, total_size, nr);
+
 out:
-       btrfs_unlock_up_safe(path, 1);
        return ret;
 }
 
@@ -3749,7 +3831,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                }
 
                /* delete the leaf if it is mostly empty */
-               if (used < BTRFS_LEAF_DATA_SIZE(root) / 4) {
+               if (used < BTRFS_LEAF_DATA_SIZE(root) / 4 &&
+                   !trans->transaction->delayed_refs.flushing) {
                        /* push_leaf_left fixes the path.
                         * make sure the path still points to our leaf
                         * for possible call to del_ptr below
@@ -3757,6 +3840,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        slot = path->slots[1];
                        extent_buffer_get(leaf);
 
+                       btrfs_set_path_blocking(path);
                        wret = push_leaf_left(trans, root, path, 1, 1);
                        if (wret < 0 && wret != -ENOSPC)
                                ret = wret;
@@ -4042,28 +4126,44 @@ next:
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
 {
        int slot;
-       int level = 1;
+       int level;
        struct extent_buffer *c;
-       struct extent_buffer *next = NULL;
+       struct extent_buffer *next;
        struct btrfs_key key;
        u32 nritems;
        int ret;
+       int old_spinning = path->leave_spinning;
+       int force_blocking = 0;
 
        nritems = btrfs_header_nritems(path->nodes[0]);
        if (nritems == 0)
                return 1;
 
-       btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
+       /*
+        * we take the blocks in an order that upsets lockdep.  Using
+        * blocking mode is the only way around it.
+        */
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       force_blocking = 1;
+#endif
 
+       btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
+again:
+       level = 1;
+       next = NULL;
        btrfs_release_path(root, path);
+
        path->keep_locks = 1;
+
+       if (!force_blocking)
+               path->leave_spinning = 1;
+
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        path->keep_locks = 0;
 
        if (ret < 0)
                return ret;
 
-       btrfs_set_path_blocking(path);
        nritems = btrfs_header_nritems(path->nodes[0]);
        /*
         * by releasing the path above we dropped all our locks.  A balance
@@ -4073,19 +4173,24 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
         */
        if (nritems > 0 && path->slots[0] < nritems - 1) {
                path->slots[0]++;
+               ret = 0;
                goto done;
        }
 
        while (level < BTRFS_MAX_LEVEL) {
-               if (!path->nodes[level])
-                       return 1;
+               if (!path->nodes[level]) {
+                       ret = 1;
+                       goto done;
+               }
 
                slot = path->slots[level] + 1;
                c = path->nodes[level];
                if (slot >= btrfs_header_nritems(c)) {
                        level++;
-                       if (level == BTRFS_MAX_LEVEL)
-                               return 1;
+                       if (level == BTRFS_MAX_LEVEL) {
+                               ret = 1;
+                               goto done;
+                       }
                        continue;
                }
 
@@ -4094,16 +4199,22 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
                        free_extent_buffer(next);
                }
 
-               /* the path was set to blocking above */
-               if (level == 1 && (path->locks[1] || path->skip_locking) &&
-                   path->reada)
-                       reada_for_search(root, path, level, slot, 0);
+               next = c;
+               ret = read_block_for_search(NULL, root, path, &next, level,
+                                           slot, &key);
+               if (ret == -EAGAIN)
+                       goto again;
 
-               next = read_node_slot(root, c, slot);
                if (!path->skip_locking) {
-                       btrfs_assert_tree_locked(c);
-                       btrfs_tree_lock(next);
-                       btrfs_set_lock_blocking(next);
+                       ret = btrfs_try_spin_lock(next);
+                       if (!ret) {
+                               btrfs_set_path_blocking(path);
+                               btrfs_tree_lock(next);
+                               if (!force_blocking)
+                                       btrfs_clear_path_blocking(path, next);
+                       }
+                       if (force_blocking)
+                               btrfs_set_lock_blocking(next);
                }
                break;
        }
@@ -4113,27 +4224,42 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
                c = path->nodes[level];
                if (path->locks[level])
                        btrfs_tree_unlock(c);
+
                free_extent_buffer(c);
                path->nodes[level] = next;
                path->slots[level] = 0;
                if (!path->skip_locking)
                        path->locks[level] = 1;
+
                if (!level)
                        break;
 
-               btrfs_set_path_blocking(path);
-               if (level == 1 && path->locks[1] && path->reada)
-                       reada_for_search(root, path, level, slot, 0);
-               next = read_node_slot(root, next, 0);
+               ret = read_block_for_search(NULL, root, path, &next, level,
+                                           0, &key);
+               if (ret == -EAGAIN)
+                       goto again;
+
                if (!path->skip_locking) {
                        btrfs_assert_tree_locked(path->nodes[level]);
-                       btrfs_tree_lock(next);
-                       btrfs_set_lock_blocking(next);
+                       ret = btrfs_try_spin_lock(next);
+                       if (!ret) {
+                               btrfs_set_path_blocking(path);
+                               btrfs_tree_lock(next);
+                               if (!force_blocking)
+                                       btrfs_clear_path_blocking(path, next);
+                       }
+                       if (force_blocking)
+                               btrfs_set_lock_blocking(next);
                }
        }
+       ret = 0;
 done:
        unlock_up(path, 0, 1);
-       return 0;
+       path->leave_spinning = old_spinning;
+       if (!old_spinning)
+               btrfs_set_path_blocking(path);
+
+       return ret;
 }
 
 /*
index 5e1d4e30e9d863a6c66c36549136bb9abd088738..ad96495dedc52f79a05cdbccfea20383b871164f 100644 (file)
@@ -45,6 +45,13 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_MAX_LEVEL 8
 
+/*
+ * files bigger than this get some pre-flushing when they are added
+ * to the ordered operations list.  That way we limit the total
+ * work done by the commit
+ */
+#define BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT (8 * 1024 * 1024)
+
 /* holds pointers to all of the tree roots */
 #define BTRFS_ROOT_TREE_OBJECTID 1ULL
 
@@ -136,12 +143,15 @@ static int btrfs_csum_sizes[] = { 4, 0 };
 #define BTRFS_FT_MAX           9
 
 /*
- * the key defines the order in the tree, and so it also defines (optimal)
- * block layout.  objectid corresonds to the inode number.  The flags
- * tells us things about the object, and is a kind of stream selector.
- * so for a given inode, keys with flags of 1 might refer to the inode
- * data, flags of 2 may point to file data in the btree and flags == 3
- * may point to extents.
+ * The key defines the order in the tree, and so it also defines (optimal)
+ * block layout.
+ *
+ * objectid corresponds to the inode number.
+ *
+ * type tells us things about the object, and is a kind of stream selector.
+ * so for a given inode, keys with type of 1 might refer to the inode data,
+ * type of 2 may point to file data in the btree and type == 3 may point to
+ * extents.
  *
  * offset is the starting byte offset for this key in the stream.
  *
@@ -193,7 +203,7 @@ struct btrfs_dev_item {
 
        /*
         * starting byte of this partition on the device,
-        * to allowr for stripe alignment in the future
+        * to allow for stripe alignment in the future
         */
        __le64 start_offset;
 
@@ -401,15 +411,16 @@ struct btrfs_path {
        int locks[BTRFS_MAX_LEVEL];
        int reada;
        /* keep some upper locks as we walk down */
-       int keep_locks;
-       int skip_locking;
        int lowest_level;
 
        /*
         * set by btrfs_split_item, tells search_slot to keep all locks
         * and to force calls to keep space in the nodes
         */
-       int search_for_split;
+       unsigned int search_for_split:1;
+       unsigned int keep_locks:1;
+       unsigned int skip_locking:1;
+       unsigned int leave_spinning:1;
 };
 
 /*
@@ -625,18 +636,35 @@ struct btrfs_space_info {
        struct rw_semaphore groups_sem;
 };
 
-struct btrfs_free_space {
-       struct rb_node bytes_index;
-       struct rb_node offset_index;
-       u64 offset;
-       u64 bytes;
+/*
+ * free clusters are used to claim free space in relatively large chunks,
+ * allowing us to do less seeky writes.  They are used for all metadata
+ * allocations and data allocations in ssd mode.
+ */
+struct btrfs_free_cluster {
+       spinlock_t lock;
+       spinlock_t refill_lock;
+       struct rb_root root;
+
+       /* largest extent in this cluster */
+       u64 max_size;
+
+       /* first extent starting offset */
+       u64 window_start;
+
+       struct btrfs_block_group_cache *block_group;
+       /*
+        * when a cluster is allocated from a block group, we put the
+        * cluster onto a list in the block group so that it can
+        * be freed before the block group is freed.
+        */
+       struct list_head block_group_list;
 };
 
 struct btrfs_block_group_cache {
        struct btrfs_key key;
        struct btrfs_block_group_item item;
        spinlock_t lock;
-       struct mutex alloc_mutex;
        struct mutex cache_mutex;
        u64 pinned;
        u64 reserved;
@@ -648,6 +676,7 @@ struct btrfs_block_group_cache {
        struct btrfs_space_info *space_info;
 
        /* free space cache stuff */
+       spinlock_t tree_lock;
        struct rb_root free_space_bytes;
        struct rb_root free_space_offset;
 
@@ -659,6 +688,11 @@ struct btrfs_block_group_cache {
 
        /* usage count */
        atomic_t count;
+
+       /* List of struct btrfs_free_clusters for this block group.
+        * Today it will only have one thing on it, but that may change
+        */
+       struct list_head cluster_list;
 };
 
 struct btrfs_leaf_ref_tree {
@@ -688,15 +722,18 @@ struct btrfs_fs_info {
        struct rb_root block_group_cache_tree;
 
        struct extent_io_tree pinned_extents;
-       struct extent_io_tree pending_del;
-       struct extent_io_tree extent_ins;
 
        /* logical->physical extent mapping */
        struct btrfs_mapping_tree mapping_tree;
 
        u64 generation;
        u64 last_trans_committed;
-       u64 last_trans_new_blockgroup;
+
+       /*
+        * this is updated to the current trans every time a full commit
+        * is required instead of the faster short fsync log commits
+        */
+       u64 last_trans_log_full_commit;
        u64 open_ioctl_trans;
        unsigned long mount_opt;
        u64 max_extent;
@@ -717,12 +754,20 @@ struct btrfs_fs_info {
        struct mutex tree_log_mutex;
        struct mutex transaction_kthread_mutex;
        struct mutex cleaner_mutex;
-       struct mutex extent_ins_mutex;
-       struct mutex pinned_mutex;
        struct mutex chunk_mutex;
        struct mutex drop_mutex;
        struct mutex volume_mutex;
        struct mutex tree_reloc_mutex;
+
+       /*
+        * this protects the ordered operations list only while we are
+        * processing all of the entries on it.  This way we make
+        * sure the commit code doesn't find the list temporarily empty
+        * because another function happens to be doing non-waiting preflush
+        * before jumping into the main commit.
+        */
+       struct mutex ordered_operations_mutex;
+
        struct list_head trans_list;
        struct list_head hashers;
        struct list_head dead_roots;
@@ -737,9 +782,28 @@ struct btrfs_fs_info {
         * ordered extents
         */
        spinlock_t ordered_extent_lock;
+
+       /*
+        * all of the data=ordered extents pending writeback
+        * these can span multiple transactions and basically include
+        * every dirty data page that isn't from nodatacow
+        */
        struct list_head ordered_extents;
+
+       /*
+        * all of the inodes that have delalloc bytes.  It is possible for
+        * this list to be empty even when there is still dirty data=ordered
+        * extents waiting to finish IO.
+        */
        struct list_head delalloc_inodes;
 
+       /*
+        * special rename and truncate targets that must be on disk before
+        * we're allowed to commit.  This is basically the ext3 style
+        * data=ordered list.
+        */
+       struct list_head ordered_operations;
+
        /*
         * there is a pool of worker threads for checksumming during writes
         * and a pool for checksumming after reads.  This is because readers
@@ -781,6 +845,11 @@ struct btrfs_fs_info {
        atomic_t throttle_gen;
 
        u64 total_pinned;
+
+       /* protected by the delalloc lock, used to keep from writing
+        * metadata until there is a nice batch
+        */
+       u64 dirty_metadata_bytes;
        struct list_head dirty_cowonly_roots;
 
        struct btrfs_fs_devices *fs_devices;
@@ -795,8 +864,12 @@ struct btrfs_fs_info {
        spinlock_t delalloc_lock;
        spinlock_t new_trans_lock;
        u64 delalloc_bytes;
-       u64 last_alloc;
-       u64 last_data_alloc;
+
+       /* data_alloc_cluster is only used in ssd mode */
+       struct btrfs_free_cluster data_alloc_cluster;
+
+       /* all metadata allocations go through this cluster */
+       struct btrfs_free_cluster meta_alloc_cluster;
 
        spinlock_t ref_cache_lock;
        u64 total_ref_cache_size;
@@ -888,7 +961,6 @@ struct btrfs_root {
 };
 
 /*
-
  * inode items have the data typically returned from stat and store other
  * info about object characteristics.  There is one for every file and dir in
  * the FS
@@ -919,7 +991,7 @@ struct btrfs_root {
 #define BTRFS_EXTENT_CSUM_KEY  128
 
 /*
- * root items point to tree roots.  There are typically in the root
+ * root items point to tree roots.  They are typically in the root
  * tree used by the super block to find all the other trees
  */
 #define BTRFS_ROOT_ITEM_KEY    132
@@ -966,6 +1038,8 @@ struct btrfs_root {
 #define BTRFS_MOUNT_SSD                        (1 << 3)
 #define BTRFS_MOUNT_DEGRADED           (1 << 4)
 #define BTRFS_MOUNT_COMPRESS           (1 << 5)
+#define BTRFS_MOUNT_NOTREELOG           (1 << 6)
+#define BTRFS_MOUNT_FLUSHONCOMMIT       (1 << 7)
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
@@ -1704,18 +1778,16 @@ static inline struct dentry *fdentry(struct file *file)
 }
 
 /* extent-tree.c */
+void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
+int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, unsigned long count);
 int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
-int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, u64 bytenr,
-                           u64 num_bytes, u32 *refs);
 int btrfs_update_pinned_extents(struct btrfs_root *root,
                                u64 bytenr, u64 num, int pin);
 int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, struct extent_buffer *leaf);
 int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, u64 objectid, u64 bytenr);
-int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
-                        struct btrfs_root *root);
 int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
 struct btrfs_block_group_cache *btrfs_lookup_block_group(
                                                 struct btrfs_fs_info *info,
@@ -1777,7 +1849,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                         u64 root_objectid, u64 ref_generation,
                         u64 owner_objectid);
 int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, u64 bytenr,
+                           struct btrfs_root *root, u64 bytenr, u64 num_bytes,
                            u64 orig_parent, u64 parent,
                            u64 root_objectid, u64 ref_generation,
                            u64 owner_objectid);
@@ -1838,7 +1910,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 int btrfs_cow_block(struct btrfs_trans_handle *trans,
                    struct btrfs_root *root, struct extent_buffer *buf,
                    struct extent_buffer *parent, int parent_slot,
-                   struct extent_buffer **cow_ret, u64 prealloc_dest);
+                   struct extent_buffer **cow_ret);
 int btrfs_copy_root(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root,
                      struct extent_buffer *buf,
@@ -2060,7 +2132,7 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
 unsigned long btrfs_force_ra(struct address_space *mapping,
                              struct file_ra_state *ra, struct file *file,
                              pgoff_t offset, pgoff_t last_index);
-int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page);
+int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_delete_inode(struct inode *inode);
 void btrfs_put_inode(struct inode *inode);
@@ -2133,21 +2205,4 @@ int btrfs_check_acl(struct inode *inode, int mask);
 int btrfs_init_acl(struct inode *inode, struct inode *dir);
 int btrfs_acl_chmod(struct inode *inode);
 
-/* free-space-cache.c */
-int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
-                        u64 bytenr, u64 size);
-int btrfs_add_free_space_lock(struct btrfs_block_group_cache *block_group,
-                             u64 offset, u64 bytes);
-int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
-                           u64 bytenr, u64 size);
-int btrfs_remove_free_space_lock(struct btrfs_block_group_cache *block_group,
-                                u64 offset, u64 bytes);
-void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
-                                  *block_group);
-struct btrfs_free_space *btrfs_find_free_space(struct btrfs_block_group_cache
-                                              *block_group, u64 offset,
-                                              u64 bytes);
-void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
-                          u64 bytes);
-u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group);
 #endif
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
new file mode 100644 (file)
index 0000000..d6c01c0
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2009 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/sched.h>
+#include <linux/sort.h>
+#include "ctree.h"
+#include "delayed-ref.h"
+#include "transaction.h"
+
+/*
+ * delayed back reference update tracking.  For subvolume trees
+ * we queue up extent allocations and backref maintenance for
+ * delayed processing.   This avoids deep call chains where we
+ * add extents in the middle of btrfs_search_slot, and it allows
+ * us to buffer up frequently modified backrefs in an rb tree instead
+ * of hammering updates on the extent allocation tree.
+ *
+ * Right now this code is only used for reference counted trees, but
+ * the long term goal is to get rid of the similar code for delayed
+ * extent tree modifications.
+ */
+
+/*
+ * entries in the rb tree are ordered by the byte number of the extent
+ * and by the byte number of the parent block.
+ */
+static int comp_entry(struct btrfs_delayed_ref_node *ref,
+                     u64 bytenr, u64 parent)
+{
+       if (bytenr < ref->bytenr)
+               return -1;
+       if (bytenr > ref->bytenr)
+               return 1;
+       if (parent < ref->parent)
+               return -1;
+       if (parent > ref->parent)
+               return 1;
+       return 0;
+}
+
+/*
+ * insert a new ref into the rbtree.  This returns any existing refs
+ * for the same (bytenr,parent) tuple, or NULL if the new node was properly
+ * inserted.
+ */
+static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
+                                                 u64 bytenr, u64 parent,
+                                                 struct rb_node *node)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent_node = NULL;
+       struct btrfs_delayed_ref_node *entry;
+       int cmp;
+
+       while (*p) {
+               parent_node = *p;
+               entry = rb_entry(parent_node, struct btrfs_delayed_ref_node,
+                                rb_node);
+
+               cmp = comp_entry(entry, bytenr, parent);
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else if (cmp > 0)
+                       p = &(*p)->rb_right;
+               else
+                       return entry;
+       }
+
+       entry = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
+       rb_link_node(node, parent_node, p);
+       rb_insert_color(node, root);
+       return NULL;
+}
+
+/*
+ * find an entry based on (bytenr,parent).  This returns the delayed
+ * ref if it was able to find one, or NULL if nothing was in that spot
+ */
+static struct btrfs_delayed_ref_node *tree_search(struct rb_root *root,
+                                 u64 bytenr, u64 parent,
+                                 struct btrfs_delayed_ref_node **last)
+{
+       struct rb_node *n = root->rb_node;
+       struct btrfs_delayed_ref_node *entry;
+       int cmp;
+
+       while (n) {
+               entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
+               WARN_ON(!entry->in_tree);
+               if (last)
+                       *last = entry;
+
+               cmp = comp_entry(entry, bytenr, parent);
+               if (cmp < 0)
+                       n = n->rb_left;
+               else if (cmp > 0)
+                       n = n->rb_right;
+               else
+                       return entry;
+       }
+       return NULL;
+}
+
+int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
+                          struct btrfs_delayed_ref_head *head)
+{
+       struct btrfs_delayed_ref_root *delayed_refs;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       assert_spin_locked(&delayed_refs->lock);
+       if (mutex_trylock(&head->mutex))
+               return 0;
+
+       atomic_inc(&head->node.refs);
+       spin_unlock(&delayed_refs->lock);
+
+       mutex_lock(&head->mutex);
+       spin_lock(&delayed_refs->lock);
+       if (!head->node.in_tree) {
+               mutex_unlock(&head->mutex);
+               btrfs_put_delayed_ref(&head->node);
+               return -EAGAIN;
+       }
+       btrfs_put_delayed_ref(&head->node);
+       return 0;
+}
+
+int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
+                          struct list_head *cluster, u64 start)
+{
+       int count = 0;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct rb_node *node;
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_head *head;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       if (start == 0) {
+               node = rb_first(&delayed_refs->root);
+       } else {
+               ref = NULL;
+               tree_search(&delayed_refs->root, start, (u64)-1, &ref);
+               if (ref) {
+                       struct btrfs_delayed_ref_node *tmp;
+
+                       node = rb_prev(&ref->rb_node);
+                       while (node) {
+                               tmp = rb_entry(node,
+                                              struct btrfs_delayed_ref_node,
+                                              rb_node);
+                               if (tmp->bytenr < start)
+                                       break;
+                               ref = tmp;
+                               node = rb_prev(&ref->rb_node);
+                       }
+                       node = &ref->rb_node;
+               } else
+                       node = rb_first(&delayed_refs->root);
+       }
+again:
+       while (node && count < 32) {
+               ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
+               if (btrfs_delayed_ref_is_head(ref)) {
+                       head = btrfs_delayed_node_to_head(ref);
+                       if (list_empty(&head->cluster)) {
+                               list_add_tail(&head->cluster, cluster);
+                               delayed_refs->run_delayed_start =
+                                       head->node.bytenr;
+                               count++;
+
+                               WARN_ON(delayed_refs->num_heads_ready == 0);
+                               delayed_refs->num_heads_ready--;
+                       } else if (count) {
+                               /* the goal of the clustering is to find extents
+                                * that are likely to end up in the same extent
+                                * leaf on disk.  So, we don't want them spread
+                                * all over the tree.  Stop now if we've hit
+                                * a head that was already in use
+                                */
+                               break;
+                       }
+               }
+               node = rb_next(node);
+       }
+       if (count) {
+               return 0;
+       } else if (start) {
+               /*
+                * we've gone to the end of the rbtree without finding any
+                * clusters.  start from the beginning and try again
+                */
+               start = 0;
+               node = rb_first(&delayed_refs->root);
+               goto again;
+       }
+       return 1;
+}
+
+/*
+ * This checks to see if there are any delayed refs in the
+ * btree for a given bytenr.  It returns one if it finds any
+ * and zero otherwise.
+ *
+ * If it only finds a head node, it returns 0.
+ *
+ * The idea is to use this when deciding if you can safely delete an
+ * extent from the extent allocation tree.  There may be a pending
+ * ref in the rbtree that adds or removes references, so as long as this
+ * returns one you need to leave the BTRFS_EXTENT_ITEM in the extent
+ * allocation tree.
+ */
+int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr)
+{
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct rb_node *prev_node;
+       int ret = 0;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+
+       ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+       if (ref) {
+               prev_node = rb_prev(&ref->rb_node);
+               if (!prev_node)
+                       goto out;
+               ref = rb_entry(prev_node, struct btrfs_delayed_ref_node,
+                              rb_node);
+               if (ref->bytenr == bytenr)
+                       ret = 1;
+       }
+out:
+       spin_unlock(&delayed_refs->lock);
+       return ret;
+}
+
+/*
+ * helper function to lookup reference count
+ *
+ * the head node for delayed ref is used to store the sum of all the
+ * reference count modifications queued up in the rbtree.  This way you
+ * can check to see what the reference count would be if all of the
+ * delayed refs are processed.
+ */
+int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 bytenr,
+                           u64 num_bytes, u32 *refs)
+{
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_head *head;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_path *path;
+       struct extent_buffer *leaf;
+       struct btrfs_extent_item *ei;
+       struct btrfs_key key;
+       u32 num_refs;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = bytenr;
+       key.type = BTRFS_EXTENT_ITEM_KEY;
+       key.offset = num_bytes;
+       delayed_refs = &trans->transaction->delayed_refs;
+again:
+       ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+                               &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
+
+       if (ret == 0) {
+               leaf = path->nodes[0];
+               ei = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_extent_item);
+               num_refs = btrfs_extent_refs(leaf, ei);
+       } else {
+               num_refs = 0;
+               ret = 0;
+       }
+
+       spin_lock(&delayed_refs->lock);
+       ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+       if (ref) {
+               head = btrfs_delayed_node_to_head(ref);
+               if (mutex_trylock(&head->mutex)) {
+                       num_refs += ref->ref_mod;
+                       mutex_unlock(&head->mutex);
+                       *refs = num_refs;
+                       goto out;
+               }
+
+               atomic_inc(&ref->refs);
+               spin_unlock(&delayed_refs->lock);
+
+               btrfs_release_path(root->fs_info->extent_root, path);
+
+               mutex_lock(&head->mutex);
+               mutex_unlock(&head->mutex);
+               btrfs_put_delayed_ref(ref);
+               goto again;
+       } else {
+               *refs = num_refs;
+       }
+out:
+       spin_unlock(&delayed_refs->lock);
+       btrfs_free_path(path);
+       return ret;
+}
+
+/*
+ * helper function to update an extent delayed ref in the
+ * rbtree.  existing and update must both have the same
+ * bytenr and parent
+ *
+ * This may free existing if the update cancels out whatever
+ * operation it was doing.
+ */
+static noinline void
+update_existing_ref(struct btrfs_trans_handle *trans,
+                   struct btrfs_delayed_ref_root *delayed_refs,
+                   struct btrfs_delayed_ref_node *existing,
+                   struct btrfs_delayed_ref_node *update)
+{
+       struct btrfs_delayed_ref *existing_ref;
+       struct btrfs_delayed_ref *ref;
+
+       existing_ref = btrfs_delayed_node_to_ref(existing);
+       ref = btrfs_delayed_node_to_ref(update);
+
+       if (ref->pin)
+               existing_ref->pin = 1;
+
+       if (ref->action != existing_ref->action) {
+               /*
+                * this is effectively undoing either an add or a
+                * drop.  We decrement the ref_mod, and if it goes
+                * down to zero we just delete the entry without
+                * every changing the extent allocation tree.
+                */
+               existing->ref_mod--;
+               if (existing->ref_mod == 0) {
+                       rb_erase(&existing->rb_node,
+                                &delayed_refs->root);
+                       existing->in_tree = 0;
+                       btrfs_put_delayed_ref(existing);
+                       delayed_refs->num_entries--;
+                       if (trans->delayed_ref_updates)
+                               trans->delayed_ref_updates--;
+               }
+       } else {
+               if (existing_ref->action == BTRFS_ADD_DELAYED_REF) {
+                       /* if we're adding refs, make sure all the
+                        * details match up.  The extent could
+                        * have been totally freed and reallocated
+                        * by a different owner before the delayed
+                        * ref entries were removed.
+                        */
+                       existing_ref->owner_objectid = ref->owner_objectid;
+                       existing_ref->generation = ref->generation;
+                       existing_ref->root = ref->root;
+                       existing->num_bytes = update->num_bytes;
+               }
+               /*
+                * the action on the existing ref matches
+                * the action on the ref we're trying to add.
+                * Bump the ref_mod by one so the backref that
+                * is eventually added/removed has the correct
+                * reference count
+                */
+               existing->ref_mod += update->ref_mod;
+       }
+}
+
+/*
+ * helper function to update the accounting in the head ref
+ * existing and update must have the same bytenr
+ */
+static noinline void
+update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
+                        struct btrfs_delayed_ref_node *update)
+{
+       struct btrfs_delayed_ref_head *existing_ref;
+       struct btrfs_delayed_ref_head *ref;
+
+       existing_ref = btrfs_delayed_node_to_head(existing);
+       ref = btrfs_delayed_node_to_head(update);
+
+       if (ref->must_insert_reserved) {
+               /* if the extent was freed and then
+                * reallocated before the delayed ref
+                * entries were processed, we can end up
+                * with an existing head ref without
+                * the must_insert_reserved flag set.
+                * Set it again here
+                */
+               existing_ref->must_insert_reserved = ref->must_insert_reserved;
+
+               /*
+                * update the num_bytes so we make sure the accounting
+                * is done correctly
+                */
+               existing->num_bytes = update->num_bytes;
+
+       }
+
+       /*
+        * update the reference mod on the head to reflect this new operation
+        */
+       existing->ref_mod += update->ref_mod;
+}
+
+/*
+ * helper function to actually insert a delayed ref into the rbtree.
+ * this does all the dirty work in terms of maintaining the correct
+ * overall modification count in the head node and properly dealing
+ * with updating existing nodes as new modifications are queued.
+ */
+static noinline int __btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
+                         struct btrfs_delayed_ref_node *ref,
+                         u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid, int action,
+                         int pin)
+{
+       struct btrfs_delayed_ref_node *existing;
+       struct btrfs_delayed_ref *full_ref;
+       struct btrfs_delayed_ref_head *head_ref = NULL;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       int count_mod = 1;
+       int must_insert_reserved = 0;
+
+       /*
+        * the head node stores the sum of all the mods, so dropping a ref
+        * should drop the sum in the head node by one.
+        */
+       if (parent == (u64)-1) {
+               if (action == BTRFS_DROP_DELAYED_REF)
+                       count_mod = -1;
+               else if (action == BTRFS_UPDATE_DELAYED_HEAD)
+                       count_mod = 0;
+       }
+
+       /*
+        * BTRFS_ADD_DELAYED_EXTENT means that we need to update
+        * the reserved accounting when the extent is finally added, or
+        * if a later modification deletes the delayed ref without ever
+        * inserting the extent into the extent allocation tree.
+        * ref->must_insert_reserved is the flag used to record
+        * that accounting mods are required.
+        *
+        * Once we record must_insert_reserved, switch the action to
+        * BTRFS_ADD_DELAYED_REF because other special casing is not required.
+        */
+       if (action == BTRFS_ADD_DELAYED_EXTENT) {
+               must_insert_reserved = 1;
+               action = BTRFS_ADD_DELAYED_REF;
+       } else {
+               must_insert_reserved = 0;
+       }
+
+
+       delayed_refs = &trans->transaction->delayed_refs;
+
+       /* first set the basic ref node struct up */
+       atomic_set(&ref->refs, 1);
+       ref->bytenr = bytenr;
+       ref->parent = parent;
+       ref->ref_mod = count_mod;
+       ref->in_tree = 1;
+       ref->num_bytes = num_bytes;
+
+       if (btrfs_delayed_ref_is_head(ref)) {
+               head_ref = btrfs_delayed_node_to_head(ref);
+               head_ref->must_insert_reserved = must_insert_reserved;
+               INIT_LIST_HEAD(&head_ref->cluster);
+               mutex_init(&head_ref->mutex);
+       } else {
+               full_ref = btrfs_delayed_node_to_ref(ref);
+               full_ref->root = ref_root;
+               full_ref->generation = ref_generation;
+               full_ref->owner_objectid = owner_objectid;
+               full_ref->pin = pin;
+               full_ref->action = action;
+       }
+
+       existing = tree_insert(&delayed_refs->root, bytenr,
+                              parent, &ref->rb_node);
+
+       if (existing) {
+               if (btrfs_delayed_ref_is_head(ref))
+                       update_existing_head_ref(existing, ref);
+               else
+                       update_existing_ref(trans, delayed_refs, existing, ref);
+
+               /*
+                * we've updated the existing ref, free the newly
+                * allocated ref
+                */
+               kfree(ref);
+       } else {
+               if (btrfs_delayed_ref_is_head(ref)) {
+                       delayed_refs->num_heads++;
+                       delayed_refs->num_heads_ready++;
+               }
+               delayed_refs->num_entries++;
+               trans->delayed_ref_updates++;
+       }
+       return 0;
+}
+
+/*
+ * add a delayed ref to the tree.  This does all of the accounting required
+ * to make sure the delayed ref is eventually processed before this
+ * transaction commits.
+ */
+int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid, int action,
+                         int pin)
+{
+       struct btrfs_delayed_ref *ref;
+       struct btrfs_delayed_ref_head *head_ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       int ret;
+
+       ref = kmalloc(sizeof(*ref), GFP_NOFS);
+       if (!ref)
+               return -ENOMEM;
+
+       /*
+        * the parent = 0 case comes from cases where we don't actually
+        * know the parent yet.  It will get updated later via a add/drop
+        * pair.
+        */
+       if (parent == 0)
+               parent = bytenr;
+
+       head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
+       if (!head_ref) {
+               kfree(ref);
+               return -ENOMEM;
+       }
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+
+       /*
+        * insert both the head node and the new ref without dropping
+        * the spin lock
+        */
+       ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes,
+                                     (u64)-1, 0, 0, 0, action, pin);
+       BUG_ON(ret);
+
+       ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes,
+                                     parent, ref_root, ref_generation,
+                                     owner_objectid, action, pin);
+       BUG_ON(ret);
+       spin_unlock(&delayed_refs->lock);
+       return 0;
+}
+
+/*
+ * this does a simple search for the head node for a given extent.
+ * It must be called with the delayed ref spinlock held, and it returns
+ * the head node if any where found, or NULL if not.
+ */
+struct btrfs_delayed_ref_head *
+btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
+{
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+       if (ref)
+               return btrfs_delayed_node_to_head(ref);
+       return NULL;
+}
+
+/*
+ * add a delayed ref to the tree.  This does all of the accounting required
+ * to make sure the delayed ref is eventually processed before this
+ * transaction commits.
+ *
+ * The main point of this call is to add and remove a backreference in a single
+ * shot, taking the lock only once, and only searching for the head node once.
+ *
+ * It is the same as doing a ref add and delete in two separate calls.
+ */
+int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 orig_parent,
+                         u64 parent, u64 orig_ref_root, u64 ref_root,
+                         u64 orig_ref_generation, u64 ref_generation,
+                         u64 owner_objectid, int pin)
+{
+       struct btrfs_delayed_ref *ref;
+       struct btrfs_delayed_ref *old_ref;
+       struct btrfs_delayed_ref_head *head_ref;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       int ret;
+
+       ref = kmalloc(sizeof(*ref), GFP_NOFS);
+       if (!ref)
+               return -ENOMEM;
+
+       old_ref = kmalloc(sizeof(*old_ref), GFP_NOFS);
+       if (!old_ref) {
+               kfree(ref);
+               return -ENOMEM;
+       }
+
+       /*
+        * the parent = 0 case comes from cases where we don't actually
+        * know the parent yet.  It will get updated later via a add/drop
+        * pair.
+        */
+       if (parent == 0)
+               parent = bytenr;
+       if (orig_parent == 0)
+               orig_parent = bytenr;
+
+       head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
+       if (!head_ref) {
+               kfree(ref);
+               kfree(old_ref);
+               return -ENOMEM;
+       }
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+
+       /*
+        * insert both the head node and the new ref without dropping
+        * the spin lock
+        */
+       ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes,
+                                     (u64)-1, 0, 0, 0,
+                                     BTRFS_UPDATE_DELAYED_HEAD, 0);
+       BUG_ON(ret);
+
+       ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes,
+                                     parent, ref_root, ref_generation,
+                                     owner_objectid, BTRFS_ADD_DELAYED_REF, 0);
+       BUG_ON(ret);
+
+       ret = __btrfs_add_delayed_ref(trans, &old_ref->node, bytenr, num_bytes,
+                                     orig_parent, orig_ref_root,
+                                     orig_ref_generation, owner_objectid,
+                                     BTRFS_DROP_DELAYED_REF, pin);
+       BUG_ON(ret);
+       spin_unlock(&delayed_refs->lock);
+       return 0;
+}
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
new file mode 100644 (file)
index 0000000..3bec2ff
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+#ifndef __DELAYED_REF__
+#define __DELAYED_REF__
+
+/* these are the possible values of struct btrfs_delayed_ref->action */
+#define BTRFS_ADD_DELAYED_REF    1 /* add one backref to the tree */
+#define BTRFS_DROP_DELAYED_REF   2 /* delete one backref from the tree */
+#define BTRFS_ADD_DELAYED_EXTENT 3 /* record a full extent allocation */
+#define BTRFS_UPDATE_DELAYED_HEAD 4 /* not changing ref count on head ref */
+
+struct btrfs_delayed_ref_node {
+       struct rb_node rb_node;
+
+       /* the starting bytenr of the extent */
+       u64 bytenr;
+
+       /* the parent our backref will point to */
+       u64 parent;
+
+       /* the size of the extent */
+       u64 num_bytes;
+
+       /* ref count on this data structure */
+       atomic_t refs;
+
+       /*
+        * how many refs is this entry adding or deleting.  For
+        * head refs, this may be a negative number because it is keeping
+        * track of the total mods done to the reference count.
+        * For individual refs, this will always be a positive number
+        *
+        * It may be more than one, since it is possible for a single
+        * parent to have more than one ref on an extent
+        */
+       int ref_mod;
+
+       /* is this node still in the rbtree? */
+       unsigned int in_tree:1;
+};
+
+/*
+ * the head refs are used to hold a lock on a given extent, which allows us
+ * to make sure that only one process is running the delayed refs
+ * at a time for a single extent.  They also store the sum of all the
+ * reference count modifications we've queued up.
+ */
+struct btrfs_delayed_ref_head {
+       struct btrfs_delayed_ref_node node;
+
+       /*
+        * the mutex is held while running the refs, and it is also
+        * held when checking the sum of reference modifications.
+        */
+       struct mutex mutex;
+
+       struct list_head cluster;
+
+       /*
+        * when a new extent is allocated, it is just reserved in memory
+        * The actual extent isn't inserted into the extent allocation tree
+        * until the delayed ref is processed.  must_insert_reserved is
+        * used to flag a delayed ref so the accounting can be updated
+        * when a full insert is done.
+        *
+        * It is possible the extent will be freed before it is ever
+        * inserted into the extent allocation tree.  In this case
+        * we need to update the in ram accounting to properly reflect
+        * the free has happened.
+        */
+       unsigned int must_insert_reserved:1;
+};
+
+struct btrfs_delayed_ref {
+       struct btrfs_delayed_ref_node node;
+
+       /* the root objectid our ref will point to */
+       u64 root;
+
+       /* the generation for the backref */
+       u64 generation;
+
+       /* owner_objectid of the backref  */
+       u64 owner_objectid;
+
+       /* operation done by this entry in the rbtree */
+       u8 action;
+
+       /* if pin == 1, when the extent is freed it will be pinned until
+        * transaction commit
+        */
+       unsigned int pin:1;
+};
+
+struct btrfs_delayed_ref_root {
+       struct rb_root root;
+
+       /* this spin lock protects the rbtree and the entries inside */
+       spinlock_t lock;
+
+       /* how many delayed ref updates we've queued, used by the
+        * throttling code
+        */
+       unsigned long num_entries;
+
+       /* total number of head nodes in tree */
+       unsigned long num_heads;
+
+       /* total number of head nodes ready for processing */
+       unsigned long num_heads_ready;
+
+       /*
+        * set when the tree is flushing before a transaction commit,
+        * used by the throttling code to decide if new updates need
+        * to be run right away
+        */
+       int flushing;
+
+       u64 run_delayed_start;
+};
+
+static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
+{
+       WARN_ON(atomic_read(&ref->refs) == 0);
+       if (atomic_dec_and_test(&ref->refs)) {
+               WARN_ON(ref->in_tree);
+               kfree(ref);
+       }
+}
+
+int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid, int action,
+                         int pin);
+
+struct btrfs_delayed_ref_head *
+btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
+int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr);
+int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 bytenr,
+                           u64 num_bytes, u32 *refs);
+int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
+                         u64 bytenr, u64 num_bytes, u64 orig_parent,
+                         u64 parent, u64 orig_ref_root, u64 ref_root,
+                         u64 orig_ref_generation, u64 ref_generation,
+                         u64 owner_objectid, int pin);
+int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
+                          struct btrfs_delayed_ref_head *head);
+int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
+                          struct list_head *cluster, u64 search_start);
+/*
+ * a node might live in a head or a regular ref, this lets you
+ * test for the proper type to use.
+ */
+static int btrfs_delayed_ref_is_head(struct btrfs_delayed_ref_node *node)
+{
+       return node->parent == (u64)-1;
+}
+
+/*
+ * helper functions to cast a node into its container
+ */
+static inline struct btrfs_delayed_ref *
+btrfs_delayed_node_to_ref(struct btrfs_delayed_ref_node *node)
+{
+       WARN_ON(btrfs_delayed_ref_is_head(node));
+       return container_of(node, struct btrfs_delayed_ref, node);
+
+}
+
+static inline struct btrfs_delayed_ref_head *
+btrfs_delayed_node_to_head(struct btrfs_delayed_ref_node *node)
+{
+       WARN_ON(!btrfs_delayed_ref_is_head(node));
+       return container_of(node, struct btrfs_delayed_ref_head, node);
+
+}
+#endif
index 926a0b287a7d752994fc5a11894f21e91d5561f8..1d70236ba00c7bf4abf5181d2efd3b20d5867e2e 100644 (file)
@@ -145,7 +145,10 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        key.objectid = dir;
        btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
        key.offset = btrfs_name_hash(name, name_len);
+
        path = btrfs_alloc_path();
+       path->leave_spinning = 1;
+
        data_size = sizeof(*dir_item) + name_len;
        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
                                        name, name_len);
index 6ec80c0fc8697a0a9171e72a8dd4e63905c7993e..92caa8035f36f9beecc3c21551722a0eefdd911e 100644 (file)
@@ -38,6 +38,7 @@
 #include "locking.h"
 #include "ref-cache.h"
 #include "tree-log.h"
+#include "free-space-cache.h"
 
 static struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
@@ -668,14 +669,31 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 static int btree_writepage(struct page *page, struct writeback_control *wbc)
 {
        struct extent_io_tree *tree;
+       struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
+       struct extent_buffer *eb;
+       int was_dirty;
+
        tree = &BTRFS_I(page->mapping->host)->io_tree;
+       if (!(current->flags & PF_MEMALLOC)) {
+               return extent_write_full_page(tree, page,
+                                             btree_get_extent, wbc);
+       }
 
-       if (current->flags & PF_MEMALLOC) {
-               redirty_page_for_writepage(wbc, page);
-               unlock_page(page);
-               return 0;
+       redirty_page_for_writepage(wbc, page);
+       eb = btrfs_find_tree_block(root, page_offset(page),
+                                     PAGE_CACHE_SIZE);
+       WARN_ON(!eb);
+
+       was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
+       if (!was_dirty) {
+               spin_lock(&root->fs_info->delalloc_lock);
+               root->fs_info->dirty_metadata_bytes += PAGE_CACHE_SIZE;
+               spin_unlock(&root->fs_info->delalloc_lock);
        }
-       return extent_write_full_page(tree, page, btree_get_extent, wbc);
+       free_extent_buffer(eb);
+
+       unlock_page(page);
+       return 0;
 }
 
 static int btree_writepages(struct address_space *mapping,
@@ -684,15 +702,15 @@ static int btree_writepages(struct address_space *mapping,
        struct extent_io_tree *tree;
        tree = &BTRFS_I(mapping->host)->io_tree;
        if (wbc->sync_mode == WB_SYNC_NONE) {
+               struct btrfs_root *root = BTRFS_I(mapping->host)->root;
                u64 num_dirty;
-               u64 start = 0;
                unsigned long thresh = 32 * 1024 * 1024;
 
                if (wbc->for_kupdate)
                        return 0;
 
-               num_dirty = count_range_bits(tree, &start, (u64)-1,
-                                            thresh, EXTENT_DIRTY);
+               /* this is a bit racy, but that's ok */
+               num_dirty = root->fs_info->dirty_metadata_bytes;
                if (num_dirty < thresh)
                        return 0;
        }
@@ -859,9 +877,17 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
            root->fs_info->running_transaction->transid) {
                btrfs_assert_tree_locked(buf);
 
-               /* ugh, clear_extent_buffer_dirty can be expensive */
-               btrfs_set_lock_blocking(buf);
+               if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)) {
+                       spin_lock(&root->fs_info->delalloc_lock);
+                       if (root->fs_info->dirty_metadata_bytes >= buf->len)
+                               root->fs_info->dirty_metadata_bytes -= buf->len;
+                       else
+                               WARN_ON(1);
+                       spin_unlock(&root->fs_info->delalloc_lock);
+               }
 
+               /* ugh, clear_extent_buffer_dirty needs to lock the page */
+               btrfs_set_lock_blocking(buf);
                clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
                                          buf);
        }
@@ -1387,8 +1413,6 @@ static int bio_ready_for_csum(struct bio *bio)
 
        ret = extent_range_uptodate(io_tree, start + length,
                                    start + buf_len - 1);
-       if (ret == 1)
-               return ret;
        return ret;
 }
 
@@ -1471,12 +1495,6 @@ static int transaction_kthread(void *arg)
                vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
                mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
-               if (root->fs_info->total_ref_cache_size > 20 * 1024 * 1024) {
-                       printk(KERN_INFO "btrfs: total reference cache "
-                              "size %llu\n",
-                              root->fs_info->total_ref_cache_size);
-               }
-
                mutex_lock(&root->fs_info->trans_mutex);
                cur = root->fs_info->running_transaction;
                if (!cur) {
@@ -1493,6 +1511,7 @@ static int transaction_kthread(void *arg)
                mutex_unlock(&root->fs_info->trans_mutex);
                trans = btrfs_start_transaction(root, 1);
                ret = btrfs_commit_transaction(trans, root);
+
 sleep:
                wake_up_process(root->fs_info->cleaner_kthread);
                mutex_unlock(&root->fs_info->transaction_kthread_mutex);
@@ -1552,6 +1571,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        INIT_LIST_HEAD(&fs_info->dead_roots);
        INIT_LIST_HEAD(&fs_info->hashers);
        INIT_LIST_HEAD(&fs_info->delalloc_inodes);
+       INIT_LIST_HEAD(&fs_info->ordered_operations);
        spin_lock_init(&fs_info->delalloc_lock);
        spin_lock_init(&fs_info->new_trans_lock);
        spin_lock_init(&fs_info->ref_cache_lock);
@@ -1611,10 +1631,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        extent_io_tree_init(&fs_info->pinned_extents,
                             fs_info->btree_inode->i_mapping, GFP_NOFS);
-       extent_io_tree_init(&fs_info->pending_del,
-                            fs_info->btree_inode->i_mapping, GFP_NOFS);
-       extent_io_tree_init(&fs_info->extent_ins,
-                            fs_info->btree_inode->i_mapping, GFP_NOFS);
        fs_info->do_barriers = 1;
 
        INIT_LIST_HEAD(&fs_info->dead_reloc_roots);
@@ -1627,15 +1643,18 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        insert_inode_hash(fs_info->btree_inode);
 
        mutex_init(&fs_info->trans_mutex);
+       mutex_init(&fs_info->ordered_operations_mutex);
        mutex_init(&fs_info->tree_log_mutex);
        mutex_init(&fs_info->drop_mutex);
-       mutex_init(&fs_info->extent_ins_mutex);
-       mutex_init(&fs_info->pinned_mutex);
        mutex_init(&fs_info->chunk_mutex);
        mutex_init(&fs_info->transaction_kthread_mutex);
        mutex_init(&fs_info->cleaner_mutex);
        mutex_init(&fs_info->volume_mutex);
        mutex_init(&fs_info->tree_reloc_mutex);
+
+       btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
+       btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
+
        init_waitqueue_head(&fs_info->transaction_throttle);
        init_waitqueue_head(&fs_info->transaction_wait);
        init_waitqueue_head(&fs_info->async_submit_wait);
@@ -2358,8 +2377,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
        struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
        u64 transid = btrfs_header_generation(buf);
        struct inode *btree_inode = root->fs_info->btree_inode;
-
-       btrfs_set_lock_blocking(buf);
+       int was_dirty;
 
        btrfs_assert_tree_locked(buf);
        if (transid != root->fs_info->generation) {
@@ -2370,7 +2388,13 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
                        (unsigned long long)root->fs_info->generation);
                WARN_ON(1);
        }
-       set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, buf);
+       was_dirty = set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
+                                           buf);
+       if (!was_dirty) {
+               spin_lock(&root->fs_info->delalloc_lock);
+               root->fs_info->dirty_metadata_bytes += buf->len;
+               spin_unlock(&root->fs_info->delalloc_lock);
+       }
 }
 
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
@@ -2410,6 +2434,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
 int btree_lock_page_hook(struct page *page)
 {
        struct inode *inode = page->mapping->host;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_buffer *eb;
        unsigned long len;
@@ -2425,6 +2450,16 @@ int btree_lock_page_hook(struct page *page)
 
        btrfs_tree_lock(eb);
        btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
+
+       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
+               spin_lock(&root->fs_info->delalloc_lock);
+               if (root->fs_info->dirty_metadata_bytes >= eb->len)
+                       root->fs_info->dirty_metadata_bytes -= eb->len;
+               else
+                       WARN_ON(1);
+               spin_unlock(&root->fs_info->delalloc_lock);
+       }
+
        btrfs_tree_unlock(eb);
        free_extent_buffer(eb);
 out:
index 95029db227be5767d17eeab2a11cb36b63709849..c958ecbc19168ef0e7ef8e7bdd123f5f527b55f7 100644 (file)
@@ -72,6 +72,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
+void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
 int wait_on_tree_block_writeback(struct btrfs_root *root,
index fefe83ad20595eba078f6480781eefb0fe81c659..178df4c67de447e87514e90284a7ccc294dc8df1 100644 (file)
@@ -31,6 +31,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "ref-cache.h"
+#include "free-space-cache.h"
 
 #define PENDING_EXTENT_INSERT 0
 #define PENDING_EXTENT_DELETE 1
@@ -49,17 +50,23 @@ struct pending_extent_op {
        int del;
 };
 
-static int finish_current_insert(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *extent_root, int all);
-static int del_pending_extents(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *extent_root, int all);
-static int pin_down_bytes(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root,
-                         u64 bytenr, u64 num_bytes, int is_data);
+static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
+                                        struct btrfs_root *root, u64 parent,
+                                        u64 root_objectid, u64 ref_generation,
+                                        u64 owner, struct btrfs_key *ins,
+                                        int ref_mod);
+static int update_reserved_extents(struct btrfs_root *root,
+                                  u64 bytenr, u64 num, int reserve);
 static int update_block_group(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
                              u64 bytenr, u64 num_bytes, int alloc,
                              int mark_free);
+static noinline int __btrfs_free_extent(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       u64 bytenr, u64 num_bytes, u64 parent,
+                                       u64 root_objectid, u64 ref_generation,
+                                       u64 owner_objectid, int pin,
+                                       int ref_to_drop);
 
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 alloc_bytes,
@@ -160,7 +167,6 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group,
        u64 extent_start, extent_end, size;
        int ret;
 
-       mutex_lock(&info->pinned_mutex);
        while (start < end) {
                ret = find_first_extent_bit(&info->pinned_extents, start,
                                            &extent_start, &extent_end,
@@ -186,7 +192,6 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group,
                ret = btrfs_add_free_space(block_group, start, size);
                BUG_ON(ret);
        }
-       mutex_unlock(&info->pinned_mutex);
 
        return 0;
 }
@@ -285,8 +290,8 @@ next:
                           block_group->key.objectid +
                           block_group->key.offset);
 
-       remove_sb_from_cache(root, block_group);
        block_group->cached = 1;
+       remove_sb_from_cache(root, block_group);
        ret = 0;
 err:
        btrfs_free_path(path);
@@ -320,7 +325,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
        return cache;
 }
 
-static inline void put_block_group(struct btrfs_block_group_cache *cache)
+void btrfs_put_block_group(struct btrfs_block_group_cache *cache)
 {
        if (atomic_dec_and_test(&cache->count))
                kfree(cache);
@@ -393,12 +398,12 @@ again:
                            div_factor(cache->key.offset, factor)) {
                                group_start = cache->key.objectid;
                                spin_unlock(&cache->lock);
-                               put_block_group(cache);
+                               btrfs_put_block_group(cache);
                                goto found;
                        }
                }
                spin_unlock(&cache->lock);
-               put_block_group(cache);
+               btrfs_put_block_group(cache);
                cond_resched();
        }
        if (!wrapped) {
@@ -554,262 +559,13 @@ out:
        return ret;
 }
 
-/*
- * updates all the backrefs that are pending on update_list for the
- * extent_root
- */
-static noinline int update_backrefs(struct btrfs_trans_handle *trans,
-                                   struct btrfs_root *extent_root,
-                                   struct btrfs_path *path,
-                                   struct list_head *update_list)
-{
-       struct btrfs_key key;
-       struct btrfs_extent_ref *ref;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct pending_extent_op *op;
-       struct extent_buffer *leaf;
-       int ret = 0;
-       struct list_head *cur = update_list->next;
-       u64 ref_objectid;
-       u64 ref_root = extent_root->root_key.objectid;
-
-       op = list_entry(cur, struct pending_extent_op, list);
-
-search:
-       key.objectid = op->bytenr;
-       key.type = BTRFS_EXTENT_REF_KEY;
-       key.offset = op->orig_parent;
-
-       ret = btrfs_search_slot(trans, extent_root, &key, path, 0, 1);
-       BUG_ON(ret);
-
-       leaf = path->nodes[0];
-
-loop:
-       ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref);
-
-       ref_objectid = btrfs_ref_objectid(leaf, ref);
-
-       if (btrfs_ref_root(leaf, ref) != ref_root ||
-           btrfs_ref_generation(leaf, ref) != op->orig_generation ||
-           (ref_objectid != op->level &&
-            ref_objectid != BTRFS_MULTIPLE_OBJECTIDS)) {
-               printk(KERN_ERR "btrfs couldn't find %llu, parent %llu, "
-                      "root %llu, owner %u\n",
-                      (unsigned long long)op->bytenr,
-                      (unsigned long long)op->orig_parent,
-                      (unsigned long long)ref_root, op->level);
-               btrfs_print_leaf(extent_root, leaf);
-               BUG();
-       }
-
-       key.objectid = op->bytenr;
-       key.offset = op->parent;
-       key.type = BTRFS_EXTENT_REF_KEY;
-       ret = btrfs_set_item_key_safe(trans, extent_root, path, &key);
-       BUG_ON(ret);
-       ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref);
-       btrfs_set_ref_generation(leaf, ref, op->generation);
-
-       cur = cur->next;
-
-       list_del_init(&op->list);
-       unlock_extent(&info->extent_ins, op->bytenr,
-                     op->bytenr + op->num_bytes - 1, GFP_NOFS);
-       kfree(op);
-
-       if (cur == update_list) {
-               btrfs_mark_buffer_dirty(path->nodes[0]);
-               btrfs_release_path(extent_root, path);
-               goto out;
-       }
-
-       op = list_entry(cur, struct pending_extent_op, list);
-
-       path->slots[0]++;
-       while (path->slots[0] < btrfs_header_nritems(leaf)) {
-               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               if (key.objectid == op->bytenr &&
-                   key.type == BTRFS_EXTENT_REF_KEY)
-                       goto loop;
-               path->slots[0]++;
-       }
-
-       btrfs_mark_buffer_dirty(path->nodes[0]);
-       btrfs_release_path(extent_root, path);
-       goto search;
-
-out:
-       return 0;
-}
-
-static noinline int insert_extents(struct btrfs_trans_handle *trans,
-                                  struct btrfs_root *extent_root,
-                                  struct btrfs_path *path,
-                                  struct list_head *insert_list, int nr)
-{
-       struct btrfs_key *keys;
-       u32 *data_size;
-       struct pending_extent_op *op;
-       struct extent_buffer *leaf;
-       struct list_head *cur = insert_list->next;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       u64 ref_root = extent_root->root_key.objectid;
-       int i = 0, last = 0, ret;
-       int total = nr * 2;
-
-       if (!nr)
-               return 0;
-
-       keys = kzalloc(total * sizeof(struct btrfs_key), GFP_NOFS);
-       if (!keys)
-               return -ENOMEM;
-
-       data_size = kzalloc(total * sizeof(u32), GFP_NOFS);
-       if (!data_size) {
-               kfree(keys);
-               return -ENOMEM;
-       }
-
-       list_for_each_entry(op, insert_list, list) {
-               keys[i].objectid = op->bytenr;
-               keys[i].offset = op->num_bytes;
-               keys[i].type = BTRFS_EXTENT_ITEM_KEY;
-               data_size[i] = sizeof(struct btrfs_extent_item);
-               i++;
-
-               keys[i].objectid = op->bytenr;
-               keys[i].offset = op->parent;
-               keys[i].type = BTRFS_EXTENT_REF_KEY;
-               data_size[i] = sizeof(struct btrfs_extent_ref);
-               i++;
-       }
-
-       op = list_entry(cur, struct pending_extent_op, list);
-       i = 0;
-       while (i < total) {
-               int c;
-               ret = btrfs_insert_some_items(trans, extent_root, path,
-                                             keys+i, data_size+i, total-i);
-               BUG_ON(ret < 0);
-
-               if (last && ret > 1)
-                       BUG();
-
-               leaf = path->nodes[0];
-               for (c = 0; c < ret; c++) {
-                       int ref_first = keys[i].type == BTRFS_EXTENT_REF_KEY;
-
-                       /*
-                        * if the first item we inserted was a backref, then
-                        * the EXTENT_ITEM will be the odd c's, else it will
-                        * be the even c's
-                        */
-                       if ((ref_first && (c % 2)) ||
-                           (!ref_first && !(c % 2))) {
-                               struct btrfs_extent_item *itm;
-
-                               itm = btrfs_item_ptr(leaf, path->slots[0] + c,
-                                                    struct btrfs_extent_item);
-                               btrfs_set_extent_refs(path->nodes[0], itm, 1);
-                               op->del++;
-                       } else {
-                               struct btrfs_extent_ref *ref;
-
-                               ref = btrfs_item_ptr(leaf, path->slots[0] + c,
-                                                    struct btrfs_extent_ref);
-                               btrfs_set_ref_root(leaf, ref, ref_root);
-                               btrfs_set_ref_generation(leaf, ref,
-                                                        op->generation);
-                               btrfs_set_ref_objectid(leaf, ref, op->level);
-                               btrfs_set_ref_num_refs(leaf, ref, 1);
-                               op->del++;
-                       }
-
-                       /*
-                        * using del to see when its ok to free up the
-                        * pending_extent_op.  In the case where we insert the
-                        * last item on the list in order to help do batching
-                        * we need to not free the extent op until we actually
-                        * insert the extent_item
-                        */
-                       if (op->del == 2) {
-                               unlock_extent(&info->extent_ins, op->bytenr,
-                                             op->bytenr + op->num_bytes - 1,
-                                             GFP_NOFS);
-                               cur = cur->next;
-                               list_del_init(&op->list);
-                               kfree(op);
-                               if (cur != insert_list)
-                                       op = list_entry(cur,
-                                               struct pending_extent_op,
-                                               list);
-                       }
-               }
-               btrfs_mark_buffer_dirty(leaf);
-               btrfs_release_path(extent_root, path);
-
-               /*
-                * Ok backref's and items usually go right next to eachother,
-                * but if we could only insert 1 item that means that we
-                * inserted on the end of a leaf, and we have no idea what may
-                * be on the next leaf so we just play it safe.  In order to
-                * try and help this case we insert the last thing on our
-                * insert list so hopefully it will end up being the last
-                * thing on the leaf and everything else will be before it,
-                * which will let us insert a whole bunch of items at the same
-                * time.
-                */
-               if (ret == 1 && !last && (i + ret < total)) {
-                       /*
-                        * last: where we will pick up the next time around
-                        * i: our current key to insert, will be total - 1
-                        * cur: the current op we are screwing with
-                        * op: duh
-                        */
-                       last = i + ret;
-                       i = total - 1;
-                       cur = insert_list->prev;
-                       op = list_entry(cur, struct pending_extent_op, list);
-               } else if (last) {
-                       /*
-                        * ok we successfully inserted the last item on the
-                        * list, lets reset everything
-                        *
-                        * i: our current key to insert, so where we left off
-                        *    last time
-                        * last: done with this
-                        * cur: the op we are messing with
-                        * op: duh
-                        * total: since we inserted the last key, we need to
-                        *        decrement total so we dont overflow
-                        */
-                       i = last;
-                       last = 0;
-                       total--;
-                       if (i < total) {
-                               cur = insert_list->next;
-                               op = list_entry(cur, struct pending_extent_op,
-                                               list);
-                       }
-               } else {
-                       i += ret;
-               }
-
-               cond_resched();
-       }
-       ret = 0;
-       kfree(keys);
-       kfree(data_size);
-       return ret;
-}
-
 static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
                                          struct btrfs_path *path,
                                          u64 bytenr, u64 parent,
                                          u64 ref_root, u64 ref_generation,
-                                         u64 owner_objectid)
+                                         u64 owner_objectid,
+                                         int refs_to_add)
 {
        struct btrfs_key key;
        struct extent_buffer *leaf;
@@ -829,9 +585,10 @@ static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
                btrfs_set_ref_root(leaf, ref, ref_root);
                btrfs_set_ref_generation(leaf, ref, ref_generation);
                btrfs_set_ref_objectid(leaf, ref, owner_objectid);
-               btrfs_set_ref_num_refs(leaf, ref, 1);
+               btrfs_set_ref_num_refs(leaf, ref, refs_to_add);
        } else if (ret == -EEXIST) {
                u64 existing_owner;
+
                BUG_ON(owner_objectid < BTRFS_FIRST_FREE_OBJECTID);
                leaf = path->nodes[0];
                ref = btrfs_item_ptr(leaf, path->slots[0],
@@ -845,7 +602,7 @@ static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
 
                num_refs = btrfs_ref_num_refs(leaf, ref);
                BUG_ON(num_refs == 0);
-               btrfs_set_ref_num_refs(leaf, ref, num_refs + 1);
+               btrfs_set_ref_num_refs(leaf, ref, num_refs + refs_to_add);
 
                existing_owner = btrfs_ref_objectid(leaf, ref);
                if (existing_owner != owner_objectid &&
@@ -857,6 +614,7 @@ static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
        } else {
                goto out;
        }
+       btrfs_unlock_up_safe(path, 1);
        btrfs_mark_buffer_dirty(path->nodes[0]);
 out:
        btrfs_release_path(root, path);
@@ -865,7 +623,8 @@ out:
 
 static noinline int remove_extent_backref(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
-                                         struct btrfs_path *path)
+                                         struct btrfs_path *path,
+                                         int refs_to_drop)
 {
        struct extent_buffer *leaf;
        struct btrfs_extent_ref *ref;
@@ -875,8 +634,8 @@ static noinline int remove_extent_backref(struct btrfs_trans_handle *trans,
        leaf = path->nodes[0];
        ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref);
        num_refs = btrfs_ref_num_refs(leaf, ref);
-       BUG_ON(num_refs == 0);
-       num_refs -= 1;
+       BUG_ON(num_refs < refs_to_drop);
+       num_refs -= refs_to_drop;
        if (num_refs == 0) {
                ret = btrfs_del_item(trans, root, path);
        } else {
@@ -927,332 +686,28 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
 #endif
 }
 
-static noinline int free_extents(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *extent_root,
-                                struct list_head *del_list)
-{
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct btrfs_path *path;
-       struct btrfs_key key, found_key;
-       struct extent_buffer *leaf;
-       struct list_head *cur;
-       struct pending_extent_op *op;
-       struct btrfs_extent_item *ei;
-       int ret, num_to_del, extent_slot = 0, found_extent = 0;
-       u32 refs;
-       u64 bytes_freed = 0;
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-       path->reada = 1;
-
-search:
-       /* search for the backref for the current ref we want to delete */
-       cur = del_list->next;
-       op = list_entry(cur, struct pending_extent_op, list);
-       ret = lookup_extent_backref(trans, extent_root, path, op->bytenr,
-                                   op->orig_parent,
-                                   extent_root->root_key.objectid,
-                                   op->orig_generation, op->level, 1);
-       if (ret) {
-               printk(KERN_ERR "btrfs unable to find backref byte nr %llu "
-                      "root %llu gen %llu owner %u\n",
-                      (unsigned long long)op->bytenr,
-                      (unsigned long long)extent_root->root_key.objectid,
-                      (unsigned long long)op->orig_generation, op->level);
-               btrfs_print_leaf(extent_root, path->nodes[0]);
-               WARN_ON(1);
-               goto out;
-       }
-
-       extent_slot = path->slots[0];
-       num_to_del = 1;
-       found_extent = 0;
-
-       /*
-        * if we aren't the first item on the leaf we can move back one and see
-        * if our ref is right next to our extent item
-        */
-       if (likely(extent_slot)) {
-               extent_slot--;
-               btrfs_item_key_to_cpu(path->nodes[0], &found_key,
-                                     extent_slot);
-               if (found_key.objectid == op->bytenr &&
-                   found_key.type == BTRFS_EXTENT_ITEM_KEY &&
-                   found_key.offset == op->num_bytes) {
-                       num_to_del++;
-                       found_extent = 1;
-               }
-       }
-
-       /*
-        * if we didn't find the extent we need to delete the backref and then
-        * search for the extent item key so we can update its ref count
-        */
-       if (!found_extent) {
-               key.objectid = op->bytenr;
-               key.type = BTRFS_EXTENT_ITEM_KEY;
-               key.offset = op->num_bytes;
-
-               ret = remove_extent_backref(trans, extent_root, path);
-               BUG_ON(ret);
-               btrfs_release_path(extent_root, path);
-               ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
-               BUG_ON(ret);
-               extent_slot = path->slots[0];
-       }
-
-       /* this is where we update the ref count for the extent */
-       leaf = path->nodes[0];
-       ei = btrfs_item_ptr(leaf, extent_slot, struct btrfs_extent_item);
-       refs = btrfs_extent_refs(leaf, ei);
-       BUG_ON(refs == 0);
-       refs--;
-       btrfs_set_extent_refs(leaf, ei, refs);
-
-       btrfs_mark_buffer_dirty(leaf);
-
-       /*
-        * This extent needs deleting.  The reason cur_slot is extent_slot +
-        * num_to_del is because extent_slot points to the slot where the extent
-        * is, and if the backref was not right next to the extent we will be
-        * deleting at least 1 item, and will want to start searching at the
-        * slot directly next to extent_slot.  However if we did find the
-        * backref next to the extent item them we will be deleting at least 2
-        * items and will want to start searching directly after the ref slot
-        */
-       if (!refs) {
-               struct list_head *pos, *n, *end;
-               int cur_slot = extent_slot+num_to_del;
-               u64 super_used;
-               u64 root_used;
-
-               path->slots[0] = extent_slot;
-               bytes_freed = op->num_bytes;
-
-               mutex_lock(&info->pinned_mutex);
-               ret = pin_down_bytes(trans, extent_root, op->bytenr,
-                                    op->num_bytes, op->level >=
-                                    BTRFS_FIRST_FREE_OBJECTID);
-               mutex_unlock(&info->pinned_mutex);
-               BUG_ON(ret < 0);
-               op->del = ret;
-
-               /*
-                * we need to see if we can delete multiple things at once, so
-                * start looping through the list of extents we are wanting to
-                * delete and see if their extent/backref's are right next to
-                * eachother and the extents only have 1 ref
-                */
-               for (pos = cur->next; pos != del_list; pos = pos->next) {
-                       struct pending_extent_op *tmp;
-
-                       tmp = list_entry(pos, struct pending_extent_op, list);
-
-                       /* we only want to delete extent+ref at this stage */
-                       if (cur_slot >= btrfs_header_nritems(leaf) - 1)
-                               break;
-
-                       btrfs_item_key_to_cpu(leaf, &found_key, cur_slot);
-                       if (found_key.objectid != tmp->bytenr ||
-                           found_key.type != BTRFS_EXTENT_ITEM_KEY ||
-                           found_key.offset != tmp->num_bytes)
-                               break;
-
-                       /* check to make sure this extent only has one ref */
-                       ei = btrfs_item_ptr(leaf, cur_slot,
-                                           struct btrfs_extent_item);
-                       if (btrfs_extent_refs(leaf, ei) != 1)
-                               break;
-
-                       btrfs_item_key_to_cpu(leaf, &found_key, cur_slot+1);
-                       if (found_key.objectid != tmp->bytenr ||
-                           found_key.type != BTRFS_EXTENT_REF_KEY ||
-                           found_key.offset != tmp->orig_parent)
-                               break;
-
-                       /*
-                        * the ref is right next to the extent, we can set the
-                        * ref count to 0 since we will delete them both now
-                        */
-                       btrfs_set_extent_refs(leaf, ei, 0);
-
-                       /* pin down the bytes for this extent */
-                       mutex_lock(&info->pinned_mutex);
-                       ret = pin_down_bytes(trans, extent_root, tmp->bytenr,
-                                            tmp->num_bytes, tmp->level >=
-                                            BTRFS_FIRST_FREE_OBJECTID);
-                       mutex_unlock(&info->pinned_mutex);
-                       BUG_ON(ret < 0);
-
-                       /*
-                        * use the del field to tell if we need to go ahead and
-                        * free up the extent when we delete the item or not.
-                        */
-                       tmp->del = ret;
-                       bytes_freed += tmp->num_bytes;
-
-                       num_to_del += 2;
-                       cur_slot += 2;
-               }
-               end = pos;
-
-               /* update the free space counters */
-               spin_lock(&info->delalloc_lock);
-               super_used = btrfs_super_bytes_used(&info->super_copy);
-               btrfs_set_super_bytes_used(&info->super_copy,
-                                          super_used - bytes_freed);
-
-               root_used = btrfs_root_used(&extent_root->root_item);
-               btrfs_set_root_used(&extent_root->root_item,
-                                   root_used - bytes_freed);
-               spin_unlock(&info->delalloc_lock);
-
-               /* delete the items */
-               ret = btrfs_del_items(trans, extent_root, path,
-                                     path->slots[0], num_to_del);
-               BUG_ON(ret);
-
-               /*
-                * loop through the extents we deleted and do the cleanup work
-                * on them
-                */
-               for (pos = cur, n = pos->next; pos != end;
-                    pos = n, n = pos->next) {
-                       struct pending_extent_op *tmp;
-                       tmp = list_entry(pos, struct pending_extent_op, list);
-
-                       /*
-                        * remember tmp->del tells us wether or not we pinned
-                        * down the extent
-                        */
-                       ret = update_block_group(trans, extent_root,
-                                                tmp->bytenr, tmp->num_bytes, 0,
-                                                tmp->del);
-                       BUG_ON(ret);
-
-                       list_del_init(&tmp->list);
-                       unlock_extent(&info->extent_ins, tmp->bytenr,
-                                     tmp->bytenr + tmp->num_bytes - 1,
-                                     GFP_NOFS);
-                       kfree(tmp);
-               }
-       } else if (refs && found_extent) {
-               /*
-                * the ref and extent were right next to eachother, but the
-                * extent still has a ref, so just free the backref and keep
-                * going
-                */
-               ret = remove_extent_backref(trans, extent_root, path);
-               BUG_ON(ret);
-
-               list_del_init(&op->list);
-               unlock_extent(&info->extent_ins, op->bytenr,
-                             op->bytenr + op->num_bytes - 1, GFP_NOFS);
-               kfree(op);
-       } else {
-               /*
-                * the extent has multiple refs and the backref we were looking
-                * for was not right next to it, so just unlock and go next,
-                * we're good to go
-                */
-               list_del_init(&op->list);
-               unlock_extent(&info->extent_ins, op->bytenr,
-                             op->bytenr + op->num_bytes - 1, GFP_NOFS);
-               kfree(op);
-       }
-
-       btrfs_release_path(extent_root, path);
-       if (!list_empty(del_list))
-               goto search;
-
-out:
-       btrfs_free_path(path);
-       return ret;
-}
-
 static int __btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root, u64 bytenr,
+                                    u64 num_bytes,
                                     u64 orig_parent, u64 parent,
                                     u64 orig_root, u64 ref_root,
                                     u64 orig_generation, u64 ref_generation,
                                     u64 owner_objectid)
 {
        int ret;
-       struct btrfs_root *extent_root = root->fs_info->extent_root;
-       struct btrfs_path *path;
-
-       if (root == root->fs_info->extent_root) {
-               struct pending_extent_op *extent_op;
-               u64 num_bytes;
-
-               BUG_ON(owner_objectid >= BTRFS_MAX_LEVEL);
-               num_bytes = btrfs_level_size(root, (int)owner_objectid);
-               mutex_lock(&root->fs_info->extent_ins_mutex);
-               if (test_range_bit(&root->fs_info->extent_ins, bytenr,
-                               bytenr + num_bytes - 1, EXTENT_WRITEBACK, 0)) {
-                       u64 priv;
-                       ret = get_state_private(&root->fs_info->extent_ins,
-                                               bytenr, &priv);
-                       BUG_ON(ret);
-                       extent_op = (struct pending_extent_op *)
-                                                       (unsigned long)priv;
-                       BUG_ON(extent_op->parent != orig_parent);
-                       BUG_ON(extent_op->generation != orig_generation);
+       int pin = owner_objectid < BTRFS_FIRST_FREE_OBJECTID;
 
-                       extent_op->parent = parent;
-                       extent_op->generation = ref_generation;
-               } else {
-                       extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-                       BUG_ON(!extent_op);
-
-                       extent_op->type = PENDING_BACKREF_UPDATE;
-                       extent_op->bytenr = bytenr;
-                       extent_op->num_bytes = num_bytes;
-                       extent_op->parent = parent;
-                       extent_op->orig_parent = orig_parent;
-                       extent_op->generation = ref_generation;
-                       extent_op->orig_generation = orig_generation;
-                       extent_op->level = (int)owner_objectid;
-                       INIT_LIST_HEAD(&extent_op->list);
-                       extent_op->del = 0;
-
-                       set_extent_bits(&root->fs_info->extent_ins,
-                                       bytenr, bytenr + num_bytes - 1,
-                                       EXTENT_WRITEBACK, GFP_NOFS);
-                       set_state_private(&root->fs_info->extent_ins,
-                                         bytenr, (unsigned long)extent_op);
-               }
-               mutex_unlock(&root->fs_info->extent_ins_mutex);
-               return 0;
-       }
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-       ret = lookup_extent_backref(trans, extent_root, path,
-                                   bytenr, orig_parent, orig_root,
-                                   orig_generation, owner_objectid, 1);
-       if (ret)
-               goto out;
-       ret = remove_extent_backref(trans, extent_root, path);
-       if (ret)
-               goto out;
-       ret = insert_extent_backref(trans, extent_root, path, bytenr,
-                                   parent, ref_root, ref_generation,
-                                   owner_objectid);
+       ret = btrfs_update_delayed_ref(trans, bytenr, num_bytes,
+                                      orig_parent, parent, orig_root,
+                                      ref_root, orig_generation,
+                                      ref_generation, owner_objectid, pin);
        BUG_ON(ret);
-       finish_current_insert(trans, extent_root, 0);
-       del_pending_extents(trans, extent_root, 0);
-out:
-       btrfs_free_path(path);
        return ret;
 }
 
 int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root, u64 bytenr,
-                           u64 orig_parent, u64 parent,
+                           u64 num_bytes, u64 orig_parent, u64 parent,
                            u64 ref_root, u64 ref_generation,
                            u64 owner_objectid)
 {
@@ -1260,19 +715,35 @@ int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
        if (ref_root == BTRFS_TREE_LOG_OBJECTID &&
            owner_objectid < BTRFS_FIRST_FREE_OBJECTID)
                return 0;
-       ret = __btrfs_update_extent_ref(trans, root, bytenr, orig_parent,
-                                       parent, ref_root, ref_root,
-                                       ref_generation, ref_generation,
-                                       owner_objectid);
+
+       ret = __btrfs_update_extent_ref(trans, root, bytenr, num_bytes,
+                                       orig_parent, parent, ref_root,
+                                       ref_root, ref_generation,
+                                       ref_generation, owner_objectid);
        return ret;
 }
-
 static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                  struct btrfs_root *root, u64 bytenr,
+                                 u64 num_bytes,
                                  u64 orig_parent, u64 parent,
                                  u64 orig_root, u64 ref_root,
                                  u64 orig_generation, u64 ref_generation,
                                  u64 owner_objectid)
+{
+       int ret;
+
+       ret = btrfs_add_delayed_ref(trans, bytenr, num_bytes, parent, ref_root,
+                                   ref_generation, owner_objectid,
+                                   BTRFS_ADD_DELAYED_REF, 0);
+       BUG_ON(ret);
+       return ret;
+}
+
+static noinline_for_stack int add_extent_ref(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root, u64 bytenr,
+                         u64 num_bytes, u64 parent, u64 ref_root,
+                         u64 ref_generation, u64 owner_objectid,
+                         int refs_to_add)
 {
        struct btrfs_path *path;
        int ret;
@@ -1286,17 +757,24 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        path->reada = 1;
+       path->leave_spinning = 1;
        key.objectid = bytenr;
        key.type = BTRFS_EXTENT_ITEM_KEY;
-       key.offset = (u64)-1;
+       key.offset = num_bytes;
 
-       ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
-                               0, 1);
-       if (ret < 0)
+       /* first find the extent item and update its reference count */
+       ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key,
+                               path, 0, 1);
+       if (ret < 0) {
+               btrfs_set_path_blocking(path);
                return ret;
-       BUG_ON(ret == 0 || path->slots[0] == 0);
+       }
 
-       path->slots[0]--;
+       if (ret > 0) {
+               WARN_ON(1);
+               btrfs_free_path(path);
+               return -EIO;
+       }
        l = path->nodes[0];
 
        btrfs_item_key_to_cpu(l, &key, path->slots[0]);
@@ -1310,21 +788,24 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        BUG_ON(key.type != BTRFS_EXTENT_ITEM_KEY);
 
        item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
+
        refs = btrfs_extent_refs(l, item);
-       btrfs_set_extent_refs(l, item, refs + 1);
+       btrfs_set_extent_refs(l, item, refs + refs_to_add);
+       btrfs_unlock_up_safe(path, 1);
+
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
        btrfs_release_path(root->fs_info->extent_root, path);
 
        path->reada = 1;
+       path->leave_spinning = 1;
+
+       /* now insert the actual backref */
        ret = insert_extent_backref(trans, root->fs_info->extent_root,
                                    path, bytenr, parent,
                                    ref_root, ref_generation,
-                                   owner_objectid);
+                                   owner_objectid, refs_to_add);
        BUG_ON(ret);
-       finish_current_insert(trans, root->fs_info->extent_root, 0);
-       del_pending_extents(trans, root->fs_info->extent_root, 0);
-
        btrfs_free_path(path);
        return 0;
 }
@@ -1339,68 +820,278 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        if (ref_root == BTRFS_TREE_LOG_OBJECTID &&
            owner_objectid < BTRFS_FIRST_FREE_OBJECTID)
                return 0;
-       ret = __btrfs_inc_extent_ref(trans, root, bytenr, 0, parent,
+
+       ret = __btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, parent,
                                     0, ref_root, 0, ref_generation,
                                     owner_objectid);
        return ret;
 }
 
-int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
-                        struct btrfs_root *root)
+static int drop_delayed_ref(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       struct btrfs_delayed_ref_node *node)
+{
+       int ret = 0;
+       struct btrfs_delayed_ref *ref = btrfs_delayed_node_to_ref(node);
+
+       BUG_ON(node->ref_mod == 0);
+       ret = __btrfs_free_extent(trans, root, node->bytenr, node->num_bytes,
+                                 node->parent, ref->root, ref->generation,
+                                 ref->owner_objectid, ref->pin, node->ref_mod);
+
+       return ret;
+}
+
+/* helper function to actually process a single delayed ref entry */
+static noinline int run_one_delayed_ref(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       struct btrfs_delayed_ref_node *node,
+                                       int insert_reserved)
 {
-       u64 start;
-       u64 end;
        int ret;
+       struct btrfs_delayed_ref *ref;
 
-       while(1) {
-               finish_current_insert(trans, root->fs_info->extent_root, 1);
-               del_pending_extents(trans, root->fs_info->extent_root, 1);
+       if (node->parent == (u64)-1) {
+               struct btrfs_delayed_ref_head *head;
+               /*
+                * we've hit the end of the chain and we were supposed
+                * to insert this extent into the tree.  But, it got
+                * deleted before we ever needed to insert it, so all
+                * we have to do is clean up the accounting
+                */
+               if (insert_reserved) {
+                       update_reserved_extents(root, node->bytenr,
+                                               node->num_bytes, 0);
+               }
+               head = btrfs_delayed_node_to_head(node);
+               mutex_unlock(&head->mutex);
+               return 0;
+       }
 
-               /* is there more work to do? */
-               ret = find_first_extent_bit(&root->fs_info->pending_del,
-                                           0, &start, &end, EXTENT_WRITEBACK);
-               if (!ret)
-                       continue;
-               ret = find_first_extent_bit(&root->fs_info->extent_ins,
-                                           0, &start, &end, EXTENT_WRITEBACK);
-               if (!ret)
-                       continue;
-               break;
+       ref = btrfs_delayed_node_to_ref(node);
+       if (ref->action == BTRFS_ADD_DELAYED_REF) {
+               if (insert_reserved) {
+                       struct btrfs_key ins;
+
+                       ins.objectid = node->bytenr;
+                       ins.offset = node->num_bytes;
+                       ins.type = BTRFS_EXTENT_ITEM_KEY;
+
+                       /* record the full extent allocation */
+                       ret = __btrfs_alloc_reserved_extent(trans, root,
+                                       node->parent, ref->root,
+                                       ref->generation, ref->owner_objectid,
+                                       &ins, node->ref_mod);
+                       update_reserved_extents(root, node->bytenr,
+                                               node->num_bytes, 0);
+               } else {
+                       /* just add one backref */
+                       ret = add_extent_ref(trans, root, node->bytenr,
+                                    node->num_bytes,
+                                    node->parent, ref->root, ref->generation,
+                                    ref->owner_objectid, node->ref_mod);
+               }
+               BUG_ON(ret);
+       } else if (ref->action == BTRFS_DROP_DELAYED_REF) {
+               WARN_ON(insert_reserved);
+               ret = drop_delayed_ref(trans, root, node);
        }
        return 0;
 }
 
-int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, u64 bytenr,
-                           u64 num_bytes, u32 *refs)
+static noinline struct btrfs_delayed_ref_node *
+select_delayed_ref(struct btrfs_delayed_ref_head *head)
 {
-       struct btrfs_path *path;
+       struct rb_node *node;
+       struct btrfs_delayed_ref_node *ref;
+       int action = BTRFS_ADD_DELAYED_REF;
+again:
+       /*
+        * select delayed ref of type BTRFS_ADD_DELAYED_REF first.
+        * this prevents ref count from going down to zero when
+        * there still are pending delayed ref.
+        */
+       node = rb_prev(&head->node.rb_node);
+       while (1) {
+               if (!node)
+                       break;
+               ref = rb_entry(node, struct btrfs_delayed_ref_node,
+                               rb_node);
+               if (ref->bytenr != head->node.bytenr)
+                       break;
+               if (btrfs_delayed_node_to_ref(ref)->action == action)
+                       return ref;
+               node = rb_prev(node);
+       }
+       if (action == BTRFS_ADD_DELAYED_REF) {
+               action = BTRFS_DROP_DELAYED_REF;
+               goto again;
+       }
+       return NULL;
+}
+
+static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
+                                      struct btrfs_root *root,
+                                      struct list_head *cluster)
+{
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_delayed_ref_node *ref;
+       struct btrfs_delayed_ref_head *locked_ref = NULL;
        int ret;
-       struct btrfs_key key;
-       struct extent_buffer *l;
-       struct btrfs_extent_item *item;
+       int count = 0;
+       int must_insert_reserved = 0;
 
-       WARN_ON(num_bytes < root->sectorsize);
-       path = btrfs_alloc_path();
-       path->reada = 1;
-       key.objectid = bytenr;
-       key.offset = num_bytes;
-       btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
-       ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
-                               0, 0);
-       if (ret < 0)
-               goto out;
-       if (ret != 0) {
-               btrfs_print_leaf(root, path->nodes[0]);
-               printk(KERN_INFO "btrfs failed to find block number %llu\n",
-                      (unsigned long long)bytenr);
-               BUG();
+       delayed_refs = &trans->transaction->delayed_refs;
+       while (1) {
+               if (!locked_ref) {
+                       /* pick a new head ref from the cluster list */
+                       if (list_empty(cluster))
+                               break;
+
+                       locked_ref = list_entry(cluster->next,
+                                    struct btrfs_delayed_ref_head, cluster);
+
+                       /* grab the lock that says we are going to process
+                        * all the refs for this head */
+                       ret = btrfs_delayed_ref_lock(trans, locked_ref);
+
+                       /*
+                        * we may have dropped the spin lock to get the head
+                        * mutex lock, and that might have given someone else
+                        * time to free the head.  If that's true, it has been
+                        * removed from our list and we can move on.
+                        */
+                       if (ret == -EAGAIN) {
+                               locked_ref = NULL;
+                               count++;
+                               continue;
+                       }
+               }
+
+               /*
+                * record the must insert reserved flag before we
+                * drop the spin lock.
+                */
+               must_insert_reserved = locked_ref->must_insert_reserved;
+               locked_ref->must_insert_reserved = 0;
+
+               /*
+                * locked_ref is the head node, so we have to go one
+                * node back for any delayed ref updates
+                */
+               ref = select_delayed_ref(locked_ref);
+               if (!ref) {
+                       /* All delayed refs have been processed, Go ahead
+                        * and send the head node to run_one_delayed_ref,
+                        * so that any accounting fixes can happen
+                        */
+                       ref = &locked_ref->node;
+                       list_del_init(&locked_ref->cluster);
+                       locked_ref = NULL;
+               }
+
+               ref->in_tree = 0;
+               rb_erase(&ref->rb_node, &delayed_refs->root);
+               delayed_refs->num_entries--;
+               spin_unlock(&delayed_refs->lock);
+
+               ret = run_one_delayed_ref(trans, root, ref,
+                                         must_insert_reserved);
+               BUG_ON(ret);
+               btrfs_put_delayed_ref(ref);
+
+               count++;
+               cond_resched();
+               spin_lock(&delayed_refs->lock);
+       }
+       return count;
+}
+
+/*
+ * this starts processing the delayed reference count updates and
+ * extent insertions we have queued up so far.  count can be
+ * 0, which means to process everything in the tree at the start
+ * of the run (but not newly added entries), or it can be some target
+ * number you'd like to process.
+ */
+int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, unsigned long count)
+{
+       struct rb_node *node;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_delayed_ref_node *ref;
+       struct list_head cluster;
+       int ret;
+       int run_all = count == (unsigned long)-1;
+       int run_most = 0;
+
+       if (root == root->fs_info->extent_root)
+               root = root->fs_info->tree_root;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       INIT_LIST_HEAD(&cluster);
+again:
+       spin_lock(&delayed_refs->lock);
+       if (count == 0) {
+               count = delayed_refs->num_entries * 2;
+               run_most = 1;
+       }
+       while (1) {
+               if (!(run_all || run_most) &&
+                   delayed_refs->num_heads_ready < 64)
+                       break;
+
+               /*
+                * go find something we can process in the rbtree.  We start at
+                * the beginning of the tree, and then build a cluster
+                * of refs to process starting at the first one we are able to
+                * lock
+                */
+               ret = btrfs_find_ref_cluster(trans, &cluster,
+                                            delayed_refs->run_delayed_start);
+               if (ret)
+                       break;
+
+               ret = run_clustered_refs(trans, root, &cluster);
+               BUG_ON(ret < 0);
+
+               count -= min_t(unsigned long, ret, count);
+
+               if (count == 0)
+                       break;
+       }
+
+       if (run_all) {
+               node = rb_first(&delayed_refs->root);
+               if (!node)
+                       goto out;
+               count = (unsigned long)-1;
+
+               while (node) {
+                       ref = rb_entry(node, struct btrfs_delayed_ref_node,
+                                      rb_node);
+                       if (btrfs_delayed_ref_is_head(ref)) {
+                               struct btrfs_delayed_ref_head *head;
+
+                               head = btrfs_delayed_node_to_head(ref);
+                               atomic_inc(&ref->refs);
+
+                               spin_unlock(&delayed_refs->lock);
+                               mutex_lock(&head->mutex);
+                               mutex_unlock(&head->mutex);
+
+                               btrfs_put_delayed_ref(ref);
+                               cond_resched();
+                               goto again;
+                       }
+                       node = rb_next(node);
+               }
+               spin_unlock(&delayed_refs->lock);
+               schedule_timeout(1);
+               goto again;
        }
-       l = path->nodes[0];
-       item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
-       *refs = btrfs_extent_refs(l, item);
 out:
-       btrfs_free_path(path);
+       spin_unlock(&delayed_refs->lock);
        return 0;
 }
 
@@ -1624,7 +1315,7 @@ noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
        int refi = 0;
        int slot;
        int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
-                           u64, u64, u64, u64, u64, u64, u64, u64);
+                           u64, u64, u64, u64, u64, u64, u64, u64, u64);
 
        ref_root = btrfs_header_owner(buf);
        ref_generation = btrfs_header_generation(buf);
@@ -1696,12 +1387,19 @@ noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
 
                if (level == 0) {
                        btrfs_item_key_to_cpu(buf, &key, slot);
+                       fi = btrfs_item_ptr(buf, slot,
+                                           struct btrfs_file_extent_item);
+
+                       bytenr = btrfs_file_extent_disk_bytenr(buf, fi);
+                       if (bytenr == 0)
+                               continue;
 
                        ret = process_func(trans, root, bytenr,
-                                          orig_buf->start, buf->start,
-                                          orig_root, ref_root,
-                                          orig_generation, ref_generation,
-                                          key.objectid);
+                                  btrfs_file_extent_disk_num_bytes(buf, fi),
+                                  orig_buf->start, buf->start,
+                                  orig_root, ref_root,
+                                  orig_generation, ref_generation,
+                                  key.objectid);
 
                        if (ret) {
                                faili = slot;
@@ -1709,7 +1407,7 @@ noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
                                goto fail;
                        }
                } else {
-                       ret = process_func(trans, root, bytenr,
+                       ret = process_func(trans, root, bytenr, buf->len,
                                           orig_buf->start, buf->start,
                                           orig_root, ref_root,
                                           orig_generation, ref_generation,
@@ -1786,17 +1484,17 @@ int btrfs_update_ref(struct btrfs_trans_handle *trans,
                        if (bytenr == 0)
                                continue;
                        ret = __btrfs_update_extent_ref(trans, root, bytenr,
-                                           orig_buf->start, buf->start,
-                                           orig_root, ref_root,
-                                           orig_generation, ref_generation,
-                                           key.objectid);
+                                   btrfs_file_extent_disk_num_bytes(buf, fi),
+                                   orig_buf->start, buf->start,
+                                   orig_root, ref_root, orig_generation,
+                                   ref_generation, key.objectid);
                        if (ret)
                                goto fail;
                } else {
                        bytenr = btrfs_node_blockptr(buf, slot);
                        ret = __btrfs_update_extent_ref(trans, root, bytenr,
-                                           orig_buf->start, buf->start,
-                                           orig_root, ref_root,
+                                           buf->len, orig_buf->start,
+                                           buf->start, orig_root, ref_root,
                                            orig_generation, ref_generation,
                                            level - 1);
                        if (ret)
@@ -1815,7 +1513,6 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
                                 struct btrfs_block_group_cache *cache)
 {
        int ret;
-       int pending_ret;
        struct btrfs_root *extent_root = root->fs_info->extent_root;
        unsigned long bi;
        struct extent_buffer *leaf;
@@ -1831,12 +1528,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_release_path(extent_root, path);
 fail:
-       finish_current_insert(trans, extent_root, 0);
-       pending_ret = del_pending_extents(trans, extent_root, 0);
        if (ret)
                return ret;
-       if (pending_ret)
-               return pending_ret;
        return 0;
 
 }
@@ -1900,7 +1593,7 @@ int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
        if (!block_group || block_group->ro)
                readonly = 1;
        if (block_group)
-               put_block_group(block_group);
+               btrfs_put_block_group(block_group);
        return readonly;
 }
 
@@ -2324,7 +2017,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                                WARN_ON(ret);
                        }
                }
-               put_block_group(cache);
+               btrfs_put_block_group(cache);
                total -= num_bytes;
                bytenr += num_bytes;
        }
@@ -2341,7 +2034,7 @@ static u64 first_logical_byte(struct btrfs_root *root, u64 search_start)
                return 0;
 
        bytenr = cache->key.objectid;
-       put_block_group(cache);
+       btrfs_put_block_group(cache);
 
        return bytenr;
 }
@@ -2353,7 +2046,6 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
        struct btrfs_block_group_cache *cache;
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-       WARN_ON(!mutex_is_locked(&root->fs_info->pinned_mutex));
        if (pin) {
                set_extent_dirty(&fs_info->pinned_extents,
                                bytenr, bytenr + num - 1, GFP_NOFS);
@@ -2361,6 +2053,7 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
                clear_extent_dirty(&fs_info->pinned_extents,
                                bytenr, bytenr + num - 1, GFP_NOFS);
        }
+
        while (num > 0) {
                cache = btrfs_lookup_block_group(fs_info, bytenr);
                BUG_ON(!cache);
@@ -2385,7 +2078,7 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
                        if (cache->cached)
                                btrfs_add_free_space(cache, bytenr, len);
                }
-               put_block_group(cache);
+               btrfs_put_block_group(cache);
                bytenr += len;
                num -= len;
        }
@@ -2416,7 +2109,7 @@ static int update_reserved_extents(struct btrfs_root *root,
                }
                spin_unlock(&cache->lock);
                spin_unlock(&cache->space_info->lock);
-               put_block_group(cache);
+               btrfs_put_block_group(cache);
                bytenr += len;
                num -= len;
        }
@@ -2431,7 +2124,6 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy)
        struct extent_io_tree *pinned_extents = &root->fs_info->pinned_extents;
        int ret;
 
-       mutex_lock(&root->fs_info->pinned_mutex);
        while (1) {
                ret = find_first_extent_bit(pinned_extents, last,
                                            &start, &end, EXTENT_DIRTY);
@@ -2440,230 +2132,39 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy)
                set_extent_dirty(copy, start, end, GFP_NOFS);
                last = end + 1;
        }
-       mutex_unlock(&root->fs_info->pinned_mutex);
        return 0;
-}
-
-int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *root,
-                              struct extent_io_tree *unpin)
-{
-       u64 start;
-       u64 end;
-       int ret;
-
-       mutex_lock(&root->fs_info->pinned_mutex);
-       while (1) {
-               ret = find_first_extent_bit(unpin, 0, &start, &end,
-                                           EXTENT_DIRTY);
-               if (ret)
-                       break;
-
-               ret = btrfs_discard_extent(root, start, end + 1 - start);
-
-               btrfs_update_pinned_extents(root, start, end + 1 - start, 0);
-               clear_extent_dirty(unpin, start, end, GFP_NOFS);
-
-               if (need_resched()) {
-                       mutex_unlock(&root->fs_info->pinned_mutex);
-                       cond_resched();
-                       mutex_lock(&root->fs_info->pinned_mutex);
-               }
-       }
-       mutex_unlock(&root->fs_info->pinned_mutex);
-       return ret;
-}
-
-static int finish_current_insert(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *extent_root, int all)
-{
-       u64 start;
-       u64 end;
-       u64 priv;
-       u64 search = 0;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct btrfs_path *path;
-       struct pending_extent_op *extent_op, *tmp;
-       struct list_head insert_list, update_list;
-       int ret;
-       int num_inserts = 0, max_inserts, restart = 0;
-
-       path = btrfs_alloc_path();
-       INIT_LIST_HEAD(&insert_list);
-       INIT_LIST_HEAD(&update_list);
-
-       max_inserts = extent_root->leafsize /
-               (2 * sizeof(struct btrfs_key) + 2 * sizeof(struct btrfs_item) +
-                sizeof(struct btrfs_extent_ref) +
-                sizeof(struct btrfs_extent_item));
-again:
-       mutex_lock(&info->extent_ins_mutex);
-       while (1) {
-               ret = find_first_extent_bit(&info->extent_ins, search, &start,
-                                           &end, EXTENT_WRITEBACK);
-               if (ret) {
-                       if (restart && !num_inserts &&
-                           list_empty(&update_list)) {
-                               restart = 0;
-                               search = 0;
-                               continue;
-                       }
-                       break;
-               }
-
-               ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
-               if (!ret) {
-                       if (all)
-                               restart = 1;
-                       search = end + 1;
-                       if (need_resched()) {
-                               mutex_unlock(&info->extent_ins_mutex);
-                               cond_resched();
-                               mutex_lock(&info->extent_ins_mutex);
-                       }
-                       continue;
-               }
-
-               ret = get_state_private(&info->extent_ins, start, &priv);
-               BUG_ON(ret);
-               extent_op = (struct pending_extent_op *)(unsigned long) priv;
-
-               if (extent_op->type == PENDING_EXTENT_INSERT) {
-                       num_inserts++;
-                       list_add_tail(&extent_op->list, &insert_list);
-                       search = end + 1;
-                       if (num_inserts == max_inserts) {
-                               restart = 1;
-                               break;
-                       }
-               } else if (extent_op->type == PENDING_BACKREF_UPDATE) {
-                       list_add_tail(&extent_op->list, &update_list);
-                       search = end + 1;
-               } else {
-                       BUG();
-               }
-       }
-
-       /*
-        * process the update list, clear the writeback bit for it, and if
-        * somebody marked this thing for deletion then just unlock it and be
-        * done, the free_extents will handle it
-        */
-       list_for_each_entry_safe(extent_op, tmp, &update_list, list) {
-               clear_extent_bits(&info->extent_ins, extent_op->bytenr,
-                                 extent_op->bytenr + extent_op->num_bytes - 1,
-                                 EXTENT_WRITEBACK, GFP_NOFS);
-               if (extent_op->del) {
-                       list_del_init(&extent_op->list);
-                       unlock_extent(&info->extent_ins, extent_op->bytenr,
-                                     extent_op->bytenr + extent_op->num_bytes
-                                     - 1, GFP_NOFS);
-                       kfree(extent_op);
-               }
-       }
-       mutex_unlock(&info->extent_ins_mutex);
-
-       /*
-        * still have things left on the update list, go ahead an update
-        * everything
-        */
-       if (!list_empty(&update_list)) {
-               ret = update_backrefs(trans, extent_root, path, &update_list);
-               BUG_ON(ret);
+}
 
-               /* we may have COW'ed new blocks, so lets start over */
-               if (all)
-                       restart = 1;
-       }
+int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              struct extent_io_tree *unpin)
+{
+       u64 start;
+       u64 end;
+       int ret;
 
-       /*
-        * if no inserts need to be done, but we skipped some extents and we
-        * need to make sure everything is cleaned then reset everything and
-        * go back to the beginning
-        */
-       if (!num_inserts && restart) {
-               search = 0;
-               restart = 0;
-               INIT_LIST_HEAD(&update_list);
-               INIT_LIST_HEAD(&insert_list);
-               goto again;
-       } else if (!num_inserts) {
-               goto out;
-       }
+       while (1) {
+               ret = find_first_extent_bit(unpin, 0, &start, &end,
+                                           EXTENT_DIRTY);
+               if (ret)
+                       break;
 
-       /*
-        * process the insert extents list.  Again if we are deleting this
-        * extent, then just unlock it, pin down the bytes if need be, and be
-        * done with it.  Saves us from having to actually insert the extent
-        * into the tree and then subsequently come along and delete it
-        */
-       mutex_lock(&info->extent_ins_mutex);
-       list_for_each_entry_safe(extent_op, tmp, &insert_list, list) {
-               clear_extent_bits(&info->extent_ins, extent_op->bytenr,
-                                 extent_op->bytenr + extent_op->num_bytes - 1,
-                                 EXTENT_WRITEBACK, GFP_NOFS);
-               if (extent_op->del) {
-                       u64 used;
-                       list_del_init(&extent_op->list);
-                       unlock_extent(&info->extent_ins, extent_op->bytenr,
-                                     extent_op->bytenr + extent_op->num_bytes
-                                     - 1, GFP_NOFS);
-
-                       mutex_lock(&extent_root->fs_info->pinned_mutex);
-                       ret = pin_down_bytes(trans, extent_root,
-                                            extent_op->bytenr,
-                                            extent_op->num_bytes, 0);
-                       mutex_unlock(&extent_root->fs_info->pinned_mutex);
-
-                       spin_lock(&info->delalloc_lock);
-                       used = btrfs_super_bytes_used(&info->super_copy);
-                       btrfs_set_super_bytes_used(&info->super_copy,
-                                       used - extent_op->num_bytes);
-                       used = btrfs_root_used(&extent_root->root_item);
-                       btrfs_set_root_used(&extent_root->root_item,
-                                       used - extent_op->num_bytes);
-                       spin_unlock(&info->delalloc_lock);
-
-                       ret = update_block_group(trans, extent_root,
-                                                extent_op->bytenr,
-                                                extent_op->num_bytes,
-                                                0, ret > 0);
-                       BUG_ON(ret);
-                       kfree(extent_op);
-                       num_inserts--;
-               }
-       }
-       mutex_unlock(&info->extent_ins_mutex);
+               ret = btrfs_discard_extent(root, start, end + 1 - start);
 
-       ret = insert_extents(trans, extent_root, path, &insert_list,
-                            num_inserts);
-       BUG_ON(ret);
+               /* unlocks the pinned mutex */
+               btrfs_update_pinned_extents(root, start, end + 1 - start, 0);
+               clear_extent_dirty(unpin, start, end, GFP_NOFS);
 
-       /*
-        * if restart is set for whatever reason we need to go back and start
-        * searching through the pending list again.
-        *
-        * We just inserted some extents, which could have resulted in new
-        * blocks being allocated, which would result in new blocks needing
-        * updates, so if all is set we _must_ restart to get the updated
-        * blocks.
-        */
-       if (restart || all) {
-               INIT_LIST_HEAD(&insert_list);
-               INIT_LIST_HEAD(&update_list);
-               search = 0;
-               restart = 0;
-               num_inserts = 0;
-               goto again;
+               cond_resched();
        }
-out:
-       btrfs_free_path(path);
-       return 0;
+       return ret;
 }
 
 static int pin_down_bytes(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root,
-                         u64 bytenr, u64 num_bytes, int is_data)
+                         struct btrfs_path *path,
+                         u64 bytenr, u64 num_bytes, int is_data,
+                         struct extent_buffer **must_clean)
 {
        int err = 0;
        struct extent_buffer *buf;
@@ -2686,17 +2187,18 @@ static int pin_down_bytes(struct btrfs_trans_handle *trans,
                u64 header_transid = btrfs_header_generation(buf);
                if (header_owner != BTRFS_TREE_LOG_OBJECTID &&
                    header_owner != BTRFS_TREE_RELOC_OBJECTID &&
+                   header_owner != BTRFS_DATA_RELOC_TREE_OBJECTID &&
                    header_transid == trans->transid &&
                    !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
-                       clean_tree_block(NULL, root, buf);
-                       btrfs_tree_unlock(buf);
-                       free_extent_buffer(buf);
+                       *must_clean = buf;
                        return 1;
                }
                btrfs_tree_unlock(buf);
        }
        free_extent_buffer(buf);
 pinit:
+       btrfs_set_path_blocking(path);
+       /* unlocks the pinned mutex */
        btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
 
        BUG_ON(err < 0);
@@ -2710,7 +2212,8 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root,
                         u64 bytenr, u64 num_bytes, u64 parent,
                         u64 root_objectid, u64 ref_generation,
-                        u64 owner_objectid, int pin, int mark_free)
+                        u64 owner_objectid, int pin, int mark_free,
+                        int refs_to_drop)
 {
        struct btrfs_path *path;
        struct btrfs_key key;
@@ -2732,6 +2235,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        path->reada = 1;
+       path->leave_spinning = 1;
        ret = lookup_extent_backref(trans, extent_root, path,
                                    bytenr, parent, root_objectid,
                                    ref_generation, owner_objectid, 1);
@@ -2753,9 +2257,11 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                                break;
                }
                if (!found_extent) {
-                       ret = remove_extent_backref(trans, extent_root, path);
+                       ret = remove_extent_backref(trans, extent_root, path,
+                                                   refs_to_drop);
                        BUG_ON(ret);
                        btrfs_release_path(extent_root, path);
+                       path->leave_spinning = 1;
                        ret = btrfs_search_slot(trans, extent_root,
                                                &key, path, -1, 1);
                        if (ret) {
@@ -2771,8 +2277,9 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                btrfs_print_leaf(extent_root, path->nodes[0]);
                WARN_ON(1);
                printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
-                      "root %llu gen %llu owner %llu\n",
+                      "parent %llu root %llu gen %llu owner %llu\n",
                       (unsigned long long)bytenr,
+                      (unsigned long long)parent,
                       (unsigned long long)root_objectid,
                       (unsigned long long)ref_generation,
                       (unsigned long long)owner_objectid);
@@ -2782,17 +2289,23 @@ static int __free_extent(struct btrfs_trans_handle *trans,
        ei = btrfs_item_ptr(leaf, extent_slot,
                            struct btrfs_extent_item);
        refs = btrfs_extent_refs(leaf, ei);
-       BUG_ON(refs == 0);
-       refs -= 1;
-       btrfs_set_extent_refs(leaf, ei, refs);
 
+       /*
+        * we're not allowed to delete the extent item if there
+        * are other delayed ref updates pending
+        */
+
+       BUG_ON(refs < refs_to_drop);
+       refs -= refs_to_drop;
+       btrfs_set_extent_refs(leaf, ei, refs);
        btrfs_mark_buffer_dirty(leaf);
 
-       if (refs == 0 && found_extent && path->slots[0] == extent_slot + 1) {
+       if (refs == 0 && found_extent &&
+           path->slots[0] == extent_slot + 1) {
                struct btrfs_extent_ref *ref;
                ref = btrfs_item_ptr(leaf, path->slots[0],
                                     struct btrfs_extent_ref);
-               BUG_ON(btrfs_ref_num_refs(leaf, ref) != 1);
+               BUG_ON(btrfs_ref_num_refs(leaf, ref) != refs_to_drop);
                /* if the back ref and the extent are next to each other
                 * they get deleted below in one shot
                 */
@@ -2800,11 +2313,13 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                num_to_del = 2;
        } else if (found_extent) {
                /* otherwise delete the extent back ref */
-               ret = remove_extent_backref(trans, extent_root, path);
+               ret = remove_extent_backref(trans, extent_root, path,
+                                           refs_to_drop);
                BUG_ON(ret);
                /* if refs are 0, we need to setup the path for deletion */
                if (refs == 0) {
                        btrfs_release_path(extent_root, path);
+                       path->leave_spinning = 1;
                        ret = btrfs_search_slot(trans, extent_root, &key, path,
                                                -1, 1);
                        BUG_ON(ret);
@@ -2814,16 +2329,18 @@ static int __free_extent(struct btrfs_trans_handle *trans,
        if (refs == 0) {
                u64 super_used;
                u64 root_used;
+               struct extent_buffer *must_clean = NULL;
 
                if (pin) {
-                       mutex_lock(&root->fs_info->pinned_mutex);
-                       ret = pin_down_bytes(trans, root, bytenr, num_bytes,
-                               owner_objectid >= BTRFS_FIRST_FREE_OBJECTID);
-                       mutex_unlock(&root->fs_info->pinned_mutex);
+                       ret = pin_down_bytes(trans, root, path,
+                               bytenr, num_bytes,
+                               owner_objectid >= BTRFS_FIRST_FREE_OBJECTID,
+                               &must_clean);
                        if (ret > 0)
                                mark_free = 1;
                        BUG_ON(ret < 0);
                }
+
                /* block accounting for super block */
                spin_lock(&info->delalloc_lock);
                super_used = btrfs_super_bytes_used(&info->super_copy);
@@ -2835,14 +2352,34 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                btrfs_set_root_used(&root->root_item,
                                           root_used - num_bytes);
                spin_unlock(&info->delalloc_lock);
+
+               /*
+                * it is going to be very rare for someone to be waiting
+                * on the block we're freeing.  del_items might need to
+                * schedule, so rather than get fancy, just force it
+                * to blocking here
+                */
+               if (must_clean)
+                       btrfs_set_lock_blocking(must_clean);
+
                ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
                                      num_to_del);
                BUG_ON(ret);
                btrfs_release_path(extent_root, path);
 
+               if (must_clean) {
+                       clean_tree_block(NULL, root, must_clean);
+                       btrfs_tree_unlock(must_clean);
+                       free_extent_buffer(must_clean);
+               }
+
                if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
                        ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
                        BUG_ON(ret);
+               } else {
+                       invalidate_mapping_pages(info->btree_inode->i_mapping,
+                            bytenr >> PAGE_CACHE_SHIFT,
+                            (bytenr + num_bytes - 1) >> PAGE_CACHE_SHIFT);
                }
 
                ret = update_block_group(trans, root, bytenr, num_bytes, 0,
@@ -2850,218 +2387,103 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                BUG_ON(ret);
        }
        btrfs_free_path(path);
-       finish_current_insert(trans, extent_root, 0);
        return ret;
 }
 
 /*
- * find all the blocks marked as pending in the radix tree and remove
- * them from the extent map
+ * remove an extent from the root, returns 0 on success
  */
-static int del_pending_extents(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *extent_root, int all)
+static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       u64 bytenr, u64 num_bytes, u64 parent,
+                                       u64 root_objectid, u64 ref_generation,
+                                       u64 owner_objectid, int pin,
+                                       int refs_to_drop)
 {
-       int ret;
-       int err = 0;
-       u64 start;
-       u64 end;
-       u64 priv;
-       u64 search = 0;
-       int nr = 0, skipped = 0;
-       struct extent_io_tree *pending_del;
-       struct extent_io_tree *extent_ins;
-       struct pending_extent_op *extent_op;
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct list_head delete_list;
-
-       INIT_LIST_HEAD(&delete_list);
-       extent_ins = &extent_root->fs_info->extent_ins;
-       pending_del = &extent_root->fs_info->pending_del;
-
-again:
-       mutex_lock(&info->extent_ins_mutex);
-       while (1) {
-               ret = find_first_extent_bit(pending_del, search, &start, &end,
-                                           EXTENT_WRITEBACK);
-               if (ret) {
-                       if (all && skipped && !nr) {
-                               search = 0;
-                               skipped = 0;
-                               continue;
-                       }
-                       mutex_unlock(&info->extent_ins_mutex);
-                       break;
-               }
-
-               ret = try_lock_extent(extent_ins, start, end, GFP_NOFS);
-               if (!ret) {
-                       search = end+1;
-                       skipped = 1;
-
-                       if (need_resched()) {
-                               mutex_unlock(&info->extent_ins_mutex);
-                               cond_resched();
-                               mutex_lock(&info->extent_ins_mutex);
-                       }
-
-                       continue;
-               }
-               BUG_ON(ret < 0);
-
-               ret = get_state_private(pending_del, start, &priv);
-               BUG_ON(ret);
-               extent_op = (struct pending_extent_op *)(unsigned long)priv;
-
-               clear_extent_bits(pending_del, start, end, EXTENT_WRITEBACK,
-                                 GFP_NOFS);
-               if (!test_range_bit(extent_ins, start, end,
-                                   EXTENT_WRITEBACK, 0)) {
-                       list_add_tail(&extent_op->list, &delete_list);
-                       nr++;
-               } else {
-                       kfree(extent_op);
-
-                       ret = get_state_private(&info->extent_ins, start,
-                                               &priv);
-                       BUG_ON(ret);
-                       extent_op = (struct pending_extent_op *)
-                                               (unsigned long)priv;
-
-                       clear_extent_bits(&info->extent_ins, start, end,
-                                         EXTENT_WRITEBACK, GFP_NOFS);
-
-                       if (extent_op->type == PENDING_BACKREF_UPDATE) {
-                               list_add_tail(&extent_op->list, &delete_list);
-                               search = end + 1;
-                               nr++;
-                               continue;
-                       }
-
-                       mutex_lock(&extent_root->fs_info->pinned_mutex);
-                       ret = pin_down_bytes(trans, extent_root, start,
-                                            end + 1 - start, 0);
-                       mutex_unlock(&extent_root->fs_info->pinned_mutex);
-
-                       ret = update_block_group(trans, extent_root, start,
-                                               end + 1 - start, 0, ret > 0);
-
-                       unlock_extent(extent_ins, start, end, GFP_NOFS);
-                       BUG_ON(ret);
-                       kfree(extent_op);
-               }
-               if (ret)
-                       err = ret;
-
-               search = end + 1;
-
-               if (need_resched()) {
-                       mutex_unlock(&info->extent_ins_mutex);
-                       cond_resched();
-                       mutex_lock(&info->extent_ins_mutex);
-               }
-       }
+       WARN_ON(num_bytes < root->sectorsize);
 
-       if (nr) {
-               ret = free_extents(trans, extent_root, &delete_list);
-               BUG_ON(ret);
-       }
+       /*
+        * if metadata always pin
+        * if data pin when any transaction has committed this
+        */
+       if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID ||
+           ref_generation != trans->transid)
+               pin = 1;
 
-       if (all && skipped) {
-               INIT_LIST_HEAD(&delete_list);
-               search = 0;
-               nr = 0;
-               goto again;
-       }
+       if (ref_generation != trans->transid)
+               pin = 1;
 
-       if (!err)
-               finish_current_insert(trans, extent_root, 0);
-       return err;
+       return __free_extent(trans, root, bytenr, num_bytes, parent,
+                           root_objectid, ref_generation,
+                           owner_objectid, pin, pin == 0, refs_to_drop);
 }
 
 /*
- * remove an extent from the root, returns 0 on success
+ * when we free an extent, it is possible (and likely) that we free the last
+ * delayed ref for that extent as well.  This searches the delayed ref tree for
+ * a given extent, and if there are no other delayed refs to be processed, it
+ * removes it from the tree.
  */
-static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *root,
-                              u64 bytenr, u64 num_bytes, u64 parent,
-                              u64 root_objectid, u64 ref_generation,
-                              u64 owner_objectid, int pin)
+static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
+                                     struct btrfs_root *root, u64 bytenr)
 {
-       struct btrfs_root *extent_root = root->fs_info->extent_root;
-       int pending_ret;
+       struct btrfs_delayed_ref_head *head;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_delayed_ref_node *ref;
+       struct rb_node *node;
        int ret;
 
-       WARN_ON(num_bytes < root->sectorsize);
-       if (root == extent_root) {
-               struct pending_extent_op *extent_op = NULL;
-
-               mutex_lock(&root->fs_info->extent_ins_mutex);
-               if (test_range_bit(&root->fs_info->extent_ins, bytenr,
-                               bytenr + num_bytes - 1, EXTENT_WRITEBACK, 0)) {
-                       u64 priv;
-                       ret = get_state_private(&root->fs_info->extent_ins,
-                                               bytenr, &priv);
-                       BUG_ON(ret);
-                       extent_op = (struct pending_extent_op *)
-                                               (unsigned long)priv;
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+       head = btrfs_find_delayed_ref_head(trans, bytenr);
+       if (!head)
+               goto out;
 
-                       extent_op->del = 1;
-                       if (extent_op->type == PENDING_EXTENT_INSERT) {
-                               mutex_unlock(&root->fs_info->extent_ins_mutex);
-                               return 0;
-                       }
-               }
+       node = rb_prev(&head->node.rb_node);
+       if (!node)
+               goto out;
 
-               if (extent_op) {
-                       ref_generation = extent_op->orig_generation;
-                       parent = extent_op->orig_parent;
-               }
+       ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
 
-               extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-               BUG_ON(!extent_op);
-
-               extent_op->type = PENDING_EXTENT_DELETE;
-               extent_op->bytenr = bytenr;
-               extent_op->num_bytes = num_bytes;
-               extent_op->parent = parent;
-               extent_op->orig_parent = parent;
-               extent_op->generation = ref_generation;
-               extent_op->orig_generation = ref_generation;
-               extent_op->level = (int)owner_objectid;
-               INIT_LIST_HEAD(&extent_op->list);
-               extent_op->del = 0;
-
-               set_extent_bits(&root->fs_info->pending_del,
-                               bytenr, bytenr + num_bytes - 1,
-                               EXTENT_WRITEBACK, GFP_NOFS);
-               set_state_private(&root->fs_info->pending_del,
-                                 bytenr, (unsigned long)extent_op);
-               mutex_unlock(&root->fs_info->extent_ins_mutex);
-               return 0;
-       }
-       /* if metadata always pin */
-       if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID) {
-               if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
-                       mutex_lock(&root->fs_info->pinned_mutex);
-                       btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
-                       mutex_unlock(&root->fs_info->pinned_mutex);
-                       update_reserved_extents(root, bytenr, num_bytes, 0);
-                       return 0;
-               }
-               pin = 1;
-       }
+       /* there are still entries for this ref, we can't drop it */
+       if (ref->bytenr == bytenr)
+               goto out;
 
-       /* if data pin when any transaction has committed this */
-       if (ref_generation != trans->transid)
-               pin = 1;
+       /*
+        * waiting for the lock here would deadlock.  If someone else has it
+        * locked they are already in the process of dropping it anyway
+        */
+       if (!mutex_trylock(&head->mutex))
+               goto out;
 
-       ret = __free_extent(trans, root, bytenr, num_bytes, parent,
-                           root_objectid, ref_generation,
-                           owner_objectid, pin, pin == 0);
+       /*
+        * at this point we have a head with no other entries.  Go
+        * ahead and process it.
+        */
+       head->node.in_tree = 0;
+       rb_erase(&head->node.rb_node, &delayed_refs->root);
+
+       delayed_refs->num_entries--;
+
+       /*
+        * we don't take a ref on the node because we're removing it from the
+        * tree, so we just steal the ref the tree was holding.
+        */
+       delayed_refs->num_heads--;
+       if (list_empty(&head->cluster))
+               delayed_refs->num_heads_ready--;
+
+       list_del_init(&head->cluster);
+       spin_unlock(&delayed_refs->lock);
 
-       finish_current_insert(trans, root->fs_info->extent_root, 0);
-       pending_ret = del_pending_extents(trans, root->fs_info->extent_root, 0);
-       return ret ? ret : pending_ret;
+       ret = run_one_delayed_ref(trans, root->fs_info->tree_root,
+                                 &head->node, head->must_insert_reserved);
+       BUG_ON(ret);
+       btrfs_put_delayed_ref(&head->node);
+       return 0;
+out:
+       spin_unlock(&delayed_refs->lock);
+       return 0;
 }
 
 int btrfs_free_extent(struct btrfs_trans_handle *trans,
@@ -3072,9 +2494,28 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
 {
        int ret;
 
-       ret = __btrfs_free_extent(trans, root, bytenr, num_bytes, parent,
-                                 root_objectid, ref_generation,
-                                 owner_objectid, pin);
+       /*
+        * tree log blocks never actually go into the extent allocation
+        * tree, just update pinning info and exit early.
+        *
+        * data extents referenced by the tree log do need to have
+        * their reference counts bumped.
+        */
+       if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID &&
+           owner_objectid < BTRFS_FIRST_FREE_OBJECTID) {
+               /* unlocks the pinned mutex */
+               btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
+               update_reserved_extents(root, bytenr, num_bytes, 0);
+               ret = 0;
+       } else {
+               ret = btrfs_add_delayed_ref(trans, bytenr, num_bytes, parent,
+                                      root_objectid, ref_generation,
+                                      owner_objectid,
+                                      BTRFS_DROP_DELAYED_REF, 1);
+               BUG_ON(ret);
+               ret = check_ref_cleanup(trans, root, bytenr);
+               BUG_ON(ret);
+       }
        return ret;
 }
 
@@ -3103,228 +2544,237 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
 {
        int ret = 0;
        struct btrfs_root *root = orig_root->fs_info->extent_root;
-       u64 total_needed = num_bytes;
-       u64 *last_ptr = NULL;
-       u64 last_wanted = 0;
+       struct btrfs_free_cluster *last_ptr = NULL;
        struct btrfs_block_group_cache *block_group = NULL;
-       int chunk_alloc_done = 0;
        int empty_cluster = 2 * 1024 * 1024;
        int allowed_chunk_alloc = 0;
-       struct list_head *head = NULL, *cur = NULL;
-       int loop = 0;
-       int extra_loop = 0;
        struct btrfs_space_info *space_info;
+       int last_ptr_loop = 0;
+       int loop = 0;
 
        WARN_ON(num_bytes < root->sectorsize);
        btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
        ins->objectid = 0;
        ins->offset = 0;
 
+       space_info = __find_space_info(root->fs_info, data);
+
        if (orig_root->ref_cows || empty_size)
                allowed_chunk_alloc = 1;
 
        if (data & BTRFS_BLOCK_GROUP_METADATA) {
-               last_ptr = &root->fs_info->last_alloc;
+               last_ptr = &root->fs_info->meta_alloc_cluster;
                if (!btrfs_test_opt(root, SSD))
                        empty_cluster = 64 * 1024;
        }
 
-       if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD))
-               last_ptr = &root->fs_info->last_data_alloc;
+       if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD)) {
+               last_ptr = &root->fs_info->data_alloc_cluster;
+       }
 
        if (last_ptr) {
-               if (*last_ptr) {
-                       hint_byte = *last_ptr;
-                       last_wanted = *last_ptr;
-               } else
-                       empty_size += empty_cluster;
-       } else {
-               empty_cluster = 0;
+               spin_lock(&last_ptr->lock);
+               if (last_ptr->block_group)
+                       hint_byte = last_ptr->window_start;
+               spin_unlock(&last_ptr->lock);
        }
+
        search_start = max(search_start, first_logical_byte(root, 0));
        search_start = max(search_start, hint_byte);
 
-       if (last_wanted && search_start != last_wanted) {
-               last_wanted = 0;
-               empty_size += empty_cluster;
+       if (!last_ptr) {
+               empty_cluster = 0;
+               loop = 1;
        }
 
-       total_needed += empty_size;
-       block_group = btrfs_lookup_block_group(root->fs_info, search_start);
-       if (!block_group)
-               block_group = btrfs_lookup_first_block_group(root->fs_info,
-                                                            search_start);
-       space_info = __find_space_info(root->fs_info, data);
+       if (search_start == hint_byte) {
+               block_group = btrfs_lookup_block_group(root->fs_info,
+                                                      search_start);
+               if (block_group && block_group_bits(block_group, data)) {
+                       down_read(&space_info->groups_sem);
+                       goto have_block_group;
+               } else if (block_group) {
+                       btrfs_put_block_group(block_group);
+               }
+       }
 
+search:
        down_read(&space_info->groups_sem);
-       while (1) {
-               struct btrfs_free_space *free_space;
-               /*
-                * the only way this happens if our hint points to a block
-                * group thats not of the proper type, while looping this
-                * should never happen
-                */
-               if (empty_size)
-                       extra_loop = 1;
+       list_for_each_entry(block_group, &space_info->block_groups, list) {
+               u64 offset;
 
-               if (!block_group)
-                       goto new_group_no_lock;
+               atomic_inc(&block_group->count);
+               search_start = block_group->key.objectid;
 
+have_block_group:
                if (unlikely(!block_group->cached)) {
                        mutex_lock(&block_group->cache_mutex);
                        ret = cache_block_group(root, block_group);
                        mutex_unlock(&block_group->cache_mutex);
-                       if (ret)
+                       if (ret) {
+                               btrfs_put_block_group(block_group);
                                break;
+                       }
                }
 
-               mutex_lock(&block_group->alloc_mutex);
-               if (unlikely(!block_group_bits(block_group, data)))
-                       goto new_group;
-
                if (unlikely(block_group->ro))
-                       goto new_group;
+                       goto loop;
 
-               free_space = btrfs_find_free_space(block_group, search_start,
-                                                  total_needed);
-               if (free_space) {
-                       u64 start = block_group->key.objectid;
-                       u64 end = block_group->key.objectid +
-                               block_group->key.offset;
+               if (last_ptr) {
+                       /*
+                        * the refill lock keeps out other
+                        * people trying to start a new cluster
+                        */
+                       spin_lock(&last_ptr->refill_lock);
+                       offset = btrfs_alloc_from_cluster(block_group, last_ptr,
+                                                num_bytes, search_start);
+                       if (offset) {
+                               /* we have a block, we're done */
+                               spin_unlock(&last_ptr->refill_lock);
+                               goto checks;
+                       }
 
-                       search_start = stripe_align(root, free_space->offset);
+                       spin_lock(&last_ptr->lock);
+                       /*
+                        * whoops, this cluster doesn't actually point to
+                        * this block group.  Get a ref on the block
+                        * group is does point to and try again
+                        */
+                       if (!last_ptr_loop && last_ptr->block_group &&
+                           last_ptr->block_group != block_group) {
+
+                               btrfs_put_block_group(block_group);
+                               block_group = last_ptr->block_group;
+                               atomic_inc(&block_group->count);
+                               spin_unlock(&last_ptr->lock);
+                               spin_unlock(&last_ptr->refill_lock);
+
+                               last_ptr_loop = 1;
+                               search_start = block_group->key.objectid;
+                               goto have_block_group;
+                       }
+                       spin_unlock(&last_ptr->lock);
 
-                       /* move on to the next group */
-                       if (search_start + num_bytes >= search_end)
-                               goto new_group;
+                       /*
+                        * this cluster didn't work out, free it and
+                        * start over
+                        */
+                       btrfs_return_cluster_to_free_space(NULL, last_ptr);
 
-                       /* move on to the next group */
-                       if (search_start + num_bytes > end)
-                               goto new_group;
+                       last_ptr_loop = 0;
 
-                       if (last_wanted && search_start != last_wanted) {
-                               total_needed += empty_cluster;
-                               empty_size += empty_cluster;
-                               last_wanted = 0;
+                       /* allocate a cluster in this block group */
+                       ret = btrfs_find_space_cluster(trans,
+                                              block_group, last_ptr,
+                                              offset, num_bytes,
+                                              empty_cluster + empty_size);
+                       if (ret == 0) {
                                /*
-                                * if search_start is still in this block group
-                                * then we just re-search this block group
+                                * now pull our allocation out of this
+                                * cluster
                                 */
-                               if (search_start >= start &&
-                                   search_start < end) {
-                                       mutex_unlock(&block_group->alloc_mutex);
-                                       continue;
+                               offset = btrfs_alloc_from_cluster(block_group,
+                                                 last_ptr, num_bytes,
+                                                 search_start);
+                               if (offset) {
+                                       /* we found one, proceed */
+                                       spin_unlock(&last_ptr->refill_lock);
+                                       goto checks;
                                }
-
-                               /* else we go to the next block group */
-                               goto new_group;
                        }
-
-                       if (exclude_nr > 0 &&
-                           (search_start + num_bytes > exclude_start &&
-                            search_start < exclude_start + exclude_nr)) {
-                               search_start = exclude_start + exclude_nr;
-                               /*
-                                * if search_start is still in this block group
-                                * then we just re-search this block group
-                                */
-                               if (search_start >= start &&
-                                   search_start < end) {
-                                       mutex_unlock(&block_group->alloc_mutex);
-                                       last_wanted = 0;
-                                       continue;
-                               }
-
-                               /* else we go to the next block group */
-                               goto new_group;
+                       /*
+                        * at this point we either didn't find a cluster
+                        * or we weren't able to allocate a block from our
+                        * cluster.  Free the cluster we've been trying
+                        * to use, and go to the next block group
+                        */
+                       if (loop < 2) {
+                               btrfs_return_cluster_to_free_space(NULL,
+                                                                  last_ptr);
+                               spin_unlock(&last_ptr->refill_lock);
+                               goto loop;
                        }
+                       spin_unlock(&last_ptr->refill_lock);
+               }
 
-                       ins->objectid = search_start;
-                       ins->offset = num_bytes;
+               offset = btrfs_find_space_for_alloc(block_group, search_start,
+                                                   num_bytes, empty_size);
+               if (!offset)
+                       goto loop;
+checks:
+               search_start = stripe_align(root, offset);
 
-                       btrfs_remove_free_space_lock(block_group, search_start,
-                                                    num_bytes);
-                       /* we are all good, lets return */
-                       mutex_unlock(&block_group->alloc_mutex);
-                       break;
+               /* move on to the next group */
+               if (search_start + num_bytes >= search_end) {
+                       btrfs_add_free_space(block_group, offset, num_bytes);
+                       goto loop;
                }
-new_group:
-               mutex_unlock(&block_group->alloc_mutex);
-               put_block_group(block_group);
-               block_group = NULL;
-new_group_no_lock:
-               /* don't try to compare new allocations against the
-                * last allocation any more
-                */
-               last_wanted = 0;
 
-               /*
-                * Here's how this works.
-                * loop == 0: we were searching a block group via a hint
-                *              and didn't find anything, so we start at
-                *              the head of the block groups and keep searching
-                * loop == 1: we're searching through all of the block groups
-                *              if we hit the head again we have searched
-                *              all of the block groups for this space and we
-                *              need to try and allocate, if we cant error out.
-                * loop == 2: we allocated more space and are looping through
-                *              all of the block groups again.
-                */
-               if (loop == 0) {
-                       head = &space_info->block_groups;
-                       cur = head->next;
-                       loop++;
-               } else if (loop == 1 && cur == head) {
-                       int keep_going;
-
-                       /* at this point we give up on the empty_size
-                        * allocations and just try to allocate the min
-                        * space.
-                        *
-                        * The extra_loop field was set if an empty_size
-                        * allocation was attempted above, and if this
-                        * is try we need to try the loop again without
-                        * the additional empty_size.
+               /* move on to the next group */
+               if (search_start + num_bytes >
+                   block_group->key.objectid + block_group->key.offset) {
+                       btrfs_add_free_space(block_group, offset, num_bytes);
+                       goto loop;
+               }
+
+               if (exclude_nr > 0 &&
+                   (search_start + num_bytes > exclude_start &&
+                    search_start < exclude_start + exclude_nr)) {
+                       search_start = exclude_start + exclude_nr;
+
+                       btrfs_add_free_space(block_group, offset, num_bytes);
+                       /*
+                        * if search_start is still in this block group
+                        * then we just re-search this block group
                         */
-                       total_needed -= empty_size;
-                       empty_size = 0;
-                       keep_going = extra_loop;
-                       loop++;
+                       if (search_start >= block_group->key.objectid &&
+                           search_start < (block_group->key.objectid +
+                                           block_group->key.offset))
+                               goto have_block_group;
+                       goto loop;
+               }
 
-                       if (allowed_chunk_alloc && !chunk_alloc_done) {
-                               up_read(&space_info->groups_sem);
-                               ret = do_chunk_alloc(trans, root, num_bytes +
-                                                    2 * 1024 * 1024, data, 1);
-                               down_read(&space_info->groups_sem);
-                               if (ret < 0)
-                                       goto loop_check;
-                               head = &space_info->block_groups;
-                               /*
-                                * we've allocated a new chunk, keep
-                                * trying
-                                */
-                               keep_going = 1;
-                               chunk_alloc_done = 1;
-                       } else if (!allowed_chunk_alloc) {
-                               space_info->force_alloc = 1;
-                       }
-loop_check:
-                       if (keep_going) {
-                               cur = head->next;
-                               extra_loop = 0;
-                       } else {
-                               break;
-                       }
-               } else if (cur == head) {
-                       break;
+               ins->objectid = search_start;
+               ins->offset = num_bytes;
+
+               if (offset < search_start)
+                       btrfs_add_free_space(block_group, offset,
+                                            search_start - offset);
+               BUG_ON(offset > search_start);
+
+               /* we are all good, lets return */
+               break;
+loop:
+               btrfs_put_block_group(block_group);
+       }
+       up_read(&space_info->groups_sem);
+
+       /* loop == 0, try to find a clustered alloc in every block group
+        * loop == 1, try again after forcing a chunk allocation
+        * loop == 2, set empty_size and empty_cluster to 0 and try again
+        */
+       if (!ins->objectid && loop < 3 &&
+           (empty_size || empty_cluster || allowed_chunk_alloc)) {
+               if (loop >= 2) {
+                       empty_size = 0;
+                       empty_cluster = 0;
                }
 
-               block_group = list_entry(cur, struct btrfs_block_group_cache,
-                                        list);
-               atomic_inc(&block_group->count);
+               if (allowed_chunk_alloc) {
+                       ret = do_chunk_alloc(trans, root, num_bytes +
+                                            2 * 1024 * 1024, data, 1);
+                       allowed_chunk_alloc = 0;
+               } else {
+                       space_info->force_alloc = 1;
+               }
 
-               search_start = block_group->key.objectid;
-               cur = cur->next;
+               if (loop < 3) {
+                       loop++;
+                       goto search;
+               }
+               ret = -ENOSPC;
+       } else if (!ins->objectid) {
+               ret = -ENOSPC;
        }
 
        /* we found what we needed */
@@ -3332,21 +2782,10 @@ loop_check:
                if (!(data & BTRFS_BLOCK_GROUP_DATA))
                        trans->block_group = block_group->key.objectid;
 
-               if (last_ptr)
-                       *last_ptr = ins->objectid + ins->offset;
+               btrfs_put_block_group(block_group);
                ret = 0;
-       } else if (!ret) {
-               printk(KERN_ERR "btrfs searching for %llu bytes, "
-                      "num_bytes %llu, loop %d, allowed_alloc %d\n",
-                      (unsigned long long)total_needed,
-                      (unsigned long long)num_bytes,
-                      loop, allowed_chunk_alloc);
-               ret = -ENOSPC;
        }
-       if (block_group)
-               put_block_group(block_group);
 
-       up_read(&space_info->groups_sem);
        return ret;
 }
 
@@ -3451,7 +2890,7 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
        ret = btrfs_discard_extent(root, start, len);
 
        btrfs_add_free_space(cache, start, len);
-       put_block_group(cache);
+       btrfs_put_block_group(cache);
        update_reserved_extents(root, start, len, 0);
 
        return ret;
@@ -3475,10 +2914,10 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
 static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
                                         struct btrfs_root *root, u64 parent,
                                         u64 root_objectid, u64 ref_generation,
-                                        u64 owner, struct btrfs_key *ins)
+                                        u64 owner, struct btrfs_key *ins,
+                                        int ref_mod)
 {
        int ret;
-       int pending_ret;
        u64 super_used;
        u64 root_used;
        u64 num_bytes = ins->offset;
@@ -3503,33 +2942,6 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
        btrfs_set_root_used(&root->root_item, root_used + num_bytes);
        spin_unlock(&info->delalloc_lock);
 
-       if (root == extent_root) {
-               struct pending_extent_op *extent_op;
-
-               extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-               BUG_ON(!extent_op);
-
-               extent_op->type = PENDING_EXTENT_INSERT;
-               extent_op->bytenr = ins->objectid;
-               extent_op->num_bytes = ins->offset;
-               extent_op->parent = parent;
-               extent_op->orig_parent = 0;
-               extent_op->generation = ref_generation;
-               extent_op->orig_generation = 0;
-               extent_op->level = (int)owner;
-               INIT_LIST_HEAD(&extent_op->list);
-               extent_op->del = 0;
-
-               mutex_lock(&root->fs_info->extent_ins_mutex);
-               set_extent_bits(&root->fs_info->extent_ins, ins->objectid,
-                               ins->objectid + ins->offset - 1,
-                               EXTENT_WRITEBACK, GFP_NOFS);
-               set_state_private(&root->fs_info->extent_ins,
-                                 ins->objectid, (unsigned long)extent_op);
-               mutex_unlock(&root->fs_info->extent_ins_mutex);
-               goto update_block;
-       }
-
        memcpy(&keys[0], ins, sizeof(*ins));
        keys[1].objectid = ins->objectid;
        keys[1].type = BTRFS_EXTENT_REF_KEY;
@@ -3540,37 +2952,31 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_items(trans, extent_root, path, keys,
                                       sizes, 2);
        BUG_ON(ret);
 
        extent_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
                                     struct btrfs_extent_item);
-       btrfs_set_extent_refs(path->nodes[0], extent_item, 1);
+       btrfs_set_extent_refs(path->nodes[0], extent_item, ref_mod);
        ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
                             struct btrfs_extent_ref);
 
        btrfs_set_ref_root(path->nodes[0], ref, root_objectid);
        btrfs_set_ref_generation(path->nodes[0], ref, ref_generation);
        btrfs_set_ref_objectid(path->nodes[0], ref, owner);
-       btrfs_set_ref_num_refs(path->nodes[0], ref, 1);
+       btrfs_set_ref_num_refs(path->nodes[0], ref, ref_mod);
 
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
        trans->alloc_exclude_start = 0;
        trans->alloc_exclude_nr = 0;
        btrfs_free_path(path);
-       finish_current_insert(trans, extent_root, 0);
-       pending_ret = del_pending_extents(trans, extent_root, 0);
 
        if (ret)
                goto out;
-       if (pending_ret) {
-               ret = pending_ret;
-               goto out;
-       }
 
-update_block:
        ret = update_block_group(trans, root, ins->objectid,
                                 ins->offset, 1, 0);
        if (ret) {
@@ -3592,9 +2998,12 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
 
        if (root_objectid == BTRFS_TREE_LOG_OBJECTID)
                return 0;
-       ret = __btrfs_alloc_reserved_extent(trans, root, parent, root_objectid,
-                                           ref_generation, owner, ins);
-       update_reserved_extents(root, ins->objectid, ins->offset, 0);
+
+       ret = btrfs_add_delayed_ref(trans, ins->objectid,
+                                   ins->offset, parent, root_objectid,
+                                   ref_generation, owner,
+                                   BTRFS_ADD_DELAYED_EXTENT, 0);
+       BUG_ON(ret);
        return ret;
 }
 
@@ -3619,9 +3028,9 @@ int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans,
        ret = btrfs_remove_free_space(block_group, ins->objectid,
                                      ins->offset);
        BUG_ON(ret);
-       put_block_group(block_group);
+       btrfs_put_block_group(block_group);
        ret = __btrfs_alloc_reserved_extent(trans, root, parent, root_objectid,
-                                           ref_generation, owner, ins);
+                                           ref_generation, owner, ins, 1);
        return ret;
 }
 
@@ -3640,20 +3049,18 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
                       u64 search_end, struct btrfs_key *ins, u64 data)
 {
        int ret;
-
        ret = __btrfs_reserve_extent(trans, root, num_bytes,
                                     min_alloc_size, empty_size, hint_byte,
                                     search_end, ins, data);
        BUG_ON(ret);
        if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
-               ret = __btrfs_alloc_reserved_extent(trans, root, parent,
-                                       root_objectid, ref_generation,
-                                       owner_objectid, ins);
+               ret = btrfs_add_delayed_ref(trans, ins->objectid,
+                                           ins->offset, parent, root_objectid,
+                                           ref_generation, owner_objectid,
+                                           BTRFS_ADD_DELAYED_EXTENT, 0);
                BUG_ON(ret);
-
-       } else {
-               update_reserved_extents(root, ins->objectid, ins->offset, 1);
        }
+       update_reserved_extents(root, ins->objectid, ins->offset, 1);
        return ret;
 }
 
@@ -3789,7 +3196,7 @@ int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
 
                fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
 
-               ret = __btrfs_free_extent(trans, root, disk_bytenr,
+               ret = btrfs_free_extent(trans, root, disk_bytenr,
                                btrfs_file_extent_disk_num_bytes(leaf, fi),
                                leaf->start, leaf_owner, leaf_generation,
                                key.objectid, 0);
@@ -3829,7 +3236,7 @@ static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
         */
        for (i = 0; i < ref->nritems; i++) {
                info = ref->extents + sorted[i].slot;
-               ret = __btrfs_free_extent(trans, root, info->bytenr,
+               ret = btrfs_free_extent(trans, root, info->bytenr,
                                          info->num_bytes, ref->bytenr,
                                          ref->owner, ref->generation,
                                          info->objectid, 0);
@@ -3846,12 +3253,13 @@ static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-static int drop_snap_lookup_refcount(struct btrfs_root *root, u64 start,
+static int drop_snap_lookup_refcount(struct btrfs_trans_handle *trans,
+                                    struct btrfs_root *root, u64 start,
                                     u64 len, u32 *refs)
 {
        int ret;
 
-       ret = btrfs_lookup_extent_ref(NULL, root, start, len, refs);
+       ret = btrfs_lookup_extent_ref(trans, root, start, len, refs);
        BUG_ON(ret);
 
 #if 0 /* some debugging code in case we see problems here */
@@ -3959,7 +3367,8 @@ static noinline int drop_level_one_refs(struct btrfs_trans_handle *trans,
                 * we just decrement it below and don't update any
                 * of the refs the leaf points to.
                 */
-               ret = drop_snap_lookup_refcount(root, bytenr, blocksize, &refs);
+               ret = drop_snap_lookup_refcount(trans, root, bytenr,
+                                               blocksize, &refs);
                BUG_ON(ret);
                if (refs != 1)
                        continue;
@@ -4010,7 +3419,7 @@ static noinline int drop_level_one_refs(struct btrfs_trans_handle *trans,
         */
        for (i = 0; i < refi; i++) {
                bytenr = sorted[i].bytenr;
-               ret = __btrfs_free_extent(trans, root, bytenr,
+               ret = btrfs_free_extent(trans, root, bytenr,
                                        blocksize, eb->start,
                                        root_owner, root_gen, 0, 1);
                BUG_ON(ret);
@@ -4053,7 +3462,7 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
 
        WARN_ON(*level < 0);
        WARN_ON(*level >= BTRFS_MAX_LEVEL);
-       ret = drop_snap_lookup_refcount(root, path->nodes[*level]->start,
+       ret = drop_snap_lookup_refcount(trans, root, path->nodes[*level]->start,
                                path->nodes[*level]->len, &refs);
        BUG_ON(ret);
        if (refs > 1)
@@ -4104,7 +3513,8 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
                ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
                blocksize = btrfs_level_size(root, *level - 1);
 
-               ret = drop_snap_lookup_refcount(root, bytenr, blocksize, &refs);
+               ret = drop_snap_lookup_refcount(trans, root, bytenr,
+                                               blocksize, &refs);
                BUG_ON(ret);
 
                /*
@@ -4119,7 +3529,7 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
                        root_gen = btrfs_header_generation(parent);
                        path->slots[*level]++;
 
-                       ret = __btrfs_free_extent(trans, root, bytenr,
+                       ret = btrfs_free_extent(trans, root, bytenr,
                                                blocksize, parent->start,
                                                root_owner, root_gen,
                                                *level - 1, 1);
@@ -4165,7 +3575,7 @@ out:
         * cleanup and free the reference on the last node
         * we processed
         */
-       ret = __btrfs_free_extent(trans, root, bytenr, blocksize,
+       ret = btrfs_free_extent(trans, root, bytenr, blocksize,
                                  parent->start, root_owner, root_gen,
                                  *level, 1);
        free_extent_buffer(path->nodes[*level]);
@@ -4354,6 +3764,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
        struct btrfs_path *path;
        int i;
        int orig_level;
+       int update_count;
        struct btrfs_root_item *root_item = &root->root_item;
 
        WARN_ON(!mutex_is_locked(&root->fs_info->drop_mutex));
@@ -4395,6 +3806,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
                }
        }
        while (1) {
+               unsigned long update;
                wret = walk_down_tree(trans, root, path, &level);
                if (wret > 0)
                        break;
@@ -4407,12 +3819,21 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
                        break;
                if (wret < 0)
                        ret = wret;
-               if (trans->transaction->in_commit) {
+               if (trans->transaction->in_commit ||
+                   trans->transaction->delayed_refs.flushing) {
                        ret = -EAGAIN;
                        break;
                }
                atomic_inc(&root->fs_info->throttle_gen);
                wake_up(&root->fs_info->transaction_throttle);
+               for (update_count = 0; update_count < 16; update_count++) {
+                       update = trans->delayed_ref_updates;
+                       trans->delayed_ref_updates = 0;
+                       if (update)
+                               btrfs_run_delayed_refs(trans, root, update);
+                       else
+                               break;
+               }
        }
        for (i = 0; i <= orig_level; i++) {
                if (path->nodes[i]) {
@@ -5457,6 +4878,7 @@ static noinline int replace_extents_in_leaf(struct btrfs_trans_handle *trans,
                                        root->root_key.objectid,
                                        trans->transid, key.objectid);
                BUG_ON(ret);
+
                ret = btrfs_free_extent(trans, root,
                                        bytenr, num_bytes, leaf->start,
                                        btrfs_header_owner(leaf),
@@ -5768,9 +5190,6 @@ static noinline int relocate_tree_block(struct btrfs_trans_handle *trans,
                                ref_path, NULL, NULL);
        BUG_ON(ret);
 
-       if (root == root->fs_info->extent_root)
-               btrfs_extent_post_op(trans, root);
-
        return 0;
 }
 
@@ -6038,6 +5457,7 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_inode(trans, root, path, objectid);
        if (ret)
                goto out;
@@ -6208,6 +5628,9 @@ again:
        btrfs_remove_leaf_refs(info->tree_root, (u64)-1, 1);
        mutex_unlock(&root->fs_info->cleaner_mutex);
 
+       trans = btrfs_start_transaction(info->tree_root, 1);
+       btrfs_commit_transaction(trans, info->tree_root);
+
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0)
@@ -6294,7 +5717,7 @@ next:
        WARN_ON(block_group->reserved > 0);
        WARN_ON(btrfs_block_group_used(&block_group->item) > 0);
        spin_unlock(&block_group->lock);
-       put_block_group(block_group);
+       btrfs_put_block_group(block_group);
        ret = 0;
 out:
        btrfs_free_path(path);
@@ -6421,9 +5844,10 @@ int btrfs_read_block_groups(struct btrfs_root *root)
 
                atomic_set(&cache->count, 1);
                spin_lock_init(&cache->lock);
-               mutex_init(&cache->alloc_mutex);
+               spin_lock_init(&cache->tree_lock);
                mutex_init(&cache->cache_mutex);
                INIT_LIST_HEAD(&cache->list);
+               INIT_LIST_HEAD(&cache->cluster_list);
                read_extent_buffer(leaf, &cache->item,
                                   btrfs_item_ptr_offset(leaf, path->slots[0]),
                                   sizeof(cache->item));
@@ -6466,7 +5890,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        extent_root = root->fs_info->extent_root;
 
-       root->fs_info->last_trans_new_blockgroup = trans->transid;
+       root->fs_info->last_trans_log_full_commit = trans->transid;
 
        cache = kzalloc(sizeof(*cache), GFP_NOFS);
        if (!cache)
@@ -6477,9 +5901,10 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
        atomic_set(&cache->count, 1);
        spin_lock_init(&cache->lock);
-       mutex_init(&cache->alloc_mutex);
+       spin_lock_init(&cache->tree_lock);
        mutex_init(&cache->cache_mutex);
        INIT_LIST_HEAD(&cache->list);
+       INIT_LIST_HEAD(&cache->cluster_list);
 
        btrfs_set_block_group_used(&cache->item, bytes_used);
        btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid);
@@ -6500,9 +5925,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                                sizeof(cache->item));
        BUG_ON(ret);
 
-       finish_current_insert(trans, extent_root, 0);
-       ret = del_pending_extents(trans, extent_root, 0);
-       BUG_ON(ret);
        set_avail_alloc_bits(extent_root->fs_info, type);
 
        return 0;
@@ -6542,8 +5964,8 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        spin_unlock(&block_group->space_info->lock);
        block_group->space_info->full = 0;
 
-       put_block_group(block_group);
-       put_block_group(block_group);
+       btrfs_put_block_group(block_group);
+       btrfs_put_block_group(block_group);
 
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret > 0)
index ebe6b29e60698156250708766c70bb74b903bfb6..eb2bee8b7fbfb19fb37dc26cbe6fe01ec92ea3ef 100644 (file)
@@ -2884,25 +2884,19 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                disko = 0;
                flags = 0;
 
-               switch (em->block_start) {
-               case EXTENT_MAP_LAST_BYTE:
+               if (em->block_start == EXTENT_MAP_LAST_BYTE) {
                        end = 1;
                        flags |= FIEMAP_EXTENT_LAST;
-                       break;
-               case EXTENT_MAP_HOLE:
+               } else if (em->block_start == EXTENT_MAP_HOLE) {
                        flags |= FIEMAP_EXTENT_UNWRITTEN;
-                       break;
-               case EXTENT_MAP_INLINE:
+               } else if (em->block_start == EXTENT_MAP_INLINE) {
                        flags |= (FIEMAP_EXTENT_DATA_INLINE |
                                  FIEMAP_EXTENT_NOT_ALIGNED);
-                       break;
-               case EXTENT_MAP_DELALLOC:
+               } else if (em->block_start == EXTENT_MAP_DELALLOC) {
                        flags |= (FIEMAP_EXTENT_DELALLOC |
                                  FIEMAP_EXTENT_UNKNOWN);
-                       break;
-               default:
+               } else {
                        disko = em->block_start;
-                       break;
                }
                if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
                        flags |= FIEMAP_EXTENT_ENCODED;
@@ -3124,20 +3118,15 @@ void free_extent_buffer(struct extent_buffer *eb)
 int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                              struct extent_buffer *eb)
 {
-       int set;
        unsigned long i;
        unsigned long num_pages;
        struct page *page;
 
-       u64 start = eb->start;
-       u64 end = start + eb->len - 1;
-
-       set = clear_extent_dirty(tree, start, end, GFP_NOFS);
        num_pages = num_extent_pages(eb->start, eb->len);
 
        for (i = 0; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
-               if (!set && !PageDirty(page))
+               if (!PageDirty(page))
                        continue;
 
                lock_page(page);
@@ -3146,22 +3135,6 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                else
                        set_page_private(page, EXTENT_PAGE_PRIVATE);
 
-               /*
-                * if we're on the last page or the first page and the
-                * block isn't aligned on a page boundary, do extra checks
-                * to make sure we don't clean page that is partially dirty
-                */
-               if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) ||
-                   ((i == num_pages - 1) &&
-                    ((eb->start + eb->len) & (PAGE_CACHE_SIZE - 1)))) {
-                       start = (u64)page->index << PAGE_CACHE_SHIFT;
-                       end  = start + PAGE_CACHE_SIZE - 1;
-                       if (test_range_bit(tree, start, end,
-                                          EXTENT_DIRTY, 0)) {
-                               unlock_page(page);
-                               continue;
-                       }
-               }
                clear_page_dirty_for_io(page);
                spin_lock_irq(&page->mapping->tree_lock);
                if (!PageDirty(page)) {
@@ -3187,29 +3160,13 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree,
 {
        unsigned long i;
        unsigned long num_pages;
+       int was_dirty = 0;
 
+       was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
-       for (i = 0; i < num_pages; i++) {
-               struct page *page = extent_buffer_page(eb, i);
-               /* writepage may need to do something special for the
-                * first page, we have to make sure page->private is
-                * properly set.  releasepage may drop page->private
-                * on us if the page isn't already dirty.
-                */
-               lock_page(page);
-               if (i == 0) {
-                       set_page_extent_head(page, eb->len);
-               } else if (PagePrivate(page) &&
-                          page->private != EXTENT_PAGE_PRIVATE) {
-                       set_page_extent_mapped(page);
-               }
+       for (i = 0; i < num_pages; i++)
                __set_page_dirty_nobuffers(extent_buffer_page(eb, i));
-               set_extent_dirty(tree, page_offset(page),
-                                page_offset(page) + PAGE_CACHE_SIZE - 1,
-                                GFP_NOFS);
-               unlock_page(page);
-       }
-       return 0;
+       return was_dirty;
 }
 
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
@@ -3789,6 +3746,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
                ret = 0;
                goto out;
        }
+       if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
+               ret = 0;
+               goto out;
+       }
        /* at this point we can safely release the extent buffer */
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++)
index 1f9df88afbf6922e9f4af87972f05521ed15e862..5bc20abf3f3d340b22248802e4c8d7d72f4dc4bb 100644 (file)
@@ -25,6 +25,7 @@
 /* these are bit numbers for test/set bit */
 #define EXTENT_BUFFER_UPTODATE 0
 #define EXTENT_BUFFER_BLOCKING 1
+#define EXTENT_BUFFER_DIRTY 2
 
 /*
  * page->private values.  Every page that is controlled by the extent
@@ -254,6 +255,8 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                              struct extent_buffer *eb);
 int set_extent_buffer_dirty(struct extent_io_tree *tree,
                             struct extent_buffer *eb);
+int test_extent_buffer_dirty(struct extent_io_tree *tree,
+                            struct extent_buffer *eb);
 int set_extent_buffer_uptodate(struct extent_io_tree *tree,
                               struct extent_buffer *eb);
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
index 50da69da20cec141fca63ffba2a4e92b8f93f875..b187917b36fa8c19202b1e5049f3bbf9aaef451f 100644 (file)
@@ -234,7 +234,6 @@ int add_extent_mapping(struct extent_map_tree *tree,
        rb = tree_insert(&tree->map, em->start, &em->rb_node);
        if (rb) {
                ret = -EEXIST;
-               free_extent_map(merge);
                goto out;
        }
        atomic_inc(&em->refs);
index 964652435fd1a5f40e061cfe1c3a7dd1d1198248..9b99886562d0b2c8ea9e883f3f2623b0ec6d8674 100644 (file)
@@ -52,6 +52,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
        file_key.offset = pos;
        btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, root, path, &file_key,
                                      sizeof(*item));
        if (ret < 0)
@@ -523,6 +524,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                key.offset = end_byte - 1;
                key.type = BTRFS_EXTENT_CSUM_KEY;
 
+               path->leave_spinning = 1;
                ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
                if (ret > 0) {
                        if (path->slots[0] == 0)
@@ -757,8 +759,10 @@ insert:
        } else {
                ins_size = csum_size;
        }
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, root, path, &file_key,
                                      ins_size);
+       path->leave_spinning = 0;
        if (ret < 0)
                goto fail_unlock;
        if (ret != 0) {
@@ -776,7 +780,6 @@ found:
        item_end = (struct btrfs_csum_item *)((unsigned char *)item_end +
                                      btrfs_item_size_nr(leaf, path->slots[0]));
        eb_token = NULL;
-       cond_resched();
 next_sector:
 
        if (!eb_token ||
@@ -817,9 +820,9 @@ next_sector:
                eb_token = NULL;
        }
        btrfs_mark_buffer_dirty(path->nodes[0]);
-       cond_resched();
        if (total_bytes < sums->len) {
                btrfs_release_path(root, path);
+               cond_resched();
                goto again;
        }
 out:
index dc78954861b333d75e831e27c6bbe7760f6e1de9..9c9fb46ccd08f9fe7eaf9d22991738f9231810c2 100644 (file)
@@ -606,6 +606,7 @@ next_slot:
                        btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY);
 
                        btrfs_release_path(root, path);
+                       path->leave_spinning = 1;
                        ret = btrfs_insert_empty_item(trans, root, path, &ins,
                                                      sizeof(*extent));
                        BUG_ON(ret);
@@ -639,17 +640,22 @@ next_slot:
                                                        ram_bytes);
                        btrfs_set_file_extent_type(leaf, extent, found_type);
 
+                       btrfs_unlock_up_safe(path, 1);
                        btrfs_mark_buffer_dirty(path->nodes[0]);
+                       btrfs_set_lock_blocking(path->nodes[0]);
 
                        if (disk_bytenr != 0) {
                                ret = btrfs_update_extent_ref(trans, root,
-                                               disk_bytenr, orig_parent,
+                                               disk_bytenr,
+                                               le64_to_cpu(old.disk_num_bytes),
+                                               orig_parent,
                                                leaf->start,
                                                root->root_key.objectid,
                                                trans->transid, ins.objectid);
 
                                BUG_ON(ret);
                        }
+                       path->leave_spinning = 0;
                        btrfs_release_path(root, path);
                        if (disk_bytenr != 0)
                                inode_add_bytes(inode, extent_end - end);
@@ -912,7 +918,7 @@ again:
        btrfs_set_file_extent_other_encoding(leaf, fi, 0);
 
        if (orig_parent != leaf->start) {
-               ret = btrfs_update_extent_ref(trans, root, bytenr,
+               ret = btrfs_update_extent_ref(trans, root, bytenr, num_bytes,
                                              orig_parent, leaf->start,
                                              root->root_key.objectid,
                                              trans->transid, inode->i_ino);
@@ -1155,6 +1161,20 @@ out_nolock:
                page_cache_release(pinned[1]);
        *ppos = pos;
 
+       /*
+        * we want to make sure fsync finds this change
+        * but we haven't joined a transaction running right now.
+        *
+        * Later on, someone is sure to update the inode and get the
+        * real transid recorded.
+        *
+        * We set last_trans now to the fs_info generation + 1,
+        * this will either be one more than the running transaction
+        * or the generation used for the next transaction if there isn't
+        * one running right now.
+        */
+       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
+
        if (num_written > 0 && will_write) {
                struct btrfs_trans_handle *trans;
 
@@ -1167,8 +1187,11 @@ out_nolock:
                        ret = btrfs_log_dentry_safe(trans, root,
                                                    file->f_dentry);
                        if (ret == 0) {
-                               btrfs_sync_log(trans, root);
-                               btrfs_end_transaction(trans, root);
+                               ret = btrfs_sync_log(trans, root);
+                               if (ret == 0)
+                                       btrfs_end_transaction(trans, root);
+                               else
+                                       btrfs_commit_transaction(trans, root);
                        } else {
                                btrfs_commit_transaction(trans, root);
                        }
@@ -1185,6 +1208,18 @@ out_nolock:
 
 int btrfs_release_file(struct inode *inode, struct file *filp)
 {
+       /*
+        * ordered_data_close is set by settattr when we are about to truncate
+        * a file from a non-zero size to a zero size.  This tries to
+        * flush down new bytes that may have been written if the
+        * application were using truncate to replace a file in place.
+        */
+       if (BTRFS_I(inode)->ordered_data_close) {
+               BTRFS_I(inode)->ordered_data_close = 0;
+               btrfs_add_ordered_operation(NULL, BTRFS_I(inode)->root, inode);
+               if (inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
+                       filemap_flush(inode->i_mapping);
+       }
        if (filp->private_data)
                btrfs_ioctl_trans_end(filp);
        return 0;
@@ -1260,8 +1295,11 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
        if (ret > 0) {
                ret = btrfs_commit_transaction(trans, root);
        } else {
-               btrfs_sync_log(trans, root);
-               ret = btrfs_end_transaction(trans, root);
+               ret = btrfs_sync_log(trans, root);
+               if (ret == 0)
+                       ret = btrfs_end_transaction(trans, root);
+               else
+                       ret = btrfs_commit_transaction(trans, root);
        }
        mutex_lock(&dentry->d_inode->i_mutex);
 out:
index d1e5f0e84c58c8733e90ad15d09453a31e114470..768b9523662df85274e402328c618c226be5ab77 100644 (file)
 
 #include <linux/sched.h>
 #include "ctree.h"
+#include "free-space-cache.h"
+#include "transaction.h"
+
+struct btrfs_free_space {
+       struct rb_node bytes_index;
+       struct rb_node offset_index;
+       u64 offset;
+       u64 bytes;
+};
 
 static int tree_insert_offset(struct rb_root *root, u64 offset,
                              struct rb_node *node)
@@ -68,14 +77,24 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes,
 }
 
 /*
- * searches the tree for the given offset.  If contains is set we will return
- * the free space that contains the given offset.  If contains is not set we
- * will return the free space that starts at or after the given offset and is
- * at least bytes long.
+ * searches the tree for the given offset.
+ *
+ * fuzzy == 1: this is used for allocations where we are given a hint of where
+ * to look for free space.  Because the hint may not be completely on an offset
+ * mark, or the hint may no longer point to free space we need to fudge our
+ * results a bit.  So we look for free space starting at or after offset with at
+ * least bytes size.  We prefer to find as close to the given offset as we can.
+ * Also if the offset is within a free space range, then we will return the free
+ * space that contains the given offset, which means we can return a free space
+ * chunk with an offset before the provided offset.
+ *
+ * fuzzy == 0: this is just a normal tree search.  Give us the free space that
+ * starts at the given offset which is at least bytes size, and if its not there
+ * return NULL.
  */
 static struct btrfs_free_space *tree_search_offset(struct rb_root *root,
                                                   u64 offset, u64 bytes,
-                                                  int contains)
+                                                  int fuzzy)
 {
        struct rb_node *n = root->rb_node;
        struct btrfs_free_space *entry, *ret = NULL;
@@ -84,13 +103,14 @@ static struct btrfs_free_space *tree_search_offset(struct rb_root *root,
                entry = rb_entry(n, struct btrfs_free_space, offset_index);
 
                if (offset < entry->offset) {
-                       if (!contains &&
+                       if (fuzzy &&
                            (!ret || entry->offset < ret->offset) &&
                            (bytes <= entry->bytes))
                                ret = entry;
                        n = n->rb_left;
                } else if (offset > entry->offset) {
-                       if ((entry->offset + entry->bytes - 1) >= offset &&
+                       if (fuzzy &&
+                           (entry->offset + entry->bytes - 1) >= offset &&
                            bytes <= entry->bytes) {
                                ret = entry;
                                break;
@@ -171,6 +191,7 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
        int ret = 0;
 
 
+       BUG_ON(!info->bytes);
        ret = tree_insert_offset(&block_group->free_space_offset, info->offset,
                                 &info->offset_index);
        if (ret)
@@ -184,108 +205,70 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
        return ret;
 }
 
-static int __btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
-                                 u64 offset, u64 bytes)
+int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
+                        u64 offset, u64 bytes)
 {
        struct btrfs_free_space *right_info;
        struct btrfs_free_space *left_info;
        struct btrfs_free_space *info = NULL;
-       struct btrfs_free_space *alloc_info;
        int ret = 0;
 
-       alloc_info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
-       if (!alloc_info)
+       info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
+       if (!info)
                return -ENOMEM;
 
+       info->offset = offset;
+       info->bytes = bytes;
+
+       spin_lock(&block_group->tree_lock);
+
        /*
         * first we want to see if there is free space adjacent to the range we
         * are adding, if there is remove that struct and add a new one to
         * cover the entire range
         */
        right_info = tree_search_offset(&block_group->free_space_offset,
-                                       offset+bytes, 0, 1);
+                                       offset+bytes, 0, 0);
        left_info = tree_search_offset(&block_group->free_space_offset,
                                       offset-1, 0, 1);
 
-       if (right_info && right_info->offset == offset+bytes) {
+       if (right_info) {
                unlink_free_space(block_group, right_info);
-               info = right_info;
-               info->offset = offset;
-               info->bytes += bytes;
-       } else if (right_info && right_info->offset != offset+bytes) {
-               printk(KERN_ERR "btrfs adding space in the middle of an "
-                      "existing free space area. existing: "
-                      "offset=%llu, bytes=%llu. new: offset=%llu, "
-                      "bytes=%llu\n", (unsigned long long)right_info->offset,
-                      (unsigned long long)right_info->bytes,
-                      (unsigned long long)offset,
-                      (unsigned long long)bytes);
-               BUG();
+               info->bytes += right_info->bytes;
+               kfree(right_info);
        }
 
-       if (left_info) {
+       if (left_info && left_info->offset + left_info->bytes == offset) {
                unlink_free_space(block_group, left_info);
-
-               if (unlikely((left_info->offset + left_info->bytes) !=
-                            offset)) {
-                       printk(KERN_ERR "btrfs free space to the left "
-                              "of new free space isn't "
-                              "quite right. existing: offset=%llu, "
-                              "bytes=%llu. new: offset=%llu, bytes=%llu\n",
-                              (unsigned long long)left_info->offset,
-                              (unsigned long long)left_info->bytes,
-                              (unsigned long long)offset,
-                              (unsigned long long)bytes);
-                       BUG();
-               }
-
-               if (info) {
-                       info->offset = left_info->offset;
-                       info->bytes += left_info->bytes;
-                       kfree(left_info);
-               } else {
-                       info = left_info;
-                       info->bytes += bytes;
-               }
+               info->offset = left_info->offset;
+               info->bytes += left_info->bytes;
+               kfree(left_info);
        }
 
-       if (info) {
-               ret = link_free_space(block_group, info);
-               if (!ret)
-                       info = NULL;
-               goto out;
-       }
-
-       info = alloc_info;
-       alloc_info = NULL;
-       info->offset = offset;
-       info->bytes = bytes;
-
        ret = link_free_space(block_group, info);
        if (ret)
                kfree(info);
-out:
+
+       spin_unlock(&block_group->tree_lock);
+
        if (ret) {
                printk(KERN_ERR "btrfs: unable to add free space :%d\n", ret);
-               if (ret == -EEXIST)
-                       BUG();
+               BUG_ON(ret == -EEXIST);
        }
 
-       kfree(alloc_info);
-
        return ret;
 }
 
-static int
-__btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
-                         u64 offset, u64 bytes)
+int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
+                           u64 offset, u64 bytes)
 {
        struct btrfs_free_space *info;
        int ret = 0;
 
+       spin_lock(&block_group->tree_lock);
+
        info = tree_search_offset(&block_group->free_space_offset, offset, 0,
                                  1);
-
        if (info && info->offset == offset) {
                if (info->bytes < bytes) {
                        printk(KERN_ERR "Found free space at %llu, size %llu,"
@@ -295,12 +278,14 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                               (unsigned long long)bytes);
                        WARN_ON(1);
                        ret = -EINVAL;
+                       spin_unlock(&block_group->tree_lock);
                        goto out;
                }
                unlink_free_space(block_group, info);
 
                if (info->bytes == bytes) {
                        kfree(info);
+                       spin_unlock(&block_group->tree_lock);
                        goto out;
                }
 
@@ -308,6 +293,7 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                info->bytes -= bytes;
 
                ret = link_free_space(block_group, info);
+               spin_unlock(&block_group->tree_lock);
                BUG_ON(ret);
        } else if (info && info->offset < offset &&
                   info->offset + info->bytes >= offset + bytes) {
@@ -333,70 +319,33 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                         */
                        kfree(info);
                }
-
+               spin_unlock(&block_group->tree_lock);
                /* step two, insert a new info struct to cover anything
                 * before the hole
                 */
-               ret = __btrfs_add_free_space(block_group, old_start,
-                                            offset - old_start);
+               ret = btrfs_add_free_space(block_group, old_start,
+                                          offset - old_start);
                BUG_ON(ret);
        } else {
+               spin_unlock(&block_group->tree_lock);
+               if (!info) {
+                       printk(KERN_ERR "couldn't find space %llu to free\n",
+                              (unsigned long long)offset);
+                       printk(KERN_ERR "cached is %d, offset %llu bytes %llu\n",
+                              block_group->cached, block_group->key.objectid,
+                              block_group->key.offset);
+                       btrfs_dump_free_space(block_group, bytes);
+               } else if (info) {
+                       printk(KERN_ERR "hmm, found offset=%llu bytes=%llu, "
+                              "but wanted offset=%llu bytes=%llu\n",
+                              info->offset, info->bytes, offset, bytes);
+               }
                WARN_ON(1);
        }
 out:
        return ret;
 }
 
-int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
-                        u64 offset, u64 bytes)
-{
-       int ret;
-       struct btrfs_free_space *sp;
-
-       mutex_lock(&block_group->alloc_mutex);
-       ret = __btrfs_add_free_space(block_group, offset, bytes);
-       sp = tree_search_offset(&block_group->free_space_offset, offset, 0, 1);
-       BUG_ON(!sp);
-       mutex_unlock(&block_group->alloc_mutex);
-
-       return ret;
-}
-
-int btrfs_add_free_space_lock(struct btrfs_block_group_cache *block_group,
-                             u64 offset, u64 bytes)
-{
-       int ret;
-       struct btrfs_free_space *sp;
-
-       ret = __btrfs_add_free_space(block_group, offset, bytes);
-       sp = tree_search_offset(&block_group->free_space_offset, offset, 0, 1);
-       BUG_ON(!sp);
-
-       return ret;
-}
-
-int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
-                           u64 offset, u64 bytes)
-{
-       int ret = 0;
-
-       mutex_lock(&block_group->alloc_mutex);
-       ret = __btrfs_remove_free_space(block_group, offset, bytes);
-       mutex_unlock(&block_group->alloc_mutex);
-
-       return ret;
-}
-
-int btrfs_remove_free_space_lock(struct btrfs_block_group_cache *block_group,
-                                u64 offset, u64 bytes)
-{
-       int ret;
-
-       ret = __btrfs_remove_free_space(block_group, offset, bytes);
-
-       return ret;
-}
-
 void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                           u64 bytes)
 {
@@ -408,6 +357,8 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                info = rb_entry(n, struct btrfs_free_space, offset_index);
                if (info->bytes >= bytes)
                        count++;
+               printk(KERN_ERR "entry offset %llu, bytes %llu\n", info->offset,
+                      info->bytes);
        }
        printk(KERN_INFO "%d blocks of free space at or bigger than bytes is"
               "\n", count);
@@ -428,68 +379,337 @@ u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group)
        return ret;
 }
 
+/*
+ * for a given cluster, put all of its extents back into the free
+ * space cache.  If the block group passed doesn't match the block group
+ * pointed to by the cluster, someone else raced in and freed the
+ * cluster already.  In that case, we just return without changing anything
+ */
+static int
+__btrfs_return_cluster_to_free_space(
+                            struct btrfs_block_group_cache *block_group,
+                            struct btrfs_free_cluster *cluster)
+{
+       struct btrfs_free_space *entry;
+       struct rb_node *node;
+
+       spin_lock(&cluster->lock);
+       if (cluster->block_group != block_group)
+               goto out;
+
+       cluster->window_start = 0;
+       node = rb_first(&cluster->root);
+       while(node) {
+               entry = rb_entry(node, struct btrfs_free_space, offset_index);
+               node = rb_next(&entry->offset_index);
+               rb_erase(&entry->offset_index, &cluster->root);
+               link_free_space(block_group, entry);
+       }
+       list_del_init(&cluster->block_group_list);
+
+       btrfs_put_block_group(cluster->block_group);
+       cluster->block_group = NULL;
+       cluster->root.rb_node = NULL;
+out:
+       spin_unlock(&cluster->lock);
+       return 0;
+}
+
 void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
 {
        struct btrfs_free_space *info;
        struct rb_node *node;
+       struct btrfs_free_cluster *cluster;
+       struct btrfs_free_cluster *safe;
+
+       spin_lock(&block_group->tree_lock);
+
+       list_for_each_entry_safe(cluster, safe, &block_group->cluster_list,
+                                block_group_list) {
+
+               WARN_ON(cluster->block_group != block_group);
+               __btrfs_return_cluster_to_free_space(block_group, cluster);
+       }
 
-       mutex_lock(&block_group->alloc_mutex);
        while ((node = rb_last(&block_group->free_space_bytes)) != NULL) {
                info = rb_entry(node, struct btrfs_free_space, bytes_index);
                unlink_free_space(block_group, info);
                kfree(info);
                if (need_resched()) {
-                       mutex_unlock(&block_group->alloc_mutex);
+                       spin_unlock(&block_group->tree_lock);
                        cond_resched();
-                       mutex_lock(&block_group->alloc_mutex);
+                       spin_lock(&block_group->tree_lock);
                }
        }
-       mutex_unlock(&block_group->alloc_mutex);
+       spin_unlock(&block_group->tree_lock);
 }
 
-#if 0
-static struct btrfs_free_space *btrfs_find_free_space_offset(struct
-                                                     btrfs_block_group_cache
-                                                     *block_group, u64 offset,
-                                                     u64 bytes)
+u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
+                              u64 offset, u64 bytes, u64 empty_size)
 {
-       struct btrfs_free_space *ret;
+       struct btrfs_free_space *entry = NULL;
+       u64 ret = 0;
 
-       mutex_lock(&block_group->alloc_mutex);
-       ret = tree_search_offset(&block_group->free_space_offset, offset,
-                                bytes, 0);
-       mutex_unlock(&block_group->alloc_mutex);
+       spin_lock(&block_group->tree_lock);
+       entry = tree_search_offset(&block_group->free_space_offset, offset,
+                                  bytes + empty_size, 1);
+       if (!entry)
+               entry = tree_search_bytes(&block_group->free_space_bytes,
+                                         offset, bytes + empty_size);
+       if (entry) {
+               unlink_free_space(block_group, entry);
+               ret = entry->offset;
+               entry->offset += bytes;
+               entry->bytes -= bytes;
+
+               if (!entry->bytes)
+                       kfree(entry);
+               else
+                       link_free_space(block_group, entry);
+       }
+       spin_unlock(&block_group->tree_lock);
 
        return ret;
 }
 
-static struct btrfs_free_space *btrfs_find_free_space_bytes(struct
-                                                    btrfs_block_group_cache
-                                                    *block_group, u64 offset,
-                                                    u64 bytes)
+/*
+ * given a cluster, put all of its extents back into the free space
+ * cache.  If a block group is passed, this function will only free
+ * a cluster that belongs to the passed block group.
+ *
+ * Otherwise, it'll get a reference on the block group pointed to by the
+ * cluster and remove the cluster from it.
+ */
+int btrfs_return_cluster_to_free_space(
+                              struct btrfs_block_group_cache *block_group,
+                              struct btrfs_free_cluster *cluster)
 {
-       struct btrfs_free_space *ret;
+       int ret;
 
-       mutex_lock(&block_group->alloc_mutex);
+       /* first, get a safe pointer to the block group */
+       spin_lock(&cluster->lock);
+       if (!block_group) {
+               block_group = cluster->block_group;
+               if (!block_group) {
+                       spin_unlock(&cluster->lock);
+                       return 0;
+               }
+       } else if (cluster->block_group != block_group) {
+               /* someone else has already freed it don't redo their work */
+               spin_unlock(&cluster->lock);
+               return 0;
+       }
+       atomic_inc(&block_group->count);
+       spin_unlock(&cluster->lock);
 
-       ret = tree_search_bytes(&block_group->free_space_bytes, offset, bytes);
-       mutex_unlock(&block_group->alloc_mutex);
+       /* now return any extents the cluster had on it */
+       spin_lock(&block_group->tree_lock);
+       ret = __btrfs_return_cluster_to_free_space(block_group, cluster);
+       spin_unlock(&block_group->tree_lock);
 
+       /* finally drop our ref */
+       btrfs_put_block_group(block_group);
        return ret;
 }
-#endif
 
-struct btrfs_free_space *btrfs_find_free_space(struct btrfs_block_group_cache
-                                              *block_group, u64 offset,
-                                              u64 bytes)
+/*
+ * given a cluster, try to allocate 'bytes' from it, returns 0
+ * if it couldn't find anything suitably large, or a logical disk offset
+ * if things worked out
+ */
+u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
+                            struct btrfs_free_cluster *cluster, u64 bytes,
+                            u64 min_start)
+{
+       struct btrfs_free_space *entry = NULL;
+       struct rb_node *node;
+       u64 ret = 0;
+
+       spin_lock(&cluster->lock);
+       if (bytes > cluster->max_size)
+               goto out;
+
+       if (cluster->block_group != block_group)
+               goto out;
+
+       node = rb_first(&cluster->root);
+       if (!node)
+               goto out;
+
+       entry = rb_entry(node, struct btrfs_free_space, offset_index);
+
+       while(1) {
+               if (entry->bytes < bytes || entry->offset < min_start) {
+                       struct rb_node *node;
+
+                       node = rb_next(&entry->offset_index);
+                       if (!node)
+                               break;
+                       entry = rb_entry(node, struct btrfs_free_space,
+                                        offset_index);
+                       continue;
+               }
+               ret = entry->offset;
+
+               entry->offset += bytes;
+               entry->bytes -= bytes;
+
+               if (entry->bytes == 0) {
+                       rb_erase(&entry->offset_index, &cluster->root);
+                       kfree(entry);
+               }
+               break;
+       }
+out:
+       spin_unlock(&cluster->lock);
+       return ret;
+}
+
+/*
+ * here we try to find a cluster of blocks in a block group.  The goal
+ * is to find at least bytes free and up to empty_size + bytes free.
+ * We might not find them all in one contiguous area.
+ *
+ * returns zero and sets up cluster if things worked out, otherwise
+ * it returns -enospc
+ */
+int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
+                            struct btrfs_block_group_cache *block_group,
+                            struct btrfs_free_cluster *cluster,
+                            u64 offset, u64 bytes, u64 empty_size)
 {
-       struct btrfs_free_space *ret = NULL;
+       struct btrfs_free_space *entry = NULL;
+       struct rb_node *node;
+       struct btrfs_free_space *next;
+       struct btrfs_free_space *last;
+       u64 min_bytes;
+       u64 window_start;
+       u64 window_free;
+       u64 max_extent = 0;
+       int total_retries = 0;
+       int ret;
+
+       /* for metadata, allow allocates with more holes */
+       if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) {
+               /*
+                * we want to do larger allocations when we are
+                * flushing out the delayed refs, it helps prevent
+                * making more work as we go along.
+                */
+               if (trans->transaction->delayed_refs.flushing)
+                       min_bytes = max(bytes, (bytes + empty_size) >> 1);
+               else
+                       min_bytes = max(bytes, (bytes + empty_size) >> 4);
+       } else
+               min_bytes = max(bytes, (bytes + empty_size) >> 2);
+
+       spin_lock(&block_group->tree_lock);
+       spin_lock(&cluster->lock);
+
+       /* someone already found a cluster, hooray */
+       if (cluster->block_group) {
+               ret = 0;
+               goto out;
+       }
+again:
+       min_bytes = min(min_bytes, bytes + empty_size);
+       entry = tree_search_bytes(&block_group->free_space_bytes,
+                                 offset, min_bytes);
+       if (!entry) {
+               ret = -ENOSPC;
+               goto out;
+       }
+       window_start = entry->offset;
+       window_free = entry->bytes;
+       last = entry;
+       max_extent = entry->bytes;
+
+       while(1) {
+               /* out window is just right, lets fill it */
+               if (window_free >= bytes + empty_size)
+                       break;
 
-       ret = tree_search_offset(&block_group->free_space_offset, offset,
-                                bytes, 0);
-       if (!ret)
-               ret = tree_search_bytes(&block_group->free_space_bytes,
-                                       offset, bytes);
+               node = rb_next(&last->offset_index);
+               if (!node) {
+                       ret = -ENOSPC;
+                       goto out;
+               }
+               next = rb_entry(node, struct btrfs_free_space, offset_index);
+
+               /*
+                * we haven't filled the empty size and the window is
+                * very large.  reset and try again
+                */
+               if (next->offset - window_start > (bytes + empty_size) * 2) {
+                       entry = next;
+                       window_start = entry->offset;
+                       window_free = entry->bytes;
+                       last = entry;
+                       max_extent = 0;
+                       total_retries++;
+                       if (total_retries % 256 == 0) {
+                               if (min_bytes >= (bytes + empty_size)) {
+                                       ret = -ENOSPC;
+                                       goto out;
+                               }
+                               /*
+                                * grow our allocation a bit, we're not having
+                                * much luck
+                                */
+                               min_bytes *= 2;
+                               goto again;
+                       }
+               } else {
+                       last = next;
+                       window_free += next->bytes;
+                       if (entry->bytes > max_extent)
+                               max_extent = entry->bytes;
+               }
+       }
+
+       cluster->window_start = entry->offset;
+
+       /*
+        * now we've found our entries, pull them out of the free space
+        * cache and put them into the cluster rbtree
+        *
+        * The cluster includes an rbtree, but only uses the offset index
+        * of each free space cache entry.
+        */
+       while(1) {
+               node = rb_next(&entry->offset_index);
+               unlink_free_space(block_group, entry);
+               ret = tree_insert_offset(&cluster->root, entry->offset,
+                                        &entry->offset_index);
+               BUG_ON(ret);
+
+               if (!node || entry == last)
+                       break;
+
+               entry = rb_entry(node, struct btrfs_free_space, offset_index);
+       }
+       ret = 0;
+       cluster->max_size = max_extent;
+       atomic_inc(&block_group->count);
+       list_add_tail(&cluster->block_group_list, &block_group->cluster_list);
+       cluster->block_group = block_group;
+out:
+       spin_unlock(&cluster->lock);
+       spin_unlock(&block_group->tree_lock);
 
        return ret;
 }
+
+/*
+ * simple code to zero out a cluster
+ */
+void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
+{
+       spin_lock_init(&cluster->lock);
+       spin_lock_init(&cluster->refill_lock);
+       cluster->root.rb_node = NULL;
+       cluster->max_size = 0;
+       INIT_LIST_HEAD(&cluster->block_group_list);
+       cluster->block_group = NULL;
+}
+
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
new file mode 100644 (file)
index 0000000..ab0bdc0
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_FREE_SPACE_CACHE
+#define __BTRFS_FREE_SPACE_CACHE
+
+int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
+                        u64 bytenr, u64 size);
+int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
+                           u64 bytenr, u64 size);
+void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
+                                  *block_group);
+u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
+                              u64 offset, u64 bytes, u64 empty_size);
+void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
+                          u64 bytes);
+u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group);
+int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
+                            struct btrfs_block_group_cache *block_group,
+                            struct btrfs_free_cluster *cluster,
+                            u64 offset, u64 bytes, u64 empty_size);
+void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster);
+u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
+                            struct btrfs_free_cluster *cluster, u64 bytes,
+                            u64 min_start);
+int btrfs_return_cluster_to_free_space(
+                              struct btrfs_block_group_cache *block_group,
+                              struct btrfs_free_cluster *cluster);
+#endif
index 3d46fa1f29a4d75be94f116e148a0f50321973f6..6b627c6118081ccea87d1acaf92000f995dda946 100644 (file)
@@ -73,6 +73,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
+
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret > 0) {
                ret = -ENOENT;
@@ -127,6 +129,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                      ins_len);
        if (ret == -EEXIST) {
index 7d4f948bc22a5b5c811b93b385ff36d5b49e8977..a0d1dd492a58a57bdf23464340fd6312c192fca9 100644 (file)
@@ -134,6 +134,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
+       path->leave_spinning = 1;
        btrfs_set_trans_block_group(trans, inode);
 
        key.objectid = inode->i_ino;
@@ -167,9 +168,9 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
                        cur_size = min_t(unsigned long, compressed_size,
                                       PAGE_CACHE_SIZE);
 
-                       kaddr = kmap(cpage);
+                       kaddr = kmap_atomic(cpage, KM_USER0);
                        write_extent_buffer(leaf, kaddr, ptr, cur_size);
-                       kunmap(cpage);
+                       kunmap_atomic(kaddr, KM_USER0);
 
                        i++;
                        ptr += cur_size;
@@ -204,7 +205,7 @@ fail:
  * does the checks required to make sure the data is small enough
  * to fit as an inline extent.
  */
-static int cow_file_range_inline(struct btrfs_trans_handle *trans,
+static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct inode *inode, u64 start, u64 end,
                                 size_t compressed_size,
@@ -854,11 +855,6 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
        u64 cur_end;
        int limit = 10 * 1024 * 1042;
 
-       if (!btrfs_test_opt(root, COMPRESS)) {
-               return cow_file_range(inode, locked_page, start, end,
-                                     page_started, nr_written, 1);
-       }
-
        clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED |
                         EXTENT_DELALLOC, 1, 0, GFP_NOFS);
        while (start < end) {
@@ -935,7 +931,8 @@ static noinline int csum_exist_in_range(struct btrfs_root *root,
  * If no cow copies or snapshots exist, we write directly to the existing
  * blocks on disk
  */
-static int run_delalloc_nocow(struct inode *inode, struct page *locked_page,
+static noinline int run_delalloc_nocow(struct inode *inode,
+                                      struct page *locked_page,
                              u64 start, u64 end, int *page_started, int force,
                              unsigned long *nr_written)
 {
@@ -1133,6 +1130,7 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
                              unsigned long *nr_written)
 {
        int ret;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
 
        if (btrfs_test_flag(inode, NODATACOW))
                ret = run_delalloc_nocow(inode, locked_page, start, end,
@@ -1140,10 +1138,12 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
        else if (btrfs_test_flag(inode, PREALLOC))
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
+       else if (!btrfs_test_opt(root, COMPRESS))
+               ret = cow_file_range(inode, locked_page, start, end,
+                                     page_started, nr_written, 1);
        else
                ret = cow_file_range_async(inode, locked_page, start, end,
                                           page_started, nr_written);
-
        return ret;
 }
 
@@ -1453,6 +1453,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       path->leave_spinning = 1;
        ret = btrfs_drop_extents(trans, root, inode, file_pos,
                                 file_pos + num_bytes, file_pos, &hint);
        BUG_ON(ret);
@@ -1475,6 +1476,10 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        btrfs_set_file_extent_compression(leaf, fi, compression);
        btrfs_set_file_extent_encryption(leaf, fi, encryption);
        btrfs_set_file_extent_other_encoding(leaf, fi, other_encoding);
+
+       btrfs_unlock_up_safe(path, 1);
+       btrfs_set_lock_blocking(leaf);
+
        btrfs_mark_buffer_dirty(leaf);
 
        inode_add_bytes(inode, num_bytes);
@@ -1487,11 +1492,35 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
                                          root->root_key.objectid,
                                          trans->transid, inode->i_ino, &ins);
        BUG_ON(ret);
-
        btrfs_free_path(path);
+
        return 0;
 }
 
+/*
+ * helper function for btrfs_finish_ordered_io, this
+ * just reads in some of the csum leaves to prime them into ram
+ * before we start the transaction.  It limits the amount of btree
+ * reads required while inside the transaction.
+ */
+static noinline void reada_csum(struct btrfs_root *root,
+                               struct btrfs_path *path,
+                               struct btrfs_ordered_extent *ordered_extent)
+{
+       struct btrfs_ordered_sum *sum;
+       u64 bytenr;
+
+       sum = list_entry(ordered_extent->list.next, struct btrfs_ordered_sum,
+                        list);
+       bytenr = sum->sums[0].bytenr;
+
+       /*
+        * we don't care about the results, the point of this search is
+        * just to get the btree leaves into ram
+        */
+       btrfs_lookup_csum(NULL, root->fs_info->csum_root, path, bytenr, 0);
+}
+
 /* as ordered data IO finishes, this gets called so we can finish
  * an ordered extent if the range of bytes in the file it covers are
  * fully written.
@@ -1500,8 +1529,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
-       struct btrfs_ordered_extent *ordered_extent;
+       struct btrfs_ordered_extent *ordered_extent = NULL;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct btrfs_path *path;
        int compressed = 0;
        int ret;
 
@@ -1509,9 +1539,33 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        if (!ret)
                return 0;
 
+       /*
+        * before we join the transaction, try to do some of our IO.
+        * This will limit the amount of IO that we have to do with
+        * the transaction running.  We're unlikely to need to do any
+        * IO if the file extents are new, the disk_i_size checks
+        * covers the most common case.
+        */
+       if (start < BTRFS_I(inode)->disk_i_size) {
+               path = btrfs_alloc_path();
+               if (path) {
+                       ret = btrfs_lookup_file_extent(NULL, root, path,
+                                                      inode->i_ino,
+                                                      start, 0);
+                       ordered_extent = btrfs_lookup_ordered_extent(inode,
+                                                                    start);
+                       if (!list_empty(&ordered_extent->list)) {
+                               btrfs_release_path(root, path);
+                               reada_csum(root, path, ordered_extent);
+                       }
+                       btrfs_free_path(path);
+               }
+       }
+
        trans = btrfs_join_transaction(root, 1);
 
-       ordered_extent = btrfs_lookup_ordered_extent(inode, start);
+       if (!ordered_extent)
+               ordered_extent = btrfs_lookup_ordered_extent(inode, start);
        BUG_ON(!ordered_extent);
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags))
                goto nocow;
@@ -2101,6 +2155,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
 
        path = btrfs_alloc_path();
        BUG_ON(!path);
+       path->leave_spinning = 1;
        ret = btrfs_lookup_inode(trans, root, path,
                                 &BTRFS_I(inode)->location, 1);
        if (ret) {
@@ -2147,6 +2202,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                goto err;
        }
 
+       path->leave_spinning = 1;
        di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
                                    name, name_len, -1);
        if (IS_ERR(di)) {
@@ -2190,8 +2246,6 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
                                         inode, dir->i_ino);
        BUG_ON(ret != 0 && ret != -ENOENT);
-       if (ret != -ENOENT)
-               BTRFS_I(dir)->log_dirty_trans = trans->transid;
 
        ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
                                           dir, index);
@@ -2224,6 +2278,9 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        trans = btrfs_start_transaction(root, 1);
 
        btrfs_set_trans_block_group(trans, dir);
+
+       btrfs_record_unlink_dir(trans, dir, dentry->d_inode, 0);
+
        ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
                                 dentry->d_name.name, dentry->d_name.len);
 
@@ -2498,6 +2555,7 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        key.type = (u8)-1;
 
 search_again:
+       path->leave_spinning = 1;
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret < 0)
                goto error;
@@ -2644,6 +2702,7 @@ delete:
                        break;
                }
                if (found_extent) {
+                       btrfs_set_path_blocking(path);
                        ret = btrfs_free_extent(trans, root, extent_start,
                                                extent_num_bytes,
                                                leaf->start, root_owner,
@@ -2848,11 +2907,21 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
        if (err)
                return err;
 
-       if (S_ISREG(inode->i_mode) &&
-           attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
-               err = btrfs_cont_expand(inode, attr->ia_size);
-               if (err)
-                       return err;
+       if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
+               if (attr->ia_size > inode->i_size) {
+                       err = btrfs_cont_expand(inode, attr->ia_size);
+                       if (err)
+                               return err;
+               } else if (inode->i_size > 0 &&
+                          attr->ia_size == 0) {
+
+                       /* we're truncating a file that used to have good
+                        * data down to zero.  Make sure it gets into
+                        * the ordered flush list so that any new writes
+                        * get down to disk quickly.
+                        */
+                       BTRFS_I(inode)->ordered_data_close = 1;
+               }
        }
 
        err = inode_setattr(inode, attr);
@@ -2984,13 +3053,14 @@ static noinline void init_btrfs_i(struct inode *inode)
        bi->disk_i_size = 0;
        bi->flags = 0;
        bi->index_cnt = (u64)-1;
-       bi->log_dirty_trans = 0;
+       bi->last_unlink_trans = 0;
        extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                             inode->i_mapping, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
                             inode->i_mapping, GFP_NOFS);
        INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
+       INIT_LIST_HEAD(&BTRFS_I(inode)->ordered_operations);
        btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
        mutex_init(&BTRFS_I(inode)->extent_mutex);
        mutex_init(&BTRFS_I(inode)->log_mutex);
@@ -3411,8 +3481,10 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 
        if (dir) {
                ret = btrfs_set_inode_index(dir, index);
-               if (ret)
+               if (ret) {
+                       iput(inode);
                        return ERR_PTR(ret);
+               }
        }
        /*
         * index_cnt is ignored for everything but a dir,
@@ -3449,6 +3521,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        sizes[0] = sizeof(struct btrfs_inode_item);
        sizes[1] = name_len + sizeof(*ref);
 
+       path->leave_spinning = 1;
        ret = btrfs_insert_empty_items(trans, root, path, key, sizes, 2);
        if (ret != 0)
                goto fail;
@@ -3494,6 +3567,7 @@ fail:
        if (dir)
                BTRFS_I(dir)->index_cnt--;
        btrfs_free_path(path);
+       iput(inode);
        return ERR_PTR(ret);
 }
 
@@ -3727,6 +3801,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                drop_inode = 1;
 
        nr = trans->blocks_used;
+
+       btrfs_log_new_name(trans, inode, NULL, dentry->d_parent);
        btrfs_end_transaction_throttle(trans, root);
 fail:
        if (drop_inode) {
@@ -4292,8 +4368,9 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
  * beyond EOF, then the page is guaranteed safe against truncation until we
  * unlock the page.
  */
-int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = fdentry(vma->vm_file)->d_inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
@@ -4306,10 +4383,15 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        u64 page_end;
 
        ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
-       if (ret)
+       if (ret) {
+               if (ret == -ENOMEM)
+                       ret = VM_FAULT_OOM;
+               else /* -ENOSPC, -EIO, etc */
+                       ret = VM_FAULT_SIGBUS;
                goto out;
+       }
 
-       ret = -EINVAL;
+       ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
 again:
        lock_page(page);
        size = i_size_read(inode);
@@ -4357,6 +4439,8 @@ again:
        }
        ClearPageChecked(page);
        set_page_dirty(page);
+
+       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
        unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
 
 out_unlock:
@@ -4382,6 +4466,27 @@ static void btrfs_truncate(struct inode *inode)
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
 
        trans = btrfs_start_transaction(root, 1);
+
+       /*
+        * setattr is responsible for setting the ordered_data_close flag,
+        * but that is only tested during the last file release.  That
+        * could happen well after the next commit, leaving a great big
+        * window where new writes may get lost if someone chooses to write
+        * to this file after truncating to zero
+        *
+        * The inode doesn't have any dirty data here, and so if we commit
+        * this is a noop.  If someone immediately starts writing to the inode
+        * it is very likely we'll catch some of their writes in this
+        * transaction, and the commit will find this file on the ordered
+        * data list with good things to send down.
+        *
+        * This is a best effort solution, there is still a window where
+        * using truncate to replace the contents of the file will
+        * end up with a zero length file after a crash.
+        */
+       if (inode->i_size == 0 && BTRFS_I(inode)->ordered_data_close)
+               btrfs_add_ordered_operation(trans, root, inode);
+
        btrfs_set_trans_block_group(trans, inode);
        btrfs_i_size_write(inode, inode->i_size);
 
@@ -4458,12 +4563,15 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->i_acl = BTRFS_ACL_NOT_CACHED;
        ei->i_default_acl = BTRFS_ACL_NOT_CACHED;
        INIT_LIST_HEAD(&ei->i_orphan);
+       INIT_LIST_HEAD(&ei->ordered_operations);
        return &ei->vfs_inode;
 }
 
 void btrfs_destroy_inode(struct inode *inode)
 {
        struct btrfs_ordered_extent *ordered;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+
        WARN_ON(!list_empty(&inode->i_dentry));
        WARN_ON(inode->i_data.nrpages);
 
@@ -4474,13 +4582,24 @@ void btrfs_destroy_inode(struct inode *inode)
            BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED)
                posix_acl_release(BTRFS_I(inode)->i_default_acl);
 
-       spin_lock(&BTRFS_I(inode)->root->list_lock);
+       /*
+        * Make sure we're properly removed from the ordered operation
+        * lists.
+        */
+       smp_mb();
+       if (!list_empty(&BTRFS_I(inode)->ordered_operations)) {
+               spin_lock(&root->fs_info->ordered_extent_lock);
+               list_del_init(&BTRFS_I(inode)->ordered_operations);
+               spin_unlock(&root->fs_info->ordered_extent_lock);
+       }
+
+       spin_lock(&root->list_lock);
        if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
                printk(KERN_ERR "BTRFS: inode %lu: inode still on the orphan"
                       " list\n", inode->i_ino);
                dump_stack();
        }
-       spin_unlock(&BTRFS_I(inode)->root->list_lock);
+       spin_unlock(&root->list_lock);
 
        while (1) {
                ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
@@ -4605,8 +4724,36 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (ret)
                goto out_unlock;
 
+       /*
+        * we're using rename to replace one file with another.
+        * and the replacement file is large.  Start IO on it now so
+        * we don't add too much work to the end of the transaction
+        */
+       if (new_inode && old_inode && S_ISREG(old_inode->i_mode) &&
+           new_inode->i_size &&
+           old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
+               filemap_flush(old_inode->i_mapping);
+
        trans = btrfs_start_transaction(root, 1);
 
+       /*
+        * make sure the inode gets flushed if it is replacing
+        * something.
+        */
+       if (new_inode && new_inode->i_size &&
+           old_inode && S_ISREG(old_inode->i_mode)) {
+               btrfs_add_ordered_operation(trans, root, old_inode);
+       }
+
+       /*
+        * this is an ugly little race, but the rename is required to make
+        * sure that if we crash, the inode is either at the old name
+        * or the new one.  pinning the log transaction lets us make sure
+        * we don't allow a log commit to come in after we unlink the
+        * name but before we add the new name back in.
+        */
+       btrfs_pin_log_trans(root);
+
        btrfs_set_trans_block_group(trans, new_dir);
 
        btrfs_inc_nlink(old_dentry->d_inode);
@@ -4614,6 +4761,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        new_dir->i_ctime = new_dir->i_mtime = ctime;
        old_inode->i_ctime = ctime;
 
+       if (old_dentry->d_parent != new_dentry->d_parent)
+               btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
+
        ret = btrfs_unlink_inode(trans, root, old_dir, old_dentry->d_inode,
                                 old_dentry->d_name.name,
                                 old_dentry->d_name.len);
@@ -4645,7 +4795,14 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (ret)
                goto out_fail;
 
+       btrfs_log_new_name(trans, old_inode, old_dir,
+                                      new_dentry->d_parent);
 out_fail:
+
+       /* this btrfs_end_log_trans just allows the current
+        * log-sub transaction to complete
+        */
+       btrfs_end_log_trans(root);
        btrfs_end_transaction_throttle(trans, root);
 out_unlock:
        return ret;
index bca729fc80c83e07a3847b2b7bb6e73123d6c30f..7594bec1be10066619db8ebb578d03f5d2101de1 100644 (file)
@@ -267,7 +267,7 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name,
                goto out_dput;
 
        if (!IS_POSIXACL(parent->dentry->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
 
        error = mnt_want_write(parent->mnt);
        if (error)
index 47b0a88c12a23a6d983eff4c3ff0e4bdf1347d2e..1c36e5cd8f55495843631f7e5d3e6245d47684dd 100644 (file)
@@ -60,8 +60,8 @@ void btrfs_clear_lock_blocking(struct extent_buffer *eb)
 
 /*
  * unfortunately, many of the places that currently set a lock to blocking
- * don't end up blocking for every long, and often they don't block
- * at all.  For a dbench 50 run, if we don't spin one the blocking bit
+ * don't end up blocking for very long, and often they don't block
+ * at all.  For a dbench 50 run, if we don't spin on the blocking bit
  * at all, the context switch rate can jump up to 400,000/sec or more.
  *
  * So, we're still stuck with this crummy spin on the blocking bit,
@@ -71,12 +71,13 @@ void btrfs_clear_lock_blocking(struct extent_buffer *eb)
 static int btrfs_spin_on_block(struct extent_buffer *eb)
 {
        int i;
+
        for (i = 0; i < 512; i++) {
-               cpu_relax();
                if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
                        return 1;
                if (need_resched())
                        break;
+               cpu_relax();
        }
        return 0;
 }
@@ -95,13 +96,15 @@ int btrfs_try_spin_lock(struct extent_buffer *eb)
 {
        int i;
 
-       spin_nested(eb);
-       if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-               return 1;
-       spin_unlock(&eb->lock);
-
+       if (btrfs_spin_on_block(eb)) {
+               spin_nested(eb);
+               if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
+                       return 1;
+               spin_unlock(&eb->lock);
+       }
        /* spin for a bit on the BLOCKING flag */
        for (i = 0; i < 2; i++) {
+               cpu_relax();
                if (!btrfs_spin_on_block(eb))
                        break;
 
@@ -148,6 +151,9 @@ int btrfs_tree_lock(struct extent_buffer *eb)
        DEFINE_WAIT(wait);
        wait.func = btrfs_wake_function;
 
+       if (!btrfs_spin_on_block(eb))
+               goto sleep;
+
        while(1) {
                spin_nested(eb);
 
@@ -165,9 +171,10 @@ int btrfs_tree_lock(struct extent_buffer *eb)
                 * spin for a bit, and if the blocking flag goes away,
                 * loop around
                 */
+               cpu_relax();
                if (btrfs_spin_on_block(eb))
                        continue;
-
+sleep:
                prepare_to_wait_exclusive(&eb->lock_wq, &wait,
                                          TASK_UNINTERRUPTIBLE);
 
index 77c2411a5f0f0c59b6ab97e78b2828d94a1c7401..53c87b197d701671afde64fd7f8f00b59fdb8cd2 100644 (file)
@@ -310,6 +310,16 @@ int btrfs_remove_ordered_extent(struct inode *inode,
 
        spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
        list_del_init(&entry->root_extent_list);
+
+       /*
+        * we have no more ordered extents for this inode and
+        * no dirty pages.  We can safely remove it from the
+        * list of ordered extents
+        */
+       if (RB_EMPTY_ROOT(&tree->tree) &&
+           !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
+               list_del_init(&BTRFS_I(inode)->ordered_operations);
+       }
        spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
 
        mutex_unlock(&tree->mutex);
@@ -369,6 +379,68 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
        return 0;
 }
 
+/*
+ * this is used during transaction commit to write all the inodes
+ * added to the ordered operation list.  These files must be fully on
+ * disk before the transaction commits.
+ *
+ * we have two modes here, one is to just start the IO via filemap_flush
+ * and the other is to wait for all the io.  When we wait, we have an
+ * extra check to make sure the ordered operation list really is empty
+ * before we return
+ */
+int btrfs_run_ordered_operations(struct btrfs_root *root, int wait)
+{
+       struct btrfs_inode *btrfs_inode;
+       struct inode *inode;
+       struct list_head splice;
+
+       INIT_LIST_HEAD(&splice);
+
+       mutex_lock(&root->fs_info->ordered_operations_mutex);
+       spin_lock(&root->fs_info->ordered_extent_lock);
+again:
+       list_splice_init(&root->fs_info->ordered_operations, &splice);
+
+       while (!list_empty(&splice)) {
+               btrfs_inode = list_entry(splice.next, struct btrfs_inode,
+                                  ordered_operations);
+
+               inode = &btrfs_inode->vfs_inode;
+
+               list_del_init(&btrfs_inode->ordered_operations);
+
+               /*
+                * the inode may be getting freed (in sys_unlink path).
+                */
+               inode = igrab(inode);
+
+               if (!wait && inode) {
+                       list_add_tail(&BTRFS_I(inode)->ordered_operations,
+                             &root->fs_info->ordered_operations);
+               }
+               spin_unlock(&root->fs_info->ordered_extent_lock);
+
+               if (inode) {
+                       if (wait)
+                               btrfs_wait_ordered_range(inode, 0, (u64)-1);
+                       else
+                               filemap_flush(inode->i_mapping);
+                       iput(inode);
+               }
+
+               cond_resched();
+               spin_lock(&root->fs_info->ordered_extent_lock);
+       }
+       if (wait && !list_empty(&root->fs_info->ordered_operations))
+               goto again;
+
+       spin_unlock(&root->fs_info->ordered_extent_lock);
+       mutex_unlock(&root->fs_info->ordered_operations_mutex);
+
+       return 0;
+}
+
 /*
  * Used to start IO or wait for a given ordered extent to finish.
  *
@@ -726,3 +798,49 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
 
        return ret;
 }
+
+/*
+ * add a given inode to the list of inodes that must be fully on
+ * disk before a transaction commit finishes.
+ *
+ * This basically gives us the ext3 style data=ordered mode, and it is mostly
+ * used to make sure renamed files are fully on disk.
+ *
+ * It is a noop if the inode is already fully on disk.
+ *
+ * If trans is not null, we'll do a friendly check for a transaction that
+ * is already flushing things and force the IO down ourselves.
+ */
+int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct inode *inode)
+{
+       u64 last_mod;
+
+       last_mod = max(BTRFS_I(inode)->generation, BTRFS_I(inode)->last_trans);
+
+       /*
+        * if this file hasn't been changed since the last transaction
+        * commit, we can safely return without doing anything
+        */
+       if (last_mod < root->fs_info->last_trans_committed)
+               return 0;
+
+       /*
+        * the transaction is already committing.  Just start the IO and
+        * don't bother with all of this list nonsense
+        */
+       if (trans && root->fs_info->running_transaction->blocked) {
+               btrfs_wait_ordered_range(inode, 0, (u64)-1);
+               return 0;
+       }
+
+       spin_lock(&root->fs_info->ordered_extent_lock);
+       if (list_empty(&BTRFS_I(inode)->ordered_operations)) {
+               list_add_tail(&BTRFS_I(inode)->ordered_operations,
+                             &root->fs_info->ordered_operations);
+       }
+       spin_unlock(&root->fs_info->ordered_extent_lock);
+
+       return 0;
+}
index ab66d5e8d6d697eac5110401d5e37b0f2afa8f9e..3d31c8827b013407d6f4b14796896a6aac8ba53b 100644 (file)
@@ -155,4 +155,8 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
 int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
                           loff_t end, int sync_mode);
 int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only);
+int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
+int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct inode *inode);
 #endif
index 19a4daf03ccb6d7d8730d4d8c9602a24dc0c370b..9744af9d71e95afa3a66f9ac1b2188722318aad8 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/highmem.h>
 #include <linux/time.h>
 #include <linux/init.h>
+#include <linux/seq_file.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
@@ -66,7 +67,8 @@ static void btrfs_put_super(struct super_block *sb)
 enum {
        Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
        Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
-       Opt_ssd, Opt_thread_pool, Opt_noacl,  Opt_compress, Opt_err,
+       Opt_ssd, Opt_thread_pool, Opt_noacl,  Opt_compress, Opt_notreelog,
+       Opt_flushoncommit, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -83,6 +85,8 @@ static match_table_t tokens = {
        {Opt_compress, "compress"},
        {Opt_ssd, "ssd"},
        {Opt_noacl, "noacl"},
+       {Opt_notreelog, "notreelog"},
+       {Opt_flushoncommit, "flushoncommit"},
        {Opt_err, NULL},
 };
 
@@ -222,6 +226,14 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_noacl:
                        root->fs_info->sb->s_flags &= ~MS_POSIXACL;
                        break;
+               case Opt_notreelog:
+                       printk(KERN_INFO "btrfs: disabling tree log\n");
+                       btrfs_set_opt(info->mount_opt, NOTREELOG);
+                       break;
+               case Opt_flushoncommit:
+                       printk(KERN_INFO "btrfs: turning on flush-on-commit\n");
+                       btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
+                       break;
                default:
                        break;
                }
@@ -363,9 +375,8 @@ fail_close:
 int btrfs_sync_fs(struct super_block *sb, int wait)
 {
        struct btrfs_trans_handle *trans;
-       struct btrfs_root *root;
+       struct btrfs_root *root = btrfs_sb(sb);
        int ret;
-       root = btrfs_sb(sb);
 
        if (sb->s_flags & MS_RDONLY)
                return 0;
@@ -385,6 +396,41 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        return ret;
 }
 
+static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+       struct btrfs_root *root = btrfs_sb(vfs->mnt_sb);
+       struct btrfs_fs_info *info = root->fs_info;
+
+       if (btrfs_test_opt(root, DEGRADED))
+               seq_puts(seq, ",degraded");
+       if (btrfs_test_opt(root, NODATASUM))
+               seq_puts(seq, ",nodatasum");
+       if (btrfs_test_opt(root, NODATACOW))
+               seq_puts(seq, ",nodatacow");
+       if (btrfs_test_opt(root, NOBARRIER))
+               seq_puts(seq, ",nobarrier");
+       if (info->max_extent != (u64)-1)
+               seq_printf(seq, ",max_extent=%llu", info->max_extent);
+       if (info->max_inline != 8192 * 1024)
+               seq_printf(seq, ",max_inline=%llu", info->max_inline);
+       if (info->alloc_start != 0)
+               seq_printf(seq, ",alloc_start=%llu", info->alloc_start);
+       if (info->thread_pool_size !=  min_t(unsigned long,
+                                            num_online_cpus() + 2, 8))
+               seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
+       if (btrfs_test_opt(root, COMPRESS))
+               seq_puts(seq, ",compress");
+       if (btrfs_test_opt(root, SSD))
+               seq_puts(seq, ",ssd");
+       if (btrfs_test_opt(root, NOTREELOG))
+               seq_puts(seq, ",no-treelog");
+       if (btrfs_test_opt(root, FLUSHONCOMMIT))
+               seq_puts(seq, ",flush-on-commit");
+       if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
+               seq_puts(seq, ",noacl");
+       return 0;
+}
+
 static void btrfs_write_super(struct super_block *sb)
 {
        sb->s_dirt = 0;
@@ -630,7 +676,7 @@ static struct super_operations btrfs_super_ops = {
        .put_super      = btrfs_put_super,
        .write_super    = btrfs_write_super,
        .sync_fs        = btrfs_sync_fs,
-       .show_options   = generic_show_options,
+       .show_options   = btrfs_show_options,
        .write_inode    = btrfs_write_inode,
        .dirty_inode    = btrfs_dirty_inode,
        .alloc_inode    = btrfs_alloc_inode,
index 4112d53d4f4dad195636c6ffa93deaded831af6e..2869b3361eb6be3cf82e60ba58ce1d9191360c46 100644 (file)
@@ -53,8 +53,6 @@ static noinline int join_transaction(struct btrfs_root *root)
                                             GFP_NOFS);
                BUG_ON(!cur_trans);
                root->fs_info->generation++;
-               root->fs_info->last_alloc = 0;
-               root->fs_info->last_data_alloc = 0;
                cur_trans->num_writers = 1;
                cur_trans->num_joined = 0;
                cur_trans->transid = root->fs_info->generation;
@@ -65,6 +63,15 @@ static noinline int join_transaction(struct btrfs_root *root)
                cur_trans->use_count = 1;
                cur_trans->commit_done = 0;
                cur_trans->start_time = get_seconds();
+
+               cur_trans->delayed_refs.root.rb_node = NULL;
+               cur_trans->delayed_refs.num_entries = 0;
+               cur_trans->delayed_refs.num_heads_ready = 0;
+               cur_trans->delayed_refs.num_heads = 0;
+               cur_trans->delayed_refs.flushing = 0;
+               cur_trans->delayed_refs.run_delayed_start = 0;
+               spin_lock_init(&cur_trans->delayed_refs.lock);
+
                INIT_LIST_HEAD(&cur_trans->pending_snapshots);
                list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
                extent_io_tree_init(&cur_trans->dirty_pages,
@@ -182,6 +189,8 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
        h->block_group = 0;
        h->alloc_exclude_nr = 0;
        h->alloc_exclude_start = 0;
+       h->delayed_ref_updates = 0;
+
        root->fs_info->running_transaction->use_count++;
        mutex_unlock(&root->fs_info->trans_mutex);
        return h;
@@ -271,7 +280,6 @@ void btrfs_throttle(struct btrfs_root *root)
        if (!root->fs_info->open_ioctl_trans)
                wait_current_trans(root);
        mutex_unlock(&root->fs_info->trans_mutex);
-
        throttle_on_drops(root);
 }
 
@@ -280,6 +288,27 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 {
        struct btrfs_transaction *cur_trans;
        struct btrfs_fs_info *info = root->fs_info;
+       int count = 0;
+
+       while (count < 4) {
+               unsigned long cur = trans->delayed_ref_updates;
+               trans->delayed_ref_updates = 0;
+               if (cur &&
+                   trans->transaction->delayed_refs.num_heads_ready > 64) {
+                       trans->delayed_ref_updates = 0;
+
+                       /*
+                        * do a full flush if the transaction is trying
+                        * to close
+                        */
+                       if (trans->transaction->delayed_refs.flushing)
+                               cur = 0;
+                       btrfs_run_delayed_refs(trans, root, cur);
+               } else {
+                       break;
+               }
+               count++;
+       }
 
        mutex_lock(&info->trans_mutex);
        cur_trans = info->running_transaction;
@@ -424,9 +453,10 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
        u64 old_root_bytenr;
        struct btrfs_root *tree_root = root->fs_info->tree_root;
 
-       btrfs_extent_post_op(trans, root);
        btrfs_write_dirty_block_groups(trans, root);
-       btrfs_extent_post_op(trans, root);
+
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
 
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
@@ -438,14 +468,14 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                                     btrfs_header_level(root->node));
                btrfs_set_root_generation(&root->root_item, trans->transid);
 
-               btrfs_extent_post_op(trans, root);
-
                ret = btrfs_update_root(trans, tree_root,
                                        &root->root_key,
                                        &root->root_item);
                BUG_ON(ret);
                btrfs_write_dirty_block_groups(trans, root);
-               btrfs_extent_post_op(trans, root);
+
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               BUG_ON(ret);
        }
        return 0;
 }
@@ -459,15 +489,18 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct list_head *next;
        struct extent_buffer *eb;
+       int ret;
 
-       btrfs_extent_post_op(trans, fs_info->tree_root);
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
 
        eb = btrfs_lock_root_node(fs_info->tree_root);
-       btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0);
+       btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
        btrfs_tree_unlock(eb);
        free_extent_buffer(eb);
 
-       btrfs_extent_post_op(trans, fs_info->tree_root);
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
 
        while (!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
@@ -475,6 +508,9 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
                root = list_entry(next, struct btrfs_root, dirty_list);
 
                update_cowonly_root(trans, root);
+
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               BUG_ON(ret);
        }
        return 0;
 }
@@ -634,6 +670,31 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
        return 0;
 }
 
+/*
+ * when dropping snapshots, we generate a ton of delayed refs, and it makes
+ * sense not to join the transaction while it is trying to flush the current
+ * queue of delayed refs out.
+ *
+ * This is used by the drop snapshot code only
+ */
+static noinline int wait_transaction_pre_flush(struct btrfs_fs_info *info)
+{
+       DEFINE_WAIT(wait);
+
+       mutex_lock(&info->trans_mutex);
+       while (info->running_transaction &&
+              info->running_transaction->delayed_refs.flushing) {
+               prepare_to_wait(&info->transaction_wait, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               mutex_unlock(&info->trans_mutex);
+               schedule();
+               mutex_lock(&info->trans_mutex);
+               finish_wait(&info->transaction_wait, &wait);
+       }
+       mutex_unlock(&info->trans_mutex);
+       return 0;
+}
+
 /*
  * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on
  * all of them
@@ -661,7 +722,22 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
                atomic_inc(&root->fs_info->throttles);
 
                while (1) {
+                       /*
+                        * we don't want to jump in and create a bunch of
+                        * delayed refs if the transaction is starting to close
+                        */
+                       wait_transaction_pre_flush(tree_root->fs_info);
                        trans = btrfs_start_transaction(tree_root, 1);
+
+                       /*
+                        * we've joined a transaction, make sure it isn't
+                        * closing right now
+                        */
+                       if (trans->transaction->delayed_refs.flushing) {
+                               btrfs_end_transaction(trans, tree_root);
+                               continue;
+                       }
+
                        mutex_lock(&root->fs_info->drop_mutex);
                        ret = btrfs_drop_snapshot(trans, dirty->root);
                        if (ret != -EAGAIN)
@@ -766,7 +842,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
 
        old = btrfs_lock_root_node(root);
-       btrfs_cow_block(trans, root, old, NULL, 0, &old, 0);
+       btrfs_cow_block(trans, root, old, NULL, 0, &old);
 
        btrfs_copy_root(trans, root, old, &tmp, objectid);
        btrfs_tree_unlock(old);
@@ -894,12 +970,32 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        struct extent_io_tree *pinned_copy;
        DEFINE_WAIT(wait);
        int ret;
+       int should_grow = 0;
+       unsigned long now = get_seconds();
+       int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT);
+
+       btrfs_run_ordered_operations(root, 0);
+
+       /* make a pass through all the delayed refs we have so far
+        * any runnings procs may add more while we are here
+        */
+       ret = btrfs_run_delayed_refs(trans, root, 0);
+       BUG_ON(ret);
+
+       cur_trans = trans->transaction;
+       /*
+        * set the flushing flag so procs in this transaction have to
+        * start sending their work down.
+        */
+       cur_trans->delayed_refs.flushing = 1;
+
+       ret = btrfs_run_delayed_refs(trans, root, 0);
+       BUG_ON(ret);
 
-       INIT_LIST_HEAD(&dirty_fs_roots);
        mutex_lock(&root->fs_info->trans_mutex);
-       if (trans->transaction->in_commit) {
-               cur_trans = trans->transaction;
-               trans->transaction->use_count++;
+       INIT_LIST_HEAD(&dirty_fs_roots);
+       if (cur_trans->in_commit) {
+               cur_trans->use_count++;
                mutex_unlock(&root->fs_info->trans_mutex);
                btrfs_end_transaction(trans, root);
 
@@ -922,7 +1018,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        trans->transaction->in_commit = 1;
        trans->transaction->blocked = 1;
-       cur_trans = trans->transaction;
        if (cur_trans->list.prev != &root->fs_info->trans_list) {
                prev_trans = list_entry(cur_trans->list.prev,
                                        struct btrfs_transaction, list);
@@ -937,6 +1032,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                }
        }
 
+       if (now < cur_trans->start_time || now - cur_trans->start_time < 1)
+               should_grow = 1;
+
        do {
                int snap_pending = 0;
                joined = cur_trans->num_joined;
@@ -949,26 +1047,42 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                if (cur_trans->num_writers > 1)
                        timeout = MAX_SCHEDULE_TIMEOUT;
-               else
+               else if (should_grow)
                        timeout = 1;
 
                mutex_unlock(&root->fs_info->trans_mutex);
 
-               if (snap_pending) {
+               if (flush_on_commit || snap_pending) {
+                       if (flush_on_commit)
+                               btrfs_start_delalloc_inodes(root);
                        ret = btrfs_wait_ordered_extents(root, 1);
                        BUG_ON(ret);
                }
 
-               schedule_timeout(timeout);
+               /*
+                * rename don't use btrfs_join_transaction, so, once we
+                * set the transaction to blocked above, we aren't going
+                * to get any new ordered operations.  We can safely run
+                * it here and no for sure that nothing new will be added
+                * to the list
+                */
+               btrfs_run_ordered_operations(root, 1);
+
+               smp_mb();
+               if (cur_trans->num_writers > 1 || should_grow)
+                       schedule_timeout(timeout);
 
                mutex_lock(&root->fs_info->trans_mutex);
                finish_wait(&cur_trans->writer_wait, &wait);
        } while (cur_trans->num_writers > 1 ||
-                (cur_trans->num_joined != joined));
+                (should_grow && cur_trans->num_joined != joined));
 
        ret = create_pending_snapshots(trans, root->fs_info);
        BUG_ON(ret);
 
+       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+       BUG_ON(ret);
+
        WARN_ON(cur_trans != trans->transaction);
 
        /* btrfs_commit_tree_roots is responsible for getting the
@@ -1032,6 +1146,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        btrfs_copy_pinned(root, pinned_copy);
 
        trans->transaction->blocked = 0;
+
        wake_up(&root->fs_info->transaction_throttle);
        wake_up(&root->fs_info->transaction_wait);
 
@@ -1058,6 +1173,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        mutex_lock(&root->fs_info->trans_mutex);
 
        cur_trans->commit_done = 1;
+
        root->fs_info->last_trans_committed = cur_trans->transid;
        wake_up(&cur_trans->commit_wait);
 
index ea292117f88252f2f6c14ccde2cce4eac50d9509..94f5bde2b58d40144a5d5ddf3a11607cef4b0e82 100644 (file)
 #ifndef __BTRFS_TRANSACTION__
 #define __BTRFS_TRANSACTION__
 #include "btrfs_inode.h"
+#include "delayed-ref.h"
 
 struct btrfs_transaction {
        u64 transid;
+       /*
+        * total writers in this transaction, it must be zero before the
+        * transaction can end
+        */
        unsigned long num_writers;
+
        unsigned long num_joined;
        int in_commit;
        int use_count;
@@ -34,6 +40,7 @@ struct btrfs_transaction {
        wait_queue_head_t writer_wait;
        wait_queue_head_t commit_wait;
        struct list_head pending_snapshots;
+       struct btrfs_delayed_ref_root delayed_refs;
 };
 
 struct btrfs_trans_handle {
@@ -44,6 +51,7 @@ struct btrfs_trans_handle {
        u64 block_group;
        u64 alloc_exclude_start;
        u64 alloc_exclude_nr;
+       unsigned long delayed_ref_updates;
 };
 
 struct btrfs_pending_snapshot {
index 98d25fa4570ea902abc4c8345ecf29f62af9013c..b10eacdb16200e686b3519a46747b706b927761f 100644 (file)
@@ -124,8 +124,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
        }
 
        btrfs_release_path(root, path);
-       if (is_extent)
-               btrfs_extent_post_op(trans, root);
 out:
        if (path)
                btrfs_free_path(path);
index 9c462fbd60fac14ad17f192afb08c37794295d36..25f20ea11f2789db90f796ecfd52aeae87c02910 100644 (file)
 #define LOG_INODE_ALL 0
 #define LOG_INODE_EXISTS 1
 
+/*
+ * directory trouble cases
+ *
+ * 1) on rename or unlink, if the inode being unlinked isn't in the fsync
+ * log, we must force a full commit before doing an fsync of the directory
+ * where the unlink was done.
+ * ---> record transid of last unlink/rename per directory
+ *
+ * mkdir foo/some_dir
+ * normal commit
+ * rename foo/some_dir foo2/some_dir
+ * mkdir foo/some_dir
+ * fsync foo/some_dir/some_file
+ *
+ * The fsync above will unlink the original some_dir without recording
+ * it in its new location (foo2).  After a crash, some_dir will be gone
+ * unless the fsync of some_file forces a full commit
+ *
+ * 2) we must log any new names for any file or dir that is in the fsync
+ * log. ---> check inode while renaming/linking.
+ *
+ * 2a) we must log any new names for any file or dir during rename
+ * when the directory they are being removed from was logged.
+ * ---> check inode and old parent dir during rename
+ *
+ *  2a is actually the more important variant.  With the extra logging
+ *  a crash might unlink the old name without recreating the new one
+ *
+ * 3) after a crash, we must go through any directories with a link count
+ * of zero and redo the rm -rf
+ *
+ * mkdir f1/foo
+ * normal commit
+ * rm -rf f1/foo
+ * fsync(f1)
+ *
+ * The directory f1 was fully removed from the FS, but fsync was never
+ * called on f1, only its parent dir.  After a crash the rm -rf must
+ * be replayed.  This must be able to recurse down the entire
+ * directory tree.  The inode link count fixup code takes care of the
+ * ugly details.
+ */
+
 /*
  * stages for the tree walking.  The first
  * stage (0) is to only pin down the blocks we find
 #define LOG_WALK_REPLAY_INODES 1
 #define LOG_WALK_REPLAY_ALL 2
 
-static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
+static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, struct inode *inode,
                             int inode_only);
 static int link_to_fixup_dir(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path, u64 objectid);
+static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
+                                      struct btrfs_root *root,
+                                      struct btrfs_root *log,
+                                      struct btrfs_path *path,
+                                      u64 dirid, int del_all);
 
 /*
  * tree logging is a special write ahead log used to make sure that
@@ -132,11 +180,26 @@ static int join_running_log_trans(struct btrfs_root *root)
        return ret;
 }
 
+/*
+ * This either makes the current running log transaction wait
+ * until you call btrfs_end_log_trans() or it makes any future
+ * log transactions wait until you call btrfs_end_log_trans()
+ */
+int btrfs_pin_log_trans(struct btrfs_root *root)
+{
+       int ret = -ENOENT;
+
+       mutex_lock(&root->log_mutex);
+       atomic_inc(&root->log_writers);
+       mutex_unlock(&root->log_mutex);
+       return ret;
+}
+
 /*
  * indicate we're done making changes to the log tree
  * and wake up anyone waiting to do a sync
  */
-static int end_log_trans(struct btrfs_root *root)
+int btrfs_end_log_trans(struct btrfs_root *root)
 {
        if (atomic_dec_and_test(&root->log_writers)) {
                smp_mb();
@@ -199,12 +262,9 @@ static int process_one_buffer(struct btrfs_root *log,
                              struct extent_buffer *eb,
                              struct walk_control *wc, u64 gen)
 {
-       if (wc->pin) {
-               mutex_lock(&log->fs_info->pinned_mutex);
+       if (wc->pin)
                btrfs_update_pinned_extents(log->fs_info->extent_root,
                                            eb->start, eb->len, 1);
-               mutex_unlock(&log->fs_info->pinned_mutex);
-       }
 
        if (btrfs_buffer_uptodate(eb, gen)) {
                if (wc->write)
@@ -603,6 +663,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
 
        ret = link_to_fixup_dir(trans, root, path, location.objectid);
        BUG_ON(ret);
+
        ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
        BUG_ON(ret);
        kfree(name);
@@ -804,6 +865,7 @@ conflict_again:
                                            victim_name_len)) {
                                btrfs_inc_nlink(inode);
                                btrfs_release_path(root, path);
+
                                ret = btrfs_unlink_inode(trans, root, dir,
                                                         inode, victim_name,
                                                         victim_name_len);
@@ -922,13 +984,20 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
                key.offset--;
                btrfs_release_path(root, path);
        }
-       btrfs_free_path(path);
+       btrfs_release_path(root, path);
        if (nlink != inode->i_nlink) {
                inode->i_nlink = nlink;
                btrfs_update_inode(trans, root, inode);
        }
        BTRFS_I(inode)->index_cnt = (u64)-1;
 
+       if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) {
+               ret = replay_dir_deletes(trans, root, NULL, path,
+                                        inode->i_ino, 1);
+               BUG_ON(ret);
+       }
+       btrfs_free_path(path);
+
        return 0;
 }
 
@@ -971,9 +1040,12 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
 
                iput(inode);
 
-               if (key.offset == 0)
-                       break;
-               key.offset--;
+               /*
+                * fixup on a directory may create new entries,
+                * make sure we always look for the highset possible
+                * offset
+                */
+               key.offset = (u64)-1;
        }
        btrfs_release_path(root, path);
        return 0;
@@ -1150,8 +1222,7 @@ insert:
        ret = insert_one_name(trans, root, path, key->objectid, key->offset,
                              name, name_len, log_type, &log_key);
 
-       if (ret && ret != -ENOENT)
-               BUG();
+       BUG_ON(ret && ret != -ENOENT);
        goto out;
 }
 
@@ -1313,11 +1384,11 @@ again:
                read_extent_buffer(eb, name, (unsigned long)(di + 1),
                                  name_len);
                log_di = NULL;
-               if (dir_key->type == BTRFS_DIR_ITEM_KEY) {
+               if (log && dir_key->type == BTRFS_DIR_ITEM_KEY) {
                        log_di = btrfs_lookup_dir_item(trans, log, log_path,
                                                       dir_key->objectid,
                                                       name, name_len, 0);
-               } else if (dir_key->type == BTRFS_DIR_INDEX_KEY) {
+               } else if (log && dir_key->type == BTRFS_DIR_INDEX_KEY) {
                        log_di = btrfs_lookup_dir_index_item(trans, log,
                                                     log_path,
                                                     dir_key->objectid,
@@ -1378,7 +1449,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
                                       struct btrfs_root *root,
                                       struct btrfs_root *log,
                                       struct btrfs_path *path,
-                                      u64 dirid)
+                                      u64 dirid, int del_all)
 {
        u64 range_start;
        u64 range_end;
@@ -1408,10 +1479,14 @@ again:
        range_start = 0;
        range_end = 0;
        while (1) {
-               ret = find_dir_range(log, path, dirid, key_type,
-                                    &range_start, &range_end);
-               if (ret != 0)
-                       break;
+               if (del_all)
+                       range_end = (u64)-1;
+               else {
+                       ret = find_dir_range(log, path, dirid, key_type,
+                                            &range_start, &range_end);
+                       if (ret != 0)
+                               break;
+               }
 
                dir_key.offset = range_start;
                while (1) {
@@ -1437,7 +1512,8 @@ again:
                                break;
 
                        ret = check_item_in_log(trans, root, log, path,
-                                               log_path, dir, &found_key);
+                                               log_path, dir,
+                                               &found_key);
                        BUG_ON(ret);
                        if (found_key.offset == (u64)-1)
                                break;
@@ -1514,7 +1590,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                        mode = btrfs_inode_mode(eb, inode_item);
                        if (S_ISDIR(mode)) {
                                ret = replay_dir_deletes(wc->trans,
-                                        root, log, path, key.objectid);
+                                        root, log, path, key.objectid, 0);
                                BUG_ON(ret);
                        }
                        ret = overwrite_item(wc->trans, root, path,
@@ -1533,6 +1609,17 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                                        root, inode, inode->i_size,
                                        BTRFS_EXTENT_DATA_KEY);
                                BUG_ON(ret);
+
+                               /* if the nlink count is zero here, the iput
+                                * will free the inode.  We bump it to make
+                                * sure it doesn't get freed until the link
+                                * count fixup is done
+                                */
+                               if (inode->i_nlink == 0) {
+                                       btrfs_inc_nlink(inode);
+                                       btrfs_update_inode(wc->trans,
+                                                          root, inode);
+                               }
                                iput(inode);
                        }
                        ret = link_to_fixup_dir(wc->trans, root,
@@ -1840,7 +1927,8 @@ static int update_log_root(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-static int wait_log_commit(struct btrfs_root *root, unsigned long transid)
+static int wait_log_commit(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, unsigned long transid)
 {
        DEFINE_WAIT(wait);
        int index = transid % 2;
@@ -1854,9 +1942,12 @@ static int wait_log_commit(struct btrfs_root *root, unsigned long transid)
                prepare_to_wait(&root->log_commit_wait[index],
                                &wait, TASK_UNINTERRUPTIBLE);
                mutex_unlock(&root->log_mutex);
-               if (root->log_transid < transid + 2 &&
+
+               if (root->fs_info->last_trans_log_full_commit !=
+                   trans->transid && root->log_transid < transid + 2 &&
                    atomic_read(&root->log_commit[index]))
                        schedule();
+
                finish_wait(&root->log_commit_wait[index], &wait);
                mutex_lock(&root->log_mutex);
        } while (root->log_transid < transid + 2 &&
@@ -1864,14 +1955,16 @@ static int wait_log_commit(struct btrfs_root *root, unsigned long transid)
        return 0;
 }
 
-static int wait_for_writer(struct btrfs_root *root)
+static int wait_for_writer(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root)
 {
        DEFINE_WAIT(wait);
        while (atomic_read(&root->log_writers)) {
                prepare_to_wait(&root->log_writer_wait,
                                &wait, TASK_UNINTERRUPTIBLE);
                mutex_unlock(&root->log_mutex);
-               if (atomic_read(&root->log_writers))
+               if (root->fs_info->last_trans_log_full_commit !=
+                   trans->transid && atomic_read(&root->log_writers))
                        schedule();
                mutex_lock(&root->log_mutex);
                finish_wait(&root->log_writer_wait, &wait);
@@ -1882,7 +1975,14 @@ static int wait_for_writer(struct btrfs_root *root)
 /*
  * btrfs_sync_log does sends a given tree log down to the disk and
  * updates the super blocks to record it.  When this call is done,
- * you know that any inodes previously logged are safely on disk
+ * you know that any inodes previously logged are safely on disk only
+ * if it returns 0.
+ *
+ * Any other return value means you need to call btrfs_commit_transaction.
+ * Some of the edge cases for fsyncing directories that have had unlinks
+ * or renames done in the past mean that sometimes the only safe
+ * fsync is to commit the whole FS.  When btrfs_sync_log returns -EAGAIN,
+ * that has happened.
  */
 int btrfs_sync_log(struct btrfs_trans_handle *trans,
                   struct btrfs_root *root)
@@ -1896,7 +1996,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        mutex_lock(&root->log_mutex);
        index1 = root->log_transid % 2;
        if (atomic_read(&root->log_commit[index1])) {
-               wait_log_commit(root, root->log_transid);
+               wait_log_commit(trans, root, root->log_transid);
                mutex_unlock(&root->log_mutex);
                return 0;
        }
@@ -1904,18 +2004,26 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        /* wait for previous tree log sync to complete */
        if (atomic_read(&root->log_commit[(index1 + 1) % 2]))
-               wait_log_commit(root, root->log_transid - 1);
+               wait_log_commit(trans, root, root->log_transid - 1);
 
        while (1) {
                unsigned long batch = root->log_batch;
                mutex_unlock(&root->log_mutex);
                schedule_timeout_uninterruptible(1);
                mutex_lock(&root->log_mutex);
-               wait_for_writer(root);
+
+               wait_for_writer(trans, root);
                if (batch == root->log_batch)
                        break;
        }
 
+       /* bail out if we need to do a full commit */
+       if (root->fs_info->last_trans_log_full_commit == trans->transid) {
+               ret = -EAGAIN;
+               mutex_unlock(&root->log_mutex);
+               goto out;
+       }
+
        ret = btrfs_write_and_wait_marked_extents(log, &log->dirty_log_pages);
        BUG_ON(ret);
 
@@ -1951,16 +2059,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        index2 = log_root_tree->log_transid % 2;
        if (atomic_read(&log_root_tree->log_commit[index2])) {
-               wait_log_commit(log_root_tree, log_root_tree->log_transid);
+               wait_log_commit(trans, log_root_tree,
+                               log_root_tree->log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
                goto out;
        }
        atomic_set(&log_root_tree->log_commit[index2], 1);
 
-       if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2]))
-               wait_log_commit(log_root_tree, log_root_tree->log_transid - 1);
+       if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) {
+               wait_log_commit(trans, log_root_tree,
+                               log_root_tree->log_transid - 1);
+       }
+
+       wait_for_writer(trans, log_root_tree);
 
-       wait_for_writer(log_root_tree);
+       /*
+        * now that we've moved on to the tree of log tree roots,
+        * check the full commit flag again
+        */
+       if (root->fs_info->last_trans_log_full_commit == trans->transid) {
+               mutex_unlock(&log_root_tree->log_mutex);
+               ret = -EAGAIN;
+               goto out_wake_log_root;
+       }
 
        ret = btrfs_write_and_wait_marked_extents(log_root_tree,
                                &log_root_tree->dirty_log_pages);
@@ -1985,7 +2106,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
         * in and cause problems either.
         */
        write_ctree_super(trans, root->fs_info->tree_root, 2);
+       ret = 0;
 
+out_wake_log_root:
        atomic_set(&log_root_tree->log_commit[index2], 0);
        smp_mb();
        if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
@@ -1998,7 +2121,8 @@ out:
        return 0;
 }
 
-/* * free all the extents used by the tree log.  This should be called
+/*
+ * free all the extents used by the tree log.  This should be called
  * at commit time of the full transaction
  */
 int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
@@ -2132,7 +2256,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 
        btrfs_free_path(path);
        mutex_unlock(&BTRFS_I(dir)->log_mutex);
-       end_log_trans(root);
+       btrfs_end_log_trans(root);
 
        return 0;
 }
@@ -2159,7 +2283,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
        ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino,
                                  dirid, &index);
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
-       end_log_trans(root);
+       btrfs_end_log_trans(root);
 
        return ret;
 }
@@ -2559,7 +2683,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
  *
  * This handles both files and directories.
  */
-static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
+static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, struct inode *inode,
                             int inode_only)
 {
@@ -2585,28 +2709,17 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
        min_key.offset = 0;
 
        max_key.objectid = inode->i_ino;
+
+       /* today the code can only do partial logging of directories */
+       if (!S_ISDIR(inode->i_mode))
+           inode_only = LOG_INODE_ALL;
+
        if (inode_only == LOG_INODE_EXISTS || S_ISDIR(inode->i_mode))
                max_key.type = BTRFS_XATTR_ITEM_KEY;
        else
                max_key.type = (u8)-1;
        max_key.offset = (u64)-1;
 
-       /*
-        * if this inode has already been logged and we're in inode_only
-        * mode, we don't want to delete the things that have already
-        * been written to the log.
-        *
-        * But, if the inode has been through an inode_only log,
-        * the logged_trans field is not set.  This allows us to catch
-        * any new names for this inode in the backrefs by logging it
-        * again
-        */
-       if (inode_only == LOG_INODE_EXISTS &&
-           BTRFS_I(inode)->logged_trans == trans->transid) {
-               btrfs_free_path(path);
-               btrfs_free_path(dst_path);
-               goto out;
-       }
        mutex_lock(&BTRFS_I(inode)->log_mutex);
 
        /*
@@ -2693,7 +2806,6 @@ next_slot:
        if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
                btrfs_release_path(root, path);
                btrfs_release_path(log, dst_path);
-               BTRFS_I(inode)->log_dirty_trans = 0;
                ret = log_directory_changes(trans, root, inode, path, dst_path);
                BUG_ON(ret);
        }
@@ -2702,19 +2814,69 @@ next_slot:
 
        btrfs_free_path(path);
        btrfs_free_path(dst_path);
-out:
        return 0;
 }
 
-int btrfs_log_inode(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct inode *inode,
-                   int inode_only)
+/*
+ * follow the dentry parent pointers up the chain and see if any
+ * of the directories in it require a full commit before they can
+ * be logged.  Returns zero if nothing special needs to be done or 1 if
+ * a full commit is required.
+ */
+static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
+                                              struct inode *inode,
+                                              struct dentry *parent,
+                                              struct super_block *sb,
+                                              u64 last_committed)
 {
-       int ret;
+       int ret = 0;
+       struct btrfs_root *root;
 
-       start_log_trans(trans, root);
-       ret = __btrfs_log_inode(trans, root, inode, inode_only);
-       end_log_trans(root);
+       /*
+        * for regular files, if its inode is already on disk, we don't
+        * have to worry about the parents at all.  This is because
+        * we can use the last_unlink_trans field to record renames
+        * and other fun in this file.
+        */
+       if (S_ISREG(inode->i_mode) &&
+           BTRFS_I(inode)->generation <= last_committed &&
+           BTRFS_I(inode)->last_unlink_trans <= last_committed)
+                       goto out;
+
+       if (!S_ISDIR(inode->i_mode)) {
+               if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
+                       goto out;
+               inode = parent->d_inode;
+       }
+
+       while (1) {
+               BTRFS_I(inode)->logged_trans = trans->transid;
+               smp_mb();
+
+               if (BTRFS_I(inode)->last_unlink_trans > last_committed) {
+                       root = BTRFS_I(inode)->root;
+
+                       /*
+                        * make sure any commits to the log are forced
+                        * to be full commits
+                        */
+                       root->fs_info->last_trans_log_full_commit =
+                               trans->transid;
+                       ret = 1;
+                       break;
+               }
+
+               if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
+                       break;
+
+               if (parent == sb->s_root)
+                       break;
+
+               parent = parent->d_parent;
+               inode = parent->d_inode;
+
+       }
+out:
        return ret;
 }
 
@@ -2724,31 +2886,70 @@ int btrfs_log_inode(struct btrfs_trans_handle *trans,
  * only logging is done of any parent directories that are older than
  * the last committed transaction
  */
-int btrfs_log_dentry(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct dentry *dentry)
+int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
+                   struct btrfs_root *root, struct inode *inode,
+                   struct dentry *parent, int exists_only)
 {
-       int inode_only = LOG_INODE_ALL;
+       int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
        struct super_block *sb;
-       int ret;
+       int ret = 0;
+       u64 last_committed = root->fs_info->last_trans_committed;
+
+       sb = inode->i_sb;
+
+       if (btrfs_test_opt(root, NOTREELOG)) {
+               ret = 1;
+               goto end_no_trans;
+       }
+
+       if (root->fs_info->last_trans_log_full_commit >
+           root->fs_info->last_trans_committed) {
+               ret = 1;
+               goto end_no_trans;
+       }
+
+       ret = check_parent_dirs_for_sync(trans, inode, parent,
+                                        sb, last_committed);
+       if (ret)
+               goto end_no_trans;
 
        start_log_trans(trans, root);
-       sb = dentry->d_inode->i_sb;
-       while (1) {
-               ret = __btrfs_log_inode(trans, root, dentry->d_inode,
-                                       inode_only);
-               BUG_ON(ret);
-               inode_only = LOG_INODE_EXISTS;
 
-               dentry = dentry->d_parent;
-               if (!dentry || !dentry->d_inode || sb != dentry->d_inode->i_sb)
+       ret = btrfs_log_inode(trans, root, inode, inode_only);
+       BUG_ON(ret);
+
+       /*
+        * for regular files, if its inode is already on disk, we don't
+        * have to worry about the parents at all.  This is because
+        * we can use the last_unlink_trans field to record renames
+        * and other fun in this file.
+        */
+       if (S_ISREG(inode->i_mode) &&
+           BTRFS_I(inode)->generation <= last_committed &&
+           BTRFS_I(inode)->last_unlink_trans <= last_committed)
+                       goto no_parent;
+
+       inode_only = LOG_INODE_EXISTS;
+       while (1) {
+               if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
                        break;
 
-               if (BTRFS_I(dentry->d_inode)->generation <=
-                   root->fs_info->last_trans_committed)
+               inode = parent->d_inode;
+               if (BTRFS_I(inode)->generation >
+                   root->fs_info->last_trans_committed) {
+                       ret = btrfs_log_inode(trans, root, inode, inode_only);
+                       BUG_ON(ret);
+               }
+               if (parent == sb->s_root)
                        break;
+
+               parent = parent->d_parent;
        }
-       end_log_trans(root);
-       return 0;
+no_parent:
+       ret = 0;
+       btrfs_end_log_trans(root);
+end_no_trans:
+       return ret;
 }
 
 /*
@@ -2760,12 +2961,8 @@ int btrfs_log_dentry(struct btrfs_trans_handle *trans,
 int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct dentry *dentry)
 {
-       u64 gen;
-       gen = root->fs_info->last_trans_new_blockgroup;
-       if (gen > root->fs_info->last_trans_committed)
-               return 1;
-       else
-               return btrfs_log_dentry(trans, root, dentry);
+       return btrfs_log_inode_parent(trans, root, dentry->d_inode,
+                                     dentry->d_parent, 0);
 }
 
 /*
@@ -2884,3 +3081,94 @@ again:
        kfree(log_root_tree);
        return 0;
 }
+
+/*
+ * there are some corner cases where we want to force a full
+ * commit instead of allowing a directory to be logged.
+ *
+ * They revolve around files there were unlinked from the directory, and
+ * this function updates the parent directory so that a full commit is
+ * properly done if it is fsync'd later after the unlinks are done.
+ */
+void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
+                            struct inode *dir, struct inode *inode,
+                            int for_rename)
+{
+       /*
+        * when we're logging a file, if it hasn't been renamed
+        * or unlinked, and its inode is fully committed on disk,
+        * we don't have to worry about walking up the directory chain
+        * to log its parents.
+        *
+        * So, we use the last_unlink_trans field to put this transid
+        * into the file.  When the file is logged we check it and
+        * don't log the parents if the file is fully on disk.
+        */
+       if (S_ISREG(inode->i_mode))
+               BTRFS_I(inode)->last_unlink_trans = trans->transid;
+
+       /*
+        * if this directory was already logged any new
+        * names for this file/dir will get recorded
+        */
+       smp_mb();
+       if (BTRFS_I(dir)->logged_trans == trans->transid)
+               return;
+
+       /*
+        * if the inode we're about to unlink was logged,
+        * the log will be properly updated for any new names
+        */
+       if (BTRFS_I(inode)->logged_trans == trans->transid)
+               return;
+
+       /*
+        * when renaming files across directories, if the directory
+        * there we're unlinking from gets fsync'd later on, there's
+        * no way to find the destination directory later and fsync it
+        * properly.  So, we have to be conservative and force commits
+        * so the new name gets discovered.
+        */
+       if (for_rename)
+               goto record;
+
+       /* we can safely do the unlink without any special recording */
+       return;
+
+record:
+       BTRFS_I(dir)->last_unlink_trans = trans->transid;
+}
+
+/*
+ * Call this after adding a new name for a file and it will properly
+ * update the log to reflect the new name.
+ *
+ * It will return zero if all goes well, and it will return 1 if a
+ * full transaction commit is required.
+ */
+int btrfs_log_new_name(struct btrfs_trans_handle *trans,
+                       struct inode *inode, struct inode *old_dir,
+                       struct dentry *parent)
+{
+       struct btrfs_root * root = BTRFS_I(inode)->root;
+
+       /*
+        * this will force the logging code to walk the dentry chain
+        * up for the file
+        */
+       if (S_ISREG(inode->i_mode))
+               BTRFS_I(inode)->last_unlink_trans = trans->transid;
+
+       /*
+        * if this inode hasn't been logged and directory we're renaming it
+        * from hasn't been logged, we don't need to log it
+        */
+       if (BTRFS_I(inode)->logged_trans <=
+           root->fs_info->last_trans_committed &&
+           (!old_dir || BTRFS_I(old_dir)->logged_trans <=
+                   root->fs_info->last_trans_committed))
+               return 0;
+
+       return btrfs_log_inode_parent(trans, root, inode, parent, 1);
+}
+
index b9409b32ed0299a43f0b04b4598ec8b3d9b266b8..d09c7609e16b3281a0b7658083888c277fb1ccf8 100644 (file)
 int btrfs_sync_log(struct btrfs_trans_handle *trans,
                   struct btrfs_root *root);
 int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
-int btrfs_log_dentry(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct dentry *dentry);
 int btrfs_recover_log_trees(struct btrfs_root *tree_root);
 int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct dentry *dentry);
-int btrfs_log_inode(struct btrfs_trans_handle *trans,
-                   struct btrfs_root *root, struct inode *inode,
-                   int inode_only);
 int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 const char *name, int name_len,
@@ -38,4 +33,16 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
                               const char *name, int name_len,
                               struct inode *inode, u64 dirid);
+int btrfs_join_running_log_trans(struct btrfs_root *root);
+int btrfs_end_log_trans(struct btrfs_root *root);
+int btrfs_pin_log_trans(struct btrfs_root *root);
+int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
+                   struct btrfs_root *root, struct inode *inode,
+                   struct dentry *parent, int exists_only);
+void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
+                            struct inode *dir, struct inode *inode,
+                            int for_rename);
+int btrfs_log_new_name(struct btrfs_trans_handle *trans,
+                       struct inode *inode, struct inode *old_dir,
+                       struct dentry *parent);
 #endif
index dd06e18e5aac7518191e02791073345e6a0f51cd..e0913e4697284673b4c00cd58bf911fc44fe4019 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
 #include <linux/random.h>
+#include <linux/iocontext.h>
 #include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
@@ -145,8 +146,9 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
        int again = 0;
        unsigned long num_run = 0;
        unsigned long limit;
+       unsigned long last_waited = 0;
 
-       bdi = device->bdev->bd_inode->i_mapping->backing_dev_info;
+       bdi = blk_get_backing_dev_info(device->bdev);
        fs_info = device->dev_root->fs_info;
        limit = btrfs_async_submit_limit(fs_info);
        limit = limit * 2 / 3;
@@ -207,7 +209,32 @@ loop_lock:
                if (pending && bdi_write_congested(bdi) && num_run > 16 &&
                    fs_info->fs_devices->open_devices > 1) {
                        struct bio *old_head;
+                       struct io_context *ioc;
 
+                       ioc = current->io_context;
+
+                       /*
+                        * the main goal here is that we don't want to
+                        * block if we're going to be able to submit
+                        * more requests without blocking.
+                        *
+                        * This code does two great things, it pokes into
+                        * the elevator code from a filesystem _and_
+                        * it makes assumptions about how batching works.
+                        */
+                       if (ioc && ioc->nr_batch_requests > 0 &&
+                           time_before(jiffies, ioc->last_waited + HZ/50UL) &&
+                           (last_waited == 0 ||
+                            ioc->last_waited == last_waited)) {
+                               /*
+                                * we want to go through our batch of
+                                * requests and stop.  So, we copy out
+                                * the ioc->last_waited time and test
+                                * against it before looping
+                                */
+                               last_waited = ioc->last_waited;
+                               continue;
+                       }
                        spin_lock(&device->io_lock);
 
                        old_head = device->pending_bios;
@@ -231,6 +258,18 @@ loop_lock:
        if (device->pending_bios)
                goto loop_lock;
        spin_unlock(&device->io_lock);
+
+       /*
+        * IO has already been through a long path to get here.  Checksumming,
+        * async helper threads, perhaps compression.  We've done a pretty
+        * good job of collecting a batch of IO and should just unplug
+        * the device right away.
+        *
+        * This will help anyone who is waiting on the IO, they might have
+        * already unplugged, but managed to do so before the bio they
+        * cared about found its way down here.
+        */
+       blk_run_backing_dev(bdi, NULL);
 done:
        return 0;
 }
index 86c44e9ae1101e2332dadad41b6def15932ae96c..2185de72ff7dad59154f5a568624be89ab7e8b97 100644 (file)
@@ -76,7 +76,7 @@ struct btrfs_device {
 struct btrfs_fs_devices {
        u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
 
-       /* the device with this id has the most recent coyp of the super */
+       /* the device with this id has the most recent copy of the super */
        u64 latest_devid;
        u64 latest_trans;
        u64 num_devices;
index a2fd743d97cb85380b5140e5d84ba9c50c383b84..5d55a896ff78f2a79ab9bc2dee72dae77ddb93eb 100644 (file)
@@ -199,13 +199,13 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
        head = page_buffers(page);
        bh = head;
        do {
-               if (bh->b_blocknr == block) {
+               if (!buffer_mapped(bh))
+                       all_mapped = 0;
+               else if (bh->b_blocknr == block) {
                        ret = bh;
                        get_bh(bh);
                        goto out_unlock;
                }
-               if (!buffer_mapped(bh))
-                       all_mapped = 0;
                bh = bh->b_this_page;
        } while (bh != head);
 
@@ -290,7 +290,7 @@ static void free_more_memory(void)
                                                &zone);
                if (zone)
                        try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0,
-                                               GFP_NOFS);
+                                               GFP_NOFS, NULL);
        }
 }
 
@@ -547,6 +547,39 @@ repeat:
        return err;
 }
 
+void do_thaw_all(unsigned long unused)
+{
+       struct super_block *sb;
+       char b[BDEVNAME_SIZE];
+
+       spin_lock(&sb_lock);
+restart:
+       list_for_each_entry(sb, &super_blocks, s_list) {
+               sb->s_count++;
+               spin_unlock(&sb_lock);
+               down_read(&sb->s_umount);
+               while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb))
+                       printk(KERN_WARNING "Emergency Thaw on %s\n",
+                              bdevname(sb->s_bdev, b));
+               up_read(&sb->s_umount);
+               spin_lock(&sb_lock);
+               if (__put_super_and_need_restart(sb))
+                       goto restart;
+       }
+       spin_unlock(&sb_lock);
+       printk(KERN_WARNING "Emergency Thaw complete\n");
+}
+
+/**
+ * emergency_thaw_all -- forcibly thaw every frozen filesystem
+ *
+ * Used for emergency unfreeze of all filesystems via SysRq
+ */
+void emergency_thaw_all(void)
+{
+       pdflush_operation(do_thaw_all, 0);
+}
+
 /**
  * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers
  * @mapping: the mapping which wants those buffers written
@@ -621,14 +654,7 @@ static void __set_page_dirty(struct page *page,
        spin_lock_irq(&mapping->tree_lock);
        if (page->mapping) {    /* Race with truncate? */
                WARN_ON_ONCE(warn && !PageUptodate(page));
-
-               if (mapping_cap_account_dirty(mapping)) {
-                       __inc_zone_page_state(page, NR_FILE_DIRTY);
-                       __inc_bdi_stat(mapping->backing_dev_info,
-                                       BDI_RECLAIMABLE);
-                       task_dirty_inc(current);
-                       task_io_account_write(PAGE_CACHE_SIZE);
-               }
+               account_page_dirtied(page, mapping);
                radix_tree_tag_set(&mapping->page_tree,
                                page_index(page), PAGECACHE_TAG_DIRTY);
        }
@@ -1569,6 +1595,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
        struct buffer_head *bh, *head;
        const unsigned blocksize = 1 << inode->i_blkbits;
        int nr_underway = 0;
+       int write_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
 
        BUG_ON(!PageLocked(page));
 
@@ -1660,7 +1687,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
        do {
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
-                       submit_bh(WRITE, bh);
+                       submit_bh(write_op, bh);
                        nr_underway++;
                }
                bh = next;
@@ -1714,7 +1741,7 @@ recover:
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
                        clear_buffer_dirty(bh);
-                       submit_bh(WRITE, bh);
+                       submit_bh(write_op, bh);
                        nr_underway++;
                }
                bh = next;
@@ -2320,13 +2347,14 @@ int block_commit_write(struct page *page, unsigned from, unsigned to)
  * unlock the page.
  */
 int
-block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
                   get_block_t get_block)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        unsigned long end;
        loff_t size;
-       int ret = -EINVAL;
+       int ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
 
        lock_page(page);
        size = i_size_read(inode);
@@ -2346,6 +2374,13 @@ block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
        if (!ret)
                ret = block_commit_write(page, 0, end);
 
+       if (unlikely(ret)) {
+               if (ret == -ENOMEM)
+                       ret = VM_FAULT_OOM;
+               else /* -ENOSPC, -EIO, etc */
+                       ret = VM_FAULT_SIGBUS;
+       }
+
 out_unlock:
        unlock_page(page);
        return ret;
@@ -3281,7 +3316,6 @@ EXPORT_SYMBOL(cont_write_begin);
 EXPORT_SYMBOL(end_buffer_read_sync);
 EXPORT_SYMBOL(end_buffer_write_sync);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(fsync_bdev);
 EXPORT_SYMBOL(generic_block_bmap);
 EXPORT_SYMBOL(generic_cont_expand_simple);
 EXPORT_SYMBOL(init_buffer);
diff --git a/fs/cachefiles/Kconfig b/fs/cachefiles/Kconfig
new file mode 100644 (file)
index 0000000..80e9c61
--- /dev/null
@@ -0,0 +1,39 @@
+
+config CACHEFILES
+       tristate "Filesystem caching on files"
+       depends on FSCACHE && BLOCK
+       help
+         This permits use of a mounted filesystem as a cache for other
+         filesystems - primarily networking filesystems - thus allowing fast
+         local disk to enhance the speed of slower devices.
+
+         See Documentation/filesystems/caching/cachefiles.txt for more
+         information.
+
+config CACHEFILES_DEBUG
+       bool "Debug CacheFiles"
+       depends on CACHEFILES
+       help
+         This permits debugging to be dynamically enabled in the filesystem
+         caching on files module.  If this is set, the debugging output may be
+         enabled by setting bits in /sys/modules/cachefiles/parameter/debug or
+         by including a debugging specifier in /etc/cachefilesd.conf.
+
+config CACHEFILES_HISTOGRAM
+       bool "Gather latency information on CacheFiles"
+       depends on CACHEFILES && PROC_FS
+       help
+
+         This option causes latency information to be gathered on CacheFiles
+         operation and exported through file:
+
+               /proc/fs/cachefiles/histogram
+
+         The generation of this histogram adds a certain amount of overhead to
+         execution as there are a number of points at which data is gathered,
+         and on a multi-CPU system these may be on cachelines that keep
+         bouncing between CPUs.  On the other hand, the histogram may be
+         useful for debugging purposes.  Saying 'N' here is recommended.
+
+         See Documentation/filesystems/caching/cachefiles.txt for more
+         information.
diff --git a/fs/cachefiles/Makefile b/fs/cachefiles/Makefile
new file mode 100644 (file)
index 0000000..32cbab0
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for caching in a mounted filesystem
+#
+
+cachefiles-y := \
+       bind.o \
+       daemon.o \
+       interface.o \
+       key.o \
+       main.o \
+       namei.o \
+       rdwr.o \
+       security.o \
+       xattr.o
+
+cachefiles-$(CONFIG_CACHEFILES_HISTOGRAM) += proc.o
+
+obj-$(CONFIG_CACHEFILES) := cachefiles.o
diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c
new file mode 100644 (file)
index 0000000..3797e00
--- /dev/null
@@ -0,0 +1,286 @@
+/* Bind and unbind a cache from the filesystem backing it
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/statfs.h>
+#include <linux/ctype.h>
+#include "internal.h"
+
+static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches);
+
+/*
+ * bind a directory as a cache
+ */
+int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args)
+{
+       _enter("{%u,%u,%u,%u,%u,%u},%s",
+              cache->frun_percent,
+              cache->fcull_percent,
+              cache->fstop_percent,
+              cache->brun_percent,
+              cache->bcull_percent,
+              cache->bstop_percent,
+              args);
+
+       /* start by checking things over */
+       ASSERT(cache->fstop_percent >= 0 &&
+              cache->fstop_percent < cache->fcull_percent &&
+              cache->fcull_percent < cache->frun_percent &&
+              cache->frun_percent  < 100);
+
+       ASSERT(cache->bstop_percent >= 0 &&
+              cache->bstop_percent < cache->bcull_percent &&
+              cache->bcull_percent < cache->brun_percent &&
+              cache->brun_percent  < 100);
+
+       if (*args) {
+               kerror("'bind' command doesn't take an argument");
+               return -EINVAL;
+       }
+
+       if (!cache->rootdirname) {
+               kerror("No cache directory specified");
+               return -EINVAL;
+       }
+
+       /* don't permit already bound caches to be re-bound */
+       if (test_bit(CACHEFILES_READY, &cache->flags)) {
+               kerror("Cache already bound");
+               return -EBUSY;
+       }
+
+       /* make sure we have copies of the tag and dirname strings */
+       if (!cache->tag) {
+               /* the tag string is released by the fops->release()
+                * function, so we don't release it on error here */
+               cache->tag = kstrdup("CacheFiles", GFP_KERNEL);
+               if (!cache->tag)
+                       return -ENOMEM;
+       }
+
+       /* add the cache */
+       return cachefiles_daemon_add_cache(cache);
+}
+
+/*
+ * add a cache
+ */
+static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
+{
+       struct cachefiles_object *fsdef;
+       struct nameidata nd;
+       struct kstatfs stats;
+       struct dentry *graveyard, *cachedir, *root;
+       const struct cred *saved_cred;
+       int ret;
+
+       _enter("");
+
+       /* we want to work under the module's security ID */
+       ret = cachefiles_get_security_ID(cache);
+       if (ret < 0)
+               return ret;
+
+       cachefiles_begin_secure(cache, &saved_cred);
+
+       /* allocate the root index object */
+       ret = -ENOMEM;
+
+       fsdef = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL);
+       if (!fsdef)
+               goto error_root_object;
+
+       ASSERTCMP(fsdef->backer, ==, NULL);
+
+       atomic_set(&fsdef->usage, 1);
+       fsdef->type = FSCACHE_COOKIE_TYPE_INDEX;
+
+       _debug("- fsdef %p", fsdef);
+
+       /* look up the directory at the root of the cache */
+       memset(&nd, 0, sizeof(nd));
+
+       ret = path_lookup(cache->rootdirname, LOOKUP_DIRECTORY, &nd);
+       if (ret < 0)
+               goto error_open_root;
+
+       cache->mnt = mntget(nd.path.mnt);
+       root = dget(nd.path.dentry);
+       path_put(&nd.path);
+
+       /* check parameters */
+       ret = -EOPNOTSUPP;
+       if (!root->d_inode ||
+           !root->d_inode->i_op ||
+           !root->d_inode->i_op->lookup ||
+           !root->d_inode->i_op->mkdir ||
+           !root->d_inode->i_op->setxattr ||
+           !root->d_inode->i_op->getxattr ||
+           !root->d_sb ||
+           !root->d_sb->s_op ||
+           !root->d_sb->s_op->statfs ||
+           !root->d_sb->s_op->sync_fs)
+               goto error_unsupported;
+
+       ret = -EROFS;
+       if (root->d_sb->s_flags & MS_RDONLY)
+               goto error_unsupported;
+
+       /* determine the security of the on-disk cache as this governs
+        * security ID of files we create */
+       ret = cachefiles_determine_cache_security(cache, root, &saved_cred);
+       if (ret < 0)
+               goto error_unsupported;
+
+       /* get the cache size and blocksize */
+       ret = vfs_statfs(root, &stats);
+       if (ret < 0)
+               goto error_unsupported;
+
+       ret = -ERANGE;
+       if (stats.f_bsize <= 0)
+               goto error_unsupported;
+
+       ret = -EOPNOTSUPP;
+       if (stats.f_bsize > PAGE_SIZE)
+               goto error_unsupported;
+
+       cache->bsize = stats.f_bsize;
+       cache->bshift = 0;
+       if (stats.f_bsize < PAGE_SIZE)
+               cache->bshift = PAGE_SHIFT - ilog2(stats.f_bsize);
+
+       _debug("blksize %u (shift %u)",
+              cache->bsize, cache->bshift);
+
+       _debug("size %llu, avail %llu",
+              (unsigned long long) stats.f_blocks,
+              (unsigned long long) stats.f_bavail);
+
+       /* set up caching limits */
+       do_div(stats.f_files, 100);
+       cache->fstop = stats.f_files * cache->fstop_percent;
+       cache->fcull = stats.f_files * cache->fcull_percent;
+       cache->frun  = stats.f_files * cache->frun_percent;
+
+       _debug("limits {%llu,%llu,%llu} files",
+              (unsigned long long) cache->frun,
+              (unsigned long long) cache->fcull,
+              (unsigned long long) cache->fstop);
+
+       stats.f_blocks >>= cache->bshift;
+       do_div(stats.f_blocks, 100);
+       cache->bstop = stats.f_blocks * cache->bstop_percent;
+       cache->bcull = stats.f_blocks * cache->bcull_percent;
+       cache->brun  = stats.f_blocks * cache->brun_percent;
+
+       _debug("limits {%llu,%llu,%llu} blocks",
+              (unsigned long long) cache->brun,
+              (unsigned long long) cache->bcull,
+              (unsigned long long) cache->bstop);
+
+       /* get the cache directory and check its type */
+       cachedir = cachefiles_get_directory(cache, root, "cache");
+       if (IS_ERR(cachedir)) {
+               ret = PTR_ERR(cachedir);
+               goto error_unsupported;
+       }
+
+       fsdef->dentry = cachedir;
+       fsdef->fscache.cookie = NULL;
+
+       ret = cachefiles_check_object_type(fsdef);
+       if (ret < 0)
+               goto error_unsupported;
+
+       /* get the graveyard directory */
+       graveyard = cachefiles_get_directory(cache, root, "graveyard");
+       if (IS_ERR(graveyard)) {
+               ret = PTR_ERR(graveyard);
+               goto error_unsupported;
+       }
+
+       cache->graveyard = graveyard;
+
+       /* publish the cache */
+       fscache_init_cache(&cache->cache,
+                          &cachefiles_cache_ops,
+                          "%s",
+                          fsdef->dentry->d_sb->s_id);
+
+       fscache_object_init(&fsdef->fscache, NULL, &cache->cache);
+
+       ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag);
+       if (ret < 0)
+               goto error_add_cache;
+
+       /* done */
+       set_bit(CACHEFILES_READY, &cache->flags);
+       dput(root);
+
+       printk(KERN_INFO "CacheFiles:"
+              " File cache on %s registered\n",
+              cache->cache.identifier);
+
+       /* check how much space the cache has */
+       cachefiles_has_space(cache, 0, 0);
+       cachefiles_end_secure(cache, saved_cred);
+       return 0;
+
+error_add_cache:
+       dput(cache->graveyard);
+       cache->graveyard = NULL;
+error_unsupported:
+       mntput(cache->mnt);
+       cache->mnt = NULL;
+       dput(fsdef->dentry);
+       fsdef->dentry = NULL;
+       dput(root);
+error_open_root:
+       kmem_cache_free(cachefiles_object_jar, fsdef);
+error_root_object:
+       cachefiles_end_secure(cache, saved_cred);
+       kerror("Failed to register: %d", ret);
+       return ret;
+}
+
+/*
+ * unbind a cache on fd release
+ */
+void cachefiles_daemon_unbind(struct cachefiles_cache *cache)
+{
+       _enter("");
+
+       if (test_bit(CACHEFILES_READY, &cache->flags)) {
+               printk(KERN_INFO "CacheFiles:"
+                      " File cache on %s unregistering\n",
+                      cache->cache.identifier);
+
+               fscache_withdraw_cache(&cache->cache);
+       }
+
+       dput(cache->graveyard);
+       mntput(cache->mnt);
+
+       kfree(cache->rootdirname);
+       kfree(cache->secctx);
+       kfree(cache->tag);
+
+       _leave("");
+}
diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c
new file mode 100644 (file)
index 0000000..4618516
--- /dev/null
@@ -0,0 +1,755 @@
+/* Daemon interface
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/poll.h>
+#include <linux/mount.h>
+#include <linux/statfs.h>
+#include <linux/ctype.h>
+#include <linux/fs_struct.h>
+#include "internal.h"
+
+static int cachefiles_daemon_open(struct inode *, struct file *);
+static int cachefiles_daemon_release(struct inode *, struct file *);
+static ssize_t cachefiles_daemon_read(struct file *, char __user *, size_t,
+                                     loff_t *);
+static ssize_t cachefiles_daemon_write(struct file *, const char __user *,
+                                      size_t, loff_t *);
+static unsigned int cachefiles_daemon_poll(struct file *,
+                                          struct poll_table_struct *);
+static int cachefiles_daemon_frun(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_fcull(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_fstop(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_brun(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_bcull(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_bstop(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_cull(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_debug(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_dir(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_inuse(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_secctx(struct cachefiles_cache *, char *);
+static int cachefiles_daemon_tag(struct cachefiles_cache *, char *);
+
+static unsigned long cachefiles_open;
+
+const struct file_operations cachefiles_daemon_fops = {
+       .owner          = THIS_MODULE,
+       .open           = cachefiles_daemon_open,
+       .release        = cachefiles_daemon_release,
+       .read           = cachefiles_daemon_read,
+       .write          = cachefiles_daemon_write,
+       .poll           = cachefiles_daemon_poll,
+};
+
+struct cachefiles_daemon_cmd {
+       char name[8];
+       int (*handler)(struct cachefiles_cache *cache, char *args);
+};
+
+static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = {
+       { "bind",       cachefiles_daemon_bind          },
+       { "brun",       cachefiles_daemon_brun          },
+       { "bcull",      cachefiles_daemon_bcull         },
+       { "bstop",      cachefiles_daemon_bstop         },
+       { "cull",       cachefiles_daemon_cull          },
+       { "debug",      cachefiles_daemon_debug         },
+       { "dir",        cachefiles_daemon_dir           },
+       { "frun",       cachefiles_daemon_frun          },
+       { "fcull",      cachefiles_daemon_fcull         },
+       { "fstop",      cachefiles_daemon_fstop         },
+       { "inuse",      cachefiles_daemon_inuse         },
+       { "secctx",     cachefiles_daemon_secctx        },
+       { "tag",        cachefiles_daemon_tag           },
+       { "",           NULL                            }
+};
+
+
+/*
+ * do various checks
+ */
+static int cachefiles_daemon_open(struct inode *inode, struct file *file)
+{
+       struct cachefiles_cache *cache;
+
+       _enter("");
+
+       /* only the superuser may do this */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /* the cachefiles device may only be open once at a time */
+       if (xchg(&cachefiles_open, 1) == 1)
+               return -EBUSY;
+
+       /* allocate a cache record */
+       cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL);
+       if (!cache) {
+               cachefiles_open = 0;
+               return -ENOMEM;
+       }
+
+       mutex_init(&cache->daemon_mutex);
+       cache->active_nodes = RB_ROOT;
+       rwlock_init(&cache->active_lock);
+       init_waitqueue_head(&cache->daemon_pollwq);
+
+       /* set default caching limits
+        * - limit at 1% free space and/or free files
+        * - cull below 5% free space and/or free files
+        * - cease culling above 7% free space and/or free files
+        */
+       cache->frun_percent = 7;
+       cache->fcull_percent = 5;
+       cache->fstop_percent = 1;
+       cache->brun_percent = 7;
+       cache->bcull_percent = 5;
+       cache->bstop_percent = 1;
+
+       file->private_data = cache;
+       cache->cachefilesd = file;
+       return 0;
+}
+
+/*
+ * release a cache
+ */
+static int cachefiles_daemon_release(struct inode *inode, struct file *file)
+{
+       struct cachefiles_cache *cache = file->private_data;
+
+       _enter("");
+
+       ASSERT(cache);
+
+       set_bit(CACHEFILES_DEAD, &cache->flags);
+
+       cachefiles_daemon_unbind(cache);
+
+       ASSERT(!cache->active_nodes.rb_node);
+
+       /* clean up the control file interface */
+       cache->cachefilesd = NULL;
+       file->private_data = NULL;
+       cachefiles_open = 0;
+
+       kfree(cache);
+
+       _leave("");
+       return 0;
+}
+
+/*
+ * read the cache state
+ */
+static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
+                                     size_t buflen, loff_t *pos)
+{
+       struct cachefiles_cache *cache = file->private_data;
+       char buffer[256];
+       int n;
+
+       //_enter(",,%zu,", buflen);
+
+       if (!test_bit(CACHEFILES_READY, &cache->flags))
+               return 0;
+
+       /* check how much space the cache has */
+       cachefiles_has_space(cache, 0, 0);
+
+       /* summarise */
+       clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags);
+
+       n = snprintf(buffer, sizeof(buffer),
+                    "cull=%c"
+                    " frun=%llx"
+                    " fcull=%llx"
+                    " fstop=%llx"
+                    " brun=%llx"
+                    " bcull=%llx"
+                    " bstop=%llx",
+                    test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0',
+                    (unsigned long long) cache->frun,
+                    (unsigned long long) cache->fcull,
+                    (unsigned long long) cache->fstop,
+                    (unsigned long long) cache->brun,
+                    (unsigned long long) cache->bcull,
+                    (unsigned long long) cache->bstop
+                    );
+
+       if (n > buflen)
+               return -EMSGSIZE;
+
+       if (copy_to_user(_buffer, buffer, n) != 0)
+               return -EFAULT;
+
+       return n;
+}
+
+/*
+ * command the cache
+ */
+static ssize_t cachefiles_daemon_write(struct file *file,
+                                      const char __user *_data,
+                                      size_t datalen,
+                                      loff_t *pos)
+{
+       const struct cachefiles_daemon_cmd *cmd;
+       struct cachefiles_cache *cache = file->private_data;
+       ssize_t ret;
+       char *data, *args, *cp;
+
+       //_enter(",,%zu,", datalen);
+
+       ASSERT(cache);
+
+       if (test_bit(CACHEFILES_DEAD, &cache->flags))
+               return -EIO;
+
+       if (datalen < 0 || datalen > PAGE_SIZE - 1)
+               return -EOPNOTSUPP;
+
+       /* drag the command string into the kernel so we can parse it */
+       data = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       ret = -EFAULT;
+       if (copy_from_user(data, _data, datalen) != 0)
+               goto error;
+
+       data[datalen] = '\0';
+
+       ret = -EINVAL;
+       if (memchr(data, '\0', datalen))
+               goto error;
+
+       /* strip any newline */
+       cp = memchr(data, '\n', datalen);
+       if (cp) {
+               if (cp == data)
+                       goto error;
+
+               *cp = '\0';
+       }
+
+       /* parse the command */
+       ret = -EOPNOTSUPP;
+
+       for (args = data; *args; args++)
+               if (isspace(*args))
+                       break;
+       if (*args) {
+               if (args == data)
+                       goto error;
+               *args = '\0';
+               for (args++; isspace(*args); args++)
+                       continue;
+       }
+
+       /* run the appropriate command handler */
+       for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++)
+               if (strcmp(cmd->name, data) == 0)
+                       goto found_command;
+
+error:
+       kfree(data);
+       //_leave(" = %zd", ret);
+       return ret;
+
+found_command:
+       mutex_lock(&cache->daemon_mutex);
+
+       ret = -EIO;
+       if (!test_bit(CACHEFILES_DEAD, &cache->flags))
+               ret = cmd->handler(cache, args);
+
+       mutex_unlock(&cache->daemon_mutex);
+
+       if (ret == 0)
+               ret = datalen;
+       goto error;
+}
+
+/*
+ * poll for culling state
+ * - use POLLOUT to indicate culling state
+ */
+static unsigned int cachefiles_daemon_poll(struct file *file,
+                                          struct poll_table_struct *poll)
+{
+       struct cachefiles_cache *cache = file->private_data;
+       unsigned int mask;
+
+       poll_wait(file, &cache->daemon_pollwq, poll);
+       mask = 0;
+
+       if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags))
+               mask |= POLLIN;
+
+       if (test_bit(CACHEFILES_CULLING, &cache->flags))
+               mask |= POLLOUT;
+
+       return mask;
+}
+
+/*
+ * give a range error for cache space constraints
+ * - can be tail-called
+ */
+static int cachefiles_daemon_range_error(struct cachefiles_cache *cache,
+                                        char *args)
+{
+       kerror("Free space limits must be in range"
+              " 0%%<=stop<cull<run<100%%");
+
+       return -EINVAL;
+}
+
+/*
+ * set the percentage of files at which to stop culling
+ * - command: "frun <N>%"
+ */
+static int cachefiles_daemon_frun(struct cachefiles_cache *cache, char *args)
+{
+       unsigned long frun;
+
+       _enter(",%s", args);
+
+       if (!*args)
+               return -EINVAL;
+
+       frun = simple_strtoul(args, &args, 10);
+       if (args[0] != '%' || args[1] != '\0')
+               return -EINVAL;
+
+       if (frun <= cache->fcull_percent || frun >= 100)
+               return cachefiles_daemon_range_error(cache, args);
+
+       cache->frun_percent = frun;
+       return 0;
+}
+
+/*
+ * set the percentage of files at which to start culling
+ * - command: "fcull <N>%"
+ */
+static int cachefiles_daemon_fcull(struct cachefiles_cache *cache, char *args)
+{
+       unsigned long fcull;
+
+       _enter(",%s", args);
+
+       if (!*args)
+               return -EINVAL;
+
+       fcull = simple_strtoul(args, &args, 10);
+       if (args[0] != '%' || args[1] != '\0')
+               return -EINVAL;
+
+       if (fcull <= cache->fstop_percent || fcull >= cache->frun_percent)
+               return cachefiles_daemon_range_error(cache, args);
+
+       cache->fcull_percent = fcull;
+       return 0;
+}
+
+/*
+ * set the percentage of files at which to stop allocating
+ * - command: "fstop <N>%"
+ */
+static int cachefiles_daemon_fstop(struct cachefiles_cache *cache, char *args)
+{
+       unsigned long fstop;
+
+       _enter(",%s", args);
+
+       if (!*args)
+               return -EINVAL;
+
+       fstop = simple_strtoul(args, &args, 10);
+       if (args[0] != '%' || args[1] != '\0')
+               return -EINVAL;
+
+       if (fstop < 0 || fstop >= cache->fcull_percent)
+               return cachefiles_daemon_range_error(cache, args);
+
+       cache->fstop_percent = fstop;
+       return 0;
+}
+
+/*
+ * set the percentage of blocks at which to stop culling
+ * - command: "brun <N>%"
+ */
+static int cachefiles_daemon_brun(struct cachefiles_cache *cache, char *args)
+{
+       unsigned long brun;
+
+       _enter(",%s", args);
+
+       if (!*args)
+               return -EINVAL;
+
+       brun = simple_strtoul(args, &args, 10);
+       if (args[0] != '%' || args[1] != '\0')
+               return -EINVAL;
+
+       if (brun <= cache->bcull_percent || brun >= 100)
+               return cachefiles_daemon_range_error(cache, args);
+
+       cache->brun_percent = brun;
+       return 0;
+}
+
+/*
+ * set the percentage of blocks at which to start culling
+ * - command: "bcull <N>%"
+ */
+static int cachefiles_daemon_bcull(struct cachefiles_cache *cache, char *args)
+{
+       unsigned long bcull;
+
+       _enter(",%s", args);
+
+       if (!*args)
+               return -EINVAL;
+
+       bcull = simple_strtoul(args, &args, 10);
+       if (args[0] != '%' || args[1] != '\0')
+               return -EINVAL;
+
+       if (bcull <= cache->bstop_percent || bcull >= cache->brun_percent)
+               return cachefiles_daemon_range_error(cache, args);
+
+       cache->bcull_percent = bcull;
+       return 0;
+}
+
+/*
+ * set the percentage of blocks at which to stop allocating
+ * - command: "bstop <N>%"
+ */
+static int cachefiles_daemon_bstop(struct cachefiles_cache *cache, char *args)
+{
+       unsigned long bstop;
+
+       _enter(",%s", args);
+
+       if (!*args)
+               return -EINVAL;
+
+       bstop = simple_strtoul(args, &args, 10);
+       if (args[0] != '%' || args[1] != '\0')
+               return -EINVAL;
+
+       if (bstop < 0 || bstop >= cache->bcull_percent)
+               return cachefiles_daemon_range_error(cache, args);
+
+       cache->bstop_percent = bstop;
+       return 0;
+}
+
+/*
+ * set the cache directory
+ * - command: "dir <name>"
+ */
+static int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args)
+{
+       char *dir;
+
+       _enter(",%s", args);
+
+       if (!*args) {
+               kerror("Empty directory specified");
+               return -EINVAL;
+       }
+
+       if (cache->rootdirname) {
+               kerror("Second cache directory specified");
+               return -EEXIST;
+       }
+
+       dir = kstrdup(args, GFP_KERNEL);
+       if (!dir)
+               return -ENOMEM;
+
+       cache->rootdirname = dir;
+       return 0;
+}
+
+/*
+ * set the cache security context
+ * - command: "secctx <ctx>"
+ */
+static int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args)
+{
+       char *secctx;
+
+       _enter(",%s", args);
+
+       if (!*args) {
+               kerror("Empty security context specified");
+               return -EINVAL;
+       }
+
+       if (cache->secctx) {
+               kerror("Second security context specified");
+               return -EINVAL;
+       }
+
+       secctx = kstrdup(args, GFP_KERNEL);
+       if (!secctx)
+               return -ENOMEM;
+
+       cache->secctx = secctx;
+       return 0;
+}
+
+/*
+ * set the cache tag
+ * - command: "tag <name>"
+ */
+static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args)
+{
+       char *tag;
+
+       _enter(",%s", args);
+
+       if (!*args) {
+               kerror("Empty tag specified");
+               return -EINVAL;
+       }
+
+       if (cache->tag)
+               return -EEXIST;
+
+       tag = kstrdup(args, GFP_KERNEL);
+       if (!tag)
+               return -ENOMEM;
+
+       cache->tag = tag;
+       return 0;
+}
+
+/*
+ * request a node in the cache be culled from the current working directory
+ * - command: "cull <name>"
+ */
+static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args)
+{
+       struct fs_struct *fs;
+       struct dentry *dir;
+       const struct cred *saved_cred;
+       int ret;
+
+       _enter(",%s", args);
+
+       if (strchr(args, '/'))
+               goto inval;
+
+       if (!test_bit(CACHEFILES_READY, &cache->flags)) {
+               kerror("cull applied to unready cache");
+               return -EIO;
+       }
+
+       if (test_bit(CACHEFILES_DEAD, &cache->flags)) {
+               kerror("cull applied to dead cache");
+               return -EIO;
+       }
+
+       /* extract the directory dentry from the cwd */
+       fs = current->fs;
+       read_lock(&fs->lock);
+       dir = dget(fs->pwd.dentry);
+       read_unlock(&fs->lock);
+
+       if (!S_ISDIR(dir->d_inode->i_mode))
+               goto notdir;
+
+       cachefiles_begin_secure(cache, &saved_cred);
+       ret = cachefiles_cull(cache, dir, args);
+       cachefiles_end_secure(cache, saved_cred);
+
+       dput(dir);
+       _leave(" = %d", ret);
+       return ret;
+
+notdir:
+       dput(dir);
+       kerror("cull command requires dirfd to be a directory");
+       return -ENOTDIR;
+
+inval:
+       kerror("cull command requires dirfd and filename");
+       return -EINVAL;
+}
+
+/*
+ * set debugging mode
+ * - command: "debug <mask>"
+ */
+static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args)
+{
+       unsigned long mask;
+
+       _enter(",%s", args);
+
+       mask = simple_strtoul(args, &args, 0);
+       if (args[0] != '\0')
+               goto inval;
+
+       cachefiles_debug = mask;
+       _leave(" = 0");
+       return 0;
+
+inval:
+       kerror("debug command requires mask");
+       return -EINVAL;
+}
+
+/*
+ * find out whether an object in the current working directory is in use or not
+ * - command: "inuse <name>"
+ */
+static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args)
+{
+       struct fs_struct *fs;
+       struct dentry *dir;
+       const struct cred *saved_cred;
+       int ret;
+
+       //_enter(",%s", args);
+
+       if (strchr(args, '/'))
+               goto inval;
+
+       if (!test_bit(CACHEFILES_READY, &cache->flags)) {
+               kerror("inuse applied to unready cache");
+               return -EIO;
+       }
+
+       if (test_bit(CACHEFILES_DEAD, &cache->flags)) {
+               kerror("inuse applied to dead cache");
+               return -EIO;
+       }
+
+       /* extract the directory dentry from the cwd */
+       fs = current->fs;
+       read_lock(&fs->lock);
+       dir = dget(fs->pwd.dentry);
+       read_unlock(&fs->lock);
+
+       if (!S_ISDIR(dir->d_inode->i_mode))
+               goto notdir;
+
+       cachefiles_begin_secure(cache, &saved_cred);
+       ret = cachefiles_check_in_use(cache, dir, args);
+       cachefiles_end_secure(cache, saved_cred);
+
+       dput(dir);
+       //_leave(" = %d", ret);
+       return ret;
+
+notdir:
+       dput(dir);
+       kerror("inuse command requires dirfd to be a directory");
+       return -ENOTDIR;
+
+inval:
+       kerror("inuse command requires dirfd and filename");
+       return -EINVAL;
+}
+
+/*
+ * see if we have space for a number of pages and/or a number of files in the
+ * cache
+ */
+int cachefiles_has_space(struct cachefiles_cache *cache,
+                        unsigned fnr, unsigned bnr)
+{
+       struct kstatfs stats;
+       int ret;
+
+       //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u",
+       //       (unsigned long long) cache->frun,
+       //       (unsigned long long) cache->fcull,
+       //       (unsigned long long) cache->fstop,
+       //       (unsigned long long) cache->brun,
+       //       (unsigned long long) cache->bcull,
+       //       (unsigned long long) cache->bstop,
+       //       fnr, bnr);
+
+       /* find out how many pages of blockdev are available */
+       memset(&stats, 0, sizeof(stats));
+
+       ret = vfs_statfs(cache->mnt->mnt_root, &stats);
+       if (ret < 0) {
+               if (ret == -EIO)
+                       cachefiles_io_error(cache, "statfs failed");
+               _leave(" = %d", ret);
+               return ret;
+       }
+
+       stats.f_bavail >>= cache->bshift;
+
+       //_debug("avail %llu,%llu",
+       //       (unsigned long long) stats.f_ffree,
+       //       (unsigned long long) stats.f_bavail);
+
+       /* see if there is sufficient space */
+       if (stats.f_ffree > fnr)
+               stats.f_ffree -= fnr;
+       else
+               stats.f_ffree = 0;
+
+       if (stats.f_bavail > bnr)
+               stats.f_bavail -= bnr;
+       else
+               stats.f_bavail = 0;
+
+       ret = -ENOBUFS;
+       if (stats.f_ffree < cache->fstop ||
+           stats.f_bavail < cache->bstop)
+               goto begin_cull;
+
+       ret = 0;
+       if (stats.f_ffree < cache->fcull ||
+           stats.f_bavail < cache->bcull)
+               goto begin_cull;
+
+       if (test_bit(CACHEFILES_CULLING, &cache->flags) &&
+           stats.f_ffree >= cache->frun &&
+           stats.f_bavail >= cache->brun &&
+           test_and_clear_bit(CACHEFILES_CULLING, &cache->flags)
+           ) {
+               _debug("cease culling");
+               cachefiles_state_changed(cache);
+       }
+
+       //_leave(" = 0");
+       return 0;
+
+begin_cull:
+       if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) {
+               _debug("### CULL CACHE ###");
+               cachefiles_state_changed(cache);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
new file mode 100644 (file)
index 0000000..1e96234
--- /dev/null
@@ -0,0 +1,449 @@
+/* FS-Cache interface to CacheFiles
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/mount.h>
+#include <linux/buffer_head.h>
+#include "internal.h"
+
+#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
+
+struct cachefiles_lookup_data {
+       struct cachefiles_xattr *auxdata;       /* auxiliary data */
+       char                    *key;           /* key path */
+};
+
+static int cachefiles_attr_changed(struct fscache_object *_object);
+
+/*
+ * allocate an object record for a cookie lookup and prepare the lookup data
+ */
+static struct fscache_object *cachefiles_alloc_object(
+       struct fscache_cache *_cache,
+       struct fscache_cookie *cookie)
+{
+       struct cachefiles_lookup_data *lookup_data;
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       struct cachefiles_xattr *auxdata;
+       unsigned keylen, auxlen;
+       void *buffer;
+       char *key;
+
+       cache = container_of(_cache, struct cachefiles_cache, cache);
+
+       _enter("{%s},%p,", cache->cache.identifier, cookie);
+
+       lookup_data = kmalloc(sizeof(*lookup_data), GFP_KERNEL);
+       if (!lookup_data)
+               goto nomem_lookup_data;
+
+       /* create a new object record and a temporary leaf image */
+       object = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL);
+       if (!object)
+               goto nomem_object;
+
+       ASSERTCMP(object->backer, ==, NULL);
+
+       BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
+       atomic_set(&object->usage, 1);
+
+       fscache_object_init(&object->fscache, cookie, &cache->cache);
+
+       object->type = cookie->def->type;
+
+       /* get hold of the raw key
+        * - stick the length on the front and leave space on the back for the
+        *   encoder
+        */
+       buffer = kmalloc((2 + 512) + 3, GFP_KERNEL);
+       if (!buffer)
+               goto nomem_buffer;
+
+       keylen = cookie->def->get_key(cookie->netfs_data, buffer + 2, 512);
+       ASSERTCMP(keylen, <, 512);
+
+       *(uint16_t *)buffer = keylen;
+       ((char *)buffer)[keylen + 2] = 0;
+       ((char *)buffer)[keylen + 3] = 0;
+       ((char *)buffer)[keylen + 4] = 0;
+
+       /* turn the raw key into something that can work with as a filename */
+       key = cachefiles_cook_key(buffer, keylen + 2, object->type);
+       if (!key)
+               goto nomem_key;
+
+       /* get hold of the auxiliary data and prepend the object type */
+       auxdata = buffer;
+       auxlen = 0;
+       if (cookie->def->get_aux) {
+               auxlen = cookie->def->get_aux(cookie->netfs_data,
+                                             auxdata->data, 511);
+               ASSERTCMP(auxlen, <, 511);
+       }
+
+       auxdata->len = auxlen + 1;
+       auxdata->type = cookie->def->type;
+
+       lookup_data->auxdata = auxdata;
+       lookup_data->key = key;
+       object->lookup_data = lookup_data;
+
+       _leave(" = %p [%p]", &object->fscache, lookup_data);
+       return &object->fscache;
+
+nomem_key:
+       kfree(buffer);
+nomem_buffer:
+       BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
+       kmem_cache_free(cachefiles_object_jar, object);
+       fscache_object_destroyed(&cache->cache);
+nomem_object:
+       kfree(lookup_data);
+nomem_lookup_data:
+       _leave(" = -ENOMEM");
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * attempt to look up the nominated node in this cache
+ */
+static void cachefiles_lookup_object(struct fscache_object *_object)
+{
+       struct cachefiles_lookup_data *lookup_data;
+       struct cachefiles_object *parent, *object;
+       struct cachefiles_cache *cache;
+       const struct cred *saved_cred;
+       int ret;
+
+       _enter("{OBJ%x}", _object->debug_id);
+
+       cache = container_of(_object->cache, struct cachefiles_cache, cache);
+       parent = container_of(_object->parent,
+                             struct cachefiles_object, fscache);
+       object = container_of(_object, struct cachefiles_object, fscache);
+       lookup_data = object->lookup_data;
+
+       ASSERTCMP(lookup_data, !=, NULL);
+
+       /* look up the key, creating any missing bits */
+       cachefiles_begin_secure(cache, &saved_cred);
+       ret = cachefiles_walk_to_object(parent, object,
+                                       lookup_data->key,
+                                       lookup_data->auxdata);
+       cachefiles_end_secure(cache, saved_cred);
+
+       /* polish off by setting the attributes of non-index files */
+       if (ret == 0 &&
+           object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
+               cachefiles_attr_changed(&object->fscache);
+
+       if (ret < 0) {
+               printk(KERN_WARNING "CacheFiles: Lookup failed error %d\n",
+                      ret);
+               fscache_object_lookup_error(&object->fscache);
+       }
+
+       _leave(" [%d]", ret);
+}
+
+/*
+ * indication of lookup completion
+ */
+static void cachefiles_lookup_complete(struct fscache_object *_object)
+{
+       struct cachefiles_object *object;
+
+       object = container_of(_object, struct cachefiles_object, fscache);
+
+       _enter("{OBJ%x,%p}", object->fscache.debug_id, object->lookup_data);
+
+       if (object->lookup_data) {
+               kfree(object->lookup_data->key);
+               kfree(object->lookup_data->auxdata);
+               kfree(object->lookup_data);
+               object->lookup_data = NULL;
+       }
+}
+
+/*
+ * increment the usage count on an inode object (may fail if unmounting)
+ */
+static
+struct fscache_object *cachefiles_grab_object(struct fscache_object *_object)
+{
+       struct cachefiles_object *object =
+               container_of(_object, struct cachefiles_object, fscache);
+
+       _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage));
+
+#ifdef CACHEFILES_DEBUG_SLAB
+       ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
+#endif
+
+       atomic_inc(&object->usage);
+       return &object->fscache;
+}
+
+/*
+ * update the auxilliary data for an object object on disk
+ */
+static void cachefiles_update_object(struct fscache_object *_object)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_xattr *auxdata;
+       struct cachefiles_cache *cache;
+       struct fscache_cookie *cookie;
+       const struct cred *saved_cred;
+       unsigned auxlen;
+
+       _enter("{OBJ%x}", _object->debug_id);
+
+       object = container_of(_object, struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache, struct cachefiles_cache,
+                            cache);
+       cookie = object->fscache.cookie;
+
+       if (!cookie->def->get_aux) {
+               _leave(" [no aux]");
+               return;
+       }
+
+       auxdata = kmalloc(2 + 512 + 3, GFP_KERNEL);
+       if (!auxdata) {
+               _leave(" [nomem]");
+               return;
+       }
+
+       auxlen = cookie->def->get_aux(cookie->netfs_data, auxdata->data, 511);
+       ASSERTCMP(auxlen, <, 511);
+
+       auxdata->len = auxlen + 1;
+       auxdata->type = cookie->def->type;
+
+       cachefiles_begin_secure(cache, &saved_cred);
+       cachefiles_update_object_xattr(object, auxdata);
+       cachefiles_end_secure(cache, saved_cred);
+       kfree(auxdata);
+       _leave("");
+}
+
+/*
+ * discard the resources pinned by an object and effect retirement if
+ * requested
+ */
+static void cachefiles_drop_object(struct fscache_object *_object)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       const struct cred *saved_cred;
+
+       ASSERT(_object);
+
+       object = container_of(_object, struct cachefiles_object, fscache);
+
+       _enter("{OBJ%x,%d}",
+              object->fscache.debug_id, atomic_read(&object->usage));
+
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+#ifdef CACHEFILES_DEBUG_SLAB
+       ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
+#endif
+
+       /* delete retired objects */
+       if (object->fscache.state == FSCACHE_OBJECT_RECYCLING &&
+           _object != cache->cache.fsdef
+           ) {
+               _debug("- retire object OBJ%x", object->fscache.debug_id);
+               cachefiles_begin_secure(cache, &saved_cred);
+               cachefiles_delete_object(cache, object);
+               cachefiles_end_secure(cache, saved_cred);
+       }
+
+       /* close the filesystem stuff attached to the object */
+       if (object->backer != object->dentry)
+               dput(object->backer);
+       object->backer = NULL;
+
+       /* note that the object is now inactive */
+       if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) {
+               write_lock(&cache->active_lock);
+               if (!test_and_clear_bit(CACHEFILES_OBJECT_ACTIVE,
+                                       &object->flags))
+                       BUG();
+               rb_erase(&object->active_node, &cache->active_nodes);
+               wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
+               write_unlock(&cache->active_lock);
+       }
+
+       dput(object->dentry);
+       object->dentry = NULL;
+
+       _leave("");
+}
+
+/*
+ * dispose of a reference to an object
+ */
+static void cachefiles_put_object(struct fscache_object *_object)
+{
+       struct cachefiles_object *object;
+       struct fscache_cache *cache;
+
+       ASSERT(_object);
+
+       object = container_of(_object, struct cachefiles_object, fscache);
+
+       _enter("{OBJ%x,%d}",
+              object->fscache.debug_id, atomic_read(&object->usage));
+
+#ifdef CACHEFILES_DEBUG_SLAB
+       ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
+#endif
+
+       ASSERTIFCMP(object->fscache.parent,
+                   object->fscache.parent->n_children, >, 0);
+
+       if (atomic_dec_and_test(&object->usage)) {
+               _debug("- kill object OBJ%x", object->fscache.debug_id);
+
+               ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
+               ASSERTCMP(object->fscache.parent, ==, NULL);
+               ASSERTCMP(object->backer, ==, NULL);
+               ASSERTCMP(object->dentry, ==, NULL);
+               ASSERTCMP(object->fscache.n_ops, ==, 0);
+               ASSERTCMP(object->fscache.n_children, ==, 0);
+
+               if (object->lookup_data) {
+                       kfree(object->lookup_data->key);
+                       kfree(object->lookup_data->auxdata);
+                       kfree(object->lookup_data);
+                       object->lookup_data = NULL;
+               }
+
+               cache = object->fscache.cache;
+               kmem_cache_free(cachefiles_object_jar, object);
+               fscache_object_destroyed(cache);
+       }
+
+       _leave("");
+}
+
+/*
+ * sync a cache
+ */
+static void cachefiles_sync_cache(struct fscache_cache *_cache)
+{
+       struct cachefiles_cache *cache;
+       const struct cred *saved_cred;
+       int ret;
+
+       _enter("%p", _cache);
+
+       cache = container_of(_cache, struct cachefiles_cache, cache);
+
+       /* make sure all pages pinned by operations on behalf of the netfs are
+        * written to disc */
+       cachefiles_begin_secure(cache, &saved_cred);
+       ret = fsync_super(cache->mnt->mnt_sb);
+       cachefiles_end_secure(cache, saved_cred);
+
+       if (ret == -EIO)
+               cachefiles_io_error(cache,
+                                   "Attempt to sync backing fs superblock"
+                                   " returned error %d",
+                                   ret);
+}
+
+/*
+ * notification the attributes on an object have changed
+ * - called with reads/writes excluded by FS-Cache
+ */
+static int cachefiles_attr_changed(struct fscache_object *_object)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       const struct cred *saved_cred;
+       struct iattr newattrs;
+       uint64_t ni_size;
+       loff_t oi_size;
+       int ret;
+
+       _object->cookie->def->get_attr(_object->cookie->netfs_data, &ni_size);
+
+       _enter("{OBJ%x},[%llu]",
+              _object->debug_id, (unsigned long long) ni_size);
+
+       object = container_of(_object, struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       if (ni_size == object->i_size)
+               return 0;
+
+       if (!object->backer)
+               return -ENOBUFS;
+
+       ASSERT(S_ISREG(object->backer->d_inode->i_mode));
+
+       fscache_set_store_limit(&object->fscache, ni_size);
+
+       oi_size = i_size_read(object->backer->d_inode);
+       if (oi_size == ni_size)
+               return 0;
+
+       newattrs.ia_size = ni_size;
+       newattrs.ia_valid = ATTR_SIZE;
+
+       cachefiles_begin_secure(cache, &saved_cred);
+       mutex_lock(&object->backer->d_inode->i_mutex);
+       ret = notify_change(object->backer, &newattrs);
+       mutex_unlock(&object->backer->d_inode->i_mutex);
+       cachefiles_end_secure(cache, saved_cred);
+
+       if (ret == -EIO) {
+               fscache_set_store_limit(&object->fscache, 0);
+               cachefiles_io_error_obj(object, "Size set failed");
+               ret = -ENOBUFS;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * dissociate a cache from all the pages it was backing
+ */
+static void cachefiles_dissociate_pages(struct fscache_cache *cache)
+{
+       _enter("");
+}
+
+const struct fscache_cache_ops cachefiles_cache_ops = {
+       .name                   = "cachefiles",
+       .alloc_object           = cachefiles_alloc_object,
+       .lookup_object          = cachefiles_lookup_object,
+       .lookup_complete        = cachefiles_lookup_complete,
+       .grab_object            = cachefiles_grab_object,
+       .update_object          = cachefiles_update_object,
+       .drop_object            = cachefiles_drop_object,
+       .put_object             = cachefiles_put_object,
+       .sync_cache             = cachefiles_sync_cache,
+       .attr_changed           = cachefiles_attr_changed,
+       .read_or_alloc_page     = cachefiles_read_or_alloc_page,
+       .read_or_alloc_pages    = cachefiles_read_or_alloc_pages,
+       .allocate_page          = cachefiles_allocate_page,
+       .allocate_pages         = cachefiles_allocate_pages,
+       .write_page             = cachefiles_write_page,
+       .uncache_page           = cachefiles_uncache_page,
+       .dissociate_pages       = cachefiles_dissociate_pages,
+};
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
new file mode 100644 (file)
index 0000000..19218e1
--- /dev/null
@@ -0,0 +1,360 @@
+/* General netfs cache on cache files internal defs
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/fscache-cache.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/security.h>
+
+struct cachefiles_cache;
+struct cachefiles_object;
+
+extern unsigned cachefiles_debug;
+#define CACHEFILES_DEBUG_KENTER        1
+#define CACHEFILES_DEBUG_KLEAVE        2
+#define CACHEFILES_DEBUG_KDEBUG        4
+
+/*
+ * node records
+ */
+struct cachefiles_object {
+       struct fscache_object           fscache;        /* fscache handle */
+       struct cachefiles_lookup_data   *lookup_data;   /* cached lookup data */
+       struct dentry                   *dentry;        /* the file/dir representing this object */
+       struct dentry                   *backer;        /* backing file */
+       loff_t                          i_size;         /* object size */
+       unsigned long                   flags;
+#define CACHEFILES_OBJECT_ACTIVE       0               /* T if marked active */
+       atomic_t                        usage;          /* object usage count */
+       uint8_t                         type;           /* object type */
+       uint8_t                         new;            /* T if object new */
+       spinlock_t                      work_lock;
+       struct rb_node                  active_node;    /* link in active tree (dentry is key) */
+};
+
+extern struct kmem_cache *cachefiles_object_jar;
+
+/*
+ * Cache files cache definition
+ */
+struct cachefiles_cache {
+       struct fscache_cache            cache;          /* FS-Cache record */
+       struct vfsmount                 *mnt;           /* mountpoint holding the cache */
+       struct dentry                   *graveyard;     /* directory into which dead objects go */
+       struct file                     *cachefilesd;   /* manager daemon handle */
+       const struct cred               *cache_cred;    /* security override for accessing cache */
+       struct mutex                    daemon_mutex;   /* command serialisation mutex */
+       wait_queue_head_t               daemon_pollwq;  /* poll waitqueue for daemon */
+       struct rb_root                  active_nodes;   /* active nodes (can't be culled) */
+       rwlock_t                        active_lock;    /* lock for active_nodes */
+       atomic_t                        gravecounter;   /* graveyard uniquifier */
+       unsigned                        frun_percent;   /* when to stop culling (% files) */
+       unsigned                        fcull_percent;  /* when to start culling (% files) */
+       unsigned                        fstop_percent;  /* when to stop allocating (% files) */
+       unsigned                        brun_percent;   /* when to stop culling (% blocks) */
+       unsigned                        bcull_percent;  /* when to start culling (% blocks) */
+       unsigned                        bstop_percent;  /* when to stop allocating (% blocks) */
+       unsigned                        bsize;          /* cache's block size */
+       unsigned                        bshift;         /* min(ilog2(PAGE_SIZE / bsize), 0) */
+       uint64_t                        frun;           /* when to stop culling */
+       uint64_t                        fcull;          /* when to start culling */
+       uint64_t                        fstop;          /* when to stop allocating */
+       sector_t                        brun;           /* when to stop culling */
+       sector_t                        bcull;          /* when to start culling */
+       sector_t                        bstop;          /* when to stop allocating */
+       unsigned long                   flags;
+#define CACHEFILES_READY               0       /* T if cache prepared */
+#define CACHEFILES_DEAD                        1       /* T if cache dead */
+#define CACHEFILES_CULLING             2       /* T if cull engaged */
+#define CACHEFILES_STATE_CHANGED       3       /* T if state changed (poll trigger) */
+       char                            *rootdirname;   /* name of cache root directory */
+       char                            *secctx;        /* LSM security context */
+       char                            *tag;           /* cache binding tag */
+};
+
+/*
+ * backing file read tracking
+ */
+struct cachefiles_one_read {
+       wait_queue_t                    monitor;        /* link into monitored waitqueue */
+       struct page                     *back_page;     /* backing file page we're waiting for */
+       struct page                     *netfs_page;    /* netfs page we're going to fill */
+       struct fscache_retrieval        *op;            /* retrieval op covering this */
+       struct list_head                op_link;        /* link in op's todo list */
+};
+
+/*
+ * backing file write tracking
+ */
+struct cachefiles_one_write {
+       struct page                     *netfs_page;    /* netfs page to copy */
+       struct cachefiles_object        *object;
+       struct list_head                obj_link;       /* link in object's lists */
+       fscache_rw_complete_t           end_io_func;
+       void                            *context;
+};
+
+/*
+ * auxiliary data xattr buffer
+ */
+struct cachefiles_xattr {
+       uint16_t                        len;
+       uint8_t                         type;
+       uint8_t                         data[];
+};
+
+/*
+ * note change of state for daemon
+ */
+static inline void cachefiles_state_changed(struct cachefiles_cache *cache)
+{
+       set_bit(CACHEFILES_STATE_CHANGED, &cache->flags);
+       wake_up_all(&cache->daemon_pollwq);
+}
+
+/*
+ * cf-bind.c
+ */
+extern int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args);
+extern void cachefiles_daemon_unbind(struct cachefiles_cache *cache);
+
+/*
+ * cf-daemon.c
+ */
+extern const struct file_operations cachefiles_daemon_fops;
+
+extern int cachefiles_has_space(struct cachefiles_cache *cache,
+                               unsigned fnr, unsigned bnr);
+
+/*
+ * cf-interface.c
+ */
+extern const struct fscache_cache_ops cachefiles_cache_ops;
+
+/*
+ * cf-key.c
+ */
+extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type);
+
+/*
+ * cf-namei.c
+ */
+extern int cachefiles_delete_object(struct cachefiles_cache *cache,
+                                   struct cachefiles_object *object);
+extern int cachefiles_walk_to_object(struct cachefiles_object *parent,
+                                    struct cachefiles_object *object,
+                                    const char *key,
+                                    struct cachefiles_xattr *auxdata);
+extern struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
+                                              struct dentry *dir,
+                                              const char *name);
+
+extern int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,
+                          char *filename);
+
+extern int cachefiles_check_in_use(struct cachefiles_cache *cache,
+                                  struct dentry *dir, char *filename);
+
+/*
+ * cf-proc.c
+ */
+#ifdef CONFIG_CACHEFILES_HISTOGRAM
+extern atomic_t cachefiles_lookup_histogram[HZ];
+extern atomic_t cachefiles_mkdir_histogram[HZ];
+extern atomic_t cachefiles_create_histogram[HZ];
+
+extern int __init cachefiles_proc_init(void);
+extern void cachefiles_proc_cleanup(void);
+static inline
+void cachefiles_hist(atomic_t histogram[], unsigned long start_jif)
+{
+       unsigned long jif = jiffies - start_jif;
+       if (jif >= HZ)
+               jif = HZ - 1;
+       atomic_inc(&histogram[jif]);
+}
+
+#else
+#define cachefiles_proc_init()         (0)
+#define cachefiles_proc_cleanup()      do {} while (0)
+#define cachefiles_hist(hist, start_jif) do {} while (0)
+#endif
+
+/*
+ * cf-rdwr.c
+ */
+extern int cachefiles_read_or_alloc_page(struct fscache_retrieval *,
+                                        struct page *, gfp_t);
+extern int cachefiles_read_or_alloc_pages(struct fscache_retrieval *,
+                                         struct list_head *, unsigned *,
+                                         gfp_t);
+extern int cachefiles_allocate_page(struct fscache_retrieval *, struct page *,
+                                   gfp_t);
+extern int cachefiles_allocate_pages(struct fscache_retrieval *,
+                                    struct list_head *, unsigned *, gfp_t);
+extern int cachefiles_write_page(struct fscache_storage *, struct page *);
+extern void cachefiles_uncache_page(struct fscache_object *, struct page *);
+
+/*
+ * cf-security.c
+ */
+extern int cachefiles_get_security_ID(struct cachefiles_cache *cache);
+extern int cachefiles_determine_cache_security(struct cachefiles_cache *cache,
+                                              struct dentry *root,
+                                              const struct cred **_saved_cred);
+
+static inline void cachefiles_begin_secure(struct cachefiles_cache *cache,
+                                          const struct cred **_saved_cred)
+{
+       *_saved_cred = override_creds(cache->cache_cred);
+}
+
+static inline void cachefiles_end_secure(struct cachefiles_cache *cache,
+                                        const struct cred *saved_cred)
+{
+       revert_creds(saved_cred);
+}
+
+/*
+ * cf-xattr.c
+ */
+extern int cachefiles_check_object_type(struct cachefiles_object *object);
+extern int cachefiles_set_object_xattr(struct cachefiles_object *object,
+                                      struct cachefiles_xattr *auxdata);
+extern int cachefiles_update_object_xattr(struct cachefiles_object *object,
+                                         struct cachefiles_xattr *auxdata);
+extern int cachefiles_check_object_xattr(struct cachefiles_object *object,
+                                        struct cachefiles_xattr *auxdata);
+extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
+                                         struct dentry *dentry);
+
+
+/*
+ * error handling
+ */
+#define kerror(FMT, ...) printk(KERN_ERR "CacheFiles: "FMT"\n", ##__VA_ARGS__)
+
+#define cachefiles_io_error(___cache, FMT, ...)                \
+do {                                                   \
+       kerror("I/O Error: " FMT, ##__VA_ARGS__);       \
+       fscache_io_error(&(___cache)->cache);           \
+       set_bit(CACHEFILES_DEAD, &(___cache)->flags);   \
+} while (0)
+
+#define cachefiles_io_error_obj(object, FMT, ...)                      \
+do {                                                                   \
+       struct cachefiles_cache *___cache;                              \
+                                                                       \
+       ___cache = container_of((object)->fscache.cache,                \
+                               struct cachefiles_cache, cache);        \
+       cachefiles_io_error(___cache, FMT, ##__VA_ARGS__);              \
+} while (0)
+
+
+/*
+ * debug tracing
+ */
+#define dbgprintk(FMT, ...) \
+       printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__)
+
+/* make sure we maintain the format strings, even when debugging is disabled */
+static inline void _dbprintk(const char *fmt, ...)
+       __attribute__((format(printf, 1, 2)));
+static inline void _dbprintk(const char *fmt, ...)
+{
+}
+
+#define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
+#define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__)
+
+
+#if defined(__KDEBUG)
+#define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__)
+#define _leave(FMT, ...) kleave(FMT, ##__VA_ARGS__)
+#define _debug(FMT, ...) kdebug(FMT, ##__VA_ARGS__)
+
+#elif defined(CONFIG_CACHEFILES_DEBUG)
+#define _enter(FMT, ...)                               \
+do {                                                   \
+       if (cachefiles_debug & CACHEFILES_DEBUG_KENTER) \
+               kenter(FMT, ##__VA_ARGS__);             \
+} while (0)
+
+#define _leave(FMT, ...)                               \
+do {                                                   \
+       if (cachefiles_debug & CACHEFILES_DEBUG_KLEAVE) \
+               kleave(FMT, ##__VA_ARGS__);             \
+} while (0)
+
+#define _debug(FMT, ...)                               \
+do {                                                   \
+       if (cachefiles_debug & CACHEFILES_DEBUG_KDEBUG) \
+               kdebug(FMT, ##__VA_ARGS__);             \
+} while (0)
+
+#else
+#define _enter(FMT, ...) _dbprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
+#define _leave(FMT, ...) _dbprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
+#define _debug(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__)
+#endif
+
+#if 1 /* defined(__KDEBUGALL) */
+
+#define ASSERT(X)                                                      \
+do {                                                                   \
+       if (unlikely(!(X))) {                                           \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "CacheFiles: Assertion failed\n");      \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#define ASSERTCMP(X, OP, Y)                                            \
+do {                                                                   \
+       if (unlikely(!((X) OP (Y)))) {                                  \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "CacheFiles: Assertion failed\n");      \
+               printk(KERN_ERR "%lx " #OP " %lx is false\n",           \
+                      (unsigned long)(X), (unsigned long)(Y));         \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#define ASSERTIF(C, X)                                                 \
+do {                                                                   \
+       if (unlikely((C) && !(X))) {                                    \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "CacheFiles: Assertion failed\n");      \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#define ASSERTIFCMP(C, X, OP, Y)                                       \
+do {                                                                   \
+       if (unlikely((C) && !((X) OP (Y)))) {                           \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "CacheFiles: Assertion failed\n");      \
+               printk(KERN_ERR "%lx " #OP " %lx is false\n",           \
+                      (unsigned long)(X), (unsigned long)(Y));         \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#else
+
+#define ASSERT(X)                      do {} while (0)
+#define ASSERTCMP(X, OP, Y)            do {} while (0)
+#define ASSERTIF(C, X)                 do {} while (0)
+#define ASSERTIFCMP(C, X, OP, Y)       do {} while (0)
+
+#endif
diff --git a/fs/cachefiles/key.c b/fs/cachefiles/key.c
new file mode 100644 (file)
index 0000000..81b8b2b
--- /dev/null
@@ -0,0 +1,159 @@
+/* Key to pathname encoder
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include "internal.h"
+
+static const char cachefiles_charmap[64] =
+       "0123456789"                    /* 0 - 9 */
+       "abcdefghijklmnopqrstuvwxyz"    /* 10 - 35 */
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"    /* 36 - 61 */
+       "_-"                            /* 62 - 63 */
+       ;
+
+static const char cachefiles_filecharmap[256] = {
+       /* we skip space and tab and control chars */
+       [33 ... 46] = 1,                /* '!' -> '.' */
+       /* we skip '/' as it's significant to pathwalk */
+       [48 ... 127] = 1,               /* '0' -> '~' */
+};
+
+/*
+ * turn the raw key into something cooked
+ * - the raw key should include the length in the two bytes at the front
+ * - the key may be up to 514 bytes in length (including the length word)
+ *   - "base64" encode the strange keys, mapping 3 bytes of raw to four of
+ *     cooked
+ *   - need to cut the cooked key into 252 char lengths (189 raw bytes)
+ */
+char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type)
+{
+       unsigned char csum, ch;
+       unsigned int acc;
+       char *key;
+       int loop, len, max, seg, mark, print;
+
+       _enter(",%d", keylen);
+
+       BUG_ON(keylen < 2 || keylen > 514);
+
+       csum = raw[0] + raw[1];
+       print = 1;
+       for (loop = 2; loop < keylen; loop++) {
+               ch = raw[loop];
+               csum += ch;
+               print &= cachefiles_filecharmap[ch];
+       }
+
+       if (print) {
+               /* if the path is usable ASCII, then we render it directly */
+               max = keylen - 2;
+               max += 2;       /* two base64'd length chars on the front */
+               max += 5;       /* @checksum/M */
+               max += 3 * 2;   /* maximum number of segment dividers (".../M")
+                                * is ((514 + 251) / 252) = 3
+                                */
+               max += 1;       /* NUL on end */
+       } else {
+               /* calculate the maximum length of the cooked key */
+               keylen = (keylen + 2) / 3;
+
+               max = keylen * 4;
+               max += 5;       /* @checksum/M */
+               max += 3 * 2;   /* maximum number of segment dividers (".../M")
+                                * is ((514 + 188) / 189) = 3
+                                */
+               max += 1;       /* NUL on end */
+       }
+
+       max += 1;       /* 2nd NUL on end */
+
+       _debug("max: %d", max);
+
+       key = kmalloc(max, GFP_KERNEL);
+       if (!key)
+               return NULL;
+
+       len = 0;
+
+       /* build the cooked key */
+       sprintf(key, "@%02x%c+", (unsigned) csum, 0);
+       len = 5;
+       mark = len - 1;
+
+       if (print) {
+               acc = *(uint16_t *) raw;
+               raw += 2;
+
+               key[len + 1] = cachefiles_charmap[acc & 63];
+               acc >>= 6;
+               key[len] = cachefiles_charmap[acc & 63];
+               len += 2;
+
+               seg = 250;
+               for (loop = keylen; loop > 0; loop--) {
+                       if (seg <= 0) {
+                               key[len++] = '\0';
+                               mark = len;
+                               key[len++] = '+';
+                               seg = 252;
+                       }
+
+                       key[len++] = *raw++;
+                       ASSERT(len < max);
+               }
+
+               switch (type) {
+               case FSCACHE_COOKIE_TYPE_INDEX:         type = 'I';     break;
+               case FSCACHE_COOKIE_TYPE_DATAFILE:      type = 'D';     break;
+               default:                                type = 'S';     break;
+               }
+       } else {
+               seg = 252;
+               for (loop = keylen; loop > 0; loop--) {
+                       if (seg <= 0) {
+                               key[len++] = '\0';
+                               mark = len;
+                               key[len++] = '+';
+                               seg = 252;
+                       }
+
+                       acc = *raw++;
+                       acc |= *raw++ << 8;
+                       acc |= *raw++ << 16;
+
+                       _debug("acc: %06x", acc);
+
+                       key[len++] = cachefiles_charmap[acc & 63];
+                       acc >>= 6;
+                       key[len++] = cachefiles_charmap[acc & 63];
+                       acc >>= 6;
+                       key[len++] = cachefiles_charmap[acc & 63];
+                       acc >>= 6;
+                       key[len++] = cachefiles_charmap[acc & 63];
+
+                       ASSERT(len < max);
+               }
+
+               switch (type) {
+               case FSCACHE_COOKIE_TYPE_INDEX:         type = 'J';     break;
+               case FSCACHE_COOKIE_TYPE_DATAFILE:      type = 'E';     break;
+               default:                                type = 'T';     break;
+               }
+       }
+
+       key[mark] = type;
+       key[len++] = 0;
+       key[len] = 0;
+
+       _leave(" = %p %d", key, len);
+       return key;
+}
diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c
new file mode 100644 (file)
index 0000000..4bfa8cf
--- /dev/null
@@ -0,0 +1,106 @@
+/* Network filesystem caching backend to use cache files on a premounted
+ * filesystem
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/statfs.h>
+#include <linux/sysctl.h>
+#include <linux/miscdevice.h>
+#include "internal.h"
+
+unsigned cachefiles_debug;
+module_param_named(debug, cachefiles_debug, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(cachefiles_debug, "CacheFiles debugging mask");
+
+MODULE_DESCRIPTION("Mounted-filesystem based cache");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+struct kmem_cache *cachefiles_object_jar;
+
+static struct miscdevice cachefiles_dev = {
+       .minor  = MISC_DYNAMIC_MINOR,
+       .name   = "cachefiles",
+       .fops   = &cachefiles_daemon_fops,
+};
+
+static void cachefiles_object_init_once(void *_object)
+{
+       struct cachefiles_object *object = _object;
+
+       memset(object, 0, sizeof(*object));
+       spin_lock_init(&object->work_lock);
+}
+
+/*
+ * initialise the fs caching module
+ */
+static int __init cachefiles_init(void)
+{
+       int ret;
+
+       ret = misc_register(&cachefiles_dev);
+       if (ret < 0)
+               goto error_dev;
+
+       /* create an object jar */
+       ret = -ENOMEM;
+       cachefiles_object_jar =
+               kmem_cache_create("cachefiles_object_jar",
+                                 sizeof(struct cachefiles_object),
+                                 0,
+                                 SLAB_HWCACHE_ALIGN,
+                                 cachefiles_object_init_once);
+       if (!cachefiles_object_jar) {
+               printk(KERN_NOTICE
+                      "CacheFiles: Failed to allocate an object jar\n");
+               goto error_object_jar;
+       }
+
+       ret = cachefiles_proc_init();
+       if (ret < 0)
+               goto error_proc;
+
+       printk(KERN_INFO "CacheFiles: Loaded\n");
+       return 0;
+
+error_proc:
+       kmem_cache_destroy(cachefiles_object_jar);
+error_object_jar:
+       misc_deregister(&cachefiles_dev);
+error_dev:
+       kerror("failed to register: %d", ret);
+       return ret;
+}
+
+fs_initcall(cachefiles_init);
+
+/*
+ * clean up on module removal
+ */
+static void __exit cachefiles_exit(void)
+{
+       printk(KERN_INFO "CacheFiles: Unloading\n");
+
+       cachefiles_proc_cleanup();
+       kmem_cache_destroy(cachefiles_object_jar);
+       misc_deregister(&cachefiles_dev);
+}
+
+module_exit(cachefiles_exit);
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
new file mode 100644 (file)
index 0000000..4ce818a
--- /dev/null
@@ -0,0 +1,771 @@
+/* CacheFiles path walking and related routines
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fsnotify.h>
+#include <linux/quotaops.h>
+#include <linux/xattr.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/security.h>
+#include "internal.h"
+
+static int cachefiles_wait_bit(void *flags)
+{
+       schedule();
+       return 0;
+}
+
+/*
+ * record the fact that an object is now active
+ */
+static void cachefiles_mark_object_active(struct cachefiles_cache *cache,
+                                         struct cachefiles_object *object)
+{
+       struct cachefiles_object *xobject;
+       struct rb_node **_p, *_parent = NULL;
+       struct dentry *dentry;
+
+       _enter(",%p", object);
+
+try_again:
+       write_lock(&cache->active_lock);
+
+       if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags))
+               BUG();
+
+       dentry = object->dentry;
+       _p = &cache->active_nodes.rb_node;
+       while (*_p) {
+               _parent = *_p;
+               xobject = rb_entry(_parent,
+                                  struct cachefiles_object, active_node);
+
+               ASSERT(xobject != object);
+
+               if (xobject->dentry > dentry)
+                       _p = &(*_p)->rb_left;
+               else if (xobject->dentry < dentry)
+                       _p = &(*_p)->rb_right;
+               else
+                       goto wait_for_old_object;
+       }
+
+       rb_link_node(&object->active_node, _parent, _p);
+       rb_insert_color(&object->active_node, &cache->active_nodes);
+
+       write_unlock(&cache->active_lock);
+       _leave("");
+       return;
+
+       /* an old object from a previous incarnation is hogging the slot - we
+        * need to wait for it to be destroyed */
+wait_for_old_object:
+       if (xobject->fscache.state < FSCACHE_OBJECT_DYING) {
+               printk(KERN_ERR "\n");
+               printk(KERN_ERR "CacheFiles: Error:"
+                      " Unexpected object collision\n");
+               printk(KERN_ERR "xobject: OBJ%x\n",
+                      xobject->fscache.debug_id);
+               printk(KERN_ERR "xobjstate=%s\n",
+                      fscache_object_states[xobject->fscache.state]);
+               printk(KERN_ERR "xobjflags=%lx\n", xobject->fscache.flags);
+               printk(KERN_ERR "xobjevent=%lx [%lx]\n",
+                      xobject->fscache.events, xobject->fscache.event_mask);
+               printk(KERN_ERR "xops=%u inp=%u exc=%u\n",
+                      xobject->fscache.n_ops, xobject->fscache.n_in_progress,
+                      xobject->fscache.n_exclusive);
+               printk(KERN_ERR "xcookie=%p [pr=%p nd=%p fl=%lx]\n",
+                      xobject->fscache.cookie,
+                      xobject->fscache.cookie->parent,
+                      xobject->fscache.cookie->netfs_data,
+                      xobject->fscache.cookie->flags);
+               printk(KERN_ERR "xparent=%p\n",
+                      xobject->fscache.parent);
+               printk(KERN_ERR "object: OBJ%x\n",
+                      object->fscache.debug_id);
+               printk(KERN_ERR "cookie=%p [pr=%p nd=%p fl=%lx]\n",
+                      object->fscache.cookie,
+                      object->fscache.cookie->parent,
+                      object->fscache.cookie->netfs_data,
+                      object->fscache.cookie->flags);
+               printk(KERN_ERR "parent=%p\n",
+                      object->fscache.parent);
+               BUG();
+       }
+       atomic_inc(&xobject->usage);
+       write_unlock(&cache->active_lock);
+
+       _debug(">>> wait");
+       wait_on_bit(&xobject->flags, CACHEFILES_OBJECT_ACTIVE,
+                   cachefiles_wait_bit, TASK_UNINTERRUPTIBLE);
+       _debug("<<< waited");
+
+       cache->cache.ops->put_object(&xobject->fscache);
+       goto try_again;
+}
+
+/*
+ * delete an object representation from the cache
+ * - file backed objects are unlinked
+ * - directory backed objects are stuffed into the graveyard for userspace to
+ *   delete
+ * - unlocks the directory mutex
+ */
+static int cachefiles_bury_object(struct cachefiles_cache *cache,
+                                 struct dentry *dir,
+                                 struct dentry *rep)
+{
+       struct dentry *grave, *trap;
+       char nbuffer[8 + 8 + 1];
+       int ret;
+
+       _enter(",'%*.*s','%*.*s'",
+              dir->d_name.len, dir->d_name.len, dir->d_name.name,
+              rep->d_name.len, rep->d_name.len, rep->d_name.name);
+
+       /* non-directories can just be unlinked */
+       if (!S_ISDIR(rep->d_inode->i_mode)) {
+               _debug("unlink stale object");
+               ret = vfs_unlink(dir->d_inode, rep);
+
+               mutex_unlock(&dir->d_inode->i_mutex);
+
+               if (ret == -EIO)
+                       cachefiles_io_error(cache, "Unlink failed");
+
+               _leave(" = %d", ret);
+               return ret;
+       }
+
+       /* directories have to be moved to the graveyard */
+       _debug("move stale object to graveyard");
+       mutex_unlock(&dir->d_inode->i_mutex);
+
+try_again:
+       /* first step is to make up a grave dentry in the graveyard */
+       sprintf(nbuffer, "%08x%08x",
+               (uint32_t) get_seconds(),
+               (uint32_t) atomic_inc_return(&cache->gravecounter));
+
+       /* do the multiway lock magic */
+       trap = lock_rename(cache->graveyard, dir);
+
+       /* do some checks before getting the grave dentry */
+       if (rep->d_parent != dir) {
+               /* the entry was probably culled when we dropped the parent dir
+                * lock */
+               unlock_rename(cache->graveyard, dir);
+               _leave(" = 0 [culled?]");
+               return 0;
+       }
+
+       if (!S_ISDIR(cache->graveyard->d_inode->i_mode)) {
+               unlock_rename(cache->graveyard, dir);
+               cachefiles_io_error(cache, "Graveyard no longer a directory");
+               return -EIO;
+       }
+
+       if (trap == rep) {
+               unlock_rename(cache->graveyard, dir);
+               cachefiles_io_error(cache, "May not make directory loop");
+               return -EIO;
+       }
+
+       if (d_mountpoint(rep)) {
+               unlock_rename(cache->graveyard, dir);
+               cachefiles_io_error(cache, "Mountpoint in cache");
+               return -EIO;
+       }
+
+       grave = lookup_one_len(nbuffer, cache->graveyard, strlen(nbuffer));
+       if (IS_ERR(grave)) {
+               unlock_rename(cache->graveyard, dir);
+
+               if (PTR_ERR(grave) == -ENOMEM) {
+                       _leave(" = -ENOMEM");
+                       return -ENOMEM;
+               }
+
+               cachefiles_io_error(cache, "Lookup error %ld",
+                                   PTR_ERR(grave));
+               return -EIO;
+       }
+
+       if (grave->d_inode) {
+               unlock_rename(cache->graveyard, dir);
+               dput(grave);
+               grave = NULL;
+               cond_resched();
+               goto try_again;
+       }
+
+       if (d_mountpoint(grave)) {
+               unlock_rename(cache->graveyard, dir);
+               dput(grave);
+               cachefiles_io_error(cache, "Mountpoint in graveyard");
+               return -EIO;
+       }
+
+       /* target should not be an ancestor of source */
+       if (trap == grave) {
+               unlock_rename(cache->graveyard, dir);
+               dput(grave);
+               cachefiles_io_error(cache, "May not make directory loop");
+               return -EIO;
+       }
+
+       /* attempt the rename */
+       ret = vfs_rename(dir->d_inode, rep, cache->graveyard->d_inode, grave);
+       if (ret != 0 && ret != -ENOMEM)
+               cachefiles_io_error(cache, "Rename failed with error %d", ret);
+
+       unlock_rename(cache->graveyard, dir);
+       dput(grave);
+       _leave(" = 0");
+       return 0;
+}
+
+/*
+ * delete an object representation from the cache
+ */
+int cachefiles_delete_object(struct cachefiles_cache *cache,
+                            struct cachefiles_object *object)
+{
+       struct dentry *dir;
+       int ret;
+
+       _enter(",{%p}", object->dentry);
+
+       ASSERT(object->dentry);
+       ASSERT(object->dentry->d_inode);
+       ASSERT(object->dentry->d_parent);
+
+       dir = dget_parent(object->dentry);
+
+       mutex_lock(&dir->d_inode->i_mutex);
+       ret = cachefiles_bury_object(cache, dir, object->dentry);
+
+       dput(dir);
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * walk from the parent object to the child object through the backing
+ * filesystem, creating directories as we go
+ */
+int cachefiles_walk_to_object(struct cachefiles_object *parent,
+                             struct cachefiles_object *object,
+                             const char *key,
+                             struct cachefiles_xattr *auxdata)
+{
+       struct cachefiles_cache *cache;
+       struct dentry *dir, *next = NULL;
+       unsigned long start;
+       const char *name;
+       int ret, nlen;
+
+       _enter("{%p},,%s,", parent->dentry, key);
+
+       cache = container_of(parent->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       ASSERT(parent->dentry);
+       ASSERT(parent->dentry->d_inode);
+
+       if (!(S_ISDIR(parent->dentry->d_inode->i_mode))) {
+               // TODO: convert file to dir
+               _leave("looking up in none directory");
+               return -ENOBUFS;
+       }
+
+       dir = dget(parent->dentry);
+
+advance:
+       /* attempt to transit the first directory component */
+       name = key;
+       nlen = strlen(key);
+
+       /* key ends in a double NUL */
+       key = key + nlen + 1;
+       if (!*key)
+               key = NULL;
+
+lookup_again:
+       /* search the current directory for the element name */
+       _debug("lookup '%s'", name);
+
+       mutex_lock(&dir->d_inode->i_mutex);
+
+       start = jiffies;
+       next = lookup_one_len(name, dir, nlen);
+       cachefiles_hist(cachefiles_lookup_histogram, start);
+       if (IS_ERR(next))
+               goto lookup_error;
+
+       _debug("next -> %p %s", next, next->d_inode ? "positive" : "negative");
+
+       if (!key)
+               object->new = !next->d_inode;
+
+       /* if this element of the path doesn't exist, then the lookup phase
+        * failed, and we can release any readers in the certain knowledge that
+        * there's nothing for them to actually read */
+       if (!next->d_inode)
+               fscache_object_lookup_negative(&object->fscache);
+
+       /* we need to create the object if it's negative */
+       if (key || object->type == FSCACHE_COOKIE_TYPE_INDEX) {
+               /* index objects and intervening tree levels must be subdirs */
+               if (!next->d_inode) {
+                       ret = cachefiles_has_space(cache, 1, 0);
+                       if (ret < 0)
+                               goto create_error;
+
+                       start = jiffies;
+                       ret = vfs_mkdir(dir->d_inode, next, 0);
+                       cachefiles_hist(cachefiles_mkdir_histogram, start);
+                       if (ret < 0)
+                               goto create_error;
+
+                       ASSERT(next->d_inode);
+
+                       _debug("mkdir -> %p{%p{ino=%lu}}",
+                              next, next->d_inode, next->d_inode->i_ino);
+
+               } else if (!S_ISDIR(next->d_inode->i_mode)) {
+                       kerror("inode %lu is not a directory",
+                              next->d_inode->i_ino);
+                       ret = -ENOBUFS;
+                       goto error;
+               }
+
+       } else {
+               /* non-index objects start out life as files */
+               if (!next->d_inode) {
+                       ret = cachefiles_has_space(cache, 1, 0);
+                       if (ret < 0)
+                               goto create_error;
+
+                       start = jiffies;
+                       ret = vfs_create(dir->d_inode, next, S_IFREG, NULL);
+                       cachefiles_hist(cachefiles_create_histogram, start);
+                       if (ret < 0)
+                               goto create_error;
+
+                       ASSERT(next->d_inode);
+
+                       _debug("create -> %p{%p{ino=%lu}}",
+                              next, next->d_inode, next->d_inode->i_ino);
+
+               } else if (!S_ISDIR(next->d_inode->i_mode) &&
+                          !S_ISREG(next->d_inode->i_mode)
+                          ) {
+                       kerror("inode %lu is not a file or directory",
+                              next->d_inode->i_ino);
+                       ret = -ENOBUFS;
+                       goto error;
+               }
+       }
+
+       /* process the next component */
+       if (key) {
+               _debug("advance");
+               mutex_unlock(&dir->d_inode->i_mutex);
+               dput(dir);
+               dir = next;
+               next = NULL;
+               goto advance;
+       }
+
+       /* we've found the object we were looking for */
+       object->dentry = next;
+
+       /* if we've found that the terminal object exists, then we need to
+        * check its attributes and delete it if it's out of date */
+       if (!object->new) {
+               _debug("validate '%*.*s'",
+                      next->d_name.len, next->d_name.len, next->d_name.name);
+
+               ret = cachefiles_check_object_xattr(object, auxdata);
+               if (ret == -ESTALE) {
+                       /* delete the object (the deleter drops the directory
+                        * mutex) */
+                       object->dentry = NULL;
+
+                       ret = cachefiles_bury_object(cache, dir, next);
+                       dput(next);
+                       next = NULL;
+
+                       if (ret < 0)
+                               goto delete_error;
+
+                       _debug("redo lookup");
+                       goto lookup_again;
+               }
+       }
+
+       /* note that we're now using this object */
+       cachefiles_mark_object_active(cache, object);
+
+       mutex_unlock(&dir->d_inode->i_mutex);
+       dput(dir);
+       dir = NULL;
+
+       _debug("=== OBTAINED_OBJECT ===");
+
+       if (object->new) {
+               /* attach data to a newly constructed terminal object */
+               ret = cachefiles_set_object_xattr(object, auxdata);
+               if (ret < 0)
+                       goto check_error;
+       } else {
+               /* always update the atime on an object we've just looked up
+                * (this is used to keep track of culling, and atimes are only
+                * updated by read, write and readdir but not lookup or
+                * open) */
+               touch_atime(cache->mnt, next);
+       }
+
+       /* open a file interface onto a data file */
+       if (object->type != FSCACHE_COOKIE_TYPE_INDEX) {
+               if (S_ISREG(object->dentry->d_inode->i_mode)) {
+                       const struct address_space_operations *aops;
+
+                       ret = -EPERM;
+                       aops = object->dentry->d_inode->i_mapping->a_ops;
+                       if (!aops->bmap)
+                               goto check_error;
+
+                       object->backer = object->dentry;
+               } else {
+                       BUG(); // TODO: open file in data-class subdir
+               }
+       }
+
+       object->new = 0;
+       fscache_obtained_object(&object->fscache);
+
+       _leave(" = 0 [%lu]", object->dentry->d_inode->i_ino);
+       return 0;
+
+create_error:
+       _debug("create error %d", ret);
+       if (ret == -EIO)
+               cachefiles_io_error(cache, "Create/mkdir failed");
+       goto error;
+
+check_error:
+       _debug("check error %d", ret);
+       write_lock(&cache->active_lock);
+       rb_erase(&object->active_node, &cache->active_nodes);
+       clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
+       wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
+       write_unlock(&cache->active_lock);
+
+       dput(object->dentry);
+       object->dentry = NULL;
+       goto error_out;
+
+delete_error:
+       _debug("delete error %d", ret);
+       goto error_out2;
+
+lookup_error:
+       _debug("lookup error %ld", PTR_ERR(next));
+       ret = PTR_ERR(next);
+       if (ret == -EIO)
+               cachefiles_io_error(cache, "Lookup failed");
+       next = NULL;
+error:
+       mutex_unlock(&dir->d_inode->i_mutex);
+       dput(next);
+error_out2:
+       dput(dir);
+error_out:
+       if (ret == -ENOSPC)
+               ret = -ENOBUFS;
+
+       _leave(" = error %d", -ret);
+       return ret;
+}
+
+/*
+ * get a subdirectory
+ */
+struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
+                                       struct dentry *dir,
+                                       const char *dirname)
+{
+       struct dentry *subdir;
+       unsigned long start;
+       int ret;
+
+       _enter(",,%s", dirname);
+
+       /* search the current directory for the element name */
+       mutex_lock(&dir->d_inode->i_mutex);
+
+       start = jiffies;
+       subdir = lookup_one_len(dirname, dir, strlen(dirname));
+       cachefiles_hist(cachefiles_lookup_histogram, start);
+       if (IS_ERR(subdir)) {
+               if (PTR_ERR(subdir) == -ENOMEM)
+                       goto nomem_d_alloc;
+               goto lookup_error;
+       }
+
+       _debug("subdir -> %p %s",
+              subdir, subdir->d_inode ? "positive" : "negative");
+
+       /* we need to create the subdir if it doesn't exist yet */
+       if (!subdir->d_inode) {
+               ret = cachefiles_has_space(cache, 1, 0);
+               if (ret < 0)
+                       goto mkdir_error;
+
+               _debug("attempt mkdir");
+
+               ret = vfs_mkdir(dir->d_inode, subdir, 0700);
+               if (ret < 0)
+                       goto mkdir_error;
+
+               ASSERT(subdir->d_inode);
+
+               _debug("mkdir -> %p{%p{ino=%lu}}",
+                      subdir,
+                      subdir->d_inode,
+                      subdir->d_inode->i_ino);
+       }
+
+       mutex_unlock(&dir->d_inode->i_mutex);
+
+       /* we need to make sure the subdir is a directory */
+       ASSERT(subdir->d_inode);
+
+       if (!S_ISDIR(subdir->d_inode->i_mode)) {
+               kerror("%s is not a directory", dirname);
+               ret = -EIO;
+               goto check_error;
+       }
+
+       ret = -EPERM;
+       if (!subdir->d_inode->i_op ||
+           !subdir->d_inode->i_op->setxattr ||
+           !subdir->d_inode->i_op->getxattr ||
+           !subdir->d_inode->i_op->lookup ||
+           !subdir->d_inode->i_op->mkdir ||
+           !subdir->d_inode->i_op->create ||
+           !subdir->d_inode->i_op->rename ||
+           !subdir->d_inode->i_op->rmdir ||
+           !subdir->d_inode->i_op->unlink)
+               goto check_error;
+
+       _leave(" = [%lu]", subdir->d_inode->i_ino);
+       return subdir;
+
+check_error:
+       dput(subdir);
+       _leave(" = %d [check]", ret);
+       return ERR_PTR(ret);
+
+mkdir_error:
+       mutex_unlock(&dir->d_inode->i_mutex);
+       dput(subdir);
+       kerror("mkdir %s failed with error %d", dirname, ret);
+       return ERR_PTR(ret);
+
+lookup_error:
+       mutex_unlock(&dir->d_inode->i_mutex);
+       ret = PTR_ERR(subdir);
+       kerror("Lookup %s failed with error %d", dirname, ret);
+       return ERR_PTR(ret);
+
+nomem_d_alloc:
+       mutex_unlock(&dir->d_inode->i_mutex);
+       _leave(" = -ENOMEM");
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * find out if an object is in use or not
+ * - if finds object and it's not in use:
+ *   - returns a pointer to the object and a reference on it
+ *   - returns with the directory locked
+ */
+static struct dentry *cachefiles_check_active(struct cachefiles_cache *cache,
+                                             struct dentry *dir,
+                                             char *filename)
+{
+       struct cachefiles_object *object;
+       struct rb_node *_n;
+       struct dentry *victim;
+       unsigned long start;
+       int ret;
+
+       //_enter(",%*.*s/,%s",
+       //       dir->d_name.len, dir->d_name.len, dir->d_name.name, filename);
+
+       /* look up the victim */
+       mutex_lock_nested(&dir->d_inode->i_mutex, 1);
+
+       start = jiffies;
+       victim = lookup_one_len(filename, dir, strlen(filename));
+       cachefiles_hist(cachefiles_lookup_histogram, start);
+       if (IS_ERR(victim))
+               goto lookup_error;
+
+       //_debug("victim -> %p %s",
+       //       victim, victim->d_inode ? "positive" : "negative");
+
+       /* if the object is no longer there then we probably retired the object
+        * at the netfs's request whilst the cull was in progress
+        */
+       if (!victim->d_inode) {
+               mutex_unlock(&dir->d_inode->i_mutex);
+               dput(victim);
+               _leave(" = -ENOENT [absent]");
+               return ERR_PTR(-ENOENT);
+       }
+
+       /* check to see if we're using this object */
+       read_lock(&cache->active_lock);
+
+       _n = cache->active_nodes.rb_node;
+
+       while (_n) {
+               object = rb_entry(_n, struct cachefiles_object, active_node);
+
+               if (object->dentry > victim)
+                       _n = _n->rb_left;
+               else if (object->dentry < victim)
+                       _n = _n->rb_right;
+               else
+                       goto object_in_use;
+       }
+
+       read_unlock(&cache->active_lock);
+
+       //_leave(" = %p", victim);
+       return victim;
+
+object_in_use:
+       read_unlock(&cache->active_lock);
+       mutex_unlock(&dir->d_inode->i_mutex);
+       dput(victim);
+       //_leave(" = -EBUSY [in use]");
+       return ERR_PTR(-EBUSY);
+
+lookup_error:
+       mutex_unlock(&dir->d_inode->i_mutex);
+       ret = PTR_ERR(victim);
+       if (ret == -ENOENT) {
+               /* file or dir now absent - probably retired by netfs */
+               _leave(" = -ESTALE [absent]");
+               return ERR_PTR(-ESTALE);
+       }
+
+       if (ret == -EIO) {
+               cachefiles_io_error(cache, "Lookup failed");
+       } else if (ret != -ENOMEM) {
+               kerror("Internal error: %d", ret);
+               ret = -EIO;
+       }
+
+       _leave(" = %d", ret);
+       return ERR_PTR(ret);
+}
+
+/*
+ * cull an object if it's not in use
+ * - called only by cache manager daemon
+ */
+int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,
+                   char *filename)
+{
+       struct dentry *victim;
+       int ret;
+
+       _enter(",%*.*s/,%s",
+              dir->d_name.len, dir->d_name.len, dir->d_name.name, filename);
+
+       victim = cachefiles_check_active(cache, dir, filename);
+       if (IS_ERR(victim))
+               return PTR_ERR(victim);
+
+       _debug("victim -> %p %s",
+              victim, victim->d_inode ? "positive" : "negative");
+
+       /* okay... the victim is not being used so we can cull it
+        * - start by marking it as stale
+        */
+       _debug("victim is cullable");
+
+       ret = cachefiles_remove_object_xattr(cache, victim);
+       if (ret < 0)
+               goto error_unlock;
+
+       /*  actually remove the victim (drops the dir mutex) */
+       _debug("bury");
+
+       ret = cachefiles_bury_object(cache, dir, victim);
+       if (ret < 0)
+               goto error;
+
+       dput(victim);
+       _leave(" = 0");
+       return 0;
+
+error_unlock:
+       mutex_unlock(&dir->d_inode->i_mutex);
+error:
+       dput(victim);
+       if (ret == -ENOENT) {
+               /* file or dir now absent - probably retired by netfs */
+               _leave(" = -ESTALE [absent]");
+               return -ESTALE;
+       }
+
+       if (ret != -ENOMEM) {
+               kerror("Internal error: %d", ret);
+               ret = -EIO;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * find out if an object is in use or not
+ * - called only by cache manager daemon
+ * - returns -EBUSY or 0 to indicate whether an object is in use or not
+ */
+int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir,
+                           char *filename)
+{
+       struct dentry *victim;
+
+       //_enter(",%*.*s/,%s",
+       //       dir->d_name.len, dir->d_name.len, dir->d_name.name, filename);
+
+       victim = cachefiles_check_active(cache, dir, filename);
+       if (IS_ERR(victim))
+               return PTR_ERR(victim);
+
+       mutex_unlock(&dir->d_inode->i_mutex);
+       dput(victim);
+       //_leave(" = 0");
+       return 0;
+}
diff --git a/fs/cachefiles/proc.c b/fs/cachefiles/proc.c
new file mode 100644 (file)
index 0000000..eccd339
--- /dev/null
@@ -0,0 +1,134 @@
+/* CacheFiles statistics
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include "internal.h"
+
+atomic_t cachefiles_lookup_histogram[HZ];
+atomic_t cachefiles_mkdir_histogram[HZ];
+atomic_t cachefiles_create_histogram[HZ];
+
+/*
+ * display the latency histogram
+ */
+static int cachefiles_histogram_show(struct seq_file *m, void *v)
+{
+       unsigned long index;
+       unsigned x, y, z, t;
+
+       switch ((unsigned long) v) {
+       case 1:
+               seq_puts(m, "JIFS  SECS  LOOKUPS   MKDIRS    CREATES\n");
+               return 0;
+       case 2:
+               seq_puts(m, "===== ===== ========= ========= =========\n");
+               return 0;
+       default:
+               index = (unsigned long) v - 3;
+               x = atomic_read(&cachefiles_lookup_histogram[index]);
+               y = atomic_read(&cachefiles_mkdir_histogram[index]);
+               z = atomic_read(&cachefiles_create_histogram[index]);
+               if (x == 0 && y == 0 && z == 0)
+                       return 0;
+
+               t = (index * 1000) / HZ;
+
+               seq_printf(m, "%4lu  0.%03u %9u %9u %9u\n", index, t, x, y, z);
+               return 0;
+       }
+}
+
+/*
+ * set up the iterator to start reading from the first line
+ */
+static void *cachefiles_histogram_start(struct seq_file *m, loff_t *_pos)
+{
+       if ((unsigned long long)*_pos >= HZ + 2)
+               return NULL;
+       if (*_pos == 0)
+               *_pos = 1;
+       return (void *)(unsigned long) *_pos;
+}
+
+/*
+ * move to the next line
+ */
+static void *cachefiles_histogram_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return (unsigned long long)*pos > HZ + 2 ?
+               NULL : (void *)(unsigned long) *pos;
+}
+
+/*
+ * clean up after reading
+ */
+static void cachefiles_histogram_stop(struct seq_file *m, void *v)
+{
+}
+
+static const struct seq_operations cachefiles_histogram_ops = {
+       .start          = cachefiles_histogram_start,
+       .stop           = cachefiles_histogram_stop,
+       .next           = cachefiles_histogram_next,
+       .show           = cachefiles_histogram_show,
+};
+
+/*
+ * open "/proc/fs/cachefiles/XXX" which provide statistics summaries
+ */
+static int cachefiles_histogram_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &cachefiles_histogram_ops);
+}
+
+static const struct file_operations cachefiles_histogram_fops = {
+       .owner          = THIS_MODULE,
+       .open           = cachefiles_histogram_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+/*
+ * initialise the /proc/fs/cachefiles/ directory
+ */
+int __init cachefiles_proc_init(void)
+{
+       _enter("");
+
+       if (!proc_mkdir("fs/cachefiles", NULL))
+               goto error_dir;
+
+       if (!proc_create("fs/cachefiles/histogram", S_IFREG | 0444, NULL,
+                        &cachefiles_histogram_fops))
+               goto error_histogram;
+
+       _leave(" = 0");
+       return 0;
+
+error_histogram:
+       remove_proc_entry("fs/cachefiles", NULL);
+error_dir:
+       _leave(" = -ENOMEM");
+       return -ENOMEM;
+}
+
+/*
+ * clean up the /proc/fs/cachefiles/ directory
+ */
+void cachefiles_proc_cleanup(void)
+{
+       remove_proc_entry("fs/cachefiles/histogram", NULL);
+       remove_proc_entry("fs/cachefiles", NULL);
+}
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c
new file mode 100644 (file)
index 0000000..a69787e
--- /dev/null
@@ -0,0 +1,879 @@
+/* Storage object read/write
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/mount.h>
+#include <linux/file.h>
+#include "internal.h"
+
+/*
+ * detect wake up events generated by the unlocking of pages in which we're
+ * interested
+ * - we use this to detect read completion of backing pages
+ * - the caller holds the waitqueue lock
+ */
+static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode,
+                                 int sync, void *_key)
+{
+       struct cachefiles_one_read *monitor =
+               container_of(wait, struct cachefiles_one_read, monitor);
+       struct cachefiles_object *object;
+       struct wait_bit_key *key = _key;
+       struct page *page = wait->private;
+
+       ASSERT(key);
+
+       _enter("{%lu},%u,%d,{%p,%u}",
+              monitor->netfs_page->index, mode, sync,
+              key->flags, key->bit_nr);
+
+       if (key->flags != &page->flags ||
+           key->bit_nr != PG_locked)
+               return 0;
+
+       _debug("--- monitor %p %lx ---", page, page->flags);
+
+       if (!PageUptodate(page) && !PageError(page))
+               dump_stack();
+
+       /* remove from the waitqueue */
+       list_del(&wait->task_list);
+
+       /* move onto the action list and queue for FS-Cache thread pool */
+       ASSERT(monitor->op);
+
+       object = container_of(monitor->op->op.object,
+                             struct cachefiles_object, fscache);
+
+       spin_lock(&object->work_lock);
+       list_add_tail(&monitor->op_link, &monitor->op->to_do);
+       spin_unlock(&object->work_lock);
+
+       fscache_enqueue_retrieval(monitor->op);
+       return 0;
+}
+
+/*
+ * copy data from backing pages to netfs pages to complete a read operation
+ * - driven by FS-Cache's thread pool
+ */
+static void cachefiles_read_copier(struct fscache_operation *_op)
+{
+       struct cachefiles_one_read *monitor;
+       struct cachefiles_object *object;
+       struct fscache_retrieval *op;
+       struct pagevec pagevec;
+       int error, max;
+
+       op = container_of(_op, struct fscache_retrieval, op);
+       object = container_of(op->op.object,
+                             struct cachefiles_object, fscache);
+
+       _enter("{ino=%lu}", object->backer->d_inode->i_ino);
+
+       pagevec_init(&pagevec, 0);
+
+       max = 8;
+       spin_lock_irq(&object->work_lock);
+
+       while (!list_empty(&op->to_do)) {
+               monitor = list_entry(op->to_do.next,
+                                    struct cachefiles_one_read, op_link);
+               list_del(&monitor->op_link);
+
+               spin_unlock_irq(&object->work_lock);
+
+               _debug("- copy {%lu}", monitor->back_page->index);
+
+               error = -EIO;
+               if (PageUptodate(monitor->back_page)) {
+                       copy_highpage(monitor->netfs_page, monitor->back_page);
+
+                       pagevec_add(&pagevec, monitor->netfs_page);
+                       fscache_mark_pages_cached(monitor->op, &pagevec);
+                       error = 0;
+               }
+
+               if (error)
+                       cachefiles_io_error_obj(
+                               object,
+                               "Readpage failed on backing file %lx",
+                               (unsigned long) monitor->back_page->flags);
+
+               page_cache_release(monitor->back_page);
+
+               fscache_end_io(op, monitor->netfs_page, error);
+               page_cache_release(monitor->netfs_page);
+               fscache_put_retrieval(op);
+               kfree(monitor);
+
+               /* let the thread pool have some air occasionally */
+               max--;
+               if (max < 0 || need_resched()) {
+                       if (!list_empty(&op->to_do))
+                               fscache_enqueue_retrieval(op);
+                       _leave(" [maxed out]");
+                       return;
+               }
+
+               spin_lock_irq(&object->work_lock);
+       }
+
+       spin_unlock_irq(&object->work_lock);
+       _leave("");
+}
+
+/*
+ * read the corresponding page to the given set from the backing file
+ * - an uncertain page is simply discarded, to be tried again another time
+ */
+static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
+                                           struct fscache_retrieval *op,
+                                           struct page *netpage,
+                                           struct pagevec *pagevec)
+{
+       struct cachefiles_one_read *monitor;
+       struct address_space *bmapping;
+       struct page *newpage, *backpage;
+       int ret;
+
+       _enter("");
+
+       pagevec_reinit(pagevec);
+
+       _debug("read back %p{%lu,%d}",
+              netpage, netpage->index, page_count(netpage));
+
+       monitor = kzalloc(sizeof(*monitor), GFP_KERNEL);
+       if (!monitor)
+               goto nomem;
+
+       monitor->netfs_page = netpage;
+       monitor->op = fscache_get_retrieval(op);
+
+       init_waitqueue_func_entry(&monitor->monitor, cachefiles_read_waiter);
+
+       /* attempt to get hold of the backing page */
+       bmapping = object->backer->d_inode->i_mapping;
+       newpage = NULL;
+
+       for (;;) {
+               backpage = find_get_page(bmapping, netpage->index);
+               if (backpage)
+                       goto backing_page_already_present;
+
+               if (!newpage) {
+                       newpage = page_cache_alloc_cold(bmapping);
+                       if (!newpage)
+                               goto nomem_monitor;
+               }
+
+               ret = add_to_page_cache(newpage, bmapping,
+                                       netpage->index, GFP_KERNEL);
+               if (ret == 0)
+                       goto installed_new_backing_page;
+               if (ret != -EEXIST)
+                       goto nomem_page;
+       }
+
+       /* we've installed a new backing page, so now we need to add it
+        * to the LRU list and start it reading */
+installed_new_backing_page:
+       _debug("- new %p", newpage);
+
+       backpage = newpage;
+       newpage = NULL;
+
+       page_cache_get(backpage);
+       pagevec_add(pagevec, backpage);
+       __pagevec_lru_add_file(pagevec);
+
+read_backing_page:
+       ret = bmapping->a_ops->readpage(NULL, backpage);
+       if (ret < 0)
+               goto read_error;
+
+       /* set the monitor to transfer the data across */
+monitor_backing_page:
+       _debug("- monitor add");
+
+       /* install the monitor */
+       page_cache_get(monitor->netfs_page);
+       page_cache_get(backpage);
+       monitor->back_page = backpage;
+       monitor->monitor.private = backpage;
+       add_page_wait_queue(backpage, &monitor->monitor);
+       monitor = NULL;
+
+       /* but the page may have been read before the monitor was installed, so
+        * the monitor may miss the event - so we have to ensure that we do get
+        * one in such a case */
+       if (trylock_page(backpage)) {
+               _debug("jumpstart %p {%lx}", backpage, backpage->flags);
+               unlock_page(backpage);
+       }
+       goto success;
+
+       /* if the backing page is already present, it can be in one of
+        * three states: read in progress, read failed or read okay */
+backing_page_already_present:
+       _debug("- present");
+
+       if (newpage) {
+               page_cache_release(newpage);
+               newpage = NULL;
+       }
+
+       if (PageError(backpage))
+               goto io_error;
+
+       if (PageUptodate(backpage))
+               goto backing_page_already_uptodate;
+
+       if (!trylock_page(backpage))
+               goto monitor_backing_page;
+       _debug("read %p {%lx}", backpage, backpage->flags);
+       goto read_backing_page;
+
+       /* the backing page is already up to date, attach the netfs
+        * page to the pagecache and LRU and copy the data across */
+backing_page_already_uptodate:
+       _debug("- uptodate");
+
+       pagevec_add(pagevec, netpage);
+       fscache_mark_pages_cached(op, pagevec);
+
+       copy_highpage(netpage, backpage);
+       fscache_end_io(op, netpage, 0);
+
+success:
+       _debug("success");
+       ret = 0;
+
+out:
+       if (backpage)
+               page_cache_release(backpage);
+       if (monitor) {
+               fscache_put_retrieval(monitor->op);
+               kfree(monitor);
+       }
+       _leave(" = %d", ret);
+       return ret;
+
+read_error:
+       _debug("read error %d", ret);
+       if (ret == -ENOMEM)
+               goto out;
+io_error:
+       cachefiles_io_error_obj(object, "Page read error on backing file");
+       ret = -ENOBUFS;
+       goto out;
+
+nomem_page:
+       page_cache_release(newpage);
+nomem_monitor:
+       fscache_put_retrieval(monitor->op);
+       kfree(monitor);
+nomem:
+       _leave(" = -ENOMEM");
+       return -ENOMEM;
+}
+
+/*
+ * read a page from the cache or allocate a block in which to store it
+ * - cache withdrawal is prevented by the caller
+ * - returns -EINTR if interrupted
+ * - returns -ENOMEM if ran out of memory
+ * - returns -ENOBUFS if no buffers can be made available
+ * - returns -ENOBUFS if page is beyond EOF
+ * - if the page is backed by a block in the cache:
+ *   - a read will be started which will call the callback on completion
+ *   - 0 will be returned
+ * - else if the page is unbacked:
+ *   - the metadata will be retained
+ *   - -ENODATA will be returned
+ */
+int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
+                                 struct page *page,
+                                 gfp_t gfp)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       struct pagevec pagevec;
+       struct inode *inode;
+       sector_t block0, block;
+       unsigned shift;
+       int ret;
+
+       object = container_of(op->op.object,
+                             struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       _enter("{%p},{%lx},,,", object, page->index);
+
+       if (!object->backer)
+               return -ENOBUFS;
+
+       inode = object->backer->d_inode;
+       ASSERT(S_ISREG(inode->i_mode));
+       ASSERT(inode->i_mapping->a_ops->bmap);
+       ASSERT(inode->i_mapping->a_ops->readpages);
+
+       /* calculate the shift required to use bmap */
+       if (inode->i_sb->s_blocksize > PAGE_SIZE)
+               return -ENOBUFS;
+
+       shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
+
+       op->op.flags = FSCACHE_OP_FAST;
+       op->op.processor = cachefiles_read_copier;
+
+       pagevec_init(&pagevec, 0);
+
+       /* we assume the absence or presence of the first block is a good
+        * enough indication for the page as a whole
+        * - TODO: don't use bmap() for this as it is _not_ actually good
+        *   enough for this as it doesn't indicate errors, but it's all we've
+        *   got for the moment
+        */
+       block0 = page->index;
+       block0 <<= shift;
+
+       block = inode->i_mapping->a_ops->bmap(inode->i_mapping, block0);
+       _debug("%llx -> %llx",
+              (unsigned long long) block0,
+              (unsigned long long) block);
+
+       if (block) {
+               /* submit the apparently valid page to the backing fs to be
+                * read from disk */
+               ret = cachefiles_read_backing_file_one(object, op, page,
+                                                      &pagevec);
+       } else if (cachefiles_has_space(cache, 0, 1) == 0) {
+               /* there's space in the cache we can use */
+               pagevec_add(&pagevec, page);
+               fscache_mark_pages_cached(op, &pagevec);
+               ret = -ENODATA;
+       } else {
+               ret = -ENOBUFS;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * read the corresponding pages to the given set from the backing file
+ * - any uncertain pages are simply discarded, to be tried again another time
+ */
+static int cachefiles_read_backing_file(struct cachefiles_object *object,
+                                       struct fscache_retrieval *op,
+                                       struct list_head *list,
+                                       struct pagevec *mark_pvec)
+{
+       struct cachefiles_one_read *monitor = NULL;
+       struct address_space *bmapping = object->backer->d_inode->i_mapping;
+       struct pagevec lru_pvec;
+       struct page *newpage = NULL, *netpage, *_n, *backpage = NULL;
+       int ret = 0;
+
+       _enter("");
+
+       pagevec_init(&lru_pvec, 0);
+
+       list_for_each_entry_safe(netpage, _n, list, lru) {
+               list_del(&netpage->lru);
+
+               _debug("read back %p{%lu,%d}",
+                      netpage, netpage->index, page_count(netpage));
+
+               if (!monitor) {
+                       monitor = kzalloc(sizeof(*monitor), GFP_KERNEL);
+                       if (!monitor)
+                               goto nomem;
+
+                       monitor->op = fscache_get_retrieval(op);
+                       init_waitqueue_func_entry(&monitor->monitor,
+                                                 cachefiles_read_waiter);
+               }
+
+               for (;;) {
+                       backpage = find_get_page(bmapping, netpage->index);
+                       if (backpage)
+                               goto backing_page_already_present;
+
+                       if (!newpage) {
+                               newpage = page_cache_alloc_cold(bmapping);
+                               if (!newpage)
+                                       goto nomem;
+                       }
+
+                       ret = add_to_page_cache(newpage, bmapping,
+                                               netpage->index, GFP_KERNEL);
+                       if (ret == 0)
+                               goto installed_new_backing_page;
+                       if (ret != -EEXIST)
+                               goto nomem;
+               }
+
+               /* we've installed a new backing page, so now we need to add it
+                * to the LRU list and start it reading */
+       installed_new_backing_page:
+               _debug("- new %p", newpage);
+
+               backpage = newpage;
+               newpage = NULL;
+
+               page_cache_get(backpage);
+               if (!pagevec_add(&lru_pvec, backpage))
+                       __pagevec_lru_add_file(&lru_pvec);
+
+       reread_backing_page:
+               ret = bmapping->a_ops->readpage(NULL, backpage);
+               if (ret < 0)
+                       goto read_error;
+
+               /* add the netfs page to the pagecache and LRU, and set the
+                * monitor to transfer the data across */
+       monitor_backing_page:
+               _debug("- monitor add");
+
+               ret = add_to_page_cache(netpage, op->mapping, netpage->index,
+                                       GFP_KERNEL);
+               if (ret < 0) {
+                       if (ret == -EEXIST) {
+                               page_cache_release(netpage);
+                               continue;
+                       }
+                       goto nomem;
+               }
+
+               page_cache_get(netpage);
+               if (!pagevec_add(&lru_pvec, netpage))
+                       __pagevec_lru_add_file(&lru_pvec);
+
+               /* install a monitor */
+               page_cache_get(netpage);
+               monitor->netfs_page = netpage;
+
+               page_cache_get(backpage);
+               monitor->back_page = backpage;
+               monitor->monitor.private = backpage;
+               add_page_wait_queue(backpage, &monitor->monitor);
+               monitor = NULL;
+
+               /* but the page may have been read before the monitor was
+                * installed, so the monitor may miss the event - so we have to
+                * ensure that we do get one in such a case */
+               if (trylock_page(backpage)) {
+                       _debug("2unlock %p {%lx}", backpage, backpage->flags);
+                       unlock_page(backpage);
+               }
+
+               page_cache_release(backpage);
+               backpage = NULL;
+
+               page_cache_release(netpage);
+               netpage = NULL;
+               continue;
+
+               /* if the backing page is already present, it can be in one of
+                * three states: read in progress, read failed or read okay */
+       backing_page_already_present:
+               _debug("- present %p", backpage);
+
+               if (PageError(backpage))
+                       goto io_error;
+
+               if (PageUptodate(backpage))
+                       goto backing_page_already_uptodate;
+
+               _debug("- not ready %p{%lx}", backpage, backpage->flags);
+
+               if (!trylock_page(backpage))
+                       goto monitor_backing_page;
+
+               if (PageError(backpage)) {
+                       _debug("error %lx", backpage->flags);
+                       unlock_page(backpage);
+                       goto io_error;
+               }
+
+               if (PageUptodate(backpage))
+                       goto backing_page_already_uptodate_unlock;
+
+               /* we've locked a page that's neither up to date nor erroneous,
+                * so we need to attempt to read it again */
+               goto reread_backing_page;
+
+               /* the backing page is already up to date, attach the netfs
+                * page to the pagecache and LRU and copy the data across */
+       backing_page_already_uptodate_unlock:
+               _debug("uptodate %lx", backpage->flags);
+               unlock_page(backpage);
+       backing_page_already_uptodate:
+               _debug("- uptodate");
+
+               ret = add_to_page_cache(netpage, op->mapping, netpage->index,
+                                       GFP_KERNEL);
+               if (ret < 0) {
+                       if (ret == -EEXIST) {
+                               page_cache_release(netpage);
+                               continue;
+                       }
+                       goto nomem;
+               }
+
+               copy_highpage(netpage, backpage);
+
+               page_cache_release(backpage);
+               backpage = NULL;
+
+               if (!pagevec_add(mark_pvec, netpage))
+                       fscache_mark_pages_cached(op, mark_pvec);
+
+               page_cache_get(netpage);
+               if (!pagevec_add(&lru_pvec, netpage))
+                       __pagevec_lru_add_file(&lru_pvec);
+
+               fscache_end_io(op, netpage, 0);
+               page_cache_release(netpage);
+               netpage = NULL;
+               continue;
+       }
+
+       netpage = NULL;
+
+       _debug("out");
+
+out:
+       /* tidy up */
+       pagevec_lru_add_file(&lru_pvec);
+
+       if (newpage)
+               page_cache_release(newpage);
+       if (netpage)
+               page_cache_release(netpage);
+       if (backpage)
+               page_cache_release(backpage);
+       if (monitor) {
+               fscache_put_retrieval(op);
+               kfree(monitor);
+       }
+
+       list_for_each_entry_safe(netpage, _n, list, lru) {
+               list_del(&netpage->lru);
+               page_cache_release(netpage);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+
+nomem:
+       _debug("nomem");
+       ret = -ENOMEM;
+       goto out;
+
+read_error:
+       _debug("read error %d", ret);
+       if (ret == -ENOMEM)
+               goto out;
+io_error:
+       cachefiles_io_error_obj(object, "Page read error on backing file");
+       ret = -ENOBUFS;
+       goto out;
+}
+
+/*
+ * read a list of pages from the cache or allocate blocks in which to store
+ * them
+ */
+int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
+                                  struct list_head *pages,
+                                  unsigned *nr_pages,
+                                  gfp_t gfp)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       struct list_head backpages;
+       struct pagevec pagevec;
+       struct inode *inode;
+       struct page *page, *_n;
+       unsigned shift, nrbackpages;
+       int ret, ret2, space;
+
+       object = container_of(op->op.object,
+                             struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       _enter("{OBJ%x,%d},,%d,,",
+              object->fscache.debug_id, atomic_read(&op->op.usage),
+              *nr_pages);
+
+       if (!object->backer)
+               return -ENOBUFS;
+
+       space = 1;
+       if (cachefiles_has_space(cache, 0, *nr_pages) < 0)
+               space = 0;
+
+       inode = object->backer->d_inode;
+       ASSERT(S_ISREG(inode->i_mode));
+       ASSERT(inode->i_mapping->a_ops->bmap);
+       ASSERT(inode->i_mapping->a_ops->readpages);
+
+       /* calculate the shift required to use bmap */
+       if (inode->i_sb->s_blocksize > PAGE_SIZE)
+               return -ENOBUFS;
+
+       shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
+
+       pagevec_init(&pagevec, 0);
+
+       op->op.flags = FSCACHE_OP_FAST;
+       op->op.processor = cachefiles_read_copier;
+
+       INIT_LIST_HEAD(&backpages);
+       nrbackpages = 0;
+
+       ret = space ? -ENODATA : -ENOBUFS;
+       list_for_each_entry_safe(page, _n, pages, lru) {
+               sector_t block0, block;
+
+               /* we assume the absence or presence of the first block is a
+                * good enough indication for the page as a whole
+                * - TODO: don't use bmap() for this as it is _not_ actually
+                *   good enough for this as it doesn't indicate errors, but
+                *   it's all we've got for the moment
+                */
+               block0 = page->index;
+               block0 <<= shift;
+
+               block = inode->i_mapping->a_ops->bmap(inode->i_mapping,
+                                                     block0);
+               _debug("%llx -> %llx",
+                      (unsigned long long) block0,
+                      (unsigned long long) block);
+
+               if (block) {
+                       /* we have data - add it to the list to give to the
+                        * backing fs */
+                       list_move(&page->lru, &backpages);
+                       (*nr_pages)--;
+                       nrbackpages++;
+               } else if (space && pagevec_add(&pagevec, page) == 0) {
+                       fscache_mark_pages_cached(op, &pagevec);
+                       ret = -ENODATA;
+               }
+       }
+
+       if (pagevec_count(&pagevec) > 0)
+               fscache_mark_pages_cached(op, &pagevec);
+
+       if (list_empty(pages))
+               ret = 0;
+
+       /* submit the apparently valid pages to the backing fs to be read from
+        * disk */
+       if (nrbackpages > 0) {
+               ret2 = cachefiles_read_backing_file(object, op, &backpages,
+                                                   &pagevec);
+               if (ret2 == -ENOMEM || ret2 == -EINTR)
+                       ret = ret2;
+       }
+
+       if (pagevec_count(&pagevec) > 0)
+               fscache_mark_pages_cached(op, &pagevec);
+
+       _leave(" = %d [nr=%u%s]",
+              ret, *nr_pages, list_empty(pages) ? " empty" : "");
+       return ret;
+}
+
+/*
+ * allocate a block in the cache in which to store a page
+ * - cache withdrawal is prevented by the caller
+ * - returns -EINTR if interrupted
+ * - returns -ENOMEM if ran out of memory
+ * - returns -ENOBUFS if no buffers can be made available
+ * - returns -ENOBUFS if page is beyond EOF
+ * - otherwise:
+ *   - the metadata will be retained
+ *   - 0 will be returned
+ */
+int cachefiles_allocate_page(struct fscache_retrieval *op,
+                            struct page *page,
+                            gfp_t gfp)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       struct pagevec pagevec;
+       int ret;
+
+       object = container_of(op->op.object,
+                             struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       _enter("%p,{%lx},", object, page->index);
+
+       ret = cachefiles_has_space(cache, 0, 1);
+       if (ret == 0) {
+               pagevec_init(&pagevec, 0);
+               pagevec_add(&pagevec, page);
+               fscache_mark_pages_cached(op, &pagevec);
+       } else {
+               ret = -ENOBUFS;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * allocate blocks in the cache in which to store a set of pages
+ * - cache withdrawal is prevented by the caller
+ * - returns -EINTR if interrupted
+ * - returns -ENOMEM if ran out of memory
+ * - returns -ENOBUFS if some buffers couldn't be made available
+ * - returns -ENOBUFS if some pages are beyond EOF
+ * - otherwise:
+ *   - -ENODATA will be returned
+ * - metadata will be retained for any page marked
+ */
+int cachefiles_allocate_pages(struct fscache_retrieval *op,
+                             struct list_head *pages,
+                             unsigned *nr_pages,
+                             gfp_t gfp)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       struct pagevec pagevec;
+       struct page *page;
+       int ret;
+
+       object = container_of(op->op.object,
+                             struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       _enter("%p,,,%d,", object, *nr_pages);
+
+       ret = cachefiles_has_space(cache, 0, *nr_pages);
+       if (ret == 0) {
+               pagevec_init(&pagevec, 0);
+
+               list_for_each_entry(page, pages, lru) {
+                       if (pagevec_add(&pagevec, page) == 0)
+                               fscache_mark_pages_cached(op, &pagevec);
+               }
+
+               if (pagevec_count(&pagevec) > 0)
+                       fscache_mark_pages_cached(op, &pagevec);
+               ret = -ENODATA;
+       } else {
+               ret = -ENOBUFS;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * request a page be stored in the cache
+ * - cache withdrawal is prevented by the caller
+ * - this request may be ignored if there's no cache block available, in which
+ *   case -ENOBUFS will be returned
+ * - if the op is in progress, 0 will be returned
+ */
+int cachefiles_write_page(struct fscache_storage *op, struct page *page)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       mm_segment_t old_fs;
+       struct file *file;
+       loff_t pos;
+       void *data;
+       int ret;
+
+       ASSERT(op != NULL);
+       ASSERT(page != NULL);
+
+       object = container_of(op->op.object,
+                             struct cachefiles_object, fscache);
+
+       _enter("%p,%p{%lx},,,", object, page, page->index);
+
+       if (!object->backer) {
+               _leave(" = -ENOBUFS");
+               return -ENOBUFS;
+       }
+
+       ASSERT(S_ISREG(object->backer->d_inode->i_mode));
+
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       /* write the page to the backing filesystem and let it store it in its
+        * own time */
+       dget(object->backer);
+       mntget(cache->mnt);
+       file = dentry_open(object->backer, cache->mnt, O_RDWR,
+                          cache->cache_cred);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+       } else {
+               ret = -EIO;
+               if (file->f_op->write) {
+                       pos = (loff_t) page->index << PAGE_SHIFT;
+                       data = kmap(page);
+                       old_fs = get_fs();
+                       set_fs(KERNEL_DS);
+                       ret = file->f_op->write(
+                               file, (const void __user *) data, PAGE_SIZE,
+                               &pos);
+                       set_fs(old_fs);
+                       kunmap(page);
+                       if (ret != PAGE_SIZE)
+                               ret = -EIO;
+               }
+               fput(file);
+       }
+
+       if (ret < 0) {
+               if (ret == -EIO)
+                       cachefiles_io_error_obj(
+                               object, "Write page to backing file failed");
+               ret = -ENOBUFS;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * detach a backing block from a page
+ * - cache withdrawal is prevented by the caller
+ */
+void cachefiles_uncache_page(struct fscache_object *_object, struct page *page)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+
+       object = container_of(_object, struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       _enter("%p,{%lu}", object, page->index);
+
+       spin_unlock(&object->fscache.cookie->lock);
+}
diff --git a/fs/cachefiles/security.c b/fs/cachefiles/security.c
new file mode 100644 (file)
index 0000000..b5808cd
--- /dev/null
@@ -0,0 +1,116 @@
+/* CacheFiles security management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/fs.h>
+#include <linux/cred.h>
+#include "internal.h"
+
+/*
+ * determine the security context within which we access the cache from within
+ * the kernel
+ */
+int cachefiles_get_security_ID(struct cachefiles_cache *cache)
+{
+       struct cred *new;
+       int ret;
+
+       _enter("{%s}", cache->secctx);
+
+       new = prepare_kernel_cred(current);
+       if (!new) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       if (cache->secctx) {
+               ret = set_security_override_from_ctx(new, cache->secctx);
+               if (ret < 0) {
+                       put_cred(new);
+                       printk(KERN_ERR "CacheFiles:"
+                              " Security denies permission to nominate"
+                              " security context: error %d\n",
+                              ret);
+                       goto error;
+               }
+       }
+
+       cache->cache_cred = new;
+       ret = 0;
+error:
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * see if mkdir and create can be performed in the root directory
+ */
+static int cachefiles_check_cache_dir(struct cachefiles_cache *cache,
+                                     struct dentry *root)
+{
+       int ret;
+
+       ret = security_inode_mkdir(root->d_inode, root, 0);
+       if (ret < 0) {
+               printk(KERN_ERR "CacheFiles:"
+                      " Security denies permission to make dirs: error %d",
+                      ret);
+               return ret;
+       }
+
+       ret = security_inode_create(root->d_inode, root, 0);
+       if (ret < 0)
+               printk(KERN_ERR "CacheFiles:"
+                      " Security denies permission to create files: error %d",
+                      ret);
+
+       return ret;
+}
+
+/*
+ * check the security details of the on-disk cache
+ * - must be called with security override in force
+ */
+int cachefiles_determine_cache_security(struct cachefiles_cache *cache,
+                                       struct dentry *root,
+                                       const struct cred **_saved_cred)
+{
+       struct cred *new;
+       int ret;
+
+       _enter("");
+
+       /* duplicate the cache creds for COW (the override is currently in
+        * force, so we can use prepare_creds() to do this) */
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
+       cachefiles_end_secure(cache, *_saved_cred);
+
+       /* use the cache root dir's security context as the basis with
+        * which create files */
+       ret = set_create_files_as(new, root->d_inode);
+       if (ret < 0) {
+               _leave(" = %d [cfa]", ret);
+               return ret;
+       }
+
+       put_cred(cache->cache_cred);
+       cache->cache_cred = new;
+
+       cachefiles_begin_secure(cache, _saved_cred);
+       ret = cachefiles_check_cache_dir(cache, root);
+
+       if (ret == -EOPNOTSUPP)
+               ret = 0;
+       _leave(" = %d", ret);
+       return ret;
+}
diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c
new file mode 100644 (file)
index 0000000..f3e7a0b
--- /dev/null
@@ -0,0 +1,291 @@
+/* CacheFiles extended attribute management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fsnotify.h>
+#include <linux/quotaops.h>
+#include <linux/xattr.h>
+#include "internal.h"
+
+static const char cachefiles_xattr_cache[] =
+       XATTR_USER_PREFIX "CacheFiles.cache";
+
+/*
+ * check the type label on an object
+ * - done using xattrs
+ */
+int cachefiles_check_object_type(struct cachefiles_object *object)
+{
+       struct dentry *dentry = object->dentry;
+       char type[3], xtype[3];
+       int ret;
+
+       ASSERT(dentry);
+       ASSERT(dentry->d_inode);
+
+       if (!object->fscache.cookie)
+               strcpy(type, "C3");
+       else
+               snprintf(type, 3, "%02x", object->fscache.cookie->def->type);
+
+       _enter("%p{%s}", object, type);
+
+       /* attempt to install a type label directly */
+       ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2,
+                          XATTR_CREATE);
+       if (ret == 0) {
+               _debug("SET"); /* we succeeded */
+               goto error;
+       }
+
+       if (ret != -EEXIST) {
+               kerror("Can't set xattr on %*.*s [%lu] (err %d)",
+                      dentry->d_name.len, dentry->d_name.len,
+                      dentry->d_name.name, dentry->d_inode->i_ino,
+                      -ret);
+               goto error;
+       }
+
+       /* read the current type label */
+       ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
+       if (ret < 0) {
+               if (ret == -ERANGE)
+                       goto bad_type_length;
+
+               kerror("Can't read xattr on %*.*s [%lu] (err %d)",
+                      dentry->d_name.len, dentry->d_name.len,
+                      dentry->d_name.name, dentry->d_inode->i_ino,
+                      -ret);
+               goto error;
+       }
+
+       /* check the type is what we're expecting */
+       if (ret != 2)
+               goto bad_type_length;
+
+       if (xtype[0] != type[0] || xtype[1] != type[1])
+               goto bad_type;
+
+       ret = 0;
+
+error:
+       _leave(" = %d", ret);
+       return ret;
+
+bad_type_length:
+       kerror("Cache object %lu type xattr length incorrect",
+              dentry->d_inode->i_ino);
+       ret = -EIO;
+       goto error;
+
+bad_type:
+       xtype[2] = 0;
+       kerror("Cache object %*.*s [%lu] type %s not %s",
+              dentry->d_name.len, dentry->d_name.len,
+              dentry->d_name.name, dentry->d_inode->i_ino,
+              xtype, type);
+       ret = -EIO;
+       goto error;
+}
+
+/*
+ * set the state xattr on a cache file
+ */
+int cachefiles_set_object_xattr(struct cachefiles_object *object,
+                               struct cachefiles_xattr *auxdata)
+{
+       struct dentry *dentry = object->dentry;
+       int ret;
+
+       ASSERT(object->fscache.cookie);
+       ASSERT(dentry);
+
+       _enter("%p,#%d", object, auxdata->len);
+
+       /* attempt to install the cache metadata directly */
+       _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len);
+
+       ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
+                          &auxdata->type, auxdata->len,
+                          XATTR_CREATE);
+       if (ret < 0 && ret != -ENOMEM)
+               cachefiles_io_error_obj(
+                       object,
+                       "Failed to set xattr with error %d", ret);
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * update the state xattr on a cache file
+ */
+int cachefiles_update_object_xattr(struct cachefiles_object *object,
+                                  struct cachefiles_xattr *auxdata)
+{
+       struct dentry *dentry = object->dentry;
+       int ret;
+
+       ASSERT(object->fscache.cookie);
+       ASSERT(dentry);
+
+       _enter("%p,#%d", object, auxdata->len);
+
+       /* attempt to install the cache metadata directly */
+       _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len);
+
+       ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
+                          &auxdata->type, auxdata->len,
+                          XATTR_REPLACE);
+       if (ret < 0 && ret != -ENOMEM)
+               cachefiles_io_error_obj(
+                       object,
+                       "Failed to update xattr with error %d", ret);
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * check the state xattr on a cache file
+ * - return -ESTALE if the object should be deleted
+ */
+int cachefiles_check_object_xattr(struct cachefiles_object *object,
+                                 struct cachefiles_xattr *auxdata)
+{
+       struct cachefiles_xattr *auxbuf;
+       struct dentry *dentry = object->dentry;
+       int ret;
+
+       _enter("%p,#%d", object, auxdata->len);
+
+       ASSERT(dentry);
+       ASSERT(dentry->d_inode);
+
+       auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
+       if (!auxbuf) {
+               _leave(" = -ENOMEM");
+               return -ENOMEM;
+       }
+
+       /* read the current type label */
+       ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
+                          &auxbuf->type, 512 + 1);
+       if (ret < 0) {
+               if (ret == -ENODATA)
+                       goto stale; /* no attribute - power went off
+                                    * mid-cull? */
+
+               if (ret == -ERANGE)
+                       goto bad_type_length;
+
+               cachefiles_io_error_obj(object,
+                                       "Can't read xattr on %lu (err %d)",
+                                       dentry->d_inode->i_ino, -ret);
+               goto error;
+       }
+
+       /* check the on-disk object */
+       if (ret < 1)
+               goto bad_type_length;
+
+       if (auxbuf->type != auxdata->type)
+               goto stale;
+
+       auxbuf->len = ret;
+
+       /* consult the netfs */
+       if (object->fscache.cookie->def->check_aux) {
+               enum fscache_checkaux result;
+               unsigned int dlen;
+
+               dlen = auxbuf->len - 1;
+
+               _debug("checkaux %s #%u",
+                      object->fscache.cookie->def->name, dlen);
+
+               result = fscache_check_aux(&object->fscache,
+                                          &auxbuf->data, dlen);
+
+               switch (result) {
+                       /* entry okay as is */
+               case FSCACHE_CHECKAUX_OKAY:
+                       goto okay;
+
+                       /* entry requires update */
+               case FSCACHE_CHECKAUX_NEEDS_UPDATE:
+                       break;
+
+                       /* entry requires deletion */
+               case FSCACHE_CHECKAUX_OBSOLETE:
+                       goto stale;
+
+               default:
+                       BUG();
+               }
+
+               /* update the current label */
+               ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
+                                  &auxdata->type, auxdata->len,
+                                  XATTR_REPLACE);
+               if (ret < 0) {
+                       cachefiles_io_error_obj(object,
+                                               "Can't update xattr on %lu"
+                                               " (error %d)",
+                                               dentry->d_inode->i_ino, -ret);
+                       goto error;
+               }
+       }
+
+okay:
+       ret = 0;
+
+error:
+       kfree(auxbuf);
+       _leave(" = %d", ret);
+       return ret;
+
+bad_type_length:
+       kerror("Cache object %lu xattr length incorrect",
+              dentry->d_inode->i_ino);
+       ret = -EIO;
+       goto error;
+
+stale:
+       ret = -ESTALE;
+       goto error;
+}
+
+/*
+ * remove the object's xattr to mark it stale
+ */
+int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
+                                  struct dentry *dentry)
+{
+       int ret;
+
+       ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
+       if (ret < 0) {
+               if (ret == -ENOENT || ret == -ENODATA)
+                       ret = 0;
+               else if (ret != -ENOMEM)
+                       cachefiles_io_error(cache,
+                                           "Can't remove xattr from %lu"
+                                           " (error %d)",
+                                           dentry->d_inode->i_ino, -ret);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
index 877e4d9a1159d11203170ec463202187dd3a6466..7f19fefd3d45a2790d426e68e59f80f687b4911c 100644 (file)
@@ -404,7 +404,6 @@ cifs_proc_init(void)
        if (proc_fs_cifs == NULL)
                return;
 
-       proc_fs_cifs->owner = THIS_MODULE;
        proc_create("DebugData", 0, proc_fs_cifs, &cifs_debug_data_proc_fops);
 
 #ifdef CONFIG_CIFS_STATS
index 2f35cccfcd8d202423c4e9e1434d139cf78dc084..54dce78fbb7320cdc7d6449fa347142838d51eba 100644 (file)
@@ -254,7 +254,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                return -ENOMEM;
        }
 
-       mode &= ~current->fs->umask;
+       mode &= ~current_umask();
        if (oplockEnabled)
                oplock = REQ_OPLOCK;
 
@@ -479,7 +479,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                rc = -ENOMEM;
        else if (pTcon->unix_ext) {
                struct cifs_unix_set_info_args args = {
-                       .mode   = mode & ~current->fs->umask,
+                       .mode   = mode & ~current_umask(),
                        .ctime  = NO_CHANGE_64,
                        .atime  = NO_CHANGE_64,
                        .mtime  = NO_CHANGE_64,
index a8797cc60805e4b732a4f1557f8590f353073455..f121a80fdd6fa15e7d6d61ddc8576f9be46550f0 100644 (file)
@@ -1125,7 +1125,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        goto mkdir_out;
                }
 
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
                rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
                                mode, NULL /* netfid */, pInfo, &oplock,
                                full_path, cifs_sb->local_nls,
@@ -1204,7 +1204,7 @@ mkdir_get_info:
                if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
                                direntry->d_inode->i_nlink = 2;
 
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
                /* must turn on setgid bit if parent dir has it */
                if (inode->i_mode & S_ISGID)
                        mode |= S_ISGID;
index 55efdfebdf5ae14f5937add03075fdc8e716819d..1c859dae758f8a01efa3e1e793bcfffc42fce604 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/eventpoll.h>
+#include <linux/fs_struct.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1195,16 +1196,12 @@ out:
        return ret;
 }
 
-asmlinkage ssize_t
-compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+static size_t compat_readv(struct file *file,
+                          const struct compat_iovec __user *vec,
+                          unsigned long vlen, loff_t *pos)
 {
-       struct file *file;
        ssize_t ret = -EBADF;
 
-       file = fget(fd);
-       if (!file)
-               return -EBADF;
-
        if (!(file->f_mode & FMODE_READ))
                goto out;
 
@@ -1212,25 +1209,56 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsign
        if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
                goto out;
 
-       ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
+       ret = compat_do_readv_writev(READ, file, vec, vlen, pos);
 
 out:
        if (ret > 0)
                add_rchar(current, ret);
        inc_syscr(current);
-       fput(file);
        return ret;
 }
 
 asmlinkage ssize_t
-compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
+                unsigned long vlen)
 {
        struct file *file;
-       ssize_t ret = -EBADF;
+       int fput_needed;
+       ssize_t ret;
 
-       file = fget(fd);
+       file = fget_light(fd, &fput_needed);
        if (!file)
                return -EBADF;
+       ret = compat_readv(file, vec, vlen, &file->f_pos);
+       fput_light(file, fput_needed);
+       return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
+                 unsigned long vlen, u32 pos_high, u32 pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       int fput_needed;
+       ssize_t ret;
+
+       if (pos < 0)
+               return -EINVAL;
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       ret = compat_readv(file, vec, vlen, &pos);
+       fput_light(file, fput_needed);
+       return ret;
+}
+
+static size_t compat_writev(struct file *file,
+                           const struct compat_iovec __user *vec,
+                           unsigned long vlen, loff_t *pos)
+{
+       ssize_t ret = -EBADF;
+
        if (!(file->f_mode & FMODE_WRITE))
                goto out;
 
@@ -1238,13 +1266,47 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsig
        if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
                goto out;
 
-       ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
+       ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos);
 
 out:
        if (ret > 0)
                add_wchar(current, ret);
        inc_syscw(current);
-       fput(file);
+       return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec,
+                 unsigned long vlen)
+{
+       struct file *file;
+       int fput_needed;
+       ssize_t ret;
+
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       ret = compat_writev(file, vec, vlen, &file->f_pos);
+       fput_light(file, fput_needed);
+       return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
+                  unsigned long vlen, u32 pos_high, u32 pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       int fput_needed;
+       ssize_t ret;
+
+       if (pos < 0)
+               return -EINVAL;
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       ret = compat_writev(file, vec, vlen, &pos);
+       fput_light(file, fput_needed);
        return ret;
 }
 
@@ -1441,12 +1503,15 @@ int compat_do_execve(char * filename,
        bprm->cred = prepare_exec_creds();
        if (!bprm->cred)
                goto out_unlock;
-       check_unsafe_exec(bprm);
+
+       retval = check_unsafe_exec(bprm);
+       if (retval)
+               goto out_unlock;
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_unlock;
+               goto out_unmark;
 
        sched_exec();
 
@@ -1488,6 +1553,9 @@ int compat_do_execve(char * filename,
                goto out;
 
        /* execve succeeded */
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
        acct_update_integrals(current);
@@ -1506,6 +1574,11 @@ out_file:
                fput(bprm->file);
        }
 
+out_unmark:
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
+
 out_unlock:
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
index ff786687e93b7289e74f0587c170ca5a2f1006c0..3e87ce443ea2c0fd39f32743d56d9cdcd89175d2 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/if.h>
 #include <linux/if_bridge.h>
 #include <linux/slab.h>
-#include <linux/raid/md.h>
+#include <linux/raid/md_u.h>
 #include <linux/kd.h>
 #include <linux/route.h>
 #include <linux/in6.h>
index a07338d2d140818770865aca94dfc2337e9527a6..dd3634e4c967983f2024221b33c34b81e51ad2ad 100644 (file)
@@ -318,6 +318,7 @@ out:
 static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = CRAMFS_MAGIC;
        buf->f_bsize = PAGE_CACHE_SIZE;
@@ -326,6 +327,8 @@ static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = 0;
        buf->f_files = CRAMFS_SB(sb)->files;
        buf->f_ffree = 0;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = CRAMFS_MAXPATHLEN;
        return 0;
 }
@@ -459,11 +462,14 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
 static int cramfs_readpage(struct file *file, struct page * page)
 {
        struct inode *inode = page->mapping->host;
-       u32 maxblock, bytes_filled;
+       u32 maxblock;
+       int bytes_filled;
        void *pgdata;
 
        maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        bytes_filled = 0;
+       pgdata = kmap(page);
+
        if (page->index < maxblock) {
                struct super_block *sb = inode->i_sb;
                u32 blkptr_offset = OFFSET(inode) + page->index*4;
@@ -472,30 +478,43 @@ static int cramfs_readpage(struct file *file, struct page * page)
                start_offset = OFFSET(inode) + maxblock*4;
                mutex_lock(&read_mutex);
                if (page->index)
-                       start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
-               compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
+                       start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4,
+                               4);
+               compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) -
+                       start_offset);
                mutex_unlock(&read_mutex);
-               pgdata = kmap(page);
+
                if (compr_len == 0)
                        ; /* hole */
-               else if (compr_len > (PAGE_CACHE_SIZE << 1))
-                       printk(KERN_ERR "cramfs: bad compressed blocksize %u\n", compr_len);
-               else {
+               else if (unlikely(compr_len > (PAGE_CACHE_SIZE << 1))) {
+                       pr_err("cramfs: bad compressed blocksize %u\n",
+                               compr_len);
+                       goto err;
+               } else {
                        mutex_lock(&read_mutex);
                        bytes_filled = cramfs_uncompress_block(pgdata,
                                 PAGE_CACHE_SIZE,
                                 cramfs_read(sb, start_offset, compr_len),
                                 compr_len);
                        mutex_unlock(&read_mutex);
+                       if (unlikely(bytes_filled < 0))
+                               goto err;
                }
-       } else
-               pgdata = kmap(page);
+       }
+
        memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
-       kunmap(page);
        flush_dcache_page(page);
+       kunmap(page);
        SetPageUptodate(page);
        unlock_page(page);
        return 0;
+
+err:
+       kunmap(page);
+       ClearPageUptodate(page);
+       SetPageError(page);
+       unlock_page(page);
+       return 0;
 }
 
 static const struct address_space_operations cramfs_aops = {
index fc3ccb74626ffb3a581da4049c703242352dedfa..023329800d2e42152fec5a531f91f4310cae1729 100644 (file)
@@ -50,7 +50,7 @@ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen)
 err:
        printk("Error %d while decompressing!\n", err);
        printk("%p(%d)->%p(%d)\n", src, srclen, dst, dstlen);
-       return 0;
+       return -EIO;
 }
 
 int cramfs_uncompress_init(void)
index 90bbd7e1b116d0ec48a07d8dab88c5086fb647d6..761d30be2683c42daf960535269633aab510fec3 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/syscalls.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/fsnotify.h>
 #include <linux/slab.h>
@@ -32,6 +31,7 @@
 #include <linux/seqlock.h>
 #include <linux/swap.h>
 #include <linux/bootmem.h>
+#include <linux/fs_struct.h>
 #include "internal.h"
 
 int sysctl_vfs_cache_pressure __read_mostly = 100;
index 44d725f612cf346ec2e4d9bf2801913de393b967..b6a719a909f8eee1829764ea770e879c1c9c73fe 100644 (file)
@@ -18,7 +18,7 @@ static void drop_pagecache_sb(struct super_block *sb)
 
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+               if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
                        continue;
                if (inode->i_mapping->nrpages == 0)
                        continue;
index e4a6223c314594c71402ef373ee0e6e092d55bd3..af737bb56cb71942ebed99c9bad8eb6a34bdaeb8 100644 (file)
@@ -740,8 +740,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
 out_release_free_unlock:
        crypto_free_hash(s->hash_desc.tfm);
 out_free_unlock:
-       memset(s->block_aligned_filename, 0, s->block_aligned_filename_size);
-       kfree(s->block_aligned_filename);
+       kzfree(s->block_aligned_filename);
 out_unlock:
        mutex_unlock(s->tfm_mutex);
 out:
index 96ef51489e0124d0ae77618160e99707f34dcb49..295e7fa567556f2efc99d17588af9248a409e4c0 100644 (file)
@@ -291,8 +291,7 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
        if (daemon->user_ns)
                put_user_ns(daemon->user_ns);
        mutex_unlock(&daemon->mux);
-       memset(daemon, 0, sizeof(*daemon));
-       kfree(daemon);
+       kzfree(daemon);
 out:
        return rc;
 }
index 73b19cfc91fc57510cc96d8863b776748550b65a..f04942810818ade709f8f7cfa416b21f87c6736a 100644 (file)
@@ -329,18 +329,22 @@ out_no_fs:
 }
 
 static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
-       struct efs_sb_info *sb = SUPER_INFO(dentry->d_sb);
+       struct super_block *sb = dentry->d_sb;
+       struct efs_sb_info *sbi = SUPER_INFO(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type    = EFS_SUPER_MAGIC;       /* efs magic number */
        buf->f_bsize   = EFS_BLOCKSIZE;         /* blocksize */
-       buf->f_blocks  = sb->total_groups *     /* total data blocks */
-                       (sb->group_size - sb->inode_blocks);
-       buf->f_bfree   = sb->data_free;         /* free data blocks */
-       buf->f_bavail  = sb->data_free;         /* free blocks for non-root */
-       buf->f_files   = sb->total_groups *     /* total inodes */
-                       sb->inode_blocks *
+       buf->f_blocks  = sbi->total_groups *    /* total data blocks */
+                       (sbi->group_size - sbi->inode_blocks);
+       buf->f_bfree   = sbi->data_free;        /* free data blocks */
+       buf->f_bavail  = sbi->data_free;        /* free blocks for non-root */
+       buf->f_files   = sbi->total_groups *    /* total inodes */
+                       sbi->inode_blocks *
                        (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
-       buf->f_ffree   = sb->inode_free;        /* free inodes */
+       buf->f_ffree   = sbi->inode_free;       /* free inodes */
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = EFS_MAXNAMELEN;        /* max filename length */
 
        return 0;
index 5de2c2db3aa2381ccc04b02ca440ba56d14cfaba..2a701d593d35f36d2511c25df916a5d61098b019 100644 (file)
@@ -28,6 +28,7 @@ struct eventfd_ctx {
         * issue a wakeup.
         */
        __u64 count;
+       unsigned int flags;
 };
 
 /*
@@ -50,7 +51,7 @@ int eventfd_signal(struct file *file, int n)
                n = (int) (ULLONG_MAX - ctx->count);
        ctx->count += n;
        if (waitqueue_active(&ctx->wqh))
-               wake_up_locked(&ctx->wqh);
+               wake_up_locked_poll(&ctx->wqh, POLLIN);
        spin_unlock_irqrestore(&ctx->wqh.lock, flags);
 
        return n;
@@ -87,22 +88,20 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
 {
        struct eventfd_ctx *ctx = file->private_data;
        ssize_t res;
-       __u64 ucnt;
+       __u64 ucnt = 0;
        DECLARE_WAITQUEUE(wait, current);
 
        if (count < sizeof(ucnt))
                return -EINVAL;
        spin_lock_irq(&ctx->wqh.lock);
        res = -EAGAIN;
-       ucnt = ctx->count;
-       if (ucnt > 0)
+       if (ctx->count > 0)
                res = sizeof(ucnt);
        else if (!(file->f_flags & O_NONBLOCK)) {
                __add_wait_queue(&ctx->wqh, &wait);
                for (res = 0;;) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        if (ctx->count > 0) {
-                               ucnt = ctx->count;
                                res = sizeof(ucnt);
                                break;
                        }
@@ -117,10 +116,11 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
                __remove_wait_queue(&ctx->wqh, &wait);
                __set_current_state(TASK_RUNNING);
        }
-       if (res > 0) {
-               ctx->count = 0;
+       if (likely(res > 0)) {
+               ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count;
+               ctx->count -= ucnt;
                if (waitqueue_active(&ctx->wqh))
-                       wake_up_locked(&ctx->wqh);
+                       wake_up_locked_poll(&ctx->wqh, POLLOUT);
        }
        spin_unlock_irq(&ctx->wqh.lock);
        if (res > 0 && put_user(ucnt, (__u64 __user *) buf))
@@ -166,10 +166,10 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
                __remove_wait_queue(&ctx->wqh, &wait);
                __set_current_state(TASK_RUNNING);
        }
-       if (res > 0) {
+       if (likely(res > 0)) {
                ctx->count += ucnt;
                if (waitqueue_active(&ctx->wqh))
-                       wake_up_locked(&ctx->wqh);
+                       wake_up_locked_poll(&ctx->wqh, POLLIN);
        }
        spin_unlock_irq(&ctx->wqh.lock);
 
@@ -207,7 +207,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
        BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
        BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);
 
-       if (flags & ~(EFD_CLOEXEC | EFD_NONBLOCK))
+       if (flags & ~EFD_FLAGS_SET)
                return -EINVAL;
 
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
@@ -216,13 +216,14 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
 
        init_waitqueue_head(&ctx->wqh);
        ctx->count = count;
+       ctx->flags = flags;
 
        /*
         * When we call this, the initialization must be complete, since
         * anon_inode_getfd() will install the fd.
         */
        fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx,
-                             flags & (O_CLOEXEC | O_NONBLOCK));
+                             flags & EFD_SHARED_FCNTL_FLAGS);
        if (fd < 0)
                kfree(ctx);
        return fd;
@@ -232,3 +233,4 @@ SYSCALL_DEFINE1(eventfd, unsigned int, count)
 {
        return sys_eventfd2(count, 0);
 }
+
index c5c424f23fd5fb08a873ea2eb38a6f4a623b2913..a89f370fadb5d72666b87c4b16bfaa9c3833788a 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  fs/eventpoll.c (Efficent event polling implementation)
- *  Copyright (C) 2001,...,2007         Davide Libenzi
+ *  fs/eventpoll.c (Efficient event retrieval implementation)
+ *  Copyright (C) 2001,...,2009         Davide Libenzi
  *
  *  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
  * a better scalability.
  */
 
-#define DEBUG_EPOLL 0
-
-#if DEBUG_EPOLL > 0
-#define DPRINTK(x) printk x
-#define DNPRINTK(n, x) do { if ((n) <= DEBUG_EPOLL) printk x; } while (0)
-#else /* #if DEBUG_EPOLL > 0 */
-#define DPRINTK(x) (void) 0
-#define DNPRINTK(n, x) (void) 0
-#endif /* #if DEBUG_EPOLL > 0 */
-
-#define DEBUG_EPI 0
-
-#if DEBUG_EPI != 0
-#define EPI_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */)
-#else /* #if DEBUG_EPI != 0 */
-#define EPI_SLAB_DEBUG 0
-#endif /* #if DEBUG_EPI != 0 */
-
 /* Epoll private bits inside the event mask */
 #define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET)
 
-/* Maximum number of poll wake up nests we are allowing */
-#define EP_MAX_POLLWAKE_NESTS 4
+/* Maximum number of nesting allowed inside epoll sets */
+#define EP_MAX_NESTS 4
 
 /* Maximum msec timeout value storeable in a long int */
 #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
@@ -110,24 +92,21 @@ struct epoll_filefd {
 };
 
 /*
- * Node that is linked into the "wake_task_list" member of the "struct poll_safewake".
- * It is used to keep track on all tasks that are currently inside the wake_up() code
- * to 1) short-circuit the one coming from the same task and same wait queue head
- * (loop) 2) allow a maximum number of epoll descriptors inclusion nesting
- * 3) let go the ones coming from other tasks.
+ * Structure used to track possible nested calls, for too deep recursions
+ * and loop cycles.
  */
-struct wake_task_node {
+struct nested_call_node {
        struct list_head llink;
-       struct task_struct *task;
-       wait_queue_head_t *wq;
+       void *cookie;
+       int cpu;
 };
 
 /*
- * This is used to implement the safe poll wake up avoiding to reenter
- * the poll callback from inside wake_up().
+ * This structure is used as collector for nested calls, to check for
+ * maximum recursion dept and loop cycles.
  */
-struct poll_safewake {
-       struct list_head wake_task_list;
+struct nested_calls {
+       struct list_head tasks_call_list;
        spinlock_t lock;
 };
 
@@ -213,7 +192,7 @@ struct eppoll_entry {
        struct list_head llink;
 
        /* The "base" pointer is set to the container "struct epitem" */
-       void *base;
+       struct epitem *base;
 
        /*
         * Wait queue item that will be linked to the target file wait
@@ -231,6 +210,12 @@ struct ep_pqueue {
        struct epitem *epi;
 };
 
+/* Used by the ep_send_events() function as callback private data */
+struct ep_send_events_data {
+       int maxevents;
+       struct epoll_event __user *events;
+};
+
 /*
  * Configuration options available inside /proc/sys/fs/epoll/
  */
@@ -242,8 +227,11 @@ static int max_user_watches __read_mostly;
  */
 static DEFINE_MUTEX(epmutex);
 
-/* Safe wake up implementation */
-static struct poll_safewake psw;
+/* Used for safe wake up implementation */
+static struct nested_calls poll_safewake_ncalls;
+
+/* Used to call file's f_op->poll() under the nested calls boundaries */
+static struct nested_calls poll_readywalk_ncalls;
 
 /* Slab cache used to allocate "struct epitem" */
 static struct kmem_cache *epi_cache __read_mostly;
@@ -312,89 +300,230 @@ static inline int ep_op_has_event(int op)
 }
 
 /* Initialize the poll safe wake up structure */
-static void ep_poll_safewake_init(struct poll_safewake *psw)
+static void ep_nested_calls_init(struct nested_calls *ncalls)
 {
-
-       INIT_LIST_HEAD(&psw->wake_task_list);
-       spin_lock_init(&psw->lock);
+       INIT_LIST_HEAD(&ncalls->tasks_call_list);
+       spin_lock_init(&ncalls->lock);
 }
 
-/*
- * Perform a safe wake up of the poll wait list. The problem is that
- * with the new callback'd wake up system, it is possible that the
- * poll callback is reentered from inside the call to wake_up() done
- * on the poll wait queue head. The rule is that we cannot reenter the
- * wake up code from the same task more than EP_MAX_POLLWAKE_NESTS times,
- * and we cannot reenter the same wait queue head at all. This will
- * enable to have a hierarchy of epoll file descriptor of no more than
- * EP_MAX_POLLWAKE_NESTS deep. We need the irq version of the spin lock
- * because this one gets called by the poll callback, that in turn is called
- * from inside a wake_up(), that might be called from irq context.
+/**
+ * ep_call_nested - Perform a bound (possibly) nested call, by checking
+ *                  that the recursion limit is not exceeded, and that
+ *                  the same nested call (by the meaning of same cookie) is
+ *                  no re-entered.
+ *
+ * @ncalls: Pointer to the nested_calls structure to be used for this call.
+ * @max_nests: Maximum number of allowed nesting calls.
+ * @nproc: Nested call core function pointer.
+ * @priv: Opaque data to be passed to the @nproc callback.
+ * @cookie: Cookie to be used to identify this nested call.
+ *
+ * Returns: Returns the code returned by the @nproc callback, or -1 if
+ *          the maximum recursion limit has been exceeded.
  */
-static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
+static int ep_call_nested(struct nested_calls *ncalls, int max_nests,
+                         int (*nproc)(void *, void *, int), void *priv,
+                         void *cookie)
 {
-       int wake_nests = 0;
+       int error, call_nests = 0;
        unsigned long flags;
-       struct task_struct *this_task = current;
-       struct list_head *lsthead = &psw->wake_task_list;
-       struct wake_task_node *tncur;
-       struct wake_task_node tnode;
+       int this_cpu = get_cpu();
+       struct list_head *lsthead = &ncalls->tasks_call_list;
+       struct nested_call_node *tncur;
+       struct nested_call_node tnode;
 
-       spin_lock_irqsave(&psw->lock, flags);
+       spin_lock_irqsave(&ncalls->lock, flags);
 
-       /* Try to see if the current task is already inside this wakeup call */
+       /*
+        * Try to see if the current task is already inside this wakeup call.
+        * We use a list here, since the population inside this set is always
+        * very much limited.
+        */
        list_for_each_entry(tncur, lsthead, llink) {
-
-               if (tncur->wq == wq ||
-                   (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) {
+               if (tncur->cpu == this_cpu &&
+                   (tncur->cookie == cookie || ++call_nests > max_nests)) {
                        /*
                         * Ops ... loop detected or maximum nest level reached.
                         * We abort this wake by breaking the cycle itself.
                         */
-                       spin_unlock_irqrestore(&psw->lock, flags);
-                       return;
+                       error = -1;
+                       goto out_unlock;
                }
        }
 
-       /* Add the current task to the list */
-       tnode.task = this_task;
-       tnode.wq = wq;
+       /* Add the current task and cookie to the list */
+       tnode.cpu = this_cpu;
+       tnode.cookie = cookie;
        list_add(&tnode.llink, lsthead);
 
-       spin_unlock_irqrestore(&psw->lock, flags);
+       spin_unlock_irqrestore(&ncalls->lock, flags);
 
-       /* Do really wake up now */
-       wake_up_nested(wq, 1 + wake_nests);
+       /* Call the nested function */
+       error = (*nproc)(priv, cookie, call_nests);
 
        /* Remove the current task from the list */
-       spin_lock_irqsave(&psw->lock, flags);
+       spin_lock_irqsave(&ncalls->lock, flags);
        list_del(&tnode.llink);
-       spin_unlock_irqrestore(&psw->lock, flags);
+ out_unlock:
+       spin_unlock_irqrestore(&ncalls->lock, flags);
+
+       put_cpu();
+       return error;
+}
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static inline void ep_wake_up_nested(wait_queue_head_t *wqueue,
+                                    unsigned long events, int subclass)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave_nested(&wqueue->lock, flags, subclass);
+       wake_up_locked_poll(wqueue, events);
+       spin_unlock_irqrestore(&wqueue->lock, flags);
+}
+#else
+static inline void ep_wake_up_nested(wait_queue_head_t *wqueue,
+                                    unsigned long events, int subclass)
+{
+       wake_up_poll(wqueue, events);
+}
+#endif
+
+static int ep_poll_wakeup_proc(void *priv, void *cookie, int call_nests)
+{
+       ep_wake_up_nested((wait_queue_head_t *) cookie, POLLIN,
+                         1 + call_nests);
+       return 0;
+}
+
+/*
+ * Perform a safe wake up of the poll wait list. The problem is that
+ * with the new callback'd wake up system, it is possible that the
+ * poll callback is reentered from inside the call to wake_up() done
+ * on the poll wait queue head. The rule is that we cannot reenter the
+ * wake up code from the same task more than EP_MAX_NESTS times,
+ * and we cannot reenter the same wait queue head at all. This will
+ * enable to have a hierarchy of epoll file descriptor of no more than
+ * EP_MAX_NESTS deep.
+ */
+static void ep_poll_safewake(wait_queue_head_t *wq)
+{
+       ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS,
+                      ep_poll_wakeup_proc, NULL, wq);
 }
 
 /*
- * This function unregister poll callbacks from the associated file descriptor.
- * Since this must be called without holding "ep->lock" the atomic exchange trick
- * will protect us from multiple unregister.
+ * This function unregisters poll callbacks from the associated file
+ * descriptor.  Must be called with "mtx" held (or "epmutex" if called from
+ * ep_free).
  */
 static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
 {
-       int nwait;
        struct list_head *lsthead = &epi->pwqlist;
        struct eppoll_entry *pwq;
 
-       /* This is called without locks, so we need the atomic exchange */
-       nwait = xchg(&epi->nwait, 0);
+       while (!list_empty(lsthead)) {
+               pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
 
-       if (nwait) {
-               while (!list_empty(lsthead)) {
-                       pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
+               list_del(&pwq->llink);
+               remove_wait_queue(pwq->whead, &pwq->wait);
+               kmem_cache_free(pwq_cache, pwq);
+       }
+}
 
-                       list_del_init(&pwq->llink);
-                       remove_wait_queue(pwq->whead, &pwq->wait);
-                       kmem_cache_free(pwq_cache, pwq);
-               }
+/**
+ * ep_scan_ready_list - Scans the ready list in a way that makes possible for
+ *                      the scan code, to call f_op->poll(). Also allows for
+ *                      O(NumReady) performance.
+ *
+ * @ep: Pointer to the epoll private data structure.
+ * @sproc: Pointer to the scan callback.
+ * @priv: Private opaque data passed to the @sproc callback.
+ *
+ * Returns: The same integer error code returned by the @sproc callback.
+ */
+static int ep_scan_ready_list(struct eventpoll *ep,
+                             int (*sproc)(struct eventpoll *,
+                                          struct list_head *, void *),
+                             void *priv)
+{
+       int error, pwake = 0;
+       unsigned long flags;
+       struct epitem *epi, *nepi;
+       LIST_HEAD(txlist);
+
+       /*
+        * We need to lock this because we could be hit by
+        * eventpoll_release_file() and epoll_ctl().
+        */
+       mutex_lock(&ep->mtx);
+
+       /*
+        * Steal the ready list, and re-init the original one to the
+        * empty list. Also, set ep->ovflist to NULL so that events
+        * happening while looping w/out locks, are not lost. We cannot
+        * have the poll callback to queue directly on ep->rdllist,
+        * because we want the "sproc" callback to be able to do it
+        * in a lockless way.
+        */
+       spin_lock_irqsave(&ep->lock, flags);
+       list_splice_init(&ep->rdllist, &txlist);
+       ep->ovflist = NULL;
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       /*
+        * Now call the callback function.
+        */
+       error = (*sproc)(ep, &txlist, priv);
+
+       spin_lock_irqsave(&ep->lock, flags);
+       /*
+        * During the time we spent inside the "sproc" callback, some
+        * other events might have been queued by the poll callback.
+        * We re-insert them inside the main ready-list here.
+        */
+       for (nepi = ep->ovflist; (epi = nepi) != NULL;
+            nepi = epi->next, epi->next = EP_UNACTIVE_PTR) {
+               /*
+                * We need to check if the item is already in the list.
+                * During the "sproc" callback execution time, items are
+                * queued into ->ovflist but the "txlist" might already
+                * contain them, and the list_splice() below takes care of them.
+                */
+               if (!ep_is_linked(&epi->rdllink))
+                       list_add_tail(&epi->rdllink, &ep->rdllist);
+       }
+       /*
+        * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
+        * releasing the lock, events will be queued in the normal way inside
+        * ep->rdllist.
+        */
+       ep->ovflist = EP_UNACTIVE_PTR;
+
+       /*
+        * Quickly re-inject items left on "txlist".
+        */
+       list_splice(&txlist, &ep->rdllist);
+
+       if (!list_empty(&ep->rdllist)) {
+               /*
+                * Wake up (if active) both the eventpoll wait list and
+                * the ->poll() wait list (delayed after we release the lock).
+                */
+               if (waitqueue_active(&ep->wq))
+                       wake_up_locked(&ep->wq);
+               if (waitqueue_active(&ep->poll_wait))
+                       pwake++;
        }
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       mutex_unlock(&ep->mtx);
+
+       /* We have to call this outside the lock */
+       if (pwake)
+               ep_poll_safewake(&ep->poll_wait);
+
+       return error;
 }
 
 /*
@@ -434,9 +563,6 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
 
        atomic_dec(&ep->user->epoll_watches);
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p)\n",
-                    current, ep, file));
-
        return 0;
 }
 
@@ -447,7 +573,7 @@ static void ep_free(struct eventpoll *ep)
 
        /* We need to release all tasks waiting for these file */
        if (waitqueue_active(&ep->poll_wait))
-               ep_poll_safewake(&psw, &ep->poll_wait);
+               ep_poll_safewake(&ep->poll_wait);
 
        /*
         * We need to lock this because we could be hit by
@@ -492,26 +618,54 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file)
        if (ep)
                ep_free(ep);
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
        return 0;
 }
 
+static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
+                              void *priv)
+{
+       struct epitem *epi, *tmp;
+
+       list_for_each_entry_safe(epi, tmp, head, rdllink) {
+               if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+                   epi->event.events)
+                       return POLLIN | POLLRDNORM;
+               else {
+                       /*
+                        * Item has been dropped into the ready list by the poll
+                        * callback, but it's not actually ready, as far as
+                        * caller requested events goes. We can remove it here.
+                        */
+                       list_del_init(&epi->rdllink);
+               }
+       }
+
+       return 0;
+}
+
+static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests)
+{
+       return ep_scan_ready_list(priv, ep_read_events_proc, NULL);
+}
+
 static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
 {
-       unsigned int pollflags = 0;
-       unsigned long flags;
+       int pollflags;
        struct eventpoll *ep = file->private_data;
 
        /* Insert inside our poll wait queue */
        poll_wait(file, &ep->poll_wait, wait);
 
-       /* Check our condition */
-       spin_lock_irqsave(&ep->lock, flags);
-       if (!list_empty(&ep->rdllist))
-               pollflags = POLLIN | POLLRDNORM;
-       spin_unlock_irqrestore(&ep->lock, flags);
+       /*
+        * Proceed to find out if wanted events are really available inside
+        * the ready list. This need to be done under ep_call_nested()
+        * supervision, since the call to f_op->poll() done on listed files
+        * could re-enter here.
+        */
+       pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS,
+                                  ep_poll_readyevents_proc, ep, ep);
 
-       return pollflags;
+       return pollflags != -1 ? pollflags : 0;
 }
 
 /* File callbacks that implement the eventpoll file behaviour */
@@ -541,7 +695,7 @@ void eventpoll_release_file(struct file *file)
         * We don't want to get "file->f_lock" because it is not
         * necessary. It is not necessary because we're in the "struct file"
         * cleanup path, and this means that noone is using this file anymore.
-        * So, for example, epoll_ctl() cannot hit here sicne if we reach this
+        * So, for example, epoll_ctl() cannot hit here since if we reach this
         * point, the file counter already went to zero and fget() would fail.
         * The only hit might come from ep_free() but by holding the mutex
         * will correctly serialize the operation. We do need to acquire
@@ -588,8 +742,6 @@ static int ep_alloc(struct eventpoll **pep)
 
        *pep = ep;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
-                    current, ep));
        return 0;
 
 free_uid:
@@ -623,9 +775,6 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd)
                }
        }
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%p) -> %p\n",
-                    current, file, epir));
-
        return epir;
 }
 
@@ -641,9 +790,6 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        struct epitem *epi = ep_item_from_wait(wait);
        struct eventpoll *ep = epi->ep;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
-                    current, epi->ffd.file, epi, ep));
-
        spin_lock_irqsave(&ep->lock, flags);
 
        /*
@@ -655,6 +801,15 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        if (!(epi->event.events & ~EP_PRIVATE_BITS))
                goto out_unlock;
 
+       /*
+        * Check the events coming with the callback. At this stage, not
+        * every device reports the events in the "key" parameter of the
+        * callback. We need to be able to handle both cases here, hence the
+        * test for "key" != NULL before the event match test.
+        */
+       if (key && !((unsigned long) key & epi->event.events))
+               goto out_unlock;
+
        /*
         * If we are trasfering events to userspace, we can hold no locks
         * (because we're accessing user memory, and because of linux f_op->poll()
@@ -670,12 +825,9 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        }
 
        /* If this file is already in the ready list we exit soon */
-       if (ep_is_linked(&epi->rdllink))
-               goto is_linked;
-
-       list_add_tail(&epi->rdllink, &ep->rdllist);
+       if (!ep_is_linked(&epi->rdllink))
+               list_add_tail(&epi->rdllink, &ep->rdllist);
 
-is_linked:
        /*
         * Wake up ( if active ) both the eventpoll wait list and the ->poll()
         * wait list.
@@ -690,7 +842,7 @@ out_unlock:
 
        /* We have to call this outside the lock */
        if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
+               ep_poll_safewake(&ep->poll_wait);
 
        return 1;
 }
@@ -817,10 +969,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
        /* We have to call this outside the lock */
        if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %p, %d)\n",
-                    current, ep, tfile, fd));
+               ep_poll_safewake(&ep->poll_wait);
 
        return 0;
 
@@ -851,15 +1000,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
 {
        int pwake = 0;
        unsigned int revents;
-       unsigned long flags;
 
        /*
-        * Set the new event interest mask before calling f_op->poll(), otherwise
-        * a potential race might occur. In fact if we do this operation inside
-        * the lock, an event might happen between the f_op->poll() call and the
-        * new event set registering.
+        * Set the new event interest mask before calling f_op->poll();
+        * otherwise we might miss an event that happens between the
+        * f_op->poll() call and the new event set registering.
         */
        epi->event.events = event->events;
+       epi->event.data = event->data; /* protected by mtx */
 
        /*
         * Get current event bits. We can safely use the file* here because
@@ -867,16 +1015,12 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
         */
        revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
 
-       spin_lock_irqsave(&ep->lock, flags);
-
-       /* Copy the data member from inside the lock */
-       epi->event.data = event->data;
-
        /*
         * If the item is "hot" and it is not registered inside the ready
         * list, push it inside.
         */
        if (revents & event->events) {
+               spin_lock_irq(&ep->lock);
                if (!ep_is_linked(&epi->rdllink)) {
                        list_add_tail(&epi->rdllink, &ep->rdllist);
 
@@ -886,142 +1030,84 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
                        if (waitqueue_active(&ep->poll_wait))
                                pwake++;
                }
+               spin_unlock_irq(&ep->lock);
        }
-       spin_unlock_irqrestore(&ep->lock, flags);
 
        /* We have to call this outside the lock */
        if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
+               ep_poll_safewake(&ep->poll_wait);
 
        return 0;
 }
 
-static int ep_send_events(struct eventpoll *ep, struct epoll_event __user *events,
-                         int maxevents)
+static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
+                              void *priv)
 {
-       int eventcnt, error = -EFAULT, pwake = 0;
+       struct ep_send_events_data *esed = priv;
+       int eventcnt;
        unsigned int revents;
-       unsigned long flags;
-       struct epitem *epi, *nepi;
-       struct list_head txlist;
-
-       INIT_LIST_HEAD(&txlist);
-
-       /*
-        * We need to lock this because we could be hit by
-        * eventpoll_release_file() and epoll_ctl(EPOLL_CTL_DEL).
-        */
-       mutex_lock(&ep->mtx);
-
-       /*
-        * Steal the ready list, and re-init the original one to the
-        * empty list. Also, set ep->ovflist to NULL so that events
-        * happening while looping w/out locks, are not lost. We cannot
-        * have the poll callback to queue directly on ep->rdllist,
-        * because we are doing it in the loop below, in a lockless way.
-        */
-       spin_lock_irqsave(&ep->lock, flags);
-       list_splice(&ep->rdllist, &txlist);
-       INIT_LIST_HEAD(&ep->rdllist);
-       ep->ovflist = NULL;
-       spin_unlock_irqrestore(&ep->lock, flags);
+       struct epitem *epi;
+       struct epoll_event __user *uevent;
 
        /*
-        * We can loop without lock because this is a task private list.
-        * We just splice'd out the ep->rdllist in ep_collect_ready_items().
-        * Items cannot vanish during the loop because we are holding "mtx".
+        * We can loop without lock because we are passed a task private list.
+        * Items cannot vanish during the loop because ep_scan_ready_list() is
+        * holding "mtx" during this call.
         */
-       for (eventcnt = 0; !list_empty(&txlist) && eventcnt < maxevents;) {
-               epi = list_first_entry(&txlist, struct epitem, rdllink);
+       for (eventcnt = 0, uevent = esed->events;
+            !list_empty(head) && eventcnt < esed->maxevents;) {
+               epi = list_first_entry(head, struct epitem, rdllink);
 
                list_del_init(&epi->rdllink);
 
-               /*
-                * Get the ready file event set. We can safely use the file
-                * because we are holding the "mtx" and this will guarantee
-                * that both the file and the item will not vanish.
-                */
-               revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
-               revents &= epi->event.events;
+               revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+                       epi->event.events;
 
                /*
-                * Is the event mask intersect the caller-requested one,
-                * deliver the event to userspace. Again, we are holding
-                * "mtx", so no operations coming from userspace can change
-                * the item.
+                * If the event mask intersect the caller-requested one,
+                * deliver the event to userspace. Again, ep_scan_ready_list()
+                * is holding "mtx", so no operations coming from userspace
+                * can change the item.
                 */
                if (revents) {
-                       if (__put_user(revents,
-                                      &events[eventcnt].events) ||
-                           __put_user(epi->event.data,
-                                      &events[eventcnt].data))
-                               goto errxit;
+                       if (__put_user(revents, &uevent->events) ||
+                           __put_user(epi->event.data, &uevent->data)) {
+                               list_add(&epi->rdllink, head);
+                               return eventcnt ? eventcnt : -EFAULT;
+                       }
+                       eventcnt++;
+                       uevent++;
                        if (epi->event.events & EPOLLONESHOT)
                                epi->event.events &= EP_PRIVATE_BITS;
-                       eventcnt++;
+                       else if (!(epi->event.events & EPOLLET)) {
+                               /*
+                                * If this file has been added with Level
+                                * Trigger mode, we need to insert back inside
+                                * the ready list, so that the next call to
+                                * epoll_wait() will check again the events
+                                * availability. At this point, noone can insert
+                                * into ep->rdllist besides us. The epoll_ctl()
+                                * callers are locked out by
+                                * ep_scan_ready_list() holding "mtx" and the
+                                * poll callback will queue them in ep->ovflist.
+                                */
+                               list_add_tail(&epi->rdllink, &ep->rdllist);
+                       }
                }
-               /*
-                * At this point, noone can insert into ep->rdllist besides
-                * us. The epoll_ctl() callers are locked out by us holding
-                * "mtx" and the poll callback will queue them in ep->ovflist.
-                */
-               if (!(epi->event.events & EPOLLET) &&
-                   (revents & epi->event.events))
-                       list_add_tail(&epi->rdllink, &ep->rdllist);
-       }
-       error = 0;
-
-errxit:
-
-       spin_lock_irqsave(&ep->lock, flags);
-       /*
-        * During the time we spent in the loop above, some other events
-        * might have been queued by the poll callback. We re-insert them
-        * inside the main ready-list here.
-        */
-       for (nepi = ep->ovflist; (epi = nepi) != NULL;
-            nepi = epi->next, epi->next = EP_UNACTIVE_PTR) {
-               /*
-                * If the above loop quit with errors, the epoll item might still
-                * be linked to "txlist", and the list_splice() done below will
-                * take care of those cases.
-                */
-               if (!ep_is_linked(&epi->rdllink))
-                       list_add_tail(&epi->rdllink, &ep->rdllist);
        }
-       /*
-        * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
-        * releasing the lock, events will be queued in the normal way inside
-        * ep->rdllist.
-        */
-       ep->ovflist = EP_UNACTIVE_PTR;
 
-       /*
-        * In case of error in the event-send loop, or in case the number of
-        * ready events exceeds the userspace limit, we need to splice the
-        * "txlist" back inside ep->rdllist.
-        */
-       list_splice(&txlist, &ep->rdllist);
-
-       if (!list_empty(&ep->rdllist)) {
-               /*
-                * Wake up (if active) both the eventpoll wait list and the ->poll()
-                * wait list (delayed after we release the lock).
-                */
-               if (waitqueue_active(&ep->wq))
-                       wake_up_locked(&ep->wq);
-               if (waitqueue_active(&ep->poll_wait))
-                       pwake++;
-       }
-       spin_unlock_irqrestore(&ep->lock, flags);
+       return eventcnt;
+}
 
-       mutex_unlock(&ep->mtx);
+static int ep_send_events(struct eventpoll *ep,
+                         struct epoll_event __user *events, int maxevents)
+{
+       struct ep_send_events_data esed;
 
-       /* We have to call this outside the lock */
-       if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
+       esed.maxevents = maxevents;
+       esed.events = events;
 
-       return eventcnt == 0 ? error: eventcnt;
+       return ep_scan_ready_list(ep, ep_send_events_proc, &esed);
 }
 
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
@@ -1033,7 +1119,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
        wait_queue_t wait;
 
        /*
-        * Calculate the timeout by checking for the "infinite" value ( -1 )
+        * Calculate the timeout by checking for the "infinite" value (-1)
         * and the overflow condition. The passed timeout is in milliseconds,
         * that why (t * HZ) / 1000.
         */
@@ -1076,9 +1162,8 @@ retry:
 
                set_current_state(TASK_RUNNING);
        }
-
        /* Is it worth to try to dig for events ? */
-       eavail = !list_empty(&ep->rdllist);
+       eavail = !list_empty(&ep->rdllist) || ep->ovflist != EP_UNACTIVE_PTR;
 
        spin_unlock_irqrestore(&ep->lock, flags);
 
@@ -1099,41 +1184,30 @@ retry:
  */
 SYSCALL_DEFINE1(epoll_create1, int, flags)
 {
-       int error, fd = -1;
-       struct eventpoll *ep;
+       int error;
+       struct eventpoll *ep = NULL;
 
        /* Check the EPOLL_* constant for consistency.  */
        BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
 
        if (flags & ~EPOLL_CLOEXEC)
                return -EINVAL;
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
-                    current, flags));
-
        /*
-        * Create the internal data structure ( "struct eventpoll" ).
+        * Create the internal data structure ("struct eventpoll").
         */
        error = ep_alloc(&ep);
-       if (error < 0) {
-               fd = error;
-               goto error_return;
-       }
-
+       if (error < 0)
+               return error;
        /*
         * Creates all the items needed to setup an eventpoll file. That is,
         * a file structure and a free file descriptor.
         */
-       fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
-                             flags & O_CLOEXEC);
-       if (fd < 0)
+       error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
+                                flags & O_CLOEXEC);
+       if (error < 0)
                ep_free(ep);
 
-error_return:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
-                    current, flags, fd));
-
-       return fd;
+       return error;
 }
 
 SYSCALL_DEFINE1(epoll_create, int, size)
@@ -1158,9 +1232,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        struct epitem *epi;
        struct epoll_event epds;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
-                    current, epfd, op, fd, event));
-
        error = -EFAULT;
        if (ep_op_has_event(op) &&
            copy_from_user(&epds, event, sizeof(struct epoll_event)))
@@ -1211,7 +1282,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        case EPOLL_CTL_ADD:
                if (!epi) {
                        epds.events |= POLLERR | POLLHUP;
-
                        error = ep_insert(ep, &epds, tfile, fd);
                } else
                        error = -EEXIST;
@@ -1237,8 +1307,6 @@ error_tgt_fput:
 error_fput:
        fput(file);
 error_return:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
-                    current, epfd, op, fd, event, error));
 
        return error;
 }
@@ -1254,9 +1322,6 @@ SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,
        struct file *file;
        struct eventpoll *ep;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
-                    current, epfd, events, maxevents, timeout));
-
        /* The maximum number of event must be greater than zero */
        if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
                return -EINVAL;
@@ -1293,8 +1358,6 @@ SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,
 error_fput:
        fput(file);
 error_return:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
-                    current, epfd, events, maxevents, timeout, error));
 
        return error;
 }
@@ -1359,17 +1422,18 @@ static int __init eventpoll_init(void)
                EP_ITEM_COST;
 
        /* Initialize the structure used to perform safe poll wait head wake ups */
-       ep_poll_safewake_init(&psw);
+       ep_nested_calls_init(&poll_safewake_ncalls);
+
+       /* Initialize the structure used to perform file's f_op->poll() calls */
+       ep_nested_calls_init(&poll_readywalk_ncalls);
 
        /* Allocates slab cache used to allocate "struct epitem" items */
        epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
-                       0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,
-                       NULL);
+                       0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
 
        /* Allocates slab cache used to allocate "struct eppoll_entry" */
        pwq_cache = kmem_cache_create("eventpoll_pwq",
-                       sizeof(struct eppoll_entry), 0,
-                       EPI_SLAB_DEBUG|SLAB_PANIC, NULL);
+                       sizeof(struct eppoll_entry), 0, SLAB_PANIC, NULL);
 
        return 0;
 }
index c5128fbc9165235832a3851b663eb23a2ab8935d..052a961e41aad189b264c22e11cfd65a77a1ef22 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -53,6 +53,7 @@
 #include <linux/tracehook.h>
 #include <linux/kmod.h>
 #include <linux/fsnotify.h>
+#include <linux/fs_struct.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1056,28 +1057,35 @@ EXPORT_SYMBOL(install_exec_creds);
  * - the caller must hold current->cred_exec_mutex to protect against
  *   PTRACE_ATTACH
  */
-void check_unsafe_exec(struct linux_binprm *bprm)
+int check_unsafe_exec(struct linux_binprm *bprm)
 {
        struct task_struct *p = current, *t;
        unsigned long flags;
-       unsigned n_fs, n_sighand;
+       unsigned n_fs;
+       int res = 0;
 
        bprm->unsafe = tracehook_unsafe_exec(p);
 
        n_fs = 1;
-       n_sighand = 1;
+       write_lock(&p->fs->lock);
        lock_task_sighand(p, &flags);
        for (t = next_thread(p); t != p; t = next_thread(t)) {
                if (t->fs == p->fs)
                        n_fs++;
-               n_sighand++;
        }
 
-       if (atomic_read(&p->fs->count) > n_fs ||
-           atomic_read(&p->sighand->count) > n_sighand)
+       if (p->fs->users > n_fs) {
                bprm->unsafe |= LSM_UNSAFE_SHARE;
+       } else {
+               if (p->fs->in_exec)
+                       res = -EAGAIN;
+               p->fs->in_exec = 1;
+       }
 
        unlock_task_sighand(p, &flags);
+       write_unlock(&p->fs->lock);
+
+       return res;
 }
 
 /* 
@@ -1296,12 +1304,15 @@ int do_execve(char * filename,
        bprm->cred = prepare_exec_creds();
        if (!bprm->cred)
                goto out_unlock;
-       check_unsafe_exec(bprm);
+
+       retval = check_unsafe_exec(bprm);
+       if (retval)
+               goto out_unlock;
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_unlock;
+               goto out_unmark;
 
        sched_exec();
 
@@ -1344,6 +1355,9 @@ int do_execve(char * filename,
                goto out;
 
        /* execve succeeded */
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
        acct_update_integrals(current);
@@ -1362,6 +1376,11 @@ out_file:
                fput(bprm->file);
        }
 
+out_unmark:
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
+
 out_unlock:
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
diff --git a/fs/exofs/BUGS b/fs/exofs/BUGS
new file mode 100644 (file)
index 0000000..1b2d4c6
--- /dev/null
@@ -0,0 +1,3 @@
+- Out-of-space may cause a severe problem if the object (and directory entry)
+  were written, but the inode attributes failed. Then if the filesystem was
+  unmounted and mounted the kernel can get into an endless loop doing a readdir.
diff --git a/fs/exofs/Kbuild b/fs/exofs/Kbuild
new file mode 100644 (file)
index 0000000..cc2d22d
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Kbuild for the EXOFS module
+#
+# Copyright (C) 2008 Panasas Inc.  All rights reserved.
+#
+# Authors:
+#   Boaz Harrosh <bharrosh@panasas.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+#
+# Kbuild - Gets included from the Kernels Makefile and build system
+#
+
+exofs-y := osd.o inode.o file.o symlink.o namei.o dir.o super.o
+obj-$(CONFIG_EXOFS_FS) += exofs.o
diff --git a/fs/exofs/Kconfig b/fs/exofs/Kconfig
new file mode 100644 (file)
index 0000000..86194b2
--- /dev/null
@@ -0,0 +1,13 @@
+config EXOFS_FS
+       tristate "exofs: OSD based file system support"
+       depends on SCSI_OSD_ULD
+       help
+         EXOFS is a file system that uses an OSD storage device,
+         as its backing storage.
+
+# Debugging-related stuff
+config EXOFS_DEBUG
+       bool "Enable debugging"
+       depends on EXOFS_FS
+       help
+         This option enables EXOFS debug prints.
diff --git a/fs/exofs/common.h b/fs/exofs/common.h
new file mode 100644 (file)
index 0000000..b1512c4
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * common.h - Common definitions for both Kernel and user-mode utilities
+ *
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __EXOFS_COM_H__
+#define __EXOFS_COM_H__
+
+#include <linux/types.h>
+
+#include <scsi/osd_attributes.h>
+#include <scsi/osd_initiator.h>
+#include <scsi/osd_sec.h>
+
+/****************************************************************************
+ * Object ID related defines
+ * NOTE: inode# = object ID - EXOFS_OBJ_OFF
+ ****************************************************************************/
+#define EXOFS_MIN_PID   0x10000        /* Smallest partition ID */
+#define EXOFS_OBJ_OFF  0x10000 /* offset for objects */
+#define EXOFS_SUPER_ID 0x10000 /* object ID for on-disk superblock */
+#define EXOFS_ROOT_ID  0x10002 /* object ID for root directory */
+
+/* exofs Application specific page/attribute */
+# define EXOFS_APAGE_FS_DATA   (OSD_APAGE_APP_DEFINED_FIRST + 3)
+# define EXOFS_ATTR_INODE_DATA 1
+
+/*
+ * The maximum number of files we can have is limited by the size of the
+ * inode number.  This is the largest object ID that the file system supports.
+ * Object IDs 0, 1, and 2 are always in use (see above defines).
+ */
+enum {
+       EXOFS_MAX_INO_ID = (sizeof(ino_t) * 8 == 64) ? ULLONG_MAX :
+                                       (1ULL << (sizeof(ino_t) * 8ULL - 1ULL)),
+       EXOFS_MAX_ID     = (EXOFS_MAX_INO_ID - 1 - EXOFS_OBJ_OFF),
+};
+
+/****************************************************************************
+ * Misc.
+ ****************************************************************************/
+#define EXOFS_BLKSHIFT 12
+#define EXOFS_BLKSIZE  (1UL << EXOFS_BLKSHIFT)
+
+/****************************************************************************
+ * superblock-related things
+ ****************************************************************************/
+#define EXOFS_SUPER_MAGIC      0x5DF5
+
+/*
+ * The file system control block - stored in an object's data (mainly, the one
+ * with ID EXOFS_SUPER_ID).  This is where the in-memory superblock is stored
+ * on disk.  Right now it just has a magic value, which is basically a sanity
+ * check on our ability to communicate with the object store.
+ */
+struct exofs_fscb {
+       __le64  s_nextid;       /* Highest object ID used */
+       __le32  s_numfiles;     /* Number of files on fs */
+       __le16  s_magic;        /* Magic signature */
+       __le16  s_newfs;        /* Non-zero if this is a new fs */
+};
+
+/****************************************************************************
+ * inode-related things
+ ****************************************************************************/
+#define EXOFS_IDATA            5
+
+/*
+ * The file control block - stored in an object's attributes.  This is where
+ * the in-memory inode is stored on disk.
+ */
+struct exofs_fcb {
+       __le64  i_size;                 /* Size of the file */
+       __le16  i_mode;                 /* File mode */
+       __le16  i_links_count;          /* Links count */
+       __le32  i_uid;                  /* Owner Uid */
+       __le32  i_gid;                  /* Group Id */
+       __le32  i_atime;                /* Access time */
+       __le32  i_ctime;                /* Creation time */
+       __le32  i_mtime;                /* Modification time */
+       __le32  i_flags;                /* File flags (unused for now)*/
+       __le32  i_generation;           /* File version (for NFS) */
+       __le32  i_data[EXOFS_IDATA];    /* Short symlink names and device #s */
+};
+
+#define EXOFS_INO_ATTR_SIZE    sizeof(struct exofs_fcb)
+
+/* This is the Attribute the fcb is stored in */
+static const struct __weak osd_attr g_attr_inode_data = ATTR_DEF(
+       EXOFS_APAGE_FS_DATA,
+       EXOFS_ATTR_INODE_DATA,
+       EXOFS_INO_ATTR_SIZE);
+
+/****************************************************************************
+ * dentry-related things
+ ****************************************************************************/
+#define EXOFS_NAME_LEN 255
+
+/*
+ * The on-disk directory entry
+ */
+struct exofs_dir_entry {
+       __le64          inode_no;               /* inode number           */
+       __le16          rec_len;                /* directory entry length */
+       u8              name_len;               /* name length            */
+       u8              file_type;              /* umm...file type        */
+       char            name[EXOFS_NAME_LEN];   /* file name              */
+};
+
+enum {
+       EXOFS_FT_UNKNOWN,
+       EXOFS_FT_REG_FILE,
+       EXOFS_FT_DIR,
+       EXOFS_FT_CHRDEV,
+       EXOFS_FT_BLKDEV,
+       EXOFS_FT_FIFO,
+       EXOFS_FT_SOCK,
+       EXOFS_FT_SYMLINK,
+       EXOFS_FT_MAX
+};
+
+#define EXOFS_DIR_PAD                  4
+#define EXOFS_DIR_ROUND                        (EXOFS_DIR_PAD - 1)
+#define EXOFS_DIR_REC_LEN(name_len) \
+       (((name_len) + offsetof(struct exofs_dir_entry, name)  + \
+         EXOFS_DIR_ROUND) & ~EXOFS_DIR_ROUND)
+
+/*************************
+ * function declarations *
+ *************************/
+/* osd.c                 */
+void exofs_make_credential(u8 cred_a[OSD_CAP_LEN],
+                          const struct osd_obj_id *obj);
+
+int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid);
+static inline int exofs_check_ok(struct osd_request *or)
+{
+       return exofs_check_ok_resid(or, NULL, NULL);
+}
+int exofs_sync_op(struct osd_request *or, int timeout, u8 *cred);
+int exofs_async_op(struct osd_request *or,
+       osd_req_done_fn *async_done, void *caller_context, u8 *cred);
+
+int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr);
+
+int osd_req_read_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
+
+int osd_req_write_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
+
+#endif /*ifndef __EXOFS_COM_H__*/
diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c
new file mode 100644 (file)
index 0000000..65b0c8c
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "exofs.h"
+
+static inline unsigned exofs_chunk_size(struct inode *inode)
+{
+       return inode->i_sb->s_blocksize;
+}
+
+static inline void exofs_put_page(struct page *page)
+{
+       kunmap(page);
+       page_cache_release(page);
+}
+
+/* Accesses dir's inode->i_size must be called under inode lock */
+static inline unsigned long dir_pages(struct inode *inode)
+{
+       return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+}
+
+static unsigned exofs_last_byte(struct inode *inode, unsigned long page_nr)
+{
+       loff_t last_byte = inode->i_size;
+
+       last_byte -= page_nr << PAGE_CACHE_SHIFT;
+       if (last_byte > PAGE_CACHE_SIZE)
+               last_byte = PAGE_CACHE_SIZE;
+       return last_byte;
+}
+
+static int exofs_commit_chunk(struct page *page, loff_t pos, unsigned len)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *dir = mapping->host;
+       int err = 0;
+
+       dir->i_version++;
+
+       if (!PageUptodate(page))
+               SetPageUptodate(page);
+
+       if (pos+len > dir->i_size) {
+               i_size_write(dir, pos+len);
+               mark_inode_dirty(dir);
+       }
+       set_page_dirty(page);
+
+       if (IS_DIRSYNC(dir))
+               err = write_one_page(page, 1);
+       else
+               unlock_page(page);
+
+       return err;
+}
+
+static void exofs_check_page(struct page *page)
+{
+       struct inode *dir = page->mapping->host;
+       unsigned chunk_size = exofs_chunk_size(dir);
+       char *kaddr = page_address(page);
+       unsigned offs, rec_len;
+       unsigned limit = PAGE_CACHE_SIZE;
+       struct exofs_dir_entry *p;
+       char *error;
+
+       /* if the page is the last one in the directory */
+       if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
+               limit = dir->i_size & ~PAGE_CACHE_MASK;
+               if (limit & (chunk_size - 1))
+                       goto Ebadsize;
+               if (!limit)
+                       goto out;
+       }
+       for (offs = 0; offs <= limit - EXOFS_DIR_REC_LEN(1); offs += rec_len) {
+               p = (struct exofs_dir_entry *)(kaddr + offs);
+               rec_len = le16_to_cpu(p->rec_len);
+
+               if (rec_len < EXOFS_DIR_REC_LEN(1))
+                       goto Eshort;
+               if (rec_len & 3)
+                       goto Ealign;
+               if (rec_len < EXOFS_DIR_REC_LEN(p->name_len))
+                       goto Enamelen;
+               if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
+                       goto Espan;
+       }
+       if (offs != limit)
+               goto Eend;
+out:
+       SetPageChecked(page);
+       return;
+
+Ebadsize:
+       EXOFS_ERR("ERROR [exofs_check_page]: "
+               "size of directory #%lu is not a multiple of chunk size",
+               dir->i_ino
+       );
+       goto fail;
+Eshort:
+       error = "rec_len is smaller than minimal";
+       goto bad_entry;
+Ealign:
+       error = "unaligned directory entry";
+       goto bad_entry;
+Enamelen:
+       error = "rec_len is too small for name_len";
+       goto bad_entry;
+Espan:
+       error = "directory entry across blocks";
+       goto bad_entry;
+bad_entry:
+       EXOFS_ERR(
+               "ERROR [exofs_check_page]: bad entry in directory #%lu: %s - "
+               "offset=%lu, inode=%llu, rec_len=%d, name_len=%d",
+               dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+               _LLU(le64_to_cpu(p->inode_no)),
+               rec_len, p->name_len);
+       goto fail;
+Eend:
+       p = (struct exofs_dir_entry *)(kaddr + offs);
+       EXOFS_ERR("ERROR [exofs_check_page]: "
+               "entry in directory #%lu spans the page boundary"
+               "offset=%lu, inode=%llu",
+               dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+               _LLU(le64_to_cpu(p->inode_no)));
+fail:
+       SetPageChecked(page);
+       SetPageError(page);
+}
+
+static struct page *exofs_get_page(struct inode *dir, unsigned long n)
+{
+       struct address_space *mapping = dir->i_mapping;
+       struct page *page = read_mapping_page(mapping, n, NULL);
+
+       if (!IS_ERR(page)) {
+               kmap(page);
+               if (!PageChecked(page))
+                       exofs_check_page(page);
+               if (PageError(page))
+                       goto fail;
+       }
+       return page;
+
+fail:
+       exofs_put_page(page);
+       return ERR_PTR(-EIO);
+}
+
+static inline int exofs_match(int len, const unsigned char *name,
+                                       struct exofs_dir_entry *de)
+{
+       if (len != de->name_len)
+               return 0;
+       if (!de->inode_no)
+               return 0;
+       return !memcmp(name, de->name, len);
+}
+
+static inline
+struct exofs_dir_entry *exofs_next_entry(struct exofs_dir_entry *p)
+{
+       return (struct exofs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len));
+}
+
+static inline unsigned
+exofs_validate_entry(char *base, unsigned offset, unsigned mask)
+{
+       struct exofs_dir_entry *de = (struct exofs_dir_entry *)(base + offset);
+       struct exofs_dir_entry *p =
+                       (struct exofs_dir_entry *)(base + (offset&mask));
+       while ((char *)p < (char *)de) {
+               if (p->rec_len == 0)
+                       break;
+               p = exofs_next_entry(p);
+       }
+       return (char *)p - base;
+}
+
+static unsigned char exofs_filetype_table[EXOFS_FT_MAX] = {
+       [EXOFS_FT_UNKNOWN]      = DT_UNKNOWN,
+       [EXOFS_FT_REG_FILE]     = DT_REG,
+       [EXOFS_FT_DIR]          = DT_DIR,
+       [EXOFS_FT_CHRDEV]       = DT_CHR,
+       [EXOFS_FT_BLKDEV]       = DT_BLK,
+       [EXOFS_FT_FIFO]         = DT_FIFO,
+       [EXOFS_FT_SOCK]         = DT_SOCK,
+       [EXOFS_FT_SYMLINK]      = DT_LNK,
+};
+
+#define S_SHIFT 12
+static unsigned char exofs_type_by_mode[S_IFMT >> S_SHIFT] = {
+       [S_IFREG >> S_SHIFT]    = EXOFS_FT_REG_FILE,
+       [S_IFDIR >> S_SHIFT]    = EXOFS_FT_DIR,
+       [S_IFCHR >> S_SHIFT]    = EXOFS_FT_CHRDEV,
+       [S_IFBLK >> S_SHIFT]    = EXOFS_FT_BLKDEV,
+       [S_IFIFO >> S_SHIFT]    = EXOFS_FT_FIFO,
+       [S_IFSOCK >> S_SHIFT]   = EXOFS_FT_SOCK,
+       [S_IFLNK >> S_SHIFT]    = EXOFS_FT_SYMLINK,
+};
+
+static inline
+void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode)
+{
+       mode_t mode = inode->i_mode;
+       de->file_type = exofs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
+}
+
+static int
+exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       loff_t pos = filp->f_pos;
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       unsigned int offset = pos & ~PAGE_CACHE_MASK;
+       unsigned long n = pos >> PAGE_CACHE_SHIFT;
+       unsigned long npages = dir_pages(inode);
+       unsigned chunk_mask = ~(exofs_chunk_size(inode)-1);
+       unsigned char *types = NULL;
+       int need_revalidate = (filp->f_version != inode->i_version);
+
+       if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1))
+               return 0;
+
+       types = exofs_filetype_table;
+
+       for ( ; n < npages; n++, offset = 0) {
+               char *kaddr, *limit;
+               struct exofs_dir_entry *de;
+               struct page *page = exofs_get_page(inode, n);
+
+               if (IS_ERR(page)) {
+                       EXOFS_ERR("ERROR: "
+                                  "bad page in #%lu",
+                                  inode->i_ino);
+                       filp->f_pos += PAGE_CACHE_SIZE - offset;
+                       return PTR_ERR(page);
+               }
+               kaddr = page_address(page);
+               if (unlikely(need_revalidate)) {
+                       if (offset) {
+                               offset = exofs_validate_entry(kaddr, offset,
+                                                               chunk_mask);
+                               filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
+                       }
+                       filp->f_version = inode->i_version;
+                       need_revalidate = 0;
+               }
+               de = (struct exofs_dir_entry *)(kaddr + offset);
+               limit = kaddr + exofs_last_byte(inode, n) -
+                                                       EXOFS_DIR_REC_LEN(1);
+               for (; (char *)de <= limit; de = exofs_next_entry(de)) {
+                       if (de->rec_len == 0) {
+                               EXOFS_ERR("ERROR: "
+                                       "zero-length directory entry");
+                               exofs_put_page(page);
+                               return -EIO;
+                       }
+                       if (de->inode_no) {
+                               int over;
+                               unsigned char d_type = DT_UNKNOWN;
+
+                               if (types && de->file_type < EXOFS_FT_MAX)
+                                       d_type = types[de->file_type];
+
+                               offset = (char *)de - kaddr;
+                               over = filldir(dirent, de->name, de->name_len,
+                                               (n<<PAGE_CACHE_SHIFT) | offset,
+                                               le64_to_cpu(de->inode_no),
+                                               d_type);
+                               if (over) {
+                                       exofs_put_page(page);
+                                       return 0;
+                               }
+                       }
+                       filp->f_pos += le16_to_cpu(de->rec_len);
+               }
+               exofs_put_page(page);
+       }
+
+       return 0;
+}
+
+struct exofs_dir_entry *exofs_find_entry(struct inode *dir,
+                       struct dentry *dentry, struct page **res_page)
+{
+       const unsigned char *name = dentry->d_name.name;
+       int namelen = dentry->d_name.len;
+       unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
+       unsigned long start, n;
+       unsigned long npages = dir_pages(dir);
+       struct page *page = NULL;
+       struct exofs_i_info *oi = exofs_i(dir);
+       struct exofs_dir_entry *de;
+
+       if (npages == 0)
+               goto out;
+
+       *res_page = NULL;
+
+       start = oi->i_dir_start_lookup;
+       if (start >= npages)
+               start = 0;
+       n = start;
+       do {
+               char *kaddr;
+               page = exofs_get_page(dir, n);
+               if (!IS_ERR(page)) {
+                       kaddr = page_address(page);
+                       de = (struct exofs_dir_entry *) kaddr;
+                       kaddr += exofs_last_byte(dir, n) - reclen;
+                       while ((char *) de <= kaddr) {
+                               if (de->rec_len == 0) {
+                                       EXOFS_ERR(
+                                               "ERROR: exofs_find_entry: "
+                                               "zero-length directory entry");
+                                       exofs_put_page(page);
+                                       goto out;
+                               }
+                               if (exofs_match(namelen, name, de))
+                                       goto found;
+                               de = exofs_next_entry(de);
+                       }
+                       exofs_put_page(page);
+               }
+               if (++n >= npages)
+                       n = 0;
+       } while (n != start);
+out:
+       return NULL;
+
+found:
+       *res_page = page;
+       oi->i_dir_start_lookup = n;
+       return de;
+}
+
+struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p)
+{
+       struct page *page = exofs_get_page(dir, 0);
+       struct exofs_dir_entry *de = NULL;
+
+       if (!IS_ERR(page)) {
+               de = exofs_next_entry(
+                               (struct exofs_dir_entry *)page_address(page));
+               *p = page;
+       }
+       return de;
+}
+
+ino_t exofs_parent_ino(struct dentry *child)
+{
+       struct page *page;
+       struct exofs_dir_entry *de;
+       ino_t ino;
+
+       de = exofs_dotdot(child->d_inode, &page);
+       if (!de)
+               return 0;
+
+       ino = le64_to_cpu(de->inode_no);
+       exofs_put_page(page);
+       return ino;
+}
+
+ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry)
+{
+       ino_t res = 0;
+       struct exofs_dir_entry *de;
+       struct page *page;
+
+       de = exofs_find_entry(dir, dentry, &page);
+       if (de) {
+               res = le64_to_cpu(de->inode_no);
+               exofs_put_page(page);
+       }
+       return res;
+}
+
+int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de,
+                       struct page *page, struct inode *inode)
+{
+       loff_t pos = page_offset(page) +
+                       (char *) de - (char *) page_address(page);
+       unsigned len = le16_to_cpu(de->rec_len);
+       int err;
+
+       lock_page(page);
+       err = exofs_write_begin(NULL, page->mapping, pos, len,
+                               AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+       if (err)
+               EXOFS_ERR("exofs_set_link: exofs_write_begin FAILD => %d\n",
+                         err);
+
+       de->inode_no = cpu_to_le64(inode->i_ino);
+       exofs_set_de_type(de, inode);
+       if (likely(!err))
+               err = exofs_commit_chunk(page, pos, len);
+       exofs_put_page(page);
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(dir);
+       return err;
+}
+
+int exofs_add_link(struct dentry *dentry, struct inode *inode)
+{
+       struct inode *dir = dentry->d_parent->d_inode;
+       const unsigned char *name = dentry->d_name.name;
+       int namelen = dentry->d_name.len;
+       unsigned chunk_size = exofs_chunk_size(dir);
+       unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
+       unsigned short rec_len, name_len;
+       struct page *page = NULL;
+       struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
+       struct exofs_dir_entry *de;
+       unsigned long npages = dir_pages(dir);
+       unsigned long n;
+       char *kaddr;
+       loff_t pos;
+       int err;
+
+       for (n = 0; n <= npages; n++) {
+               char *dir_end;
+
+               page = exofs_get_page(dir, n);
+               err = PTR_ERR(page);
+               if (IS_ERR(page))
+                       goto out;
+               lock_page(page);
+               kaddr = page_address(page);
+               dir_end = kaddr + exofs_last_byte(dir, n);
+               de = (struct exofs_dir_entry *)kaddr;
+               kaddr += PAGE_CACHE_SIZE - reclen;
+               while ((char *)de <= kaddr) {
+                       if ((char *)de == dir_end) {
+                               name_len = 0;
+                               rec_len = chunk_size;
+                               de->rec_len = cpu_to_le16(chunk_size);
+                               de->inode_no = 0;
+                               goto got_it;
+                       }
+                       if (de->rec_len == 0) {
+                               EXOFS_ERR("ERROR: exofs_add_link: "
+                                       "zero-length directory entry");
+                               err = -EIO;
+                               goto out_unlock;
+                       }
+                       err = -EEXIST;
+                       if (exofs_match(namelen, name, de))
+                               goto out_unlock;
+                       name_len = EXOFS_DIR_REC_LEN(de->name_len);
+                       rec_len = le16_to_cpu(de->rec_len);
+                       if (!de->inode_no && rec_len >= reclen)
+                               goto got_it;
+                       if (rec_len >= name_len + reclen)
+                               goto got_it;
+                       de = (struct exofs_dir_entry *) ((char *) de + rec_len);
+               }
+               unlock_page(page);
+               exofs_put_page(page);
+       }
+
+       EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=%p", dentry, inode);
+       return -EINVAL;
+
+got_it:
+       pos = page_offset(page) +
+               (char *)de - (char *)page_address(page);
+       err = exofs_write_begin(NULL, page->mapping, pos, rec_len, 0,
+                                                       &page, NULL);
+       if (err)
+               goto out_unlock;
+       if (de->inode_no) {
+               struct exofs_dir_entry *de1 =
+                       (struct exofs_dir_entry *)((char *)de + name_len);
+               de1->rec_len = cpu_to_le16(rec_len - name_len);
+               de->rec_len = cpu_to_le16(name_len);
+               de = de1;
+       }
+       de->name_len = namelen;
+       memcpy(de->name, name, namelen);
+       de->inode_no = cpu_to_le64(inode->i_ino);
+       exofs_set_de_type(de, inode);
+       err = exofs_commit_chunk(page, pos, rec_len);
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(dir);
+       sbi->s_numfiles++;
+
+out_put:
+       exofs_put_page(page);
+out:
+       return err;
+out_unlock:
+       unlock_page(page);
+       goto out_put;
+}
+
+int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
+       char *kaddr = page_address(page);
+       unsigned from = ((char *)dir - kaddr) & ~(exofs_chunk_size(inode)-1);
+       unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len);
+       loff_t pos;
+       struct exofs_dir_entry *pde = NULL;
+       struct exofs_dir_entry *de = (struct exofs_dir_entry *) (kaddr + from);
+       int err;
+
+       while (de < dir) {
+               if (de->rec_len == 0) {
+                       EXOFS_ERR("ERROR: exofs_delete_entry:"
+                               "zero-length directory entry");
+                       err = -EIO;
+                       goto out;
+               }
+               pde = de;
+               de = exofs_next_entry(de);
+       }
+       if (pde)
+               from = (char *)pde - (char *)page_address(page);
+       pos = page_offset(page) + from;
+       lock_page(page);
+       err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0,
+                                                       &page, NULL);
+       if (err)
+               EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILD => %d\n",
+                         err);
+       if (pde)
+               pde->rec_len = cpu_to_le16(to - from);
+       dir->inode_no = 0;
+       if (likely(!err))
+               err = exofs_commit_chunk(page, pos, to - from);
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+       mark_inode_dirty(inode);
+       sbi->s_numfiles--;
+out:
+       exofs_put_page(page);
+       return err;
+}
+
+/* kept aligned on 4 bytes */
+#define THIS_DIR ".\0\0"
+#define PARENT_DIR "..\0"
+
+int exofs_make_empty(struct inode *inode, struct inode *parent)
+{
+       struct address_space *mapping = inode->i_mapping;
+       struct page *page = grab_cache_page(mapping, 0);
+       unsigned chunk_size = exofs_chunk_size(inode);
+       struct exofs_dir_entry *de;
+       int err;
+       void *kaddr;
+
+       if (!page)
+               return -ENOMEM;
+
+       err = exofs_write_begin(NULL, page->mapping, 0, chunk_size, 0,
+                                                       &page, NULL);
+       if (err) {
+               unlock_page(page);
+               goto fail;
+       }
+
+       kaddr = kmap_atomic(page, KM_USER0);
+       de = (struct exofs_dir_entry *)kaddr;
+       de->name_len = 1;
+       de->rec_len = cpu_to_le16(EXOFS_DIR_REC_LEN(1));
+       memcpy(de->name, THIS_DIR, sizeof(THIS_DIR));
+       de->inode_no = cpu_to_le64(inode->i_ino);
+       exofs_set_de_type(de, inode);
+
+       de = (struct exofs_dir_entry *)(kaddr + EXOFS_DIR_REC_LEN(1));
+       de->name_len = 2;
+       de->rec_len = cpu_to_le16(chunk_size - EXOFS_DIR_REC_LEN(1));
+       de->inode_no = cpu_to_le64(parent->i_ino);
+       memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR));
+       exofs_set_de_type(de, inode);
+       kunmap_atomic(page, KM_USER0);
+       err = exofs_commit_chunk(page, 0, chunk_size);
+fail:
+       page_cache_release(page);
+       return err;
+}
+
+int exofs_empty_dir(struct inode *inode)
+{
+       struct page *page = NULL;
+       unsigned long i, npages = dir_pages(inode);
+
+       for (i = 0; i < npages; i++) {
+               char *kaddr;
+               struct exofs_dir_entry *de;
+               page = exofs_get_page(inode, i);
+
+               if (IS_ERR(page))
+                       continue;
+
+               kaddr = page_address(page);
+               de = (struct exofs_dir_entry *)kaddr;
+               kaddr += exofs_last_byte(inode, i) - EXOFS_DIR_REC_LEN(1);
+
+               while ((char *)de <= kaddr) {
+                       if (de->rec_len == 0) {
+                               EXOFS_ERR("ERROR: exofs_empty_dir: "
+                                         "zero-length directory entry"
+                                         "kaddr=%p, de=%p\n", kaddr, de);
+                               goto not_empty;
+                       }
+                       if (de->inode_no != 0) {
+                               /* check for . and .. */
+                               if (de->name[0] != '.')
+                                       goto not_empty;
+                               if (de->name_len > 2)
+                                       goto not_empty;
+                               if (de->name_len < 2) {
+                                       if (le64_to_cpu(de->inode_no) !=
+                                           inode->i_ino)
+                                               goto not_empty;
+                               } else if (de->name[1] != '.')
+                                       goto not_empty;
+                       }
+                       de = exofs_next_entry(de);
+               }
+               exofs_put_page(page);
+       }
+       return 1;
+
+not_empty:
+       exofs_put_page(page);
+       return 0;
+}
+
+const struct file_operations exofs_dir_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+       .readdir        = exofs_readdir,
+};
diff --git a/fs/exofs/exofs.h b/fs/exofs/exofs.h
new file mode 100644 (file)
index 0000000..0fd4c78
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/fs.h>
+#include <linux/time.h>
+#include "common.h"
+
+#ifndef __EXOFS_H__
+#define __EXOFS_H__
+
+#define EXOFS_ERR(fmt, a...) printk(KERN_ERR "exofs: " fmt, ##a)
+
+#ifdef CONFIG_EXOFS_DEBUG
+#define EXOFS_DBGMSG(fmt, a...) \
+       printk(KERN_NOTICE "exofs @%s:%d: " fmt, __func__, __LINE__, ##a)
+#else
+#define EXOFS_DBGMSG(fmt, a...) \
+       do { if (0) printk(fmt, ##a); } while (0)
+#endif
+
+/* u64 has problems with printk this will cast it to unsigned long long */
+#define _LLU(x) (unsigned long long)(x)
+
+/*
+ * our extension to the in-memory superblock
+ */
+struct exofs_sb_info {
+       struct osd_dev  *s_dev;                 /* returned by get_osd_dev    */
+       osd_id          s_pid;                  /* partition ID of file system*/
+       int             s_timeout;              /* timeout for OSD operations */
+       uint64_t        s_nextid;               /* highest object ID used     */
+       uint32_t        s_numfiles;             /* number of files on fs      */
+       spinlock_t      s_next_gen_lock;        /* spinlock for gen # update  */
+       u32             s_next_generation;      /* next gen # to use          */
+       atomic_t        s_curr_pending;         /* number of pending commands */
+       uint8_t         s_cred[OSD_CAP_LEN];    /* all-powerful credential    */
+};
+
+/*
+ * our extension to the in-memory inode
+ */
+struct exofs_i_info {
+       unsigned long  i_flags;            /* various atomic flags            */
+       uint32_t       i_data[EXOFS_IDATA];/*short symlink names and device #s*/
+       uint32_t       i_dir_start_lookup; /* which page to start lookup      */
+       wait_queue_head_t i_wq;            /* wait queue for inode            */
+       uint64_t       i_commit_size;      /* the object's written length     */
+       uint8_t        i_cred[OSD_CAP_LEN];/* all-powerful credential         */
+       struct inode   vfs_inode;          /* normal in-memory inode          */
+};
+
+/*
+ * our inode flags
+ */
+#define OBJ_2BCREATED  0       /* object will be created soon*/
+#define OBJ_CREATED    1       /* object has been created on the osd*/
+
+static inline int obj_2bcreated(struct exofs_i_info *oi)
+{
+       return test_bit(OBJ_2BCREATED, &oi->i_flags);
+}
+
+static inline void set_obj_2bcreated(struct exofs_i_info *oi)
+{
+       set_bit(OBJ_2BCREATED, &oi->i_flags);
+}
+
+static inline int obj_created(struct exofs_i_info *oi)
+{
+       return test_bit(OBJ_CREATED, &oi->i_flags);
+}
+
+static inline void set_obj_created(struct exofs_i_info *oi)
+{
+       set_bit(OBJ_CREATED, &oi->i_flags);
+}
+
+int __exofs_wait_obj_created(struct exofs_i_info *oi);
+static inline int wait_obj_created(struct exofs_i_info *oi)
+{
+       if (likely(obj_created(oi)))
+               return 0;
+
+       return __exofs_wait_obj_created(oi);
+}
+
+/*
+ * get to our inode from the vfs inode
+ */
+static inline struct exofs_i_info *exofs_i(struct inode *inode)
+{
+       return container_of(inode, struct exofs_i_info, vfs_inode);
+}
+
+/*
+ * Maximum count of links to a file
+ */
+#define EXOFS_LINK_MAX           32000
+
+/*************************
+ * function declarations *
+ *************************/
+/* inode.c               */
+void exofs_truncate(struct inode *inode);
+int exofs_setattr(struct dentry *, struct iattr *);
+int exofs_write_begin(struct file *file, struct address_space *mapping,
+               loff_t pos, unsigned len, unsigned flags,
+               struct page **pagep, void **fsdata);
+extern struct inode *exofs_iget(struct super_block *, unsigned long);
+struct inode *exofs_new_inode(struct inode *, int);
+extern int exofs_write_inode(struct inode *, int);
+extern void exofs_delete_inode(struct inode *);
+
+/* dir.c:                */
+int exofs_add_link(struct dentry *, struct inode *);
+ino_t exofs_inode_by_name(struct inode *, struct dentry *);
+int exofs_delete_entry(struct exofs_dir_entry *, struct page *);
+int exofs_make_empty(struct inode *, struct inode *);
+struct exofs_dir_entry *exofs_find_entry(struct inode *, struct dentry *,
+                                        struct page **);
+int exofs_empty_dir(struct inode *);
+struct exofs_dir_entry *exofs_dotdot(struct inode *, struct page **);
+ino_t exofs_parent_ino(struct dentry *child);
+int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
+                   struct inode *);
+
+/*********************
+ * operation vectors *
+ *********************/
+/* dir.c:            */
+extern const struct file_operations exofs_dir_operations;
+
+/* file.c            */
+extern const struct inode_operations exofs_file_inode_operations;
+extern const struct file_operations exofs_file_operations;
+
+/* inode.c           */
+extern const struct address_space_operations exofs_aops;
+
+/* namei.c           */
+extern const struct inode_operations exofs_dir_inode_operations;
+extern const struct inode_operations exofs_special_inode_operations;
+
+/* symlink.c         */
+extern const struct inode_operations exofs_symlink_inode_operations;
+extern const struct inode_operations exofs_fast_symlink_inode_operations;
+
+#endif
diff --git a/fs/exofs/file.c b/fs/exofs/file.c
new file mode 100644 (file)
index 0000000..6ed7fe4
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/buffer_head.h>
+
+#include "exofs.h"
+
+static int exofs_release_file(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
+                           int datasync)
+{
+       int ret;
+       struct address_space *mapping = filp->f_mapping;
+
+       ret = filemap_write_and_wait(mapping);
+       if (ret)
+               return ret;
+
+       /*Note: file_fsync below also calles sync_blockdev, which is a no-op
+        *      for exofs, but other then that it does sync_inode and
+        *      sync_superblock which is what we need here.
+        */
+       return file_fsync(filp, dentry, datasync);
+}
+
+static int exofs_flush(struct file *file, fl_owner_t id)
+{
+       exofs_file_fsync(file, file->f_path.dentry, 1);
+       /* TODO: Flush the OSD target */
+       return 0;
+}
+
+const struct file_operations exofs_file_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = do_sync_read,
+       .write          = do_sync_write,
+       .aio_read       = generic_file_aio_read,
+       .aio_write      = generic_file_aio_write,
+       .mmap           = generic_file_mmap,
+       .open           = generic_file_open,
+       .release        = exofs_release_file,
+       .fsync          = exofs_file_fsync,
+       .flush          = exofs_flush,
+       .splice_read    = generic_file_splice_read,
+       .splice_write   = generic_file_splice_write,
+};
+
+const struct inode_operations exofs_file_inode_operations = {
+       .truncate       = exofs_truncate,
+       .setattr        = exofs_setattr,
+};
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
new file mode 100644 (file)
index 0000000..ba8d9fa
--- /dev/null
@@ -0,0 +1,1303 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/writeback.h>
+#include <linux/buffer_head.h>
+#include <scsi/scsi_device.h>
+
+#include "exofs.h"
+
+#ifdef CONFIG_EXOFS_DEBUG
+#  define EXOFS_DEBUG_OBJ_ISIZE 1
+#endif
+
+struct page_collect {
+       struct exofs_sb_info *sbi;
+       struct request_queue *req_q;
+       struct inode *inode;
+       unsigned expected_pages;
+
+       struct bio *bio;
+       unsigned nr_pages;
+       unsigned long length;
+       loff_t pg_first; /* keep 64bit also in 32-arches */
+};
+
+static void _pcol_init(struct page_collect *pcol, unsigned expected_pages,
+               struct inode *inode)
+{
+       struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
+       struct request_queue *req_q = sbi->s_dev->scsi_device->request_queue;
+
+       pcol->sbi = sbi;
+       pcol->req_q = req_q;
+       pcol->inode = inode;
+       pcol->expected_pages = expected_pages;
+
+       pcol->bio = NULL;
+       pcol->nr_pages = 0;
+       pcol->length = 0;
+       pcol->pg_first = -1;
+
+       EXOFS_DBGMSG("_pcol_init ino=0x%lx expected_pages=%u\n", inode->i_ino,
+                    expected_pages);
+}
+
+static void _pcol_reset(struct page_collect *pcol)
+{
+       pcol->expected_pages -= min(pcol->nr_pages, pcol->expected_pages);
+
+       pcol->bio = NULL;
+       pcol->nr_pages = 0;
+       pcol->length = 0;
+       pcol->pg_first = -1;
+       EXOFS_DBGMSG("_pcol_reset ino=0x%lx expected_pages=%u\n",
+                    pcol->inode->i_ino, pcol->expected_pages);
+
+       /* this is probably the end of the loop but in writes
+        * it might not end here. don't be left with nothing
+        */
+       if (!pcol->expected_pages)
+               pcol->expected_pages = 128;
+}
+
+static int pcol_try_alloc(struct page_collect *pcol)
+{
+       int pages = min_t(unsigned, pcol->expected_pages, BIO_MAX_PAGES);
+
+       for (; pages; pages >>= 1) {
+               pcol->bio = bio_alloc(GFP_KERNEL, pages);
+               if (likely(pcol->bio))
+                       return 0;
+       }
+
+       EXOFS_ERR("Failed to kcalloc expected_pages=%u\n",
+                 pcol->expected_pages);
+       return -ENOMEM;
+}
+
+static void pcol_free(struct page_collect *pcol)
+{
+       bio_put(pcol->bio);
+       pcol->bio = NULL;
+}
+
+static int pcol_add_page(struct page_collect *pcol, struct page *page,
+                        unsigned len)
+{
+       int added_len = bio_add_pc_page(pcol->req_q, pcol->bio, page, len, 0);
+       if (unlikely(len != added_len))
+               return -ENOMEM;
+
+       ++pcol->nr_pages;
+       pcol->length += len;
+       return 0;
+}
+
+static int update_read_page(struct page *page, int ret)
+{
+       if (ret == 0) {
+               /* Everything is OK */
+               SetPageUptodate(page);
+               if (PageError(page))
+                       ClearPageError(page);
+       } else if (ret == -EFAULT) {
+               /* In this case we were trying to read something that wasn't on
+                * disk yet - return a page full of zeroes.  This should be OK,
+                * because the object should be empty (if there was a write
+                * before this read, the read would be waiting with the page
+                * locked */
+               clear_highpage(page);
+
+               SetPageUptodate(page);
+               if (PageError(page))
+                       ClearPageError(page);
+               ret = 0; /* recovered error */
+               EXOFS_DBGMSG("recovered read error\n");
+       } else /* Error */
+               SetPageError(page);
+
+       return ret;
+}
+
+static void update_write_page(struct page *page, int ret)
+{
+       if (ret) {
+               mapping_set_error(page->mapping, ret);
+               SetPageError(page);
+       }
+       end_page_writeback(page);
+}
+
+/* Called at the end of reads, to optionally unlock pages and update their
+ * status.
+ */
+static int __readpages_done(struct osd_request *or, struct page_collect *pcol,
+                           bool do_unlock)
+{
+       struct bio_vec *bvec;
+       int i;
+       u64 resid;
+       u64 good_bytes;
+       u64 length = 0;
+       int ret = exofs_check_ok_resid(or, &resid, NULL);
+
+       osd_end_request(or);
+
+       if (likely(!ret))
+               good_bytes = pcol->length;
+       else if (!resid)
+               good_bytes = 0;
+       else
+               good_bytes = pcol->length - resid;
+
+       EXOFS_DBGMSG("readpages_done(0x%lx) good_bytes=0x%llx"
+                    " length=0x%lx nr_pages=%u\n",
+                    pcol->inode->i_ino, _LLU(good_bytes), pcol->length,
+                    pcol->nr_pages);
+
+       __bio_for_each_segment(bvec, pcol->bio, i, 0) {
+               struct page *page = bvec->bv_page;
+               struct inode *inode = page->mapping->host;
+               int page_stat;
+
+               if (inode != pcol->inode)
+                       continue; /* osd might add more pages at end */
+
+               if (likely(length < good_bytes))
+                       page_stat = 0;
+               else
+                       page_stat = ret;
+
+               EXOFS_DBGMSG("    readpages_done(0x%lx, 0x%lx) %s\n",
+                         inode->i_ino, page->index,
+                         page_stat ? "bad_bytes" : "good_bytes");
+
+               ret = update_read_page(page, page_stat);
+               if (do_unlock)
+                       unlock_page(page);
+               length += bvec->bv_len;
+       }
+
+       pcol_free(pcol);
+       EXOFS_DBGMSG("readpages_done END\n");
+       return ret;
+}
+
+/* callback of async reads */
+static void readpages_done(struct osd_request *or, void *p)
+{
+       struct page_collect *pcol = p;
+
+       __readpages_done(or, pcol, true);
+       atomic_dec(&pcol->sbi->s_curr_pending);
+       kfree(p);
+}
+
+static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw)
+{
+       struct bio_vec *bvec;
+       int i;
+
+       __bio_for_each_segment(bvec, pcol->bio, i, 0) {
+               struct page *page = bvec->bv_page;
+
+               if (rw == READ)
+                       update_read_page(page, ret);
+               else
+                       update_write_page(page, ret);
+
+               unlock_page(page);
+       }
+       pcol_free(pcol);
+}
+
+static int read_exec(struct page_collect *pcol, bool is_sync)
+{
+       struct exofs_i_info *oi = exofs_i(pcol->inode);
+       struct osd_obj_id obj = {pcol->sbi->s_pid,
+                                       pcol->inode->i_ino + EXOFS_OBJ_OFF};
+       struct osd_request *or = NULL;
+       struct page_collect *pcol_copy = NULL;
+       loff_t i_start = pcol->pg_first << PAGE_CACHE_SHIFT;
+       int ret;
+
+       if (!pcol->bio)
+               return 0;
+
+       /* see comment in _readpage() about sync reads */
+       WARN_ON(is_sync && (pcol->nr_pages != 1));
+
+       or = osd_start_request(pcol->sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       osd_req_read(or, &obj, pcol->bio, i_start);
+
+       if (is_sync) {
+               exofs_sync_op(or, pcol->sbi->s_timeout, oi->i_cred);
+               return __readpages_done(or, pcol, false);
+       }
+
+       pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
+       if (!pcol_copy) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       *pcol_copy = *pcol;
+       ret = exofs_async_op(or, readpages_done, pcol_copy, oi->i_cred);
+       if (unlikely(ret))
+               goto err;
+
+       atomic_inc(&pcol->sbi->s_curr_pending);
+
+       EXOFS_DBGMSG("read_exec obj=0x%llx start=0x%llx length=0x%lx\n",
+                 obj.id, _LLU(i_start), pcol->length);
+
+       /* pages ownership was passed to pcol_copy */
+       _pcol_reset(pcol);
+       return 0;
+
+err:
+       if (!is_sync)
+               _unlock_pcol_pages(pcol, ret, READ);
+       kfree(pcol_copy);
+       if (or)
+               osd_end_request(or);
+       return ret;
+}
+
+/* readpage_strip is called either directly from readpage() or by the VFS from
+ * within read_cache_pages(), to add one more page to be read. It will try to
+ * collect as many contiguous pages as posible. If a discontinuity is
+ * encountered, or it runs out of resources, it will submit the previous segment
+ * and will start a new collection. Eventually caller must submit the last
+ * segment if present.
+ */
+static int readpage_strip(void *data, struct page *page)
+{
+       struct page_collect *pcol = data;
+       struct inode *inode = pcol->inode;
+       struct exofs_i_info *oi = exofs_i(inode);
+       loff_t i_size = i_size_read(inode);
+       pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+       size_t len;
+       int ret;
+
+       /* FIXME: Just for debugging, will be removed */
+       if (PageUptodate(page))
+               EXOFS_ERR("PageUptodate(0x%lx, 0x%lx)\n", pcol->inode->i_ino,
+                         page->index);
+
+       if (page->index < end_index)
+               len = PAGE_CACHE_SIZE;
+       else if (page->index == end_index)
+               len = i_size & ~PAGE_CACHE_MASK;
+       else
+               len = 0;
+
+       if (!len || !obj_created(oi)) {
+               /* this will be out of bounds, or doesn't exist yet.
+                * Current page is cleared and the request is split
+                */
+               clear_highpage(page);
+
+               SetPageUptodate(page);
+               if (PageError(page))
+                       ClearPageError(page);
+
+               unlock_page(page);
+               EXOFS_DBGMSG("readpage_strip(0x%lx, 0x%lx) empty page,"
+                            " splitting\n", inode->i_ino, page->index);
+
+               return read_exec(pcol, false);
+       }
+
+try_again:
+
+       if (unlikely(pcol->pg_first == -1)) {
+               pcol->pg_first = page->index;
+       } else if (unlikely((pcol->pg_first + pcol->nr_pages) !=
+                  page->index)) {
+               /* Discontinuity detected, split the request */
+               ret = read_exec(pcol, false);
+               if (unlikely(ret))
+                       goto fail;
+               goto try_again;
+       }
+
+       if (!pcol->bio) {
+               ret = pcol_try_alloc(pcol);
+               if (unlikely(ret))
+                       goto fail;
+       }
+
+       if (len != PAGE_CACHE_SIZE)
+               zero_user(page, len, PAGE_CACHE_SIZE - len);
+
+       EXOFS_DBGMSG("    readpage_strip(0x%lx, 0x%lx) len=0x%zx\n",
+                    inode->i_ino, page->index, len);
+
+       ret = pcol_add_page(pcol, page, len);
+       if (ret) {
+               EXOFS_DBGMSG("Failed pcol_add_page pages[i]=%p "
+                         "this_len=0x%zx nr_pages=%u length=0x%lx\n",
+                         page, len, pcol->nr_pages, pcol->length);
+
+               /* split the request, and start again with current page */
+               ret = read_exec(pcol, false);
+               if (unlikely(ret))
+                       goto fail;
+
+               goto try_again;
+       }
+
+       return 0;
+
+fail:
+       /* SetPageError(page); ??? */
+       unlock_page(page);
+       return ret;
+}
+
+static int exofs_readpages(struct file *file, struct address_space *mapping,
+                          struct list_head *pages, unsigned nr_pages)
+{
+       struct page_collect pcol;
+       int ret;
+
+       _pcol_init(&pcol, nr_pages, mapping->host);
+
+       ret = read_cache_pages(mapping, pages, readpage_strip, &pcol);
+       if (ret) {
+               EXOFS_ERR("read_cache_pages => %d\n", ret);
+               return ret;
+       }
+
+       return read_exec(&pcol, false);
+}
+
+static int _readpage(struct page *page, bool is_sync)
+{
+       struct page_collect pcol;
+       int ret;
+
+       _pcol_init(&pcol, 1, page->mapping->host);
+
+       /* readpage_strip might call read_exec(,async) inside at several places
+        * but this is safe for is_async=0 since read_exec will not do anything
+        * when we have a single page.
+        */
+       ret = readpage_strip(&pcol, page);
+       if (ret) {
+               EXOFS_ERR("_readpage => %d\n", ret);
+               return ret;
+       }
+
+       return read_exec(&pcol, is_sync);
+}
+
+/*
+ * We don't need the file
+ */
+static int exofs_readpage(struct file *file, struct page *page)
+{
+       return _readpage(page, false);
+}
+
+/* Callback for osd_write. All writes are asynchronouse */
+static void writepages_done(struct osd_request *or, void *p)
+{
+       struct page_collect *pcol = p;
+       struct bio_vec *bvec;
+       int i;
+       u64 resid;
+       u64  good_bytes;
+       u64  length = 0;
+
+       int ret = exofs_check_ok_resid(or, NULL, &resid);
+
+       osd_end_request(or);
+       atomic_dec(&pcol->sbi->s_curr_pending);
+
+       if (likely(!ret))
+               good_bytes = pcol->length;
+       else if (!resid)
+               good_bytes = 0;
+       else
+               good_bytes = pcol->length - resid;
+
+       EXOFS_DBGMSG("writepages_done(0x%lx) good_bytes=0x%llx"
+                    " length=0x%lx nr_pages=%u\n",
+                    pcol->inode->i_ino, _LLU(good_bytes), pcol->length,
+                    pcol->nr_pages);
+
+       __bio_for_each_segment(bvec, pcol->bio, i, 0) {
+               struct page *page = bvec->bv_page;
+               struct inode *inode = page->mapping->host;
+               int page_stat;
+
+               if (inode != pcol->inode)
+                       continue; /* osd might add more pages to a bio */
+
+               if (likely(length < good_bytes))
+                       page_stat = 0;
+               else
+                       page_stat = ret;
+
+               update_write_page(page, page_stat);
+               unlock_page(page);
+               EXOFS_DBGMSG("    writepages_done(0x%lx, 0x%lx) status=%d\n",
+                            inode->i_ino, page->index, page_stat);
+
+               length += bvec->bv_len;
+       }
+
+       pcol_free(pcol);
+       kfree(pcol);
+       EXOFS_DBGMSG("writepages_done END\n");
+}
+
+static int write_exec(struct page_collect *pcol)
+{
+       struct exofs_i_info *oi = exofs_i(pcol->inode);
+       struct osd_obj_id obj = {pcol->sbi->s_pid,
+                                       pcol->inode->i_ino + EXOFS_OBJ_OFF};
+       struct osd_request *or = NULL;
+       struct page_collect *pcol_copy = NULL;
+       loff_t i_start = pcol->pg_first << PAGE_CACHE_SHIFT;
+       int ret;
+
+       if (!pcol->bio)
+               return 0;
+
+       or = osd_start_request(pcol->sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_ERR("write_exec: Faild to osd_start_request()\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
+       if (!pcol_copy) {
+               EXOFS_ERR("write_exec: Faild to kmalloc(pcol)\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       *pcol_copy = *pcol;
+
+       osd_req_write(or, &obj, pcol_copy->bio, i_start);
+       ret = exofs_async_op(or, writepages_done, pcol_copy, oi->i_cred);
+       if (unlikely(ret)) {
+               EXOFS_ERR("write_exec: exofs_async_op() Faild\n");
+               goto err;
+       }
+
+       atomic_inc(&pcol->sbi->s_curr_pending);
+       EXOFS_DBGMSG("write_exec(0x%lx, 0x%llx) start=0x%llx length=0x%lx\n",
+                 pcol->inode->i_ino, pcol->pg_first, _LLU(i_start),
+                 pcol->length);
+       /* pages ownership was passed to pcol_copy */
+       _pcol_reset(pcol);
+       return 0;
+
+err:
+       _unlock_pcol_pages(pcol, ret, WRITE);
+       kfree(pcol_copy);
+       if (or)
+               osd_end_request(or);
+       return ret;
+}
+
+/* writepage_strip is called either directly from writepage() or by the VFS from
+ * within write_cache_pages(), to add one more page to be written to storage.
+ * It will try to collect as many contiguous pages as possible. If a
+ * discontinuity is encountered or it runs out of resources it will submit the
+ * previous segment and will start a new collection.
+ * Eventually caller must submit the last segment if present.
+ */
+static int writepage_strip(struct page *page,
+                          struct writeback_control *wbc_unused, void *data)
+{
+       struct page_collect *pcol = data;
+       struct inode *inode = pcol->inode;
+       struct exofs_i_info *oi = exofs_i(inode);
+       loff_t i_size = i_size_read(inode);
+       pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+       size_t len;
+       int ret;
+
+       BUG_ON(!PageLocked(page));
+
+       ret = wait_obj_created(oi);
+       if (unlikely(ret))
+               goto fail;
+
+       if (page->index < end_index)
+               /* in this case, the page is within the limits of the file */
+               len = PAGE_CACHE_SIZE;
+       else {
+               len = i_size & ~PAGE_CACHE_MASK;
+
+               if (page->index > end_index || !len) {
+                       /* in this case, the page is outside the limits
+                        * (truncate in progress)
+                        */
+                       ret = write_exec(pcol);
+                       if (unlikely(ret))
+                               goto fail;
+                       if (PageError(page))
+                               ClearPageError(page);
+                       unlock_page(page);
+                       return 0;
+               }
+       }
+
+try_again:
+
+       if (unlikely(pcol->pg_first == -1)) {
+               pcol->pg_first = page->index;
+       } else if (unlikely((pcol->pg_first + pcol->nr_pages) !=
+                  page->index)) {
+               /* Discontinuity detected, split the request */
+               ret = write_exec(pcol);
+               if (unlikely(ret))
+                       goto fail;
+               goto try_again;
+       }
+
+       if (!pcol->bio) {
+               ret = pcol_try_alloc(pcol);
+               if (unlikely(ret))
+                       goto fail;
+       }
+
+       EXOFS_DBGMSG("    writepage_strip(0x%lx, 0x%lx) len=0x%zx\n",
+                    inode->i_ino, page->index, len);
+
+       ret = pcol_add_page(pcol, page, len);
+       if (unlikely(ret)) {
+               EXOFS_DBGMSG("Failed pcol_add_page "
+                            "nr_pages=%u total_length=0x%lx\n",
+                            pcol->nr_pages, pcol->length);
+
+               /* split the request, next loop will start again */
+               ret = write_exec(pcol);
+               if (unlikely(ret)) {
+                       EXOFS_DBGMSG("write_exec faild => %d", ret);
+                       goto fail;
+               }
+
+               goto try_again;
+       }
+
+       BUG_ON(PageWriteback(page));
+       set_page_writeback(page);
+
+       return 0;
+
+fail:
+       set_bit(AS_EIO, &page->mapping->flags);
+       unlock_page(page);
+       return ret;
+}
+
+static int exofs_writepages(struct address_space *mapping,
+                      struct writeback_control *wbc)
+{
+       struct page_collect pcol;
+       long start, end, expected_pages;
+       int ret;
+
+       start = wbc->range_start >> PAGE_CACHE_SHIFT;
+       end = (wbc->range_end == LLONG_MAX) ?
+                       start + mapping->nrpages :
+                       wbc->range_end >> PAGE_CACHE_SHIFT;
+
+       if (start || end)
+               expected_pages = min(end - start + 1, 32L);
+       else
+               expected_pages = mapping->nrpages;
+
+       EXOFS_DBGMSG("inode(0x%lx) wbc->start=0x%llx wbc->end=0x%llx"
+                    " m->nrpages=%lu start=0x%lx end=0x%lx\n",
+                    mapping->host->i_ino, wbc->range_start, wbc->range_end,
+                    mapping->nrpages, start, end);
+
+       _pcol_init(&pcol, expected_pages, mapping->host);
+
+       ret = write_cache_pages(mapping, wbc, writepage_strip, &pcol);
+       if (ret) {
+               EXOFS_ERR("write_cache_pages => %d\n", ret);
+               return ret;
+       }
+
+       return write_exec(&pcol);
+}
+
+static int exofs_writepage(struct page *page, struct writeback_control *wbc)
+{
+       struct page_collect pcol;
+       int ret;
+
+       _pcol_init(&pcol, 1, page->mapping->host);
+
+       ret = writepage_strip(page, NULL, &pcol);
+       if (ret) {
+               EXOFS_ERR("exofs_writepage => %d\n", ret);
+               return ret;
+       }
+
+       return write_exec(&pcol);
+}
+
+int exofs_write_begin(struct file *file, struct address_space *mapping,
+               loff_t pos, unsigned len, unsigned flags,
+               struct page **pagep, void **fsdata)
+{
+       int ret = 0;
+       struct page *page;
+
+       page = *pagep;
+       if (page == NULL) {
+               ret = simple_write_begin(file, mapping, pos, len, flags, pagep,
+                                        fsdata);
+               if (ret) {
+                       EXOFS_DBGMSG("simple_write_begin faild\n");
+                       return ret;
+               }
+
+               page = *pagep;
+       }
+
+        /* read modify write */
+       if (!PageUptodate(page) && (len != PAGE_CACHE_SIZE)) {
+               ret = _readpage(page, true);
+               if (ret) {
+                       /*SetPageError was done by _readpage. Is it ok?*/
+                       unlock_page(page);
+                       EXOFS_DBGMSG("__readpage_filler faild\n");
+               }
+       }
+
+       return ret;
+}
+
+static int exofs_write_begin_export(struct file *file,
+               struct address_space *mapping,
+               loff_t pos, unsigned len, unsigned flags,
+               struct page **pagep, void **fsdata)
+{
+       *pagep = NULL;
+
+       return exofs_write_begin(file, mapping, pos, len, flags, pagep,
+                                       fsdata);
+}
+
+const struct address_space_operations exofs_aops = {
+       .readpage       = exofs_readpage,
+       .readpages      = exofs_readpages,
+       .writepage      = exofs_writepage,
+       .writepages     = exofs_writepages,
+       .write_begin    = exofs_write_begin_export,
+       .write_end      = simple_write_end,
+};
+
+/******************************************************************************
+ * INODE OPERATIONS
+ *****************************************************************************/
+
+/*
+ * Test whether an inode is a fast symlink.
+ */
+static inline int exofs_inode_is_fast_symlink(struct inode *inode)
+{
+       struct exofs_i_info *oi = exofs_i(inode);
+
+       return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0);
+}
+
+/*
+ * get_block_t - Fill in a buffer_head
+ * An OSD takes care of block allocation so we just fake an allocation by
+ * putting in the inode's sector_t in the buffer_head.
+ * TODO: What about the case of create==0 and @iblock does not exist in the
+ * object?
+ */
+static int exofs_get_block(struct inode *inode, sector_t iblock,
+                   struct buffer_head *bh_result, int create)
+{
+       map_bh(bh_result, inode->i_sb, iblock);
+       return 0;
+}
+
+const struct osd_attr g_attr_logical_length = ATTR_DEF(
+       OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
+
+/*
+ * Truncate a file to the specified size - all we have to do is set the size
+ * attribute.  We make sure the object exists first.
+ */
+void exofs_truncate(struct inode *inode)
+{
+       struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
+       struct exofs_i_info *oi = exofs_i(inode);
+       struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF};
+       struct osd_request *or;
+       struct osd_attr attr;
+       loff_t isize = i_size_read(inode);
+       __be64 newsize;
+       int ret;
+
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
+            || S_ISLNK(inode->i_mode)))
+               return;
+       if (exofs_inode_is_fast_symlink(inode))
+               return;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return;
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+
+       nobh_truncate_page(inode->i_mapping, isize, exofs_get_block);
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_ERR("ERROR: exofs_truncate: osd_start_request failed\n");
+               goto fail;
+       }
+
+       osd_req_set_attributes(or, &obj);
+
+       newsize = cpu_to_be64((u64)isize);
+       attr = g_attr_logical_length;
+       attr.val_ptr = &newsize;
+       osd_req_add_set_attr_list(or, &attr, 1);
+
+       /* if we are about to truncate an object, and it hasn't been
+        * created yet, wait
+        */
+       if (unlikely(wait_obj_created(oi)))
+               goto fail;
+
+       ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred);
+       osd_end_request(or);
+       if (ret)
+               goto fail;
+
+out:
+       mark_inode_dirty(inode);
+       return;
+fail:
+       make_bad_inode(inode);
+       goto out;
+}
+
+/*
+ * Set inode attributes - just call generic functions.
+ */
+int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       error = inode_change_ok(inode, iattr);
+       if (error)
+               return error;
+
+       error = inode_setattr(inode, iattr);
+       return error;
+}
+
+/*
+ * Read an inode from the OSD, and return it as is.  We also return the size
+ * attribute in the 'sanity' argument if we got compiled with debugging turned
+ * on.
+ */
+static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
+                   struct exofs_fcb *inode, uint64_t *sanity)
+{
+       struct exofs_sb_info *sbi = sb->s_fs_info;
+       struct osd_request *or;
+       struct osd_attr attr;
+       struct osd_obj_id obj = {sbi->s_pid,
+                                oi->vfs_inode.i_ino + EXOFS_OBJ_OFF};
+       int ret;
+
+       exofs_make_credential(oi->i_cred, &obj);
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_ERR("exofs_get_inode: osd_start_request failed.\n");
+               return -ENOMEM;
+       }
+       osd_req_get_attributes(or, &obj);
+
+       /* we need the inode attribute */
+       osd_req_add_get_attr_list(or, &g_attr_inode_data, 1);
+
+#ifdef EXOFS_DEBUG_OBJ_ISIZE
+       /* we get the size attributes to do a sanity check */
+       osd_req_add_get_attr_list(or, &g_attr_logical_length, 1);
+#endif
+
+       ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred);
+       if (ret)
+               goto out;
+
+       attr = g_attr_inode_data;
+       ret = extract_attr_from_req(or, &attr);
+       if (ret) {
+               EXOFS_ERR("exofs_get_inode: extract_attr_from_req failed\n");
+               goto out;
+       }
+
+       WARN_ON(attr.len != EXOFS_INO_ATTR_SIZE);
+       memcpy(inode, attr.val_ptr, EXOFS_INO_ATTR_SIZE);
+
+#ifdef EXOFS_DEBUG_OBJ_ISIZE
+       attr = g_attr_logical_length;
+       ret = extract_attr_from_req(or, &attr);
+       if (ret) {
+               EXOFS_ERR("ERROR: extract attr from or failed\n");
+               goto out;
+       }
+       *sanity = get_unaligned_be64(attr.val_ptr);
+#endif
+
+out:
+       osd_end_request(or);
+       return ret;
+}
+
+/*
+ * Fill in an inode read from the OSD and set it up for use
+ */
+struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
+{
+       struct exofs_i_info *oi;
+       struct exofs_fcb fcb;
+       struct inode *inode;
+       uint64_t uninitialized_var(sanity);
+       int ret;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+       oi = exofs_i(inode);
+
+       /* read the inode from the osd */
+       ret = exofs_get_inode(sb, oi, &fcb, &sanity);
+       if (ret)
+               goto bad_inode;
+
+       init_waitqueue_head(&oi->i_wq);
+       set_obj_created(oi);
+
+       /* copy stuff from on-disk struct to in-memory struct */
+       inode->i_mode = le16_to_cpu(fcb.i_mode);
+       inode->i_uid = le32_to_cpu(fcb.i_uid);
+       inode->i_gid = le32_to_cpu(fcb.i_gid);
+       inode->i_nlink = le16_to_cpu(fcb.i_links_count);
+       inode->i_ctime.tv_sec = (signed)le32_to_cpu(fcb.i_ctime);
+       inode->i_atime.tv_sec = (signed)le32_to_cpu(fcb.i_atime);
+       inode->i_mtime.tv_sec = (signed)le32_to_cpu(fcb.i_mtime);
+       inode->i_ctime.tv_nsec =
+               inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = 0;
+       oi->i_commit_size = le64_to_cpu(fcb.i_size);
+       i_size_write(inode, oi->i_commit_size);
+       inode->i_blkbits = EXOFS_BLKSHIFT;
+       inode->i_generation = le32_to_cpu(fcb.i_generation);
+
+#ifdef EXOFS_DEBUG_OBJ_ISIZE
+       if ((inode->i_size != sanity) &&
+               (!exofs_inode_is_fast_symlink(inode))) {
+               EXOFS_ERR("WARNING: Size of object from inode and "
+                         "attributes differ (%lld != %llu)\n",
+                         inode->i_size, _LLU(sanity));
+       }
+#endif
+
+       oi->i_dir_start_lookup = 0;
+
+       if ((inode->i_nlink == 0) && (inode->i_mode == 0)) {
+               ret = -ESTALE;
+               goto bad_inode;
+       }
+
+       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+               if (fcb.i_data[0])
+                       inode->i_rdev =
+                               old_decode_dev(le32_to_cpu(fcb.i_data[0]));
+               else
+                       inode->i_rdev =
+                               new_decode_dev(le32_to_cpu(fcb.i_data[1]));
+       } else {
+               memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
+       }
+
+       if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &exofs_file_inode_operations;
+               inode->i_fop = &exofs_file_operations;
+               inode->i_mapping->a_ops = &exofs_aops;
+       } else if (S_ISDIR(inode->i_mode)) {
+               inode->i_op = &exofs_dir_inode_operations;
+               inode->i_fop = &exofs_dir_operations;
+               inode->i_mapping->a_ops = &exofs_aops;
+       } else if (S_ISLNK(inode->i_mode)) {
+               if (exofs_inode_is_fast_symlink(inode))
+                       inode->i_op = &exofs_fast_symlink_inode_operations;
+               else {
+                       inode->i_op = &exofs_symlink_inode_operations;
+                       inode->i_mapping->a_ops = &exofs_aops;
+               }
+       } else {
+               inode->i_op = &exofs_special_inode_operations;
+               if (fcb.i_data[0])
+                       init_special_inode(inode, inode->i_mode,
+                          old_decode_dev(le32_to_cpu(fcb.i_data[0])));
+               else
+                       init_special_inode(inode, inode->i_mode,
+                          new_decode_dev(le32_to_cpu(fcb.i_data[1])));
+       }
+
+       unlock_new_inode(inode);
+       return inode;
+
+bad_inode:
+       iget_failed(inode);
+       return ERR_PTR(ret);
+}
+
+int __exofs_wait_obj_created(struct exofs_i_info *oi)
+{
+       if (!obj_created(oi)) {
+               BUG_ON(!obj_2bcreated(oi));
+               wait_event(oi->i_wq, obj_created(oi));
+       }
+       return unlikely(is_bad_inode(&oi->vfs_inode)) ? -EIO : 0;
+}
+/*
+ * Callback function from exofs_new_inode().  The important thing is that we
+ * set the obj_created flag so that other methods know that the object exists on
+ * the OSD.
+ */
+static void create_done(struct osd_request *or, void *p)
+{
+       struct inode *inode = p;
+       struct exofs_i_info *oi = exofs_i(inode);
+       struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
+       int ret;
+
+       ret = exofs_check_ok(or);
+       osd_end_request(or);
+       atomic_dec(&sbi->s_curr_pending);
+
+       if (unlikely(ret)) {
+               EXOFS_ERR("object=0x%llx creation faild in pid=0x%llx",
+                         _LLU(sbi->s_pid), _LLU(inode->i_ino + EXOFS_OBJ_OFF));
+               make_bad_inode(inode);
+       } else
+               set_obj_created(oi);
+
+       atomic_dec(&inode->i_count);
+       wake_up(&oi->i_wq);
+}
+
+/*
+ * Set up a new inode and create an object for it on the OSD
+ */
+struct inode *exofs_new_inode(struct inode *dir, int mode)
+{
+       struct super_block *sb;
+       struct inode *inode;
+       struct exofs_i_info *oi;
+       struct exofs_sb_info *sbi;
+       struct osd_request *or;
+       struct osd_obj_id obj;
+       int ret;
+
+       sb = dir->i_sb;
+       inode = new_inode(sb);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       oi = exofs_i(inode);
+
+       init_waitqueue_head(&oi->i_wq);
+       set_obj_2bcreated(oi);
+
+       sbi = sb->s_fs_info;
+
+       sb->s_dirt = 1;
+       inode->i_uid = current->cred->fsuid;
+       if (dir->i_mode & S_ISGID) {
+               inode->i_gid = dir->i_gid;
+               if (S_ISDIR(mode))
+                       mode |= S_ISGID;
+       } else {
+               inode->i_gid = current->cred->fsgid;
+       }
+       inode->i_mode = mode;
+
+       inode->i_ino = sbi->s_nextid++;
+       inode->i_blkbits = EXOFS_BLKSHIFT;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+       oi->i_commit_size = inode->i_size = 0;
+       spin_lock(&sbi->s_next_gen_lock);
+       inode->i_generation = sbi->s_next_generation++;
+       spin_unlock(&sbi->s_next_gen_lock);
+       insert_inode_hash(inode);
+
+       mark_inode_dirty(inode);
+
+       obj.partition = sbi->s_pid;
+       obj.id = inode->i_ino + EXOFS_OBJ_OFF;
+       exofs_make_credential(oi->i_cred, &obj);
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_ERR("exofs_new_inode: osd_start_request failed\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       osd_req_create_object(or, &obj);
+
+       /* increment the refcount so that the inode will still be around when we
+        * reach the callback
+        */
+       atomic_inc(&inode->i_count);
+
+       ret = exofs_async_op(or, create_done, inode, oi->i_cred);
+       if (ret) {
+               atomic_dec(&inode->i_count);
+               osd_end_request(or);
+               return ERR_PTR(-EIO);
+       }
+       atomic_inc(&sbi->s_curr_pending);
+
+       return inode;
+}
+
+/*
+ * struct to pass two arguments to update_inode's callback
+ */
+struct updatei_args {
+       struct exofs_sb_info    *sbi;
+       struct exofs_fcb        fcb;
+};
+
+/*
+ * Callback function from exofs_update_inode().
+ */
+static void updatei_done(struct osd_request *or, void *p)
+{
+       struct updatei_args *args = p;
+
+       osd_end_request(or);
+
+       atomic_dec(&args->sbi->s_curr_pending);
+
+       kfree(args);
+}
+
+/*
+ * Write the inode to the OSD.  Just fill up the struct, and set the attribute
+ * synchronously or asynchronously depending on the do_sync flag.
+ */
+static int exofs_update_inode(struct inode *inode, int do_sync)
+{
+       struct exofs_i_info *oi = exofs_i(inode);
+       struct super_block *sb = inode->i_sb;
+       struct exofs_sb_info *sbi = sb->s_fs_info;
+       struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF};
+       struct osd_request *or;
+       struct osd_attr attr;
+       struct exofs_fcb *fcb;
+       struct updatei_args *args;
+       int ret;
+
+       args = kzalloc(sizeof(*args), GFP_KERNEL);
+       if (!args)
+               return -ENOMEM;
+
+       fcb = &args->fcb;
+
+       fcb->i_mode = cpu_to_le16(inode->i_mode);
+       fcb->i_uid = cpu_to_le32(inode->i_uid);
+       fcb->i_gid = cpu_to_le32(inode->i_gid);
+       fcb->i_links_count = cpu_to_le16(inode->i_nlink);
+       fcb->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
+       fcb->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
+       fcb->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
+       oi->i_commit_size = i_size_read(inode);
+       fcb->i_size = cpu_to_le64(oi->i_commit_size);
+       fcb->i_generation = cpu_to_le32(inode->i_generation);
+
+       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+               if (old_valid_dev(inode->i_rdev)) {
+                       fcb->i_data[0] =
+                               cpu_to_le32(old_encode_dev(inode->i_rdev));
+                       fcb->i_data[1] = 0;
+               } else {
+                       fcb->i_data[0] = 0;
+                       fcb->i_data[1] =
+                               cpu_to_le32(new_encode_dev(inode->i_rdev));
+                       fcb->i_data[2] = 0;
+               }
+       } else
+               memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data));
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_ERR("exofs_update_inode: osd_start_request failed.\n");
+               ret = -ENOMEM;
+               goto free_args;
+       }
+
+       osd_req_set_attributes(or, &obj);
+
+       attr = g_attr_inode_data;
+       attr.val_ptr = fcb;
+       osd_req_add_set_attr_list(or, &attr, 1);
+
+       if (!obj_created(oi)) {
+               EXOFS_DBGMSG("!obj_created\n");
+               BUG_ON(!obj_2bcreated(oi));
+               wait_event(oi->i_wq, obj_created(oi));
+               EXOFS_DBGMSG("wait_event done\n");
+       }
+
+       if (do_sync) {
+               ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred);
+               osd_end_request(or);
+               goto free_args;
+       } else {
+               args->sbi = sbi;
+
+               ret = exofs_async_op(or, updatei_done, args, oi->i_cred);
+               if (ret) {
+                       osd_end_request(or);
+                       goto free_args;
+               }
+               atomic_inc(&sbi->s_curr_pending);
+               goto out; /* deallocation in updatei_done */
+       }
+
+free_args:
+       kfree(args);
+out:
+       EXOFS_DBGMSG("ret=>%d\n", ret);
+       return ret;
+}
+
+int exofs_write_inode(struct inode *inode, int wait)
+{
+       return exofs_update_inode(inode, wait);
+}
+
+/*
+ * Callback function from exofs_delete_inode() - don't have much cleaning up to
+ * do.
+ */
+static void delete_done(struct osd_request *or, void *p)
+{
+       struct exofs_sb_info *sbi;
+       osd_end_request(or);
+       sbi = p;
+       atomic_dec(&sbi->s_curr_pending);
+}
+
+/*
+ * Called when the refcount of an inode reaches zero.  We remove the object
+ * from the OSD here.  We make sure the object was created before we try and
+ * delete it.
+ */
+void exofs_delete_inode(struct inode *inode)
+{
+       struct exofs_i_info *oi = exofs_i(inode);
+       struct super_block *sb = inode->i_sb;
+       struct exofs_sb_info *sbi = sb->s_fs_info;
+       struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF};
+       struct osd_request *or;
+       int ret;
+
+       truncate_inode_pages(&inode->i_data, 0);
+
+       if (is_bad_inode(inode))
+               goto no_delete;
+
+       mark_inode_dirty(inode);
+       exofs_update_inode(inode, inode_needs_sync(inode));
+
+       inode->i_size = 0;
+       if (inode->i_blocks)
+               exofs_truncate(inode);
+
+       clear_inode(inode);
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_ERR("exofs_delete_inode: osd_start_request failed\n");
+               return;
+       }
+
+       osd_req_remove_object(or, &obj);
+
+       /* if we are deleting an obj that hasn't been created yet, wait */
+       if (!obj_created(oi)) {
+               BUG_ON(!obj_2bcreated(oi));
+               wait_event(oi->i_wq, obj_created(oi));
+       }
+
+       ret = exofs_async_op(or, delete_done, sbi, oi->i_cred);
+       if (ret) {
+               EXOFS_ERR(
+                      "ERROR: @exofs_delete_inode exofs_async_op failed\n");
+               osd_end_request(or);
+               return;
+       }
+       atomic_inc(&sbi->s_curr_pending);
+
+       return;
+
+no_delete:
+       clear_inode(inode);
+}
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
new file mode 100644 (file)
index 0000000..77fdd76
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "exofs.h"
+
+static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
+{
+       int err = exofs_add_link(dentry, inode);
+       if (!err) {
+               d_instantiate(dentry, inode);
+               return 0;
+       }
+       inode_dec_link_count(inode);
+       iput(inode);
+       return err;
+}
+
+static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
+                                  struct nameidata *nd)
+{
+       struct inode *inode;
+       ino_t ino;
+
+       if (dentry->d_name.len > EXOFS_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       ino = exofs_inode_by_name(dir, dentry);
+       inode = NULL;
+       if (ino) {
+               inode = exofs_iget(dir->i_sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
+       }
+       return d_splice_alias(inode, dentry);
+}
+
+static int exofs_create(struct inode *dir, struct dentry *dentry, int mode,
+                        struct nameidata *nd)
+{
+       struct inode *inode = exofs_new_inode(dir, mode);
+       int err = PTR_ERR(inode);
+       if (!IS_ERR(inode)) {
+               inode->i_op = &exofs_file_inode_operations;
+               inode->i_fop = &exofs_file_operations;
+               inode->i_mapping->a_ops = &exofs_aops;
+               mark_inode_dirty(inode);
+               err = exofs_add_nondir(dentry, inode);
+       }
+       return err;
+}
+
+static int exofs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+                      dev_t rdev)
+{
+       struct inode *inode;
+       int err;
+
+       if (!new_valid_dev(rdev))
+               return -EINVAL;
+
+       inode = exofs_new_inode(dir, mode);
+       err = PTR_ERR(inode);
+       if (!IS_ERR(inode)) {
+               init_special_inode(inode, inode->i_mode, rdev);
+               mark_inode_dirty(inode);
+               err = exofs_add_nondir(dentry, inode);
+       }
+       return err;
+}
+
+static int exofs_symlink(struct inode *dir, struct dentry *dentry,
+                         const char *symname)
+{
+       struct super_block *sb = dir->i_sb;
+       int err = -ENAMETOOLONG;
+       unsigned l = strlen(symname)+1;
+       struct inode *inode;
+       struct exofs_i_info *oi;
+
+       if (l > sb->s_blocksize)
+               goto out;
+
+       inode = exofs_new_inode(dir, S_IFLNK | S_IRWXUGO);
+       err = PTR_ERR(inode);
+       if (IS_ERR(inode))
+               goto out;
+
+       oi = exofs_i(inode);
+       if (l > sizeof(oi->i_data)) {
+               /* slow symlink */
+               inode->i_op = &exofs_symlink_inode_operations;
+               inode->i_mapping->a_ops = &exofs_aops;
+               memset(oi->i_data, 0, sizeof(oi->i_data));
+
+               err = page_symlink(inode, symname, l);
+               if (err)
+                       goto out_fail;
+       } else {
+               /* fast symlink */
+               inode->i_op = &exofs_fast_symlink_inode_operations;
+               memcpy(oi->i_data, symname, l);
+               inode->i_size = l-1;
+       }
+       mark_inode_dirty(inode);
+
+       err = exofs_add_nondir(dentry, inode);
+out:
+       return err;
+
+out_fail:
+       inode_dec_link_count(inode);
+       iput(inode);
+       goto out;
+}
+
+static int exofs_link(struct dentry *old_dentry, struct inode *dir,
+               struct dentry *dentry)
+{
+       struct inode *inode = old_dentry->d_inode;
+
+       if (inode->i_nlink >= EXOFS_LINK_MAX)
+               return -EMLINK;
+
+       inode->i_ctime = CURRENT_TIME;
+       inode_inc_link_count(inode);
+       atomic_inc(&inode->i_count);
+
+       return exofs_add_nondir(dentry, inode);
+}
+
+static int exofs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       struct inode *inode;
+       int err = -EMLINK;
+
+       if (dir->i_nlink >= EXOFS_LINK_MAX)
+               goto out;
+
+       inode_inc_link_count(dir);
+
+       inode = exofs_new_inode(dir, S_IFDIR | mode);
+       err = PTR_ERR(inode);
+       if (IS_ERR(inode))
+               goto out_dir;
+
+       inode->i_op = &exofs_dir_inode_operations;
+       inode->i_fop = &exofs_dir_operations;
+       inode->i_mapping->a_ops = &exofs_aops;
+
+       inode_inc_link_count(inode);
+
+       err = exofs_make_empty(inode, dir);
+       if (err)
+               goto out_fail;
+
+       err = exofs_add_link(dentry, inode);
+       if (err)
+               goto out_fail;
+
+       d_instantiate(dentry, inode);
+out:
+       return err;
+
+out_fail:
+       inode_dec_link_count(inode);
+       inode_dec_link_count(inode);
+       iput(inode);
+out_dir:
+       inode_dec_link_count(dir);
+       goto out;
+}
+
+static int exofs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       struct exofs_dir_entry *de;
+       struct page *page;
+       int err = -ENOENT;
+
+       de = exofs_find_entry(dir, dentry, &page);
+       if (!de)
+               goto out;
+
+       err = exofs_delete_entry(de, page);
+       if (err)
+               goto out;
+
+       inode->i_ctime = dir->i_ctime;
+       inode_dec_link_count(inode);
+       err = 0;
+out:
+       return err;
+}
+
+static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       int err = -ENOTEMPTY;
+
+       if (exofs_empty_dir(inode)) {
+               err = exofs_unlink(dir, dentry);
+               if (!err) {
+                       inode->i_size = 0;
+                       inode_dec_link_count(inode);
+                       inode_dec_link_count(dir);
+               }
+       }
+       return err;
+}
+
+static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
+               struct inode *new_dir, struct dentry *new_dentry)
+{
+       struct inode *old_inode = old_dentry->d_inode;
+       struct inode *new_inode = new_dentry->d_inode;
+       struct page *dir_page = NULL;
+       struct exofs_dir_entry *dir_de = NULL;
+       struct page *old_page;
+       struct exofs_dir_entry *old_de;
+       int err = -ENOENT;
+
+       old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
+       if (!old_de)
+               goto out;
+
+       if (S_ISDIR(old_inode->i_mode)) {
+               err = -EIO;
+               dir_de = exofs_dotdot(old_inode, &dir_page);
+               if (!dir_de)
+                       goto out_old;
+       }
+
+       if (new_inode) {
+               struct page *new_page;
+               struct exofs_dir_entry *new_de;
+
+               err = -ENOTEMPTY;
+               if (dir_de && !exofs_empty_dir(new_inode))
+                       goto out_dir;
+
+               err = -ENOENT;
+               new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
+               if (!new_de)
+                       goto out_dir;
+               inode_inc_link_count(old_inode);
+               err = exofs_set_link(new_dir, new_de, new_page, old_inode);
+               new_inode->i_ctime = CURRENT_TIME;
+               if (dir_de)
+                       drop_nlink(new_inode);
+               inode_dec_link_count(new_inode);
+               if (err)
+                       goto out_dir;
+       } else {
+               if (dir_de) {
+                       err = -EMLINK;
+                       if (new_dir->i_nlink >= EXOFS_LINK_MAX)
+                               goto out_dir;
+               }
+               inode_inc_link_count(old_inode);
+               err = exofs_add_link(new_dentry, old_inode);
+               if (err) {
+                       inode_dec_link_count(old_inode);
+                       goto out_dir;
+               }
+               if (dir_de)
+                       inode_inc_link_count(new_dir);
+       }
+
+       old_inode->i_ctime = CURRENT_TIME;
+
+       exofs_delete_entry(old_de, old_page);
+       inode_dec_link_count(old_inode);
+
+       if (dir_de) {
+               err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
+               inode_dec_link_count(old_dir);
+               if (err)
+                       goto out_dir;
+       }
+       return 0;
+
+
+out_dir:
+       if (dir_de) {
+               kunmap(dir_page);
+               page_cache_release(dir_page);
+       }
+out_old:
+       kunmap(old_page);
+       page_cache_release(old_page);
+out:
+       return err;
+}
+
+const struct inode_operations exofs_dir_inode_operations = {
+       .create         = exofs_create,
+       .lookup         = exofs_lookup,
+       .link           = exofs_link,
+       .unlink         = exofs_unlink,
+       .symlink        = exofs_symlink,
+       .mkdir          = exofs_mkdir,
+       .rmdir          = exofs_rmdir,
+       .mknod          = exofs_mknod,
+       .rename         = exofs_rename,
+       .setattr        = exofs_setattr,
+};
+
+const struct inode_operations exofs_special_inode_operations = {
+       .setattr        = exofs_setattr,
+};
diff --git a/fs/exofs/osd.c b/fs/exofs/osd.c
new file mode 100644 (file)
index 0000000..b249ae9
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <scsi/scsi_device.h>
+#include <scsi/osd_sense.h>
+
+#include "exofs.h"
+
+int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid)
+{
+       struct osd_sense_info osi;
+       int ret = osd_req_decode_sense(or, &osi);
+
+       if (ret) { /* translate to Linux codes */
+               if (osi.additional_code == scsi_invalid_field_in_cdb) {
+                       if (osi.cdb_field_offset == OSD_CFO_STARTING_BYTE)
+                               ret = -EFAULT;
+                       if (osi.cdb_field_offset == OSD_CFO_OBJECT_ID)
+                               ret = -ENOENT;
+                       else
+                               ret = -EINVAL;
+               } else if (osi.additional_code == osd_quota_error)
+                       ret = -ENOSPC;
+               else
+                       ret = -EIO;
+       }
+
+       /* FIXME: should be include in osd_sense_info */
+       if (in_resid)
+               *in_resid = or->in.req ? or->in.req->data_len : 0;
+
+       if (out_resid)
+               *out_resid = or->out.req ? or->out.req->data_len : 0;
+
+       return ret;
+}
+
+void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj)
+{
+       osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
+}
+
+/*
+ * Perform a synchronous OSD operation.
+ */
+int exofs_sync_op(struct osd_request *or, int timeout, uint8_t *credential)
+{
+       int ret;
+
+       or->timeout = timeout;
+       ret = osd_finalize_request(or, 0, credential, NULL);
+       if (ret) {
+               EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret);
+               return ret;
+       }
+
+       ret = osd_execute_request(or);
+
+       if (ret)
+               EXOFS_DBGMSG("osd_execute_request() => %d\n", ret);
+       /* osd_req_decode_sense(or, ret); */
+       return ret;
+}
+
+/*
+ * Perform an asynchronous OSD operation.
+ */
+int exofs_async_op(struct osd_request *or, osd_req_done_fn *async_done,
+                  void *caller_context, u8 *cred)
+{
+       int ret;
+
+       ret = osd_finalize_request(or, 0, cred, NULL);
+       if (ret) {
+               EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret);
+               return ret;
+       }
+
+       ret = osd_execute_request_async(or, async_done, caller_context);
+
+       if (ret)
+               EXOFS_DBGMSG("osd_execute_request_async() => %d\n", ret);
+       return ret;
+}
+
+int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr)
+{
+       struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
+       void *iter = NULL;
+       int nelem;
+
+       do {
+               nelem = 1;
+               osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter);
+               if ((cur_attr.attr_page == attr->attr_page) &&
+                   (cur_attr.attr_id == attr->attr_id)) {
+                       attr->len = cur_attr.len;
+                       attr->val_ptr = cur_attr.val_ptr;
+                       return 0;
+               }
+       } while (iter);
+
+       return -EIO;
+}
+
+int osd_req_read_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
+{
+       struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
+       struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
+
+       if (!bio)
+               return -ENOMEM;
+
+       osd_req_read(or, obj, bio, offset);
+       return 0;
+}
+
+int osd_req_write_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
+{
+       struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
+       struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
+
+       if (!bio)
+               return -ENOMEM;
+
+       osd_req_write(or, obj, bio, offset);
+       return 0;
+}
diff --git a/fs/exofs/super.c b/fs/exofs/super.c
new file mode 100644 (file)
index 0000000..9f1985e
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/vfs.h>
+#include <linux/random.h>
+#include <linux/exportfs.h>
+
+#include "exofs.h"
+
+/******************************************************************************
+ * MOUNT OPTIONS
+ *****************************************************************************/
+
+/*
+ * struct to hold what we get from mount options
+ */
+struct exofs_mountopt {
+       const char *dev_name;
+       uint64_t pid;
+       int timeout;
+};
+
+/*
+ * exofs-specific mount-time options.
+ */
+enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err };
+
+/*
+ * Our mount-time options.  These should ideally be 64-bit unsigned, but the
+ * kernel's parsing functions do not currently support that.  32-bit should be
+ * sufficient for most applications now.
+ */
+static match_table_t tokens = {
+       {Opt_pid, "pid=%u"},
+       {Opt_to, "to=%u"},
+       {Opt_err, NULL}
+};
+
+/*
+ * The main option parsing method.  Also makes sure that all of the mandatory
+ * mount options were set.
+ */
+static int parse_options(char *options, struct exofs_mountopt *opts)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+       bool s_pid = false;
+
+       EXOFS_DBGMSG("parse_options %s\n", options);
+       /* defaults */
+       memset(opts, 0, sizeof(*opts));
+       opts->timeout = BLK_DEFAULT_SG_TIMEOUT;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               char str[32];
+
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_pid:
+                       if (0 == match_strlcpy(str, &args[0], sizeof(str)))
+                               return -EINVAL;
+                       opts->pid = simple_strtoull(str, NULL, 0);
+                       if (opts->pid < EXOFS_MIN_PID) {
+                               EXOFS_ERR("Partition ID must be >= %u",
+                                         EXOFS_MIN_PID);
+                               return -EINVAL;
+                       }
+                       s_pid = 1;
+                       break;
+               case Opt_to:
+                       if (match_int(&args[0], &option))
+                               return -EINVAL;
+                       if (option <= 0) {
+                               EXOFS_ERR("Timout must be > 0");
+                               return -EINVAL;
+                       }
+                       opts->timeout = option * HZ;
+                       break;
+               }
+       }
+
+       if (!s_pid) {
+               EXOFS_ERR("Need to specify the following options:\n");
+               EXOFS_ERR("    -o pid=pid_no_to_use\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ * INODE CACHE
+ *****************************************************************************/
+
+/*
+ * Our inode cache.  Isn't it pretty?
+ */
+static struct kmem_cache *exofs_inode_cachep;
+
+/*
+ * Allocate an inode in the cache
+ */
+static struct inode *exofs_alloc_inode(struct super_block *sb)
+{
+       struct exofs_i_info *oi;
+
+       oi = kmem_cache_alloc(exofs_inode_cachep, GFP_KERNEL);
+       if (!oi)
+               return NULL;
+
+       oi->vfs_inode.i_version = 1;
+       return &oi->vfs_inode;
+}
+
+/*
+ * Remove an inode from the cache
+ */
+static void exofs_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(exofs_inode_cachep, exofs_i(inode));
+}
+
+/*
+ * Initialize the inode
+ */
+static void exofs_init_once(void *foo)
+{
+       struct exofs_i_info *oi = foo;
+
+       inode_init_once(&oi->vfs_inode);
+}
+
+/*
+ * Create and initialize the inode cache
+ */
+static int init_inodecache(void)
+{
+       exofs_inode_cachep = kmem_cache_create("exofs_inode_cache",
+                               sizeof(struct exofs_i_info), 0,
+                               SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                               exofs_init_once);
+       if (exofs_inode_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/*
+ * Destroy the inode cache
+ */
+static void destroy_inodecache(void)
+{
+       kmem_cache_destroy(exofs_inode_cachep);
+}
+
+/******************************************************************************
+ * SUPERBLOCK FUNCTIONS
+ *****************************************************************************/
+static const struct super_operations exofs_sops;
+static const struct export_operations exofs_export_ops;
+
+/*
+ * Write the superblock to the OSD
+ */
+static void exofs_write_super(struct super_block *sb)
+{
+       struct exofs_sb_info *sbi;
+       struct exofs_fscb *fscb;
+       struct osd_request *or;
+       struct osd_obj_id obj;
+       int ret;
+
+       fscb = kzalloc(sizeof(struct exofs_fscb), GFP_KERNEL);
+       if (!fscb) {
+               EXOFS_ERR("exofs_write_super: memory allocation failed.\n");
+               return;
+       }
+
+       lock_kernel();
+       sbi = sb->s_fs_info;
+       fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
+       fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles);
+       fscb->s_magic = cpu_to_le16(sb->s_magic);
+       fscb->s_newfs = 0;
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_ERR("exofs_write_super: osd_start_request failed.\n");
+               goto out;
+       }
+
+       obj.partition = sbi->s_pid;
+       obj.id = EXOFS_SUPER_ID;
+       ret = osd_req_write_kern(or, &obj, 0, fscb, sizeof(*fscb));
+       if (unlikely(ret)) {
+               EXOFS_ERR("exofs_write_super: osd_req_write_kern failed.\n");
+               goto out;
+       }
+
+       ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred);
+       if (unlikely(ret)) {
+               EXOFS_ERR("exofs_write_super: exofs_sync_op failed.\n");
+               goto out;
+       }
+       sb->s_dirt = 0;
+
+out:
+       if (or)
+               osd_end_request(or);
+       unlock_kernel();
+       kfree(fscb);
+}
+
+/*
+ * This function is called when the vfs is freeing the superblock.  We just
+ * need to free our own part.
+ */
+static void exofs_put_super(struct super_block *sb)
+{
+       int num_pend;
+       struct exofs_sb_info *sbi = sb->s_fs_info;
+
+       /* make sure there are no pending commands */
+       for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0;
+            num_pend = atomic_read(&sbi->s_curr_pending)) {
+               wait_queue_head_t wq;
+               init_waitqueue_head(&wq);
+               wait_event_timeout(wq,
+                                 (atomic_read(&sbi->s_curr_pending) == 0),
+                                 msecs_to_jiffies(100));
+       }
+
+       osduld_put_device(sbi->s_dev);
+       kfree(sb->s_fs_info);
+       sb->s_fs_info = NULL;
+}
+
+/*
+ * Read the superblock from the OSD and fill in the fields
+ */
+static int exofs_fill_super(struct super_block *sb, void *data, int silent)
+{
+       struct inode *root;
+       struct exofs_mountopt *opts = data;
+       struct exofs_sb_info *sbi;      /*extended info                  */
+       struct exofs_fscb fscb;         /*on-disk superblock info        */
+       struct osd_request *or = NULL;
+       struct osd_obj_id obj;
+       int ret;
+
+       sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+       if (!sbi)
+               return -ENOMEM;
+       sb->s_fs_info = sbi;
+
+       /* use mount options to fill superblock */
+       sbi->s_dev = osduld_path_lookup(opts->dev_name);
+       if (IS_ERR(sbi->s_dev)) {
+               ret = PTR_ERR(sbi->s_dev);
+               sbi->s_dev = NULL;
+               goto free_sbi;
+       }
+
+       sbi->s_pid = opts->pid;
+       sbi->s_timeout = opts->timeout;
+
+       /* fill in some other data by hand */
+       memset(sb->s_id, 0, sizeof(sb->s_id));
+       strcpy(sb->s_id, "exofs");
+       sb->s_blocksize = EXOFS_BLKSIZE;
+       sb->s_blocksize_bits = EXOFS_BLKSHIFT;
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
+       atomic_set(&sbi->s_curr_pending, 0);
+       sb->s_bdev = NULL;
+       sb->s_dev = 0;
+
+       /* read data from on-disk superblock object */
+       obj.partition = sbi->s_pid;
+       obj.id = EXOFS_SUPER_ID;
+       exofs_make_credential(sbi->s_cred, &obj);
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               if (!silent)
+                       EXOFS_ERR(
+                              "exofs_fill_super: osd_start_request failed.\n");
+               ret = -ENOMEM;
+               goto free_sbi;
+       }
+       ret = osd_req_read_kern(or, &obj, 0, &fscb, sizeof(fscb));
+       if (unlikely(ret)) {
+               if (!silent)
+                       EXOFS_ERR(
+                              "exofs_fill_super: osd_req_read_kern failed.\n");
+               ret = -ENOMEM;
+               goto free_sbi;
+       }
+
+       ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred);
+       if (unlikely(ret)) {
+               if (!silent)
+                       EXOFS_ERR("exofs_fill_super: exofs_sync_op failed.\n");
+               ret = -EIO;
+               goto free_sbi;
+       }
+
+       sb->s_magic = le16_to_cpu(fscb.s_magic);
+       sbi->s_nextid = le64_to_cpu(fscb.s_nextid);
+       sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles);
+
+       /* make sure what we read from the object store is correct */
+       if (sb->s_magic != EXOFS_SUPER_MAGIC) {
+               if (!silent)
+                       EXOFS_ERR("ERROR: Bad magic value\n");
+               ret = -EINVAL;
+               goto free_sbi;
+       }
+
+       /* start generation numbers from a random point */
+       get_random_bytes(&sbi->s_next_generation, sizeof(u32));
+       spin_lock_init(&sbi->s_next_gen_lock);
+
+       /* set up operation vectors */
+       sb->s_op = &exofs_sops;
+       sb->s_export_op = &exofs_export_ops;
+       root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF);
+       if (IS_ERR(root)) {
+               EXOFS_ERR("ERROR: exofs_iget failed\n");
+               ret = PTR_ERR(root);
+               goto free_sbi;
+       }
+       sb->s_root = d_alloc_root(root);
+       if (!sb->s_root) {
+               iput(root);
+               EXOFS_ERR("ERROR: get root inode failed\n");
+               ret = -ENOMEM;
+               goto free_sbi;
+       }
+
+       if (!S_ISDIR(root->i_mode)) {
+               dput(sb->s_root);
+               sb->s_root = NULL;
+               EXOFS_ERR("ERROR: corrupt root inode (mode = %hd)\n",
+                      root->i_mode);
+               ret = -EINVAL;
+               goto free_sbi;
+       }
+
+       ret = 0;
+out:
+       if (or)
+               osd_end_request(or);
+       return ret;
+
+free_sbi:
+       osduld_put_device(sbi->s_dev); /* NULL safe */
+       kfree(sbi);
+       goto out;
+}
+
+/*
+ * Set up the superblock (calls exofs_fill_super eventually)
+ */
+static int exofs_get_sb(struct file_system_type *type,
+                         int flags, const char *dev_name,
+                         void *data, struct vfsmount *mnt)
+{
+       struct exofs_mountopt opts;
+       int ret;
+
+       ret = parse_options(data, &opts);
+       if (ret)
+               return ret;
+
+       opts.dev_name = dev_name;
+       return get_sb_nodev(type, flags, &opts, exofs_fill_super, mnt);
+}
+
+/*
+ * Return information about the file system state in the buffer.  This is used
+ * by the 'df' command, for example.
+ */
+static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct super_block *sb = dentry->d_sb;
+       struct exofs_sb_info *sbi = sb->s_fs_info;
+       struct osd_obj_id obj = {sbi->s_pid, 0};
+       struct osd_attr attrs[] = {
+               ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS,
+                       OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)),
+               ATTR_DEF(OSD_APAGE_PARTITION_INFORMATION,
+                       OSD_ATTR_PI_USED_CAPACITY, sizeof(__be64)),
+       };
+       uint64_t capacity = ULLONG_MAX;
+       uint64_t used = ULLONG_MAX;
+       struct osd_request *or;
+       uint8_t cred_a[OSD_CAP_LEN];
+       int ret;
+
+       /* get used/capacity attributes */
+       exofs_make_credential(cred_a, &obj);
+
+       or = osd_start_request(sbi->s_dev, GFP_KERNEL);
+       if (unlikely(!or)) {
+               EXOFS_DBGMSG("exofs_statfs: osd_start_request failed.\n");
+               return -ENOMEM;
+       }
+
+       osd_req_get_attributes(or, &obj);
+       osd_req_add_get_attr_list(or, attrs, ARRAY_SIZE(attrs));
+       ret = exofs_sync_op(or, sbi->s_timeout, cred_a);
+       if (unlikely(ret))
+               goto out;
+
+       ret = extract_attr_from_req(or, &attrs[0]);
+       if (likely(!ret))
+               capacity = get_unaligned_be64(attrs[0].val_ptr);
+       else
+               EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n");
+
+       ret = extract_attr_from_req(or, &attrs[1]);
+       if (likely(!ret))
+               used = get_unaligned_be64(attrs[1].val_ptr);
+       else
+               EXOFS_DBGMSG("exofs_statfs: get used-space failed.\n");
+
+       /* fill in the stats buffer */
+       buf->f_type = EXOFS_SUPER_MAGIC;
+       buf->f_bsize = EXOFS_BLKSIZE;
+       buf->f_blocks = (capacity >> EXOFS_BLKSHIFT);
+       buf->f_bfree = ((capacity - used) >> EXOFS_BLKSHIFT);
+       buf->f_bavail = buf->f_bfree;
+       buf->f_files = sbi->s_numfiles;
+       buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles;
+       buf->f_namelen = EXOFS_NAME_LEN;
+
+out:
+       osd_end_request(or);
+       return ret;
+}
+
+static const struct super_operations exofs_sops = {
+       .alloc_inode    = exofs_alloc_inode,
+       .destroy_inode  = exofs_destroy_inode,
+       .write_inode    = exofs_write_inode,
+       .delete_inode   = exofs_delete_inode,
+       .put_super      = exofs_put_super,
+       .write_super    = exofs_write_super,
+       .statfs         = exofs_statfs,
+};
+
+/******************************************************************************
+ * EXPORT OPERATIONS
+ *****************************************************************************/
+
+struct dentry *exofs_get_parent(struct dentry *child)
+{
+       unsigned long ino = exofs_parent_ino(child);
+
+       if (!ino)
+               return NULL;
+
+       return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino));
+}
+
+static struct inode *exofs_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
+{
+       struct inode *inode;
+
+       inode = exofs_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (generation && inode->i_generation != generation) {
+               /* we didn't find the right inode.. */
+               iput(inode);
+               return ERR_PTR(-ESTALE);
+       }
+       return inode;
+}
+
+static struct dentry *exofs_fh_to_dentry(struct super_block *sb,
+                               struct fid *fid, int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   exofs_nfs_get_inode);
+}
+
+static struct dentry *exofs_fh_to_parent(struct super_block *sb,
+                               struct fid *fid, int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   exofs_nfs_get_inode);
+}
+
+static const struct export_operations exofs_export_ops = {
+       .fh_to_dentry = exofs_fh_to_dentry,
+       .fh_to_parent = exofs_fh_to_parent,
+       .get_parent = exofs_get_parent,
+};
+
+/******************************************************************************
+ * INSMOD/RMMOD
+ *****************************************************************************/
+
+/*
+ * struct that describes this file system
+ */
+static struct file_system_type exofs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "exofs",
+       .get_sb         = exofs_get_sb,
+       .kill_sb        = generic_shutdown_super,
+};
+
+static int __init init_exofs(void)
+{
+       int err;
+
+       err = init_inodecache();
+       if (err)
+               goto out;
+
+       err = register_filesystem(&exofs_type);
+       if (err)
+               goto out_d;
+
+       return 0;
+out_d:
+       destroy_inodecache();
+out:
+       return err;
+}
+
+static void __exit exit_exofs(void)
+{
+       unregister_filesystem(&exofs_type);
+       destroy_inodecache();
+}
+
+MODULE_AUTHOR("Avishay Traeger <avishay@gmail.com>");
+MODULE_DESCRIPTION("exofs");
+MODULE_LICENSE("GPL");
+
+module_init(init_exofs)
+module_exit(exit_exofs)
diff --git a/fs/exofs/symlink.c b/fs/exofs/symlink.c
new file mode 100644 (file)
index 0000000..36e2d7b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2005, 2006
+ * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
+ * Copyright (C) 2005, 2006
+ * International Business Machines
+ * Copyright (C) 2008, 2009
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Copyrights for code taken from ext2:
+ *     Copyright (C) 1992, 1993, 1994, 1995
+ *     Remy Card (card@masi.ibp.fr)
+ *     Laboratoire MASI - Institut Blaise Pascal
+ *     Universite Pierre et Marie Curie (Paris VI)
+ *     from
+ *     linux/fs/minix/inode.c
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is part of exofs.
+ *
+ * exofs 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.  Since it is based on ext2, and the only
+ * valid version of GPL for the Linux kernel is version 2, the only valid
+ * version of GPL for exofs is version 2.
+ *
+ * exofs 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 exofs; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/namei.h>
+
+#include "exofs.h"
+
+static void *exofs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       struct exofs_i_info *oi = exofs_i(dentry->d_inode);
+
+       nd_set_link(nd, (char *)oi->i_data);
+       return NULL;
+}
+
+const struct inode_operations exofs_symlink_inode_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = page_follow_link_light,
+       .put_link       = page_put_link,
+};
+
+const struct inode_operations exofs_fast_symlink_inode_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = exofs_follow_link,
+};
index ae8c4f850b27d0e83e28e684a07637a992abbe69..d46e38cb85c557e273e8206c32b38c9426799ae3 100644 (file)
@@ -318,7 +318,7 @@ ext2_init_acl(struct inode *inode, struct inode *dir)
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                struct posix_acl *clone;
index b60bb241880c86f50420e13411dc19b1148e1a51..d81ef2fdb08e0aeca8e533963db7f7feeecbd386 100644 (file)
@@ -323,7 +323,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                struct posix_acl *clone;
index 5853f4440af41949081cfd2bf3e2b8f1b9363c18..3d724a95882f618672a45ee8f945d9164f80b89f 100644 (file)
@@ -42,7 +42,7 @@ const struct file_operations ext3_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ext3_readdir,         /* we take BKL. needed?*/
-       .ioctl          = ext3_ioctl,           /* BKL held */
+       .unlocked_ioctl = ext3_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext3_compat_ioctl,
 #endif
index 3be1e0689c9aa34443b5695f7800c41fbcafceef..5b49704b231b27b53a8d52dc15a1c62118f6124f 100644 (file)
  */
 static int ext3_release_file (struct inode * inode, struct file * filp)
 {
+       if (EXT3_I(inode)->i_state & EXT3_STATE_FLUSH_ON_CLOSE) {
+               filemap_flush(inode->i_mapping);
+               EXT3_I(inode)->i_state &= ~EXT3_STATE_FLUSH_ON_CLOSE;
+       }
        /* if we are the last writer on the inode, drop the block reservation */
        if ((filp->f_mode & FMODE_WRITE) &&
                        (atomic_read(&inode->i_writecount) == 1))
@@ -112,7 +116,7 @@ const struct file_operations ext3_file_operations = {
        .write          = do_sync_write,
        .aio_read       = generic_file_aio_read,
        .aio_write      = ext3_file_write,
-       .ioctl          = ext3_ioctl,
+       .unlocked_ioctl = ext3_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext3_compat_ioctl,
 #endif
index 4a09ff169870517b13f65e0d26507c6505e465b2..466a332e0bd124c871143cfd682392074252aa76 100644 (file)
@@ -1149,12 +1149,15 @@ static int ext3_write_begin(struct file *file, struct address_space *mapping,
                                struct page **pagep, void **fsdata)
 {
        struct inode *inode = mapping->host;
-       int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
+       int ret;
        handle_t *handle;
        int retries = 0;
        struct page *page;
        pgoff_t index;
        unsigned from, to;
+       /* Reserve one block more for addition to orphan list in case
+        * we allocate blocks but write fails for some reason */
+       int needed_blocks = ext3_writepage_trans_blocks(inode) + 1;
 
        index = pos >> PAGE_CACHE_SHIFT;
        from = pos & (PAGE_CACHE_SIZE - 1);
@@ -1184,14 +1187,19 @@ retry:
        }
 write_begin_failed:
        if (ret) {
-               ext3_journal_stop(handle);
-               unlock_page(page);
-               page_cache_release(page);
                /*
                 * block_write_begin may have instantiated a few blocks
                 * outside i_size.  Trim these off again. Don't need
                 * i_size_read because we hold i_mutex.
+                *
+                * Add inode to orphan list in case we crash before truncate
+                * finishes.
                 */
+               if (pos + len > inode->i_size)
+                       ext3_orphan_add(handle, inode);
+               ext3_journal_stop(handle);
+               unlock_page(page);
+               page_cache_release(page);
                if (pos + len > inode->i_size)
                        vmtruncate(inode, inode->i_size);
        }
@@ -1211,6 +1219,18 @@ int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
        return err;
 }
 
+/* For ordered writepage and write_end functions */
+static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
+{
+       /*
+        * Write could have mapped the buffer but it didn't copy the data in
+        * yet. So avoid filing such buffer into a transaction.
+        */
+       if (buffer_mapped(bh) && buffer_uptodate(bh))
+               return ext3_journal_dirty_data(handle, bh);
+       return 0;
+}
+
 /* For write_end() in data=journal mode */
 static int write_end_fn(handle_t *handle, struct buffer_head *bh)
 {
@@ -1221,26 +1241,20 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh)
 }
 
 /*
- * Generic write_end handler for ordered and writeback ext3 journal modes.
- * We can't use generic_write_end, because that unlocks the page and we need to
- * unlock the page after ext3_journal_stop, but ext3_journal_stop must run
- * after block_write_end.
+ * This is nasty and subtle: ext3_write_begin() could have allocated blocks
+ * for the whole page but later we failed to copy the data in. Update inode
+ * size according to what we managed to copy. The rest is going to be
+ * truncated in write_end function.
  */
-static int ext3_generic_write_end(struct file *file,
-                               struct address_space *mapping,
-                               loff_t pos, unsigned len, unsigned copied,
-                               struct page *page, void *fsdata)
+static void update_file_sizes(struct inode *inode, loff_t pos, unsigned copied)
 {
-       struct inode *inode = file->f_mapping->host;
-
-       copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
-
-       if (pos+copied > inode->i_size) {
-               i_size_write(inode, pos+copied);
+       /* What matters to us is i_disksize. We don't write i_size anywhere */
+       if (pos + copied > inode->i_size)
+               i_size_write(inode, pos + copied);
+       if (pos + copied > EXT3_I(inode)->i_disksize) {
+               EXT3_I(inode)->i_disksize = pos + copied;
                mark_inode_dirty(inode);
        }
-
-       return copied;
 }
 
 /*
@@ -1260,35 +1274,29 @@ static int ext3_ordered_write_end(struct file *file,
        unsigned from, to;
        int ret = 0, ret2;
 
-       from = pos & (PAGE_CACHE_SIZE - 1);
-       to = from + len;
+       copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
 
+       from = pos & (PAGE_CACHE_SIZE - 1);
+       to = from + copied;
        ret = walk_page_buffers(handle, page_buffers(page),
-               from, to, NULL, ext3_journal_dirty_data);
+               from, to, NULL, journal_dirty_data_fn);
 
-       if (ret == 0) {
-               /*
-                * generic_write_end() will run mark_inode_dirty() if i_size
-                * changes.  So let's piggyback the i_disksize mark_inode_dirty
-                * into that.
-                */
-               loff_t new_i_size;
-
-               new_i_size = pos + copied;
-               if (new_i_size > EXT3_I(inode)->i_disksize)
-                       EXT3_I(inode)->i_disksize = new_i_size;
-               ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
-                                                       page, fsdata);
-               copied = ret2;
-               if (ret2 < 0)
-                       ret = ret2;
-       }
+       if (ret == 0)
+               update_file_sizes(inode, pos, copied);
+       /*
+        * There may be allocated blocks outside of i_size because
+        * we failed to copy some data. Prepare for truncate.
+        */
+       if (pos + len > inode->i_size)
+               ext3_orphan_add(handle, inode);
        ret2 = ext3_journal_stop(handle);
        if (!ret)
                ret = ret2;
        unlock_page(page);
        page_cache_release(page);
 
+       if (pos + len > inode->i_size)
+               vmtruncate(inode, inode->i_size);
        return ret ? ret : copied;
 }
 
@@ -1299,25 +1307,22 @@ static int ext3_writeback_write_end(struct file *file,
 {
        handle_t *handle = ext3_journal_current_handle();
        struct inode *inode = file->f_mapping->host;
-       int ret = 0, ret2;
-       loff_t new_i_size;
-
-       new_i_size = pos + copied;
-       if (new_i_size > EXT3_I(inode)->i_disksize)
-               EXT3_I(inode)->i_disksize = new_i_size;
-
-       ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
-                                                       page, fsdata);
-       copied = ret2;
-       if (ret2 < 0)
-               ret = ret2;
+       int ret;
 
-       ret2 = ext3_journal_stop(handle);
-       if (!ret)
-               ret = ret2;
+       copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
+       update_file_sizes(inode, pos, copied);
+       /*
+        * There may be allocated blocks outside of i_size because
+        * we failed to copy some data. Prepare for truncate.
+        */
+       if (pos + len > inode->i_size)
+               ext3_orphan_add(handle, inode);
+       ret = ext3_journal_stop(handle);
        unlock_page(page);
        page_cache_release(page);
 
+       if (pos + len > inode->i_size)
+               vmtruncate(inode, inode->i_size);
        return ret ? ret : copied;
 }
 
@@ -1338,15 +1343,23 @@ static int ext3_journalled_write_end(struct file *file,
        if (copied < len) {
                if (!PageUptodate(page))
                        copied = 0;
-               page_zero_new_buffers(page, from+copied, to);
+               page_zero_new_buffers(page, from + copied, to);
+               to = from + copied;
        }
 
        ret = walk_page_buffers(handle, page_buffers(page), from,
                                to, &partial, write_end_fn);
        if (!partial)
                SetPageUptodate(page);
-       if (pos+copied > inode->i_size)
-               i_size_write(inode, pos+copied);
+
+       if (pos + copied > inode->i_size)
+               i_size_write(inode, pos + copied);
+       /*
+        * There may be allocated blocks outside of i_size because
+        * we failed to copy some data. Prepare for truncate.
+        */
+       if (pos + len > inode->i_size)
+               ext3_orphan_add(handle, inode);
        EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
        if (inode->i_size > EXT3_I(inode)->i_disksize) {
                EXT3_I(inode)->i_disksize = inode->i_size;
@@ -1361,6 +1374,8 @@ static int ext3_journalled_write_end(struct file *file,
        unlock_page(page);
        page_cache_release(page);
 
+       if (pos + len > inode->i_size)
+               vmtruncate(inode, inode->i_size);
        return ret ? ret : copied;
 }
 
@@ -1428,17 +1443,11 @@ static int bput_one(handle_t *handle, struct buffer_head *bh)
        return 0;
 }
 
-static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
-{
-       if (buffer_mapped(bh))
-               return ext3_journal_dirty_data(handle, bh);
-       return 0;
-}
-
 static int buffer_unmapped(handle_t *handle, struct buffer_head *bh)
 {
        return !buffer_mapped(bh);
 }
+
 /*
  * Note that we always start a transaction even if we're not journalling
  * data.  This is to preserve ordering: any hole instantiation within
@@ -2354,6 +2363,9 @@ void ext3_truncate(struct inode *inode)
        if (!ext3_can_truncate(inode))
                return;
 
+       if (inode->i_size == 0 && ext3_should_writeback_data(inode))
+               ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE;
+
        /*
         * We have to lock the EOF page here, because lock_page() nests
         * outside journal_start().
index 5e86ce9a86e05b20d3ffe297dd4b9191fee08994..88974814783a346ca18d9eddea1c417cccbf695b 100644 (file)
 #include <linux/mount.h>
 #include <linux/time.h>
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
-int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
-               unsigned long arg)
+long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        struct ext3_inode_info *ei = EXT3_I(inode);
        unsigned int flags;
        unsigned short rsv_window_size;
@@ -39,29 +38,25 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                unsigned int oldflags;
                unsigned int jflag;
 
+               if (!is_owner_or_cap(inode))
+                       return -EACCES;
+
+               if (get_user(flags, (int __user *) arg))
+                       return -EFAULT;
+
                err = mnt_want_write(filp->f_path.mnt);
                if (err)
                        return err;
 
-               if (!is_owner_or_cap(inode)) {
-                       err = -EACCES;
-                       goto flags_out;
-               }
-
-               if (get_user(flags, (int __user *) arg)) {
-                       err = -EFAULT;
-                       goto flags_out;
-               }
-
                flags = ext3_mask_flags(inode->i_mode, flags);
 
                mutex_lock(&inode->i_mutex);
+
                /* Is it quota file? Do not allow user to mess with it */
-               if (IS_NOQUOTA(inode)) {
-                       mutex_unlock(&inode->i_mutex);
-                       err = -EPERM;
+               err = -EPERM;
+               if (IS_NOQUOTA(inode))
                        goto flags_out;
-               }
+
                oldflags = ei->i_flags;
 
                /* The JOURNAL_DATA flag is modifiable only by root */
@@ -74,11 +69,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                 * This test looks nicer. Thanks to Pauline Middelink
                 */
                if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
-                       if (!capable(CAP_LINUX_IMMUTABLE)) {
-                               mutex_unlock(&inode->i_mutex);
-                               err = -EPERM;
+                       if (!capable(CAP_LINUX_IMMUTABLE))
                                goto flags_out;
-                       }
                }
 
                /*
@@ -86,17 +78,12 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                 * the relevant capability.
                 */
                if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
-                       if (!capable(CAP_SYS_RESOURCE)) {
-                               mutex_unlock(&inode->i_mutex);
-                               err = -EPERM;
+                       if (!capable(CAP_SYS_RESOURCE))
                                goto flags_out;
-                       }
                }
 
-
                handle = ext3_journal_start(inode, 1);
                if (IS_ERR(handle)) {
-                       mutex_unlock(&inode->i_mutex);
                        err = PTR_ERR(handle);
                        goto flags_out;
                }
@@ -116,15 +103,13 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                err = ext3_mark_iloc_dirty(handle, inode, &iloc);
 flags_err:
                ext3_journal_stop(handle);
-               if (err) {
-                       mutex_unlock(&inode->i_mutex);
-                       return err;
-               }
+               if (err)
+                       goto flags_out;
 
                if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
                        err = ext3_change_inode_journal_flag(inode, jflag);
-               mutex_unlock(&inode->i_mutex);
 flags_out:
+               mutex_unlock(&inode->i_mutex);
                mnt_drop_write(filp->f_path.mnt);
                return err;
        }
@@ -140,6 +125,7 @@ flags_out:
 
                if (!is_owner_or_cap(inode))
                        return -EPERM;
+
                err = mnt_want_write(filp->f_path.mnt);
                if (err)
                        return err;
@@ -147,6 +133,7 @@ flags_out:
                        err = -EFAULT;
                        goto setversion_out;
                }
+
                handle = ext3_journal_start(inode, 1);
                if (IS_ERR(handle)) {
                        err = PTR_ERR(handle);
@@ -299,9 +286,6 @@ group_add_out:
 #ifdef CONFIG_COMPAT
 long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int ret;
-
        /* These are just misnamed, they actually get/put from/to user an int */
        switch (cmd) {
        case EXT3_IOC32_GETFLAGS:
@@ -341,9 +325,6 @@ long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        default:
                return -ENOIOCTLCMD;
        }
-       lock_kernel();
-       ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
-       unlock_kernel();
-       return ret;
+       return ext3_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
 }
 #endif
index e2fc63cbba8b81e91945eee43d35c4b482f58fdc..6ff7b9730234bd97f2a67a1d01b08692630549ba 100644 (file)
@@ -161,12 +161,12 @@ static struct dx_frame *dx_probe(struct qstr *entry,
                                 struct dx_frame *frame,
                                 int *err);
 static void dx_release (struct dx_frame *frames);
-static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
+static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize,
                        struct dx_hash_info *hinfo, struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
 static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
                struct dx_map_entry *offsets, int count);
-static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
+static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize);
 static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
 static int ext3_htree_next_block(struct inode *dir, __u32 hash,
                                 struct dx_frame *frame,
@@ -708,14 +708,14 @@ errout:
  * Create map of hash values, offsets, and sizes, stored at end of block.
  * Returns number of entries mapped.
  */
-static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
-                       struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
+static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize,
+               struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
 {
        int count = 0;
        char *base = (char *) de;
        struct dx_hash_info h = *hinfo;
 
-       while ((char *) de < base + size)
+       while ((char *) de < base + blocksize)
        {
                if (de->name_len && de->inode) {
                        ext3fs_dirhash(de->name, de->name_len, &h);
@@ -1047,8 +1047,16 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
                        return ERR_PTR(-EIO);
                }
                inode = ext3_iget(dir->i_sb, ino);
-               if (IS_ERR(inode))
-                       return ERR_CAST(inode);
+               if (unlikely(IS_ERR(inode))) {
+                       if (PTR_ERR(inode) == -ESTALE) {
+                               ext3_error(dir->i_sb, __func__,
+                                               "deleted inode referenced: %lu",
+                                               ino);
+                               return ERR_PTR(-EIO);
+                       } else {
+                               return ERR_CAST(inode);
+                       }
+               }
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1120,13 +1128,14 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
  * Compact each dir entry in the range to the minimal rec_len.
  * Returns pointer to last entry in range.
  */
-static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
+static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize)
 {
-       struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
+       struct ext3_dir_entry_2 *next, *to, *prev;
+       struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *)base;
        unsigned rec_len = 0;
 
        prev = to = de;
-       while ((char*)de < base + size) {
+       while ((char *)de < base + blocksize) {
                next = ext3_next_entry(de);
                if (de->inode && de->name_len) {
                        rec_len = EXT3_DIR_REC_LEN(de->name_len);
@@ -2265,7 +2274,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
        struct inode * old_inode, * new_inode;
        struct buffer_head * old_bh, * new_bh, * dir_bh;
        struct ext3_dir_entry_2 * old_de, * new_de;
-       int retval;
+       int retval, flush_file = 0;
 
        old_bh = new_bh = dir_bh = NULL;
 
@@ -2401,6 +2410,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
                ext3_mark_inode_dirty(handle, new_inode);
                if (!new_inode->i_nlink)
                        ext3_orphan_add(handle, new_inode);
+               if (ext3_should_writeback_data(new_inode))
+                       flush_file = 1;
        }
        retval = 0;
 
@@ -2409,6 +2420,8 @@ end_rename:
        brelse (old_bh);
        brelse (new_bh);
        ext3_journal_stop(handle);
+       if (retval == 0 && flush_file)
+               filemap_flush(old_inode->i_mapping);
        return retval;
 }
 
index 7505482a08fabddda2efc9a52be043d323be9b75..418b6f3b0ae82b097aa4def6685477357d0b5e18 100644 (file)
@@ -18,7 +18,7 @@ config EXT4_FS
          filesystem; while there will be some performance gains from
          the delayed allocation and inode table readahead, the best
          performance gains will require enabling ext4 features in the
-         filesystem, or formating a new filesystem as an ext4
+         filesystem, or formatting a new filesystem as an ext4
          filesystem initially.
 
          To compile this file system support as a module, choose M here. The
index 694ed6fadcc8c59e1936a49919c67a427ba670e5..647e0d65a2844e227a774cf4b629e5739a0df0cd 100644 (file)
@@ -323,7 +323,7 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                struct posix_acl *clone;
index 38f40d55899c81e3f483c5237989bd68cf134db3..53c72ad85877314c16c0eef0f19fb3889a6743da 100644 (file)
@@ -55,7 +55,8 @@ static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
 }
 
 static int ext4_group_used_meta_blocks(struct super_block *sb,
-                               ext4_group_t block_group)
+                                      ext4_group_t block_group,
+                                      struct ext4_group_desc *gdp)
 {
        ext4_fsblk_t tmp;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -63,10 +64,6 @@ static int ext4_group_used_meta_blocks(struct super_block *sb,
        int used_blocks = sbi->s_itb_per_group + 2;
 
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
-               struct ext4_group_desc *gdp;
-               struct buffer_head *bh;
-
-               gdp = ext4_get_group_desc(sb, block_group, &bh);
                if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
                                        block_group))
                        used_blocks--;
@@ -177,7 +174,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                 */
                mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
        }
-       return free_blocks - ext4_group_used_meta_blocks(sb, block_group);
+       return free_blocks - ext4_group_used_meta_blocks(sb, block_group, gdp);
 }
 
 
@@ -473,9 +470,8 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_blocks += blocks_freed;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_add(blocks_freed,
+                          &sbi->s_flex_groups[flex_group].free_blocks);
        }
        /*
         * request to reload the buddy with the
index 2df2e40b01af0cc031d4546306079c0d4a6669ac..b64789929a65bc00243e9b10298f056aadaeb306 100644 (file)
@@ -67,7 +67,8 @@ int ext4_check_dir_entry(const char *function, struct inode *dir,
                         unsigned int offset)
 {
        const char *error_msg = NULL;
-       const int rlen = ext4_rec_len_from_disk(de->rec_len);
+       const int rlen = ext4_rec_len_from_disk(de->rec_len,
+                                               dir->i_sb->s_blocksize);
 
        if (rlen < EXT4_DIR_REC_LEN(1))
                error_msg = "rec_len is smaller than minimal";
@@ -178,10 +179,11 @@ revalidate:
                                 * least that it is non-zero.  A
                                 * failure will be detected in the
                                 * dirent test below. */
-                               if (ext4_rec_len_from_disk(de->rec_len)
-                                               < EXT4_DIR_REC_LEN(1))
+                               if (ext4_rec_len_from_disk(de->rec_len,
+                                       sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
                                        break;
-                               i += ext4_rec_len_from_disk(de->rec_len);
+                               i += ext4_rec_len_from_disk(de->rec_len,
+                                                           sb->s_blocksize);
                        }
                        offset = i;
                        filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
@@ -203,7 +205,8 @@ revalidate:
                                ret = stored;
                                goto out;
                        }
-                       offset += ext4_rec_len_from_disk(de->rec_len);
+                       offset += ext4_rec_len_from_disk(de->rec_len,
+                                       sb->s_blocksize);
                        if (le32_to_cpu(de->inode)) {
                                /* We might block in the next section
                                 * if the data destination is
@@ -225,7 +228,8 @@ revalidate:
                                        goto revalidate;
                                stored++;
                        }
-                       filp->f_pos += ext4_rec_len_from_disk(de->rec_len);
+                       filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
+                                               sb->s_blocksize);
                }
                offset = 0;
                brelse(bh);
index 6083bb38057b8bca9fd18f83a871435d787f2468..d0f15ef56de1b1b6b325d0a86207e78260b1f40a 100644 (file)
  */
 #undef EXT4FS_DEBUG
 
-/*
- * Define EXT4_RESERVATION to reserve data blocks for expanding files
- */
-#define EXT4_DEFAULT_RESERVE_BLOCKS    8
-/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
-#define EXT4_MAX_RESERVE_BLOCKS                1027
-#define EXT4_RESERVE_WINDOW_NOT_ALLOCATED 0
-
 /*
  * Debug code
  */
@@ -54,8 +46,6 @@
 #define ext4_debug(f, a...)    do {} while (0)
 #endif
 
-#define EXT4_MULTIBLOCK_ALLOCATOR      1
-
 /* prefer goal again. length */
 #define EXT4_MB_HINT_MERGE             1
 /* blocks already reserved */
@@ -180,8 +170,9 @@ struct ext4_group_desc
  */
 
 struct flex_groups {
-       __u32 free_inodes;
-       __u32 free_blocks;
+       atomic_t free_inodes;
+       atomic_t free_blocks;
+       atomic_t used_dirs;
 };
 
 #define EXT4_BG_INODE_UNINIT   0x0001 /* Inode table/bitmap not in use */
@@ -249,6 +240,30 @@ struct flex_groups {
 #define EXT4_FL_USER_VISIBLE           0x000BDFFF /* User visible flags */
 #define EXT4_FL_USER_MODIFIABLE                0x000B80FF /* User modifiable flags */
 
+/* Flags that should be inherited by new inodes from their parent. */
+#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
+                          EXT4_SYNC_FL | EXT4_IMMUTABLE_FL | EXT4_APPEND_FL |\
+                          EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
+                          EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
+                          EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
+
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
+
+/* Flags that are appropriate for non-directories/regular files. */
+#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL)
+
+/* Mask out flags that are inappropriate for the given type of inode. */
+static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags)
+{
+       if (S_ISDIR(mode))
+               return flags;
+       else if (S_ISREG(mode))
+               return flags & EXT4_REG_FLMASK;
+       else
+               return flags & EXT4_OTHER_FLMASK;
+}
+
 /*
  * Inode dynamic state flags
  */
@@ -256,6 +271,7 @@ struct flex_groups {
 #define EXT4_STATE_NEW                 0x00000002 /* inode is newly created */
 #define EXT4_STATE_XATTR               0x00000004 /* has in-inode xattrs */
 #define EXT4_STATE_NO_EXPAND           0x00000008 /* No space for expansion */
+#define EXT4_STATE_DA_ALLOC_CLOSE      0x00000010 /* Alloc DA blks on close */
 
 /* Used to pass group descriptor data when online resize is done */
 struct ext4_new_group_input {
@@ -303,7 +319,9 @@ struct ext4_new_group_data {
 #define EXT4_IOC_GROUP_EXTEND          _IOW('f', 7, unsigned long)
 #define EXT4_IOC_GROUP_ADD             _IOW('f', 8, struct ext4_new_group_input)
 #define EXT4_IOC_MIGRATE               _IO('f', 9)
+ /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */
  /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
+#define EXT4_IOC_ALLOC_DA_BLKS         _IO('f', 12)
 
 /*
  * ioctl commands in 32 bit emulation
@@ -531,7 +549,7 @@ do {                                                                               \
 #define EXT4_MOUNT_NO_UID32            0x02000  /* Disable 32-bit UIDs */
 #define EXT4_MOUNT_XATTR_USER          0x04000 /* Extended user attributes */
 #define EXT4_MOUNT_POSIX_ACL           0x08000 /* POSIX Access Control Lists */
-#define EXT4_MOUNT_RESERVATION         0x10000 /* Preallocation */
+#define EXT4_MOUNT_NO_AUTO_DA_ALLOC    0x10000 /* No auto delalloc mapping */
 #define EXT4_MOUNT_BARRIER             0x20000 /* Use block barriers */
 #define EXT4_MOUNT_NOBH                        0x40000 /* No bufferheads */
 #define EXT4_MOUNT_QUOTA               0x80000 /* Some quota option set */
@@ -666,7 +684,8 @@ struct ext4_super_block {
        __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
        __u8    s_reserved_char_pad2;
        __le16  s_reserved_pad;
-       __u32   s_reserved[162];        /* Padding to the end of the block */
+       __le64  s_kbytes_written;       /* nr of lifetime kilobytes written */
+       __u32   s_reserved[160];        /* Padding to the end of the block */
 };
 
 #ifdef __KERNEL__
@@ -813,6 +832,12 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 #define EXT4_DEF_MIN_BATCH_TIME        0
 #define EXT4_DEF_MAX_BATCH_TIME        15000 /* 15ms */
 
+/*
+ * Minimum number of groups in a flexgroup before we separate out
+ * directories into the first block group of a flexgroup
+ */
+#define EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME        4
+
 /*
  * Structure of a directory entry
  */
@@ -865,24 +890,6 @@ struct ext4_dir_entry_2 {
                                         ~EXT4_DIR_ROUND)
 #define EXT4_MAX_REC_LEN               ((1<<16)-1)
 
-static inline unsigned ext4_rec_len_from_disk(__le16 dlen)
-{
-       unsigned len = le16_to_cpu(dlen);
-
-       if (len == EXT4_MAX_REC_LEN || len == 0)
-               return 1 << 16;
-       return len;
-}
-
-static inline __le16 ext4_rec_len_to_disk(unsigned len)
-{
-       if (len == (1 << 16))
-               return cpu_to_le16(EXT4_MAX_REC_LEN);
-       else if (len > (1 << 16))
-               BUG();
-       return cpu_to_le16(len);
-}
-
 /*
  * Hash Tree Directory indexing
  * (c) Daniel Phillips, 2001
@@ -970,22 +977,6 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
 
 extern struct proc_dir_entry *ext4_proc_root;
 
-#ifdef CONFIG_PROC_FS
-extern const struct file_operations ext4_ui_proc_fops;
-
-#define        EXT4_PROC_HANDLER(name, var)                                    \
-do {                                                                   \
-       proc = proc_create_data(name, mode, sbi->s_proc,                \
-                               &ext4_ui_proc_fops, &sbi->s_##var);     \
-       if (proc == NULL) {                                             \
-               printk(KERN_ERR "EXT4-fs: can't create %s\n", name);    \
-               goto err_out;                                           \
-       }                                                               \
-} while (0)
-#else
-#define EXT4_PROC_HANDLER(name, var)
-#endif
-
 /*
  * Function prototypes
  */
@@ -1092,13 +1083,14 @@ extern int ext4_can_truncate(struct inode *inode);
 extern void ext4_truncate(struct inode *);
 extern void ext4_set_inode_flags(struct inode *);
 extern void ext4_get_inode_flags(struct ext4_inode_info *);
+extern int ext4_alloc_da_blocks(struct inode *inode);
 extern void ext4_set_aops(struct inode *inode);
 extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks);
 extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
 extern int ext4_block_truncate_page(handle_t *handle,
                struct address_space *mapping, loff_t from);
-extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page);
+extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t ext4_get_reserved_space(struct inode *inode);
 
 /* ioctl.c */
@@ -1107,7 +1099,10 @@ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* migrate.c */
 extern int ext4_ext_migrate(struct inode *);
+
 /* namei.c */
+extern unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize);
+extern __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize);
 extern int ext4_orphan_add(handle_t *, struct inode *);
 extern int ext4_orphan_del(handle_t *, struct inode *);
 extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
index 18cb67b2cbbc85c46b8c6e09efbeb13d1513b618..f0c3ec85bd488a83cfc31f8bb4f601306112e787 100644 (file)
@@ -241,5 +241,6 @@ extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
 extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *,
                                                ext4_lblk_t *, ext4_fsblk_t *);
 extern void ext4_ext_drop_refs(struct ext4_ext_path *);
+extern int ext4_ext_check_inode(struct inode *inode);
 #endif /* _EXT4_EXTENTS */
 
index e69acc16f5c4300be5b5cd641f515fba320a98db..4ce2187123aad818de707f4e82a988fdb8ee14a3 100644 (file)
@@ -33,9 +33,6 @@ typedef __u32 ext4_lblk_t;
 /* data type for block group number */
 typedef unsigned int ext4_group_t;
 
-#define rsv_start rsv_window._rsv_start
-#define rsv_end rsv_window._rsv_end
-
 /*
  * storage for cached extent
  */
@@ -125,6 +122,9 @@ struct ext4_inode_info {
        struct list_head i_prealloc_list;
        spinlock_t i_prealloc_lock;
 
+       /* ialloc */
+       ext4_group_t    i_last_alloc_group;
+
        /* allocation reservation info for delalloc */
        unsigned int i_reserved_data_blocks;
        unsigned int i_reserved_meta_blocks;
index 039b6ea1a0429b30e5e95253b42ed83d24494869..57b71fefbccf753fb05e2436eea4da2da7663b3a 100644 (file)
@@ -62,12 +62,10 @@ struct ext4_sb_info {
        struct percpu_counter s_freeinodes_counter;
        struct percpu_counter s_dirs_counter;
        struct percpu_counter s_dirtyblocks_counter;
-       struct blockgroup_lock s_blockgroup_lock;
+       struct blockgroup_lock *s_blockgroup_lock;
        struct proc_dir_entry *s_proc;
-
-       /* root of the per fs reservation window tree */
-       spinlock_t s_rsv_window_lock;
-       struct rb_root s_rsv_window_root;
+       struct kobject s_kobj;
+       struct completion s_kobj_unregister;
 
        /* Journaling */
        struct inode *s_journal_inode;
@@ -146,6 +144,10 @@ struct ext4_sb_info {
        /* locality groups */
        struct ext4_locality_group *s_locality_groups;
 
+       /* for write statistics */
+       unsigned long s_sectors_written_start;
+       u64 s_kbytes_written;
+
        unsigned int s_log_groups_per_flex;
        struct flex_groups *s_flex_groups;
 };
@@ -153,7 +155,7 @@ struct ext4_sb_info {
 static inline spinlock_t *
 sb_bgl_lock(struct ext4_sb_info *sbi, unsigned int block_group)
 {
-       return bgl_lock_ptr(&sbi->s_blockgroup_lock, block_group);
+       return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group);
 }
 
 #endif /* _EXT4_SB */
index e0aa4fe4f596fcb11549de818436edced6887f3b..ac77d8b8251da9cb6ac720db55e8b7e72ec97a91 100644 (file)
@@ -152,6 +152,8 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
        ext4_fsblk_t bg_start;
        ext4_fsblk_t last_block;
        ext4_grpblk_t colour;
+       ext4_group_t block_group;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
        int depth;
 
        if (path) {
@@ -170,10 +172,31 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
        }
 
        /* OK. use inode's group */
-       bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
+       block_group = ei->i_block_group;
+       if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
+               /*
+                * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME
+                * block groups per flexgroup, reserve the first block 
+                * group for directories and special files.  Regular 
+                * files will start at the second block group.  This
+                * tends to speed up directory access and improves 
+                * fsck times.
+                */
+               block_group &= ~(flex_size-1);
+               if (S_ISREG(inode->i_mode))
+                       block_group++;
+       }
+       bg_start = (block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
                le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block);
        last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
 
+       /*
+        * If we are doing delayed allocation, we don't need take
+        * colour into account.
+        */
+       if (test_opt(inode->i_sb, DELALLOC))
+               return bg_start;
+
        if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
                colour = (current->pid % 16) *
                        (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
@@ -301,7 +324,64 @@ ext4_ext_max_entries(struct inode *inode, int depth)
        return max;
 }
 
-static int __ext4_ext_check_header(const char *function, struct inode *inode,
+static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
+{
+       ext4_fsblk_t block = ext_pblock(ext);
+       int len = ext4_ext_get_actual_len(ext);
+       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+       if (unlikely(block < le32_to_cpu(es->s_first_data_block) ||
+                       ((block + len) > ext4_blocks_count(es))))
+               return 0;
+       else
+               return 1;
+}
+
+static int ext4_valid_extent_idx(struct inode *inode,
+                               struct ext4_extent_idx *ext_idx)
+{
+       ext4_fsblk_t block = idx_pblock(ext_idx);
+       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+       if (unlikely(block < le32_to_cpu(es->s_first_data_block) ||
+                       (block > ext4_blocks_count(es))))
+               return 0;
+       else
+               return 1;
+}
+
+static int ext4_valid_extent_entries(struct inode *inode,
+                               struct ext4_extent_header *eh,
+                               int depth)
+{
+       struct ext4_extent *ext;
+       struct ext4_extent_idx *ext_idx;
+       unsigned short entries;
+       if (eh->eh_entries == 0)
+               return 1;
+
+       entries = le16_to_cpu(eh->eh_entries);
+
+       if (depth == 0) {
+               /* leaf entries */
+               ext = EXT_FIRST_EXTENT(eh);
+               while (entries) {
+                       if (!ext4_valid_extent(inode, ext))
+                               return 0;
+                       ext++;
+                       entries--;
+               }
+       } else {
+               ext_idx = EXT_FIRST_INDEX(eh);
+               while (entries) {
+                       if (!ext4_valid_extent_idx(inode, ext_idx))
+                               return 0;
+                       ext_idx++;
+                       entries--;
+               }
+       }
+       return 1;
+}
+
+static int __ext4_ext_check(const char *function, struct inode *inode,
                                        struct ext4_extent_header *eh,
                                        int depth)
 {
@@ -329,11 +409,15 @@ static int __ext4_ext_check_header(const char *function, struct inode *inode,
                error_msg = "invalid eh_entries";
                goto corrupted;
        }
+       if (!ext4_valid_extent_entries(inode, eh, depth)) {
+               error_msg = "invalid extent entries";
+               goto corrupted;
+       }
        return 0;
 
 corrupted:
        ext4_error(inode->i_sb, function,
-                       "bad header in inode #%lu: %s - magic %x, "
+                       "bad header/extent in inode #%lu: %s - magic %x, "
                        "entries %u, max %u(%u), depth %u(%u)",
                        inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
                        le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
@@ -342,8 +426,13 @@ corrupted:
        return -EIO;
 }
 
-#define ext4_ext_check_header(inode, eh, depth)        \
-       __ext4_ext_check_header(__func__, inode, eh, depth)
+#define ext4_ext_check(inode, eh, depth)       \
+       __ext4_ext_check(__func__, inode, eh, depth)
+
+int ext4_ext_check_inode(struct inode *inode)
+{
+       return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode));
+}
 
 #ifdef EXT_DEBUG
 static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
@@ -547,9 +636,6 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
 
        eh = ext_inode_hdr(inode);
        depth = ext_depth(inode);
-       if (ext4_ext_check_header(inode, eh, depth))
-               return ERR_PTR(-EIO);
-
 
        /* account possible depth increase */
        if (!path) {
@@ -565,6 +651,8 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
        i = depth;
        /* walk through the tree */
        while (i) {
+               int need_to_validate = 0;
+
                ext_debug("depth %d: num %d, max %d\n",
                          ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
 
@@ -573,10 +661,17 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                path[ppos].p_depth = i;
                path[ppos].p_ext = NULL;
 
-               bh = sb_bread(inode->i_sb, path[ppos].p_block);
-               if (!bh)
+               bh = sb_getblk(inode->i_sb, path[ppos].p_block);
+               if (unlikely(!bh))
                        goto err;
-
+               if (!bh_uptodate_or_lock(bh)) {
+                       if (bh_submit_read(bh) < 0) {
+                               put_bh(bh);
+                               goto err;
+                       }
+                       /* validate the extent entries */
+                       need_to_validate = 1;
+               }
                eh = ext_block_hdr(bh);
                ppos++;
                BUG_ON(ppos > depth);
@@ -584,7 +679,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                path[ppos].p_hdr = eh;
                i--;
 
-               if (ext4_ext_check_header(inode, eh, i))
+               if (need_to_validate && ext4_ext_check(inode, eh, i))
                        goto err;
        }
 
@@ -1181,7 +1276,7 @@ got_index:
                        return -EIO;
                eh = ext_block_hdr(bh);
                /* subtract from p_depth to get proper eh_depth */
-               if (ext4_ext_check_header(inode, eh, path->p_depth - depth)) {
+               if (ext4_ext_check(inode, eh, path->p_depth - depth)) {
                        put_bh(bh);
                        return -EIO;
                }
@@ -1194,7 +1289,7 @@ got_index:
        if (bh == NULL)
                return -EIO;
        eh = ext_block_hdr(bh);
-       if (ext4_ext_check_header(inode, eh, path->p_depth - depth)) {
+       if (ext4_ext_check(inode, eh, path->p_depth - depth)) {
                put_bh(bh);
                return -EIO;
        }
@@ -2137,7 +2232,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
                return -ENOMEM;
        }
        path[0].p_hdr = ext_inode_hdr(inode);
-       if (ext4_ext_check_header(inode, path[0].p_hdr, depth)) {
+       if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
                err = -EIO;
                goto out;
        }
@@ -2191,7 +2286,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
                                err = -EIO;
                                break;
                        }
-                       if (ext4_ext_check_header(inode, ext_block_hdr(bh),
+                       if (ext4_ext_check(inode, ext_block_hdr(bh),
                                                        depth - i - 1)) {
                                err = -EIO;
                                break;
index f731cb545a0359cc664de79a3fe9ab6c7ca4f3b8..588af8c77246f71b9a2b088602dba33b88c43f52 100644 (file)
  */
 static int ext4_release_file(struct inode *inode, struct file *filp)
 {
+       if (EXT4_I(inode)->i_state & EXT4_STATE_DA_ALLOC_CLOSE) {
+               ext4_alloc_da_blocks(inode);
+               EXT4_I(inode)->i_state &= ~EXT4_STATE_DA_ALLOC_CLOSE;
+       }
        /* if we are the last writer on the inode, drop the block reservation */
        if ((filp->f_mode & FMODE_WRITE) &&
-                       (atomic_read(&inode->i_writecount) == 1))
+                       (atomic_read(&inode->i_writecount) == 1) &&
+                       !EXT4_I(inode)->i_reserved_data_blocks)
        {
                down_write(&EXT4_I(inode)->i_data_sem);
                ext4_discard_preallocations(inode);
index fb51b40e3e8f5a60960d8584815f390d71ae1124..47b84e8df56859ca1e741cfb6543b5966ee45657 100644 (file)
@@ -189,7 +189,6 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
        struct ext4_super_block *es;
        struct ext4_sb_info *sbi;
        int fatal = 0, err, count, cleared;
-       ext4_group_t flex_group;
 
        if (atomic_read(&inode->i_count) > 1) {
                printk(KERN_ERR "ext4_free_inode: inode has count=%d\n",
@@ -268,6 +267,13 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                        if (is_directory) {
                                count = ext4_used_dirs_count(sb, gdp) - 1;
                                ext4_used_dirs_set(sb, gdp, count);
+                               if (sbi->s_log_groups_per_flex) {
+                                       ext4_group_t f;
+
+                                       f = ext4_flex_group(sbi, block_group);
+                                       atomic_dec(&sbi->s_flex_groups[f].free_inodes);
+                               }
+
                        }
                        gdp->bg_checksum = ext4_group_desc_csum(sbi,
                                                        block_group, gdp);
@@ -277,10 +283,10 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                                percpu_counter_dec(&sbi->s_dirs_counter);
 
                        if (sbi->s_log_groups_per_flex) {
-                               flex_group = ext4_flex_group(sbi, block_group);
-                               spin_lock(sb_bgl_lock(sbi, flex_group));
-                               sbi->s_flex_groups[flex_group].free_inodes++;
-                               spin_unlock(sb_bgl_lock(sbi, flex_group));
+                               ext4_group_t f;
+
+                               f = ext4_flex_group(sbi, block_group);
+                               atomic_inc(&sbi->s_flex_groups[f].free_inodes);
                        }
                }
                BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata");
@@ -360,9 +366,9 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
                sbi->s_log_groups_per_flex;
 
 find_close_to_parent:
-       flexbg_free_blocks = flex_group[best_flex].free_blocks;
+       flexbg_free_blocks = atomic_read(&flex_group[best_flex].free_blocks);
        flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
-       if (flex_group[best_flex].free_inodes &&
+       if (atomic_read(&flex_group[best_flex].free_inodes) &&
            flex_freeb_ratio > free_block_ratio)
                goto found_flexbg;
 
@@ -375,24 +381,24 @@ find_close_to_parent:
                if (i == parent_fbg_group || i == parent_fbg_group - 1)
                        continue;
 
-               flexbg_free_blocks = flex_group[i].free_blocks;
+               flexbg_free_blocks = atomic_read(&flex_group[i].free_blocks);
                flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
 
                if (flex_freeb_ratio > free_block_ratio &&
-                   flex_group[i].free_inodes) {
+                   (atomic_read(&flex_group[i].free_inodes))) {
                        best_flex = i;
                        goto found_flexbg;
                }
 
-               if (flex_group[best_flex].free_inodes == 0 ||
-                   (flex_group[i].free_blocks >
-                    flex_group[best_flex].free_blocks &&
-                    flex_group[i].free_inodes))
+               if ((atomic_read(&flex_group[best_flex].free_inodes) == 0) ||
+                   ((atomic_read(&flex_group[i].free_blocks) >
+                     atomic_read(&flex_group[best_flex].free_blocks)) &&
+                    atomic_read(&flex_group[i].free_inodes)))
                        best_flex = i;
        }
 
-       if (!flex_group[best_flex].free_inodes ||
-           !flex_group[best_flex].free_blocks)
+       if (!atomic_read(&flex_group[best_flex].free_inodes) ||
+           !atomic_read(&flex_group[best_flex].free_blocks))
                return -1;
 
 found_flexbg:
@@ -410,6 +416,42 @@ out:
        return 0;
 }
 
+struct orlov_stats {
+       __u32 free_inodes;
+       __u32 free_blocks;
+       __u32 used_dirs;
+};
+
+/*
+ * Helper function for Orlov's allocator; returns critical information
+ * for a particular block group or flex_bg.  If flex_size is 1, then g
+ * is a block group number; otherwise it is flex_bg number.
+ */
+void get_orlov_stats(struct super_block *sb, ext4_group_t g,
+                      int flex_size, struct orlov_stats *stats)
+{
+       struct ext4_group_desc *desc;
+       struct flex_groups *flex_group = EXT4_SB(sb)->s_flex_groups;
+
+       if (flex_size > 1) {
+               stats->free_inodes = atomic_read(&flex_group[g].free_inodes);
+               stats->free_blocks = atomic_read(&flex_group[g].free_blocks);
+               stats->used_dirs = atomic_read(&flex_group[g].used_dirs);
+               return;
+       }
+
+       desc = ext4_get_group_desc(sb, g, NULL);
+       if (desc) {
+               stats->free_inodes = ext4_free_inodes_count(sb, desc);
+               stats->free_blocks = ext4_free_blks_count(sb, desc);
+               stats->used_dirs = ext4_used_dirs_count(sb, desc);
+       } else {
+               stats->free_inodes = 0;
+               stats->free_blocks = 0;
+               stats->used_dirs = 0;
+       }
+}
+
 /*
  * Orlov's allocator for directories.
  *
@@ -425,35 +467,34 @@ out:
  * it has too many directories already (max_dirs) or
  * it has too few free inodes left (min_inodes) or
  * it has too few free blocks left (min_blocks) or
- * it's already running too large debt (max_debt).
  * Parent's group is preferred, if it doesn't satisfy these
  * conditions we search cyclically through the rest. If none
  * of the groups look good we just look for a group with more
  * free inodes than average (starting at parent's group).
- *
- * Debt is incremented each time we allocate a directory and decremented
- * when we allocate an inode, within 0--255.
  */
 
-#define INODE_COST 64
-#define BLOCK_COST 256
-
 static int find_group_orlov(struct super_block *sb, struct inode *parent,
-                               ext4_group_t *group)
+                           ext4_group_t *group, int mode)
 {
        ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_super_block *es = sbi->s_es;
        ext4_group_t ngroups = sbi->s_groups_count;
        int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
        unsigned int freei, avefreei;
        ext4_fsblk_t freeb, avefreeb;
-       ext4_fsblk_t blocks_per_dir;
        unsigned int ndirs;
-       int max_debt, max_dirs, min_inodes;
+       int max_dirs, min_inodes;
        ext4_grpblk_t min_blocks;
-       ext4_group_t i;
+       ext4_group_t i, grp, g;
        struct ext4_group_desc *desc;
+       struct orlov_stats stats;
+       int flex_size = ext4_flex_bg_size(sbi);
+
+       if (flex_size > 1) {
+               ngroups = (ngroups + flex_size - 1) >>
+                       sbi->s_log_groups_per_flex;
+               parent_group >>= sbi->s_log_groups_per_flex;
+       }
 
        freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter);
        avefreei = freei / ngroups;
@@ -462,71 +503,97 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
        do_div(avefreeb, ngroups);
        ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter);
 
-       if ((parent == sb->s_root->d_inode) ||
-           (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL)) {
+       if (S_ISDIR(mode) &&
+           ((parent == sb->s_root->d_inode) ||
+            (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL))) {
                int best_ndir = inodes_per_group;
-               ext4_group_t grp;
                int ret = -1;
 
                get_random_bytes(&grp, sizeof(grp));
                parent_group = (unsigned)grp % ngroups;
                for (i = 0; i < ngroups; i++) {
-                       grp = (parent_group + i) % ngroups;
-                       desc = ext4_get_group_desc(sb, grp, NULL);
-                       if (!desc || !ext4_free_inodes_count(sb, desc))
+                       g = (parent_group + i) % ngroups;
+                       get_orlov_stats(sb, g, flex_size, &stats);
+                       if (!stats.free_inodes)
                                continue;
-                       if (ext4_used_dirs_count(sb, desc) >= best_ndir)
+                       if (stats.used_dirs >= best_ndir)
                                continue;
-                       if (ext4_free_inodes_count(sb, desc) < avefreei)
+                       if (stats.free_inodes < avefreei)
                                continue;
-                       if (ext4_free_blks_count(sb, desc) < avefreeb)
+                       if (stats.free_blocks < avefreeb)
                                continue;
-                       *group = grp;
+                       grp = g;
                        ret = 0;
-                       best_ndir = ext4_used_dirs_count(sb, desc);
+                       best_ndir = stats.used_dirs;
+               }
+               if (ret)
+                       goto fallback;
+       found_flex_bg:
+               if (flex_size == 1) {
+                       *group = grp;
+                       return 0;
+               }
+
+               /*
+                * We pack inodes at the beginning of the flexgroup's
+                * inode tables.  Block allocation decisions will do
+                * something similar, although regular files will
+                * start at 2nd block group of the flexgroup.  See
+                * ext4_ext_find_goal() and ext4_find_near().
+                */
+               grp *= flex_size;
+               for (i = 0; i < flex_size; i++) {
+                       if (grp+i >= sbi->s_groups_count)
+                               break;
+                       desc = ext4_get_group_desc(sb, grp+i, NULL);
+                       if (desc && ext4_free_inodes_count(sb, desc)) {
+                               *group = grp+i;
+                               return 0;
+                       }
                }
-               if (ret == 0)
-                       return ret;
                goto fallback;
        }
 
-       blocks_per_dir = ext4_blocks_count(es) - freeb;
-       do_div(blocks_per_dir, ndirs);
-
        max_dirs = ndirs / ngroups + inodes_per_group / 16;
-       min_inodes = avefreei - inodes_per_group / 4;
-       min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb) / 4;
-
-       max_debt = EXT4_BLOCKS_PER_GROUP(sb);
-       max_debt /= max_t(int, blocks_per_dir, BLOCK_COST);
-       if (max_debt * INODE_COST > inodes_per_group)
-               max_debt = inodes_per_group / INODE_COST;
-       if (max_debt > 255)
-               max_debt = 255;
-       if (max_debt == 0)
-               max_debt = 1;
+       min_inodes = avefreei - inodes_per_group*flex_size / 4;
+       if (min_inodes < 1)
+               min_inodes = 1;
+       min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb)*flex_size / 4;
+
+       /*
+        * Start looking in the flex group where we last allocated an
+        * inode for this parent directory
+        */
+       if (EXT4_I(parent)->i_last_alloc_group != ~0) {
+               parent_group = EXT4_I(parent)->i_last_alloc_group;
+               if (flex_size > 1)
+                       parent_group >>= sbi->s_log_groups_per_flex;
+       }
 
        for (i = 0; i < ngroups; i++) {
-               *group = (parent_group + i) % ngroups;
-               desc = ext4_get_group_desc(sb, *group, NULL);
-               if (!desc || !ext4_free_inodes_count(sb, desc))
-                       continue;
-               if (ext4_used_dirs_count(sb, desc) >= max_dirs)
+               grp = (parent_group + i) % ngroups;
+               get_orlov_stats(sb, grp, flex_size, &stats);
+               if (stats.used_dirs >= max_dirs)
                        continue;
-               if (ext4_free_inodes_count(sb, desc) < min_inodes)
+               if (stats.free_inodes < min_inodes)
                        continue;
-               if (ext4_free_blks_count(sb, desc) < min_blocks)
+               if (stats.free_blocks < min_blocks)
                        continue;
-               return 0;
+               goto found_flex_bg;
        }
 
 fallback:
+       ngroups = sbi->s_groups_count;
+       avefreei = freei / ngroups;
+       parent_group = EXT4_I(parent)->i_block_group;
        for (i = 0; i < ngroups; i++) {
-               *group = (parent_group + i) % ngroups;
-               desc = ext4_get_group_desc(sb, *group, NULL);
+               grp = (parent_group + i) % ngroups;
+               desc = ext4_get_group_desc(sb, grp, NULL);
                if (desc && ext4_free_inodes_count(sb, desc) &&
-                       ext4_free_inodes_count(sb, desc) >= avefreei)
+                   ext4_free_inodes_count(sb, desc) >= avefreei) {
+                       *group = grp;
                        return 0;
+               }
        }
 
        if (avefreei) {
@@ -542,12 +609,51 @@ fallback:
 }
 
 static int find_group_other(struct super_block *sb, struct inode *parent,
-                               ext4_group_t *group)
+                           ext4_group_t *group, int mode)
 {
        ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
        ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
        struct ext4_group_desc *desc;
-       ext4_group_t i;
+       ext4_group_t i, last;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(sb));
+
+       /*
+        * Try to place the inode is the same flex group as its
+        * parent.  If we can't find space, use the Orlov algorithm to
+        * find another flex group, and store that information in the
+        * parent directory's inode information so that use that flex
+        * group for future allocations.
+        */
+       if (flex_size > 1) {
+               int retry = 0;
+
+       try_again:
+               parent_group &= ~(flex_size-1);
+               last = parent_group + flex_size;
+               if (last > ngroups)
+                       last = ngroups;
+               for  (i = parent_group; i < last; i++) {
+                       desc = ext4_get_group_desc(sb, i, NULL);
+                       if (desc && ext4_free_inodes_count(sb, desc)) {
+                               *group = i;
+                               return 0;
+                       }
+               }
+               if (!retry && EXT4_I(parent)->i_last_alloc_group != ~0) {
+                       retry = 1;
+                       parent_group = EXT4_I(parent)->i_last_alloc_group;
+                       goto try_again;
+               }
+               /*
+                * If this didn't work, use the Orlov search algorithm
+                * to find a new flex group; we pass in the mode to
+                * avoid the topdir algorithms.
+                */
+               *group = parent_group + flex_size;
+               if (*group > ngroups)
+                       *group = 0;
+               return find_group_orlov(sb, parent, group, mode);
+       }
 
        /*
         * Try to place the inode in its parent directory
@@ -665,6 +771,11 @@ static int ext4_claim_inode(struct super_block *sb,
        if (S_ISDIR(mode)) {
                count = ext4_used_dirs_count(sb, gdp) + 1;
                ext4_used_dirs_set(sb, gdp, count);
+               if (sbi->s_log_groups_per_flex) {
+                       ext4_group_t f = ext4_flex_group(sbi, group);
+
+                       atomic_inc(&sbi->s_flex_groups[f].free_inodes);
+               }
        }
        gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
 err_ret:
@@ -716,10 +827,10 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
        sbi = EXT4_SB(sb);
        es = sbi->s_es;
 
-       if (sbi->s_log_groups_per_flex) {
+       if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) {
                ret2 = find_group_flex(sb, dir, &group);
                if (ret2 == -1) {
-                       ret2 = find_group_other(sb, dir, &group);
+                       ret2 = find_group_other(sb, dir, &group, mode);
                        if (ret2 == 0 && once)
                                once = 0;
                                printk(KERN_NOTICE "ext4: find_group_flex "
@@ -733,11 +844,12 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
                if (test_opt(sb, OLDALLOC))
                        ret2 = find_group_dir(sb, dir, &group);
                else
-                       ret2 = find_group_orlov(sb, dir, &group);
+                       ret2 = find_group_orlov(sb, dir, &group, mode);
        } else
-               ret2 = find_group_other(sb, dir, &group);
+               ret2 = find_group_other(sb, dir, &group, mode);
 
 got_group:
+       EXT4_I(dir)->i_last_alloc_group = group;
        err = -ENOSPC;
        if (ret2 == -1)
                goto out;
@@ -858,9 +970,7 @@ got:
 
        if (sbi->s_log_groups_per_flex) {
                flex_group = ext4_flex_group(sbi, group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_inodes--;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes);
        }
 
        inode->i_uid = current_fsuid();
@@ -885,19 +995,16 @@ got:
        ei->i_disksize = 0;
 
        /*
-        * Don't inherit extent flag from directory. We set extent flag on
-        * newly created directory and file only if -o extent mount option is
-        * specified
+        * Don't inherit extent flag from directory, amongst others. We set
+        * extent flag on newly created directory and file only if -o extent
+        * mount option is specified
         */
-       ei->i_flags = EXT4_I(dir)->i_flags & ~(EXT4_INDEX_FL|EXT4_EXTENTS_FL);
-       if (S_ISLNK(mode))
-               ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL);
-       /* dirsync only applies to directories */
-       if (!S_ISDIR(mode))
-               ei->i_flags &= ~EXT4_DIRSYNC_FL;
+       ei->i_flags =
+               ext4_mask_flags(mode, EXT4_I(dir)->i_flags & EXT4_FL_INHERITED);
        ei->i_file_acl = 0;
        ei->i_dtime = 0;
        ei->i_block_group = group;
+       ei->i_last_alloc_group = ~0;
 
        ext4_set_inode_flags(inode);
        if (IS_DIRSYNC(inode))
index 71d3ecd5db798ce6bcab06331ca7ec4819f62ea1..a2e7952bc5f9a6e3f3ed877dde89fb93ef4b4035 100644 (file)
@@ -371,6 +371,34 @@ static int ext4_block_to_path(struct inode *inode,
        return n;
 }
 
+static int __ext4_check_blockref(const char *function, struct inode *inode,
+                                unsigned int *p, unsigned int max) {
+
+       unsigned int maxblocks = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es);
+       unsigned int *bref = p;
+       while (bref < p+max) {
+               if (unlikely(*bref >= maxblocks)) {
+                       ext4_error(inode->i_sb, function,
+                                  "block reference %u >= max (%u) "
+                                  "in inode #%lu, offset=%d",
+                                  *bref, maxblocks,
+                                  inode->i_ino, (int)(bref-p));
+                       return -EIO;
+               }
+               bref++;
+       }
+       return 0;
+}
+
+
+#define ext4_check_indirect_blockref(inode, bh)                         \
+        __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data,  \
+                             EXT4_ADDR_PER_BLOCK((inode)->i_sb))
+
+#define ext4_check_inode_blockref(inode)                                \
+        __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data,   \
+                             EXT4_NDIR_BLOCKS)
+
 /**
  *     ext4_get_branch - read the chain of indirect blocks leading to data
  *     @inode: inode in question
@@ -415,9 +443,22 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
        if (!p->key)
                goto no_block;
        while (--depth) {
-               bh = sb_bread(sb, le32_to_cpu(p->key));
-               if (!bh)
+               bh = sb_getblk(sb, le32_to_cpu(p->key));
+               if (unlikely(!bh))
                        goto failure;
+                  
+               if (!bh_uptodate_or_lock(bh)) {
+                       if (bh_submit_read(bh) < 0) {
+                               put_bh(bh);
+                               goto failure;
+                       }
+                       /* validate block references */
+                       if (ext4_check_indirect_blockref(inode, bh)) {
+                               put_bh(bh);
+                               goto failure;
+                       }
+               }
+               
                add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets);
                /* Reader: end */
                if (!p->key)
@@ -459,6 +500,8 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
        ext4_fsblk_t bg_start;
        ext4_fsblk_t last_block;
        ext4_grpblk_t colour;
+       ext4_group_t block_group;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
 
        /* Try to find previous block */
        for (p = ind->p - 1; p >= start; p--) {
@@ -474,9 +517,22 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
         * It is going to be referred to from the inode itself? OK, just put it
         * into the same cylinder group then.
         */
-       bg_start = ext4_group_first_block_no(inode->i_sb, ei->i_block_group);
+       block_group = ei->i_block_group;
+       if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
+               block_group &= ~(flex_size-1);
+               if (S_ISREG(inode->i_mode))
+                       block_group++;
+       }
+       bg_start = ext4_group_first_block_no(inode->i_sb, block_group);
        last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
 
+       /*
+        * If we are doing delayed allocation, we don't need take
+        * colour into account.
+        */
+       if (test_opt(inode->i_sb, DELALLOC))
+               return bg_start;
+
        if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
                colour = (current->pid % 16) *
                        (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
@@ -1052,9 +1108,16 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
        /*
         * free those over-booking quota for metadata blocks
         */
-
        if (mdb_free)
                vfs_dq_release_reservation_block(inode, mdb_free);
+
+       /*
+        * If we have done all the pending block allocations and if
+        * there aren't any writers on the inode, we can discard the
+        * inode's preallocations.
+        */
+       if (!total && (atomic_read(&inode->i_writecount) == 0))
+               ext4_discard_preallocations(inode);
 }
 
 /*
@@ -1688,9 +1751,10 @@ static void ext4_da_page_release_reservation(struct page *page,
 
 struct mpage_da_data {
        struct inode *inode;
-       struct buffer_head lbh;                 /* extent of blocks */
+       sector_t b_blocknr;             /* start block number of extent */
+       size_t b_size;                  /* size of extent */
+       unsigned long b_state;          /* state of the extent */
        unsigned long first_page, next_page;    /* extent of pages */
-       get_block_t *get_block;
        struct writeback_control *wbc;
        int io_done;
        int pages_written;
@@ -1704,7 +1768,6 @@ struct mpage_da_data {
  * @mpd->inode: inode
  * @mpd->first_page: first page of the extent
  * @mpd->next_page: page after the last page of the extent
- * @mpd->get_block: the filesystem's block mapper function
  *
  * By the time mpage_da_submit_io() is called we expect all blocks
  * to be allocated. this may be wrong if allocation failed.
@@ -1724,7 +1787,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
        /*
         * We need to start from the first_page to the next_page - 1
         * to make sure we also write the mapped dirty buffer_heads.
-        * If we look at mpd->lbh.b_blocknr we would only be looking
+        * If we look at mpd->b_blocknr we would only be looking
         * at the currently mapped buffer_heads.
         */
        index = mpd->first_page;
@@ -1914,68 +1977,111 @@ static void ext4_print_free_blocks(struct inode *inode)
        return;
 }
 
+#define                EXT4_DELALLOC_RSVED     1
+static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
+                                  struct buffer_head *bh_result, int create)
+{
+       int ret;
+       unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
+       loff_t disksize = EXT4_I(inode)->i_disksize;
+       handle_t *handle = NULL;
+
+       handle = ext4_journal_current_handle();
+       BUG_ON(!handle);
+       ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
+                                  bh_result, create, 0, EXT4_DELALLOC_RSVED);
+       if (ret <= 0)
+               return ret;
+
+       bh_result->b_size = (ret << inode->i_blkbits);
+
+       if (ext4_should_order_data(inode)) {
+               int retval;
+               retval = ext4_jbd2_file_inode(handle, inode);
+               if (retval)
+                       /*
+                        * Failed to add inode for ordered mode. Don't
+                        * update file size
+                        */
+                       return retval;
+       }
+
+       /*
+        * Update on-disk size along with block allocation we don't
+        * use 'extend_disksize' as size may change within already
+        * allocated block -bzzz
+        */
+       disksize = ((loff_t) iblock + ret) << inode->i_blkbits;
+       if (disksize > i_size_read(inode))
+               disksize = i_size_read(inode);
+       if (disksize > EXT4_I(inode)->i_disksize) {
+               ext4_update_i_disksize(inode, disksize);
+               ret = ext4_mark_inode_dirty(handle, inode);
+               return ret;
+       }
+       return 0;
+}
+
 /*
  * mpage_da_map_blocks - go through given space
  *
- * @mpd->lbh - bh describing space
- * @mpd->get_block - the filesystem's block mapper function
+ * @mpd - bh describing space
  *
  * The function skips space we know is already mapped to disk blocks.
  *
  */
-static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
+static int mpage_da_map_blocks(struct mpage_da_data *mpd)
 {
        int err = 0;
        struct buffer_head new;
-       struct buffer_head *lbh = &mpd->lbh;
        sector_t next;
 
        /*
         * We consider only non-mapped and non-allocated blocks
         */
-       if (buffer_mapped(lbh) && !buffer_delay(lbh))
+       if ((mpd->b_state  & (1 << BH_Mapped)) &&
+           !(mpd->b_state & (1 << BH_Delay)))
                return 0;
-       new.b_state = lbh->b_state;
+       new.b_state = mpd->b_state;
        new.b_blocknr = 0;
-       new.b_size = lbh->b_size;
-       next = lbh->b_blocknr;
+       new.b_size = mpd->b_size;
+       next = mpd->b_blocknr;
        /*
         * If we didn't accumulate anything
         * to write simply return
         */
        if (!new.b_size)
                return 0;
-       err = mpd->get_block(mpd->inode, next, &new, 1);
-       if (err) {
 
-               /* If get block returns with error
-                * we simply return. Later writepage
-                * will redirty the page and writepages
-                * will find the dirty page again
+       err = ext4_da_get_block_write(mpd->inode, next, &new, 1);
+       if (err) {
+               /*
+                * If get block returns with error we simply
+                * return. Later writepage will redirty the page and
+                * writepages will find the dirty page again
                 */
                if (err == -EAGAIN)
                        return 0;
 
                if (err == -ENOSPC &&
-                               ext4_count_free_blocks(mpd->inode->i_sb)) {
+                   ext4_count_free_blocks(mpd->inode->i_sb)) {
                        mpd->retval = err;
                        return 0;
                }
 
                /*
-                * get block failure will cause us
-                * to loop in writepages. Because
-                * a_ops->writepage won't be able to
-                * make progress. The page will be redirtied
-                * by writepage and writepages will again
-                * try to write the same.
+                * get block failure will cause us to loop in
+                * writepages, because a_ops->writepage won't be able
+                * to make progress. The page will be redirtied by
+                * writepage and writepages will again try to write
+                * the same.
                 */
                printk(KERN_EMERG "%s block allocation failed for inode %lu "
                                  "at logical offset %llu with max blocks "
                                  "%zd with error %d\n",
                                  __func__, mpd->inode->i_ino,
                                  (unsigned long long)next,
-                                 lbh->b_size >> mpd->inode->i_blkbits, err);
+                                 mpd->b_size >> mpd->inode->i_blkbits, err);
                printk(KERN_EMERG "This should not happen.!! "
                                        "Data will be lost\n");
                if (err == -ENOSPC) {
@@ -1983,7 +2089,7 @@ static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
                }
                /* invlaidate all the pages */
                ext4_da_block_invalidatepages(mpd, next,
-                               lbh->b_size >> mpd->inode->i_blkbits);
+                               mpd->b_size >> mpd->inode->i_blkbits);
                return err;
        }
        BUG_ON(new.b_size == 0);
@@ -1995,7 +2101,8 @@ static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
         * If blocks are delayed marked, we need to
         * put actual blocknr and drop delayed bit
         */
-       if (buffer_delay(lbh) || buffer_unwritten(lbh))
+       if ((mpd->b_state & (1 << BH_Delay)) ||
+           (mpd->b_state & (1 << BH_Unwritten)))
                mpage_put_bnr_to_bhs(mpd, next, &new);
 
        return 0;
@@ -2014,12 +2121,11 @@ static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
  * the function is used to collect contig. blocks in same state
  */
 static void mpage_add_bh_to_extent(struct mpage_da_data *mpd,
-                                  sector_t logical, struct buffer_head *bh)
+                                  sector_t logical, size_t b_size,
+                                  unsigned long b_state)
 {
        sector_t next;
-       size_t b_size = bh->b_size;
-       struct buffer_head *lbh = &mpd->lbh;
-       int nrblocks = lbh->b_size >> mpd->inode->i_blkbits;
+       int nrblocks = mpd->b_size >> mpd->inode->i_blkbits;
 
        /* check if thereserved journal credits might overflow */
        if (!(EXT4_I(mpd->inode)->i_flags & EXT4_EXTENTS_FL)) {
@@ -2046,19 +2152,19 @@ static void mpage_add_bh_to_extent(struct mpage_da_data *mpd,
        /*
         * First block in the extent
         */
-       if (lbh->b_size == 0) {
-               lbh->b_blocknr = logical;
-               lbh->b_size = b_size;
-               lbh->b_state = bh->b_state & BH_FLAGS;
+       if (mpd->b_size == 0) {
+               mpd->b_blocknr = logical;
+               mpd->b_size = b_size;
+               mpd->b_state = b_state & BH_FLAGS;
                return;
        }
 
-       next = lbh->b_blocknr + nrblocks;
+       next = mpd->b_blocknr + nrblocks;
        /*
         * Can we merge the block to our big extent?
         */
-       if (logical == next && (bh->b_state & BH_FLAGS) == lbh->b_state) {
-               lbh->b_size += b_size;
+       if (logical == next && (b_state & BH_FLAGS) == mpd->b_state) {
+               mpd->b_size += b_size;
                return;
        }
 
@@ -2087,7 +2193,7 @@ static int __mpage_da_writepage(struct page *page,
 {
        struct mpage_da_data *mpd = data;
        struct inode *inode = mpd->inode;
-       struct buffer_head *bh, *head, fake;
+       struct buffer_head *bh, *head;
        sector_t logical;
 
        if (mpd->io_done) {
@@ -2129,9 +2235,9 @@ static int __mpage_da_writepage(struct page *page,
                /*
                 * ... and blocks
                 */
-               mpd->lbh.b_size = 0;
-               mpd->lbh.b_state = 0;
-               mpd->lbh.b_blocknr = 0;
+               mpd->b_size = 0;
+               mpd->b_state = 0;
+               mpd->b_blocknr = 0;
        }
 
        mpd->next_page = page->index + 1;
@@ -2139,16 +2245,8 @@ static int __mpage_da_writepage(struct page *page,
                  (PAGE_CACHE_SHIFT - inode->i_blkbits);
 
        if (!page_has_buffers(page)) {
-               /*
-                * There is no attached buffer heads yet (mmap?)
-                * we treat the page asfull of dirty blocks
-                */
-               bh = &fake;
-               bh->b_size = PAGE_CACHE_SIZE;
-               bh->b_state = 0;
-               set_buffer_dirty(bh);
-               set_buffer_uptodate(bh);
-               mpage_add_bh_to_extent(mpd, logical, bh);
+               mpage_add_bh_to_extent(mpd, logical, PAGE_CACHE_SIZE,
+                                      (1 << BH_Dirty) | (1 << BH_Uptodate));
                if (mpd->io_done)
                        return MPAGE_DA_EXTENT_TAIL;
        } else {
@@ -2166,8 +2264,10 @@ static int __mpage_da_writepage(struct page *page,
                         * with the page in ext4_da_writepage
                         */
                        if (buffer_dirty(bh) &&
-                               (!buffer_mapped(bh) || buffer_delay(bh))) {
-                               mpage_add_bh_to_extent(mpd, logical, bh);
+                           (!buffer_mapped(bh) || buffer_delay(bh))) {
+                               mpage_add_bh_to_extent(mpd, logical,
+                                                      bh->b_size,
+                                                      bh->b_state);
                                if (mpd->io_done)
                                        return MPAGE_DA_EXTENT_TAIL;
                        } else if (buffer_dirty(bh) && (buffer_mapped(bh))) {
@@ -2179,9 +2279,8 @@ static int __mpage_da_writepage(struct page *page,
                                 * unmapped buffer_head later we need to
                                 * use the b_state flag of that buffer_head.
                                 */
-                               if (mpd->lbh.b_size == 0)
-                                       mpd->lbh.b_state =
-                                               bh->b_state & BH_FLAGS;
+                               if (mpd->b_size == 0)
+                                       mpd->b_state = bh->b_state & BH_FLAGS;
                        }
                        logical++;
                } while ((bh = bh->b_this_page) != head);
@@ -2190,51 +2289,6 @@ static int __mpage_da_writepage(struct page *page,
        return 0;
 }
 
-/*
- * mpage_da_writepages - walk the list of dirty pages of the given
- * address space, allocates non-allocated blocks, maps newly-allocated
- * blocks to existing bhs and issue IO them
- *
- * @mapping: address space structure to write
- * @wbc: subtract the number of written pages from *@wbc->nr_to_write
- * @get_block: the filesystem's block mapper function.
- *
- * This is a library function, which implements the writepages()
- * address_space_operation.
- */
-static int mpage_da_writepages(struct address_space *mapping,
-                              struct writeback_control *wbc,
-                              struct mpage_da_data *mpd)
-{
-       int ret;
-
-       if (!mpd->get_block)
-               return generic_writepages(mapping, wbc);
-
-       mpd->lbh.b_size = 0;
-       mpd->lbh.b_state = 0;
-       mpd->lbh.b_blocknr = 0;
-       mpd->first_page = 0;
-       mpd->next_page = 0;
-       mpd->io_done = 0;
-       mpd->pages_written = 0;
-       mpd->retval = 0;
-
-       ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, mpd);
-       /*
-        * Handle last extent of pages
-        */
-       if (!mpd->io_done && mpd->next_page != mpd->first_page) {
-               if (mpage_da_map_blocks(mpd) == 0)
-                       mpage_da_submit_io(mpd);
-
-               mpd->io_done = 1;
-               ret = MPAGE_DA_EXTENT_TAIL;
-       }
-       wbc->nr_to_write -= mpd->pages_written;
-       return ret;
-}
-
 /*
  * this is a special callback for ->write_begin() only
  * it's intention is to return mapped block or reserve space
@@ -2274,51 +2328,6 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
 
        return ret;
 }
-#define                EXT4_DELALLOC_RSVED     1
-static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
-                                  struct buffer_head *bh_result, int create)
-{
-       int ret;
-       unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
-       loff_t disksize = EXT4_I(inode)->i_disksize;
-       handle_t *handle = NULL;
-
-       handle = ext4_journal_current_handle();
-       BUG_ON(!handle);
-       ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
-                       bh_result, create, 0, EXT4_DELALLOC_RSVED);
-       if (ret > 0) {
-
-               bh_result->b_size = (ret << inode->i_blkbits);
-
-               if (ext4_should_order_data(inode)) {
-                       int retval;
-                       retval = ext4_jbd2_file_inode(handle, inode);
-                       if (retval)
-                               /*
-                                * Failed to add inode for ordered
-                                * mode. Don't update file size
-                                */
-                               return retval;
-               }
-
-               /*
-                * Update on-disk size along with block allocation
-                * we don't use 'extend_disksize' as size may change
-                * within already allocated block -bzzz
-                */
-               disksize = ((loff_t) iblock + ret) << inode->i_blkbits;
-               if (disksize > i_size_read(inode))
-                       disksize = i_size_read(inode);
-               if (disksize > EXT4_I(inode)->i_disksize) {
-                       ext4_update_i_disksize(inode, disksize);
-                       ret = ext4_mark_inode_dirty(handle, inode);
-                       return ret;
-               }
-               ret = 0;
-       }
-       return ret;
-}
 
 static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
 {
@@ -2569,8 +2578,38 @@ retry:
                        dump_stack();
                        goto out_writepages;
                }
-               mpd.get_block = ext4_da_get_block_write;
-               ret = mpage_da_writepages(mapping, wbc, &mpd);
+
+               /*
+                * Now call __mpage_da_writepage to find the next
+                * contiguous region of logical blocks that need
+                * blocks to be allocated by ext4.  We don't actually
+                * submit the blocks for I/O here, even though
+                * write_cache_pages thinks it will, and will set the
+                * pages as clean for write before calling
+                * __mpage_da_writepage().
+                */
+               mpd.b_size = 0;
+               mpd.b_state = 0;
+               mpd.b_blocknr = 0;
+               mpd.first_page = 0;
+               mpd.next_page = 0;
+               mpd.io_done = 0;
+               mpd.pages_written = 0;
+               mpd.retval = 0;
+               ret = write_cache_pages(mapping, wbc, __mpage_da_writepage,
+                                       &mpd);
+               /*
+                * If we have a contigous extent of pages and we
+                * haven't done the I/O yet, map the blocks and submit
+                * them for I/O.
+                */
+               if (!mpd.io_done && mpd.next_page != mpd.first_page) {
+                       if (mpage_da_map_blocks(&mpd) == 0)
+                               mpage_da_submit_io(&mpd);
+                       mpd.io_done = 1;
+                       ret = MPAGE_DA_EXTENT_TAIL;
+               }
+               wbc->nr_to_write -= mpd.pages_written;
 
                ext4_journal_stop(handle);
 
@@ -2846,6 +2885,48 @@ out:
        return;
 }
 
+/*
+ * Force all delayed allocation blocks to be allocated for a given inode.
+ */
+int ext4_alloc_da_blocks(struct inode *inode)
+{
+       if (!EXT4_I(inode)->i_reserved_data_blocks &&
+           !EXT4_I(inode)->i_reserved_meta_blocks)
+               return 0;
+
+       /*
+        * We do something simple for now.  The filemap_flush() will
+        * also start triggering a write of the data blocks, which is
+        * not strictly speaking necessary (and for users of
+        * laptop_mode, not even desirable).  However, to do otherwise
+        * would require replicating code paths in:
+        * 
+        * ext4_da_writepages() ->
+        *    write_cache_pages() ---> (via passed in callback function)
+        *        __mpage_da_writepage() -->
+        *           mpage_add_bh_to_extent()
+        *           mpage_da_map_blocks()
+        *
+        * The problem is that write_cache_pages(), located in
+        * mm/page-writeback.c, marks pages clean in preparation for
+        * doing I/O, which is not desirable if we're not planning on
+        * doing I/O at all.
+        *
+        * We could call write_cache_pages(), and then redirty all of
+        * the pages by calling redirty_page_for_writeback() but that
+        * would be ugly in the extreme.  So instead we would need to
+        * replicate parts of the code in the above functions,
+        * simplifying them becuase we wouldn't actually intend to
+        * write out the pages, but rather only collect contiguous
+        * logical block extents, call the multi-block allocator, and
+        * then update the buffer heads with the block allocations.
+        * 
+        * For now, though, we'll cheat by calling filemap_flush(),
+        * which will map the blocks, and start the I/O, but not
+        * actually wait for the I/O to complete.
+        */
+       return filemap_flush(inode->i_mapping);
+}
 
 /*
  * bmap() is special.  It gets used by applications such as lilo and by
@@ -3868,6 +3949,9 @@ void ext4_truncate(struct inode *inode)
        if (!ext4_can_truncate(inode))
                return;
 
+       if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
+               ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE;
+
        if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
                ext4_ext_truncate(inode);
                return;
@@ -4110,12 +4194,7 @@ make_io:
                        unsigned num;
 
                        table = ext4_inode_table(sb, gdp);
-                       /* Make sure s_inode_readahead_blks is a power of 2 */
-                       while (EXT4_SB(sb)->s_inode_readahead_blks &
-                              (EXT4_SB(sb)->s_inode_readahead_blks-1))
-                               EXT4_SB(sb)->s_inode_readahead_blks = 
-                                  (EXT4_SB(sb)->s_inode_readahead_blks &
-                                   (EXT4_SB(sb)->s_inode_readahead_blks-1));
+                       /* s_inode_readahead_blks is always a power of 2 */
                        b = block & ~(EXT4_SB(sb)->s_inode_readahead_blks-1);
                        if (table > b)
                                b = table;
@@ -4287,6 +4366,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        ei->i_disksize = inode->i_size;
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
        ei->i_block_group = iloc.block_group;
+       ei->i_last_alloc_group = ~0;
        /*
         * NOTE! The in-memory inode i_data array is in little-endian order
         * even on big-endian machines: we do NOT byteswap the block numbers!
@@ -4329,6 +4409,20 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32;
        }
 
+       if (ei->i_flags & EXT4_EXTENTS_FL) {
+               /* Validate extent which is part of inode */
+               ret = ext4_ext_check_inode(inode);
+       } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+                  (S_ISLNK(inode->i_mode) &&
+                   !ext4_inode_is_fast_symlink(inode))) {
+               /* Validate block references which are part of inode */
+               ret = ext4_check_inode_blockref(inode);
+       }
+       if (ret) {
+               brelse(bh);
+               goto bad_inode;
+       }
+
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext4_file_inode_operations;
                inode->i_fop = &ext4_file_operations;
@@ -4345,7 +4439,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        inode->i_op = &ext4_symlink_inode_operations;
                        ext4_set_aops(inode);
                }
-       } else {
+       } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
+             S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
                inode->i_op = &ext4_special_inode_operations;
                if (raw_inode->i_block[0])
                        init_special_inode(inode, inode->i_mode,
@@ -4353,6 +4448,13 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                else
                        init_special_inode(inode, inode->i_mode,
                           new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
+       } else {
+               brelse(bh);
+               ret = -EIO;
+               ext4_error(inode->i_sb, __func__, 
+                          "bogus i_mode (%o) for inode=%lu",
+                          inode->i_mode, inode->i_ino);
+               goto bad_inode;
        }
        brelse(iloc.bh);
        ext4_set_inode_flags(inode);
@@ -5146,8 +5248,9 @@ static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh)
        return !buffer_mapped(bh);
 }
 
-int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        loff_t size;
        unsigned long len;
        int ret = -EINVAL;
@@ -5199,6 +5302,8 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
                goto out_unlock;
        ret = 0;
 out_unlock:
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        up_read(&inode->i_alloc_sem);
        return ret;
 }
index 42dc83fb247a98f6dd4450314bf2f96d4e36c175..91e75f7a9e732c4ba6cdf909cfd3607f32dbd800 100644 (file)
@@ -48,8 +48,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (err)
                        return err;
 
-               if (!S_ISDIR(inode->i_mode))
-                       flags &= ~EXT4_DIRSYNC_FL;
+               flags = ext4_mask_flags(inode->i_mode, flags);
 
                err = -EPERM;
                mutex_lock(&inode->i_mutex);
@@ -263,6 +262,20 @@ setversion_out:
                return err;
        }
 
+       case EXT4_IOC_ALLOC_DA_BLKS:
+       {
+               int err;
+               if (!is_owner_or_cap(inode))
+                       return -EACCES;
+
+               err = mnt_want_write(filp->f_path.mnt);
+               if (err)
+                       return err;
+               err = ext4_alloc_da_blocks(inode);
+               mnt_drop_write(filp->f_path.mnt);
+               return err;
+       }
+
        default:
                return -ENOTTY;
        }
index b038188bd039e8f8c2762c13318c078fd353b17a..f871677a798499c4327629cf282d4f75b38d44b3 100644 (file)
  * The allocation request involve request for multiple number of blocks
  * near to the goal(block) value specified.
  *
- * During initialization phase of the allocator we decide to use the group
- * preallocation or inode preallocation depending on the size file. The
- * size of the file could be the resulting file size we would have after
- * allocation or the current file size which ever is larger. If the size is
- * less that sbi->s_mb_stream_request we select the group
- * preallocation. The default value of s_mb_stream_request is 16
- * blocks. This can also be tuned via
- * /proc/fs/ext4/<partition>/stream_req. The value is represented in terms
- * of number of blocks.
+ * During initialization phase of the allocator we decide to use the
+ * group preallocation or inode preallocation depending on the size of
+ * the file. The size of the file could be the resulting file size we
+ * would have after allocation, or the current file size, which ever
+ * is larger. If the size is less than sbi->s_mb_stream_request we
+ * select to use the group preallocation. The default value of
+ * s_mb_stream_request is 16 blocks. This can also be tuned via
+ * /sys/fs/ext4/<partition>/mb_stream_req. The value is represented in
+ * terms of number of blocks.
  *
  * The main motivation for having small file use group preallocation is to
- * ensure that we have small file closer in the disk.
+ * ensure that we have small files closer together on the disk.
  *
- * First stage the allocator looks at the inode prealloc list
- * ext4_inode_info->i_prealloc_list contain list of prealloc spaces for
- * this particular inode. The inode prealloc space is represented as:
+ * First stage the allocator looks at the inode prealloc list,
+ * ext4_inode_info->i_prealloc_list, which contains list of prealloc
+ * spaces for this particular inode. The inode prealloc space is
+ * represented as:
  *
  * pa_lstart -> the logical start block for this prealloc space
  * pa_pstart -> the physical start block for this prealloc space
  * list. In case of inode preallocation we follow a list of heuristics
  * based on file size. This can be found in ext4_mb_normalize_request. If
  * we are doing a group prealloc we try to normalize the request to
- * sbi->s_mb_group_prealloc. Default value of s_mb_group_prealloc is set to
+ * sbi->s_mb_group_prealloc. Default value of s_mb_group_prealloc is
  * 512 blocks. This can be tuned via
- * /proc/fs/ext4/<partition/group_prealloc. The value is represented in
+ * /sys/fs/ext4/<partition/mb_group_prealloc. The value is represented in
  * terms of number of blocks. If we have mounted the file system with -O
  * stripe=<value> option the group prealloc request is normalized to the
  * stripe value (sbi->s_stripe)
  *
- * The regular allocator(using the buddy cache) support few tunables.
+ * The regular allocator(using the buddy cache) supports few tunables.
  *
- * /proc/fs/ext4/<partition>/min_to_scan
- * /proc/fs/ext4/<partition>/max_to_scan
- * /proc/fs/ext4/<partition>/order2_req
+ * /sys/fs/ext4/<partition>/mb_min_to_scan
+ * /sys/fs/ext4/<partition>/mb_max_to_scan
+ * /sys/fs/ext4/<partition>/mb_order2_req
  *
- * The regular allocator use buddy scan only if the request len is power of
+ * The regular allocator uses buddy scan only if the request len is power of
  * 2 blocks and the order of allocation is >= sbi->s_mb_order2_reqs. The
  * value of s_mb_order2_reqs can be tuned via
- * /proc/fs/ext4/<partition>/order2_req.  If the request len is equal to
+ * /sys/fs/ext4/<partition>/mb_order2_req.  If the request len is equal to
  * stripe size (sbi->s_stripe), we try to search for contigous block in
- * stripe size. This should result in better allocation on RAID setup. If
- * not we search in the specific group using bitmap for best extents. The
- * tunable min_to_scan and max_to_scan controll the behaviour here.
+ * stripe size. This should result in better allocation on RAID setups. If
+ * not, we search in the specific group using bitmap for best extents. The
+ * tunable min_to_scan and max_to_scan control the behaviour here.
  * min_to_scan indicate how long the mballoc __must__ look for a best
- * extent and max_to_scanindicate how long the mballoc __can__ look for a
+ * extent and max_to_scan indicates how long the mballoc __can__ look for a
  * best extent in the found extents. Searching for the blocks starts with
  * the group specified as the goal value in allocation context via
  * ac_g_ex. Each group is first checked based on the criteria whether it
@@ -337,8 +338,6 @@ static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group);
 static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
                                                ext4_group_t group);
-static int ext4_mb_init_per_dev_proc(struct super_block *sb);
-static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
 static void release_blocks_on_commit(journal_t *journal, transaction_t *txn);
 
 
@@ -1726,6 +1725,7 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
 {
        unsigned free, fragments;
        unsigned i, bits;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(ac->ac_sb));
        struct ext4_group_desc *desc;
        struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
 
@@ -1747,6 +1747,12 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
                if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
                        return 0;
 
+               /* Avoid using the first bg of a flexgroup for data files */
+               if ((ac->ac_flags & EXT4_MB_HINT_DATA) &&
+                   (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) &&
+                   ((group % flex_size) == 0))
+                       return 0;
+
                bits = ac->ac_sb->s_blocksize_bits + 1;
                for (i = ac->ac_2order; i <= bits; i++)
                        if (grp->bb_counters[i] > 0)
@@ -1971,7 +1977,7 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
        /*
         * We search using buddy data only if the order of the request
         * is greater than equal to the sbi_s_mb_order2_reqs
-        * You can tune it via /proc/fs/ext4/<partition>/order2_req
+        * You can tune it via /sys/fs/ext4/<partition>/mb_order2_req
         */
        if (i >= sbi->s_mb_order2_reqs) {
                /*
@@ -2693,7 +2699,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        i = (sb->s_blocksize_bits + 2) * sizeof(unsigned int);
        sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_maxs == NULL) {
-               kfree(sbi->s_mb_maxs);
+               kfree(sbi->s_mb_offsets);
                return -ENOMEM;
        }
 
@@ -2746,7 +2752,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
                spin_lock_init(&lg->lg_prealloc_lock);
        }
 
-       ext4_mb_init_per_dev_proc(sb);
        ext4_mb_history_init(sb);
 
        if (sbi->s_journal)
@@ -2829,7 +2834,6 @@ int ext4_mb_release(struct super_block *sb)
 
        free_percpu(sbi->s_locality_groups);
        ext4_mb_history_release(sb);
-       ext4_mb_destroy_per_dev_proc(sb);
 
        return 0;
 }
@@ -2890,62 +2894,6 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
        mb_debug("freed %u blocks in %u structures\n", count, count2);
 }
 
-#define EXT4_MB_STATS_NAME             "stats"
-#define EXT4_MB_MAX_TO_SCAN_NAME       "max_to_scan"
-#define EXT4_MB_MIN_TO_SCAN_NAME       "min_to_scan"
-#define EXT4_MB_ORDER2_REQ             "order2_req"
-#define EXT4_MB_STREAM_REQ             "stream_req"
-#define EXT4_MB_GROUP_PREALLOC         "group_prealloc"
-
-static int ext4_mb_init_per_dev_proc(struct super_block *sb)
-{
-#ifdef CONFIG_PROC_FS
-       mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct proc_dir_entry *proc;
-
-       if (sbi->s_proc == NULL)
-               return -EINVAL;
-
-       EXT4_PROC_HANDLER(EXT4_MB_STATS_NAME, mb_stats);
-       EXT4_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, mb_max_to_scan);
-       EXT4_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, mb_min_to_scan);
-       EXT4_PROC_HANDLER(EXT4_MB_ORDER2_REQ, mb_order2_reqs);
-       EXT4_PROC_HANDLER(EXT4_MB_STREAM_REQ, mb_stream_request);
-       EXT4_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, mb_group_prealloc);
-       return 0;
-
-err_out:
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
-       return -ENOMEM;
-#else
-       return 0;
-#endif
-}
-
-static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
-{
-#ifdef CONFIG_PROC_FS
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-       if (sbi->s_proc == NULL)
-               return -EINVAL;
-
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
-#endif
-       return 0;
-}
-
 int __init init_ext4_mballoc(void)
 {
        ext4_pspace_cachep =
@@ -3096,9 +3044,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi,
                                                          ac->ac_b_ex.fe_group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_blocks -= ac->ac_b_ex.fe_len;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_sub(ac->ac_b_ex.fe_len,
+                          &sbi->s_flex_groups[flex_group].free_blocks);
        }
 
        err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
@@ -3116,7 +3063,7 @@ out_err:
  * here we normalize request for locality group
  * Group request are normalized to s_strip size if we set the same via mount
  * option. If not we set it to s_mb_group_prealloc which can be configured via
- * /proc/fs/ext4/<partition>/group_prealloc
+ * /sys/fs/ext4/<partition>/mb_group_prealloc
  *
  * XXX: should we try to preallocate more than the group has now?
  */
@@ -3608,8 +3555,11 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
        spin_unlock(&pa->pa_lock);
 
        grp_blk = pa->pa_pstart;
-       /* If linear, pa_pstart may be in the next group when pa is used up */
-       if (pa->pa_linear)
+       /* 
+        * If doing group-based preallocation, pa_pstart may be in the
+        * next group when pa is used up
+        */
+       if (pa->pa_type == MB_GROUP_PA)
                grp_blk--;
 
        ext4_get_group_no_and_offset(sb, grp_blk, &grp, NULL);
@@ -3704,7 +3654,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
        INIT_LIST_HEAD(&pa->pa_inode_list);
        INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
-       pa->pa_linear = 0;
+       pa->pa_type = MB_INODE_PA;
 
        mb_debug("new inode pa %p: %llu/%u for %u\n", pa,
                        pa->pa_pstart, pa->pa_len, pa->pa_lstart);
@@ -3767,7 +3717,7 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
        INIT_LIST_HEAD(&pa->pa_inode_list);
        INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
-       pa->pa_linear = 1;
+       pa->pa_type = MB_GROUP_PA;
 
        mb_debug("new group pa %p: %llu/%u for %u\n", pa,
                 pa->pa_pstart, pa->pa_len, pa->pa_lstart);
@@ -4021,7 +3971,7 @@ repeat:
                list_del_rcu(&pa->pa_inode_list);
                spin_unlock(pa->pa_obj_lock);
 
-               if (pa->pa_linear)
+               if (pa->pa_type == MB_GROUP_PA)
                        ext4_mb_release_group_pa(&e4b, pa, ac);
                else
                        ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
@@ -4121,7 +4071,7 @@ repeat:
        spin_unlock(&ei->i_prealloc_lock);
 
        list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) {
-               BUG_ON(pa->pa_linear != 0);
+               BUG_ON(pa->pa_type != MB_INODE_PA);
                ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
 
                err = ext4_mb_load_buddy(sb, group, &e4b);
@@ -4232,7 +4182,7 @@ static inline void ext4_mb_show_ac(struct ext4_allocation_context *ac)
  * file is determined by the current size or the resulting size after
  * allocation which ever is larger
  *
- * One can tune this size via /proc/fs/ext4/<partition>/stream_req
+ * One can tune this size via /sys/fs/ext4/<partition>/mb_stream_req
  */
 static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
 {
@@ -4373,7 +4323,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
                        continue;
                }
                /* only lg prealloc space */
-               BUG_ON(!pa->pa_linear);
+               BUG_ON(pa->pa_type != MB_GROUP_PA);
 
                /* seems this one can be freed ... */
                pa->pa_deleted = 1;
@@ -4442,7 +4392,7 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac)
                                                pa_inode_list) {
                spin_lock(&tmp_pa->pa_lock);
                if (tmp_pa->pa_deleted) {
-                       spin_unlock(&pa->pa_lock);
+                       spin_unlock(&tmp_pa->pa_lock);
                        continue;
                }
                if (!added && pa->pa_free < tmp_pa->pa_free) {
@@ -4479,7 +4429,7 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
 {
        struct ext4_prealloc_space *pa = ac->ac_pa;
        if (pa) {
-               if (pa->pa_linear) {
+               if (pa->pa_type == MB_GROUP_PA) {
                        /* see comment in ext4_mb_use_group_pa() */
                        spin_lock(&pa->pa_lock);
                        pa->pa_pstart += ac->ac_b_ex.fe_len;
@@ -4499,7 +4449,7 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
                 * doesn't grow big.  We need to release
                 * alloc_semp before calling ext4_mb_add_n_trim()
                 */
-               if (pa->pa_linear && likely(pa->pa_free)) {
+               if ((pa->pa_type == MB_GROUP_PA) && likely(pa->pa_free)) {
                        spin_lock(pa->pa_obj_lock);
                        list_del_rcu(&pa->pa_inode_list);
                        spin_unlock(pa->pa_obj_lock);
@@ -4936,9 +4886,7 @@ do_more:
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_blocks += count;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
+               atomic_add(count, &sbi->s_flex_groups[flex_group].free_blocks);
        }
 
        ext4_mb_release_desc(&e4b);
index 10a2921baf14c986c809a8746fb4b90d3a7f8fbe..dd9e6cd5f6cf4dc97ae6c97b4c6c5c9d5bee9e4d 100644 (file)
@@ -132,12 +132,15 @@ struct ext4_prealloc_space {
        ext4_lblk_t             pa_lstart;      /* log. block */
        unsigned short          pa_len;         /* len of preallocated chunk */
        unsigned short          pa_free;        /* how many blocks are free */
-       unsigned short          pa_linear;      /* consumed in one direction
-                                                * strictly, for grp prealloc */
+       unsigned short          pa_type;        /* pa type. inode or group */
        spinlock_t              *pa_obj_lock;
        struct inode            *pa_inode;      /* hack, for history only */
 };
 
+enum {
+       MB_INODE_PA = 0,
+       MB_GROUP_PA = 1
+};
 
 struct ext4_free_extent {
        ext4_lblk_t fe_logical;
@@ -247,7 +250,6 @@ static inline void ext4_mb_store_history(struct ext4_allocation_context *ac)
 
 #define in_range(b, first, len)        ((b) >= (first) && (b) <= (first) + (len) - 1)
 
-struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
 static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
                                        struct ext4_free_extent *fex)
 {
index 83410244d3ee11f483db465373665c9843df91cc..22098e1cd085911a7aeffc975ac7a0773a32bbc0 100644 (file)
@@ -161,12 +161,12 @@ static struct dx_frame *dx_probe(const struct qstr *d_name,
                                 struct dx_frame *frame,
                                 int *err);
 static void dx_release(struct dx_frame *frames);
-static int dx_make_map(struct ext4_dir_entry_2 *de, int size,
+static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
                       struct dx_hash_info *hinfo, struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
 static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
-               struct dx_map_entry *offsets, int count);
-static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size);
+               struct dx_map_entry *offsets, int count, unsigned blocksize);
+static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize);
 static void dx_insert_block(struct dx_frame *frame,
                                        u32 hash, ext4_lblk_t block);
 static int ext4_htree_next_block(struct inode *dir, __u32 hash,
@@ -180,14 +180,38 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
 static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                             struct inode *inode);
 
+unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
+{
+       unsigned len = le16_to_cpu(dlen);
+
+       if (len == EXT4_MAX_REC_LEN || len == 0)
+               return blocksize;
+       return (len & 65532) | ((len & 3) << 16);
+}
+  
+__le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
+{
+       if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
+               BUG();
+       if (len < 65536)
+               return cpu_to_le16(len);
+       if (len == blocksize) {
+               if (blocksize == 65536)
+                       return cpu_to_le16(EXT4_MAX_REC_LEN);
+               else 
+                       return cpu_to_le16(0);
+       }
+       return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
+}
+
 /*
  * p is at least 6 bytes before the end of page
  */
 static inline struct ext4_dir_entry_2 *
-ext4_next_entry(struct ext4_dir_entry_2 *p)
+ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize)
 {
        return (struct ext4_dir_entry_2 *)((char *)p +
-               ext4_rec_len_from_disk(p->rec_len));
+               ext4_rec_len_from_disk(p->rec_len, blocksize));
 }
 
 /*
@@ -294,7 +318,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_ent
                        space += EXT4_DIR_REC_LEN(de->name_len);
                        names++;
                }
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, size);
        }
        printk("(%i)\n", names);
        return (struct stats) { names, space, 1 };
@@ -585,7 +609,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
        top = (struct ext4_dir_entry_2 *) ((char *) de +
                                           dir->i_sb->s_blocksize -
                                           EXT4_DIR_REC_LEN(0));
-       for (; de < top; de = ext4_next_entry(de)) {
+       for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
                if (!ext4_check_dir_entry("htree_dirblock_to_tree", dir, de, bh,
                                        (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
                                                +((char *)de - bh->b_data))) {
@@ -663,7 +687,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        }
        if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) {
                de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, dir->i_sb->s_blocksize);
                if ((err = ext4_htree_store_dirent(dir_file, 2, 0, de)) != 0)
                        goto errout;
                count++;
@@ -713,15 +737,15 @@ errout:
  * Create map of hash values, offsets, and sizes, stored at end of block.
  * Returns number of entries mapped.
  */
-static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
-                       struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
+static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
+                      struct dx_hash_info *hinfo,
+                      struct dx_map_entry *map_tail)
 {
        int count = 0;
        char *base = (char *) de;
        struct dx_hash_info h = *hinfo;
 
-       while ((char *) de < base + size)
-       {
+       while ((char *) de < base + blocksize) {
                if (de->name_len && de->inode) {
                        ext4fs_dirhash(de->name, de->name_len, &h);
                        map_tail--;
@@ -732,7 +756,7 @@ static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
                        cond_resched();
                }
                /* XXX: do we need to check rec_len == 0 case? -Chris */
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, blocksize);
        }
        return count;
 }
@@ -832,7 +856,8 @@ static inline int search_dirblock(struct buffer_head *bh,
                        return 1;
                }
                /* prevent looping on a bad block */
-               de_len = ext4_rec_len_from_disk(de->rec_len);
+               de_len = ext4_rec_len_from_disk(de->rec_len,
+                                               dir->i_sb->s_blocksize);
                if (de_len <= 0)
                        return -1;
                offset += de_len;
@@ -996,7 +1021,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
                de = (struct ext4_dir_entry_2 *) bh->b_data;
                top = (struct ext4_dir_entry_2 *) ((char *) de + sb->s_blocksize -
                                       EXT4_DIR_REC_LEN(0));
-               for (; de < top; de = ext4_next_entry(de)) {
+               for (; de < top; de = ext4_next_entry(de, sb->s_blocksize)) {
                        int off = (block << EXT4_BLOCK_SIZE_BITS(sb))
                                  + ((char *) de - bh->b_data);
 
@@ -1052,8 +1077,16 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
                        return ERR_PTR(-EIO);
                }
                inode = ext4_iget(dir->i_sb, ino);
-               if (IS_ERR(inode))
-                       return ERR_CAST(inode);
+               if (unlikely(IS_ERR(inode))) {
+                       if (PTR_ERR(inode) == -ESTALE) {
+                               ext4_error(dir->i_sb, __func__,
+                                               "deleted inode referenced: %u",
+                                               ino);
+                               return ERR_PTR(-EIO);
+                       } else {
+                               return ERR_CAST(inode);
+                       }
+               }
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1109,7 +1142,8 @@ static inline void ext4_set_de_type(struct super_block *sb,
  * Returns pointer to last entry moved.
  */
 static struct ext4_dir_entry_2 *
-dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
+dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
+               unsigned blocksize)
 {
        unsigned rec_len = 0;
 
@@ -1118,7 +1152,7 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
                rec_len = EXT4_DIR_REC_LEN(de->name_len);
                memcpy (to, de, rec_len);
                ((struct ext4_dir_entry_2 *) to)->rec_len =
-                               ext4_rec_len_to_disk(rec_len);
+                               ext4_rec_len_to_disk(rec_len, blocksize);
                de->inode = 0;
                map++;
                to += rec_len;
@@ -1130,19 +1164,19 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
  * Compact each dir entry in the range to the minimal rec_len.
  * Returns pointer to last entry in range.
  */
-static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size)
+static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize)
 {
        struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base;
        unsigned rec_len = 0;
 
        prev = to = de;
-       while ((char*)de < base + size) {
-               next = ext4_next_entry(de);
+       while ((char*)de < base + blocksize) {
+               next = ext4_next_entry(de, blocksize);
                if (de->inode && de->name_len) {
                        rec_len = EXT4_DIR_REC_LEN(de->name_len);
                        if (de > to)
                                memmove(to, de, rec_len);
-                       to->rec_len = ext4_rec_len_to_disk(rec_len);
+                       to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize);
                        prev = to;
                        to = (struct ext4_dir_entry_2 *) (((char *) to) + rec_len);
                }
@@ -1215,10 +1249,12 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                                        hash2, split, count-split));
 
        /* Fancy dance to stay within two buffers */
-       de2 = dx_move_dirents(data1, data2, map + split, count - split);
+       de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize);
        de = dx_pack_dirents(data1, blocksize);
-       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de);
-       de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2);
+       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de,
+                                          blocksize);
+       de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2,
+                                           blocksize);
        dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1));
        dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1));
 
@@ -1268,6 +1304,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
        const char      *name = dentry->d_name.name;
        int             namelen = dentry->d_name.len;
        unsigned int    offset = 0;
+       unsigned int    blocksize = dir->i_sb->s_blocksize;
        unsigned short  reclen;
        int             nlen, rlen, err;
        char            *top;
@@ -1275,7 +1312,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
        reclen = EXT4_DIR_REC_LEN(namelen);
        if (!de) {
                de = (struct ext4_dir_entry_2 *)bh->b_data;
-               top = bh->b_data + dir->i_sb->s_blocksize - reclen;
+               top = bh->b_data + blocksize - reclen;
                while ((char *) de <= top) {
                        if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
                                                  bh, offset)) {
@@ -1287,7 +1324,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
                                return -EEXIST;
                        }
                        nlen = EXT4_DIR_REC_LEN(de->name_len);
-                       rlen = ext4_rec_len_from_disk(de->rec_len);
+                       rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
                        if ((de->inode? rlen - nlen: rlen) >= reclen)
                                break;
                        de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
@@ -1306,11 +1343,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
 
        /* By now the buffer is marked for journaling */
        nlen = EXT4_DIR_REC_LEN(de->name_len);
-       rlen = ext4_rec_len_from_disk(de->rec_len);
+       rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
        if (de->inode) {
                struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen);
-               de1->rec_len = ext4_rec_len_to_disk(rlen - nlen);
-               de->rec_len = ext4_rec_len_to_disk(nlen);
+               de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, blocksize);
+               de->rec_len = ext4_rec_len_to_disk(nlen, blocksize);
                de = de1;
        }
        de->file_type = EXT4_FT_UNKNOWN;
@@ -1380,7 +1417,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        /* The 0th block becomes the root, move the dirents out */
        fde = &root->dotdot;
        de = (struct ext4_dir_entry_2 *)((char *)fde +
-               ext4_rec_len_from_disk(fde->rec_len));
+               ext4_rec_len_from_disk(fde->rec_len, blocksize));
        if ((char *) de >= (((char *) root) + blocksize)) {
                ext4_error(dir->i_sb, __func__,
                           "invalid rec_len for '..' in inode %lu",
@@ -1402,12 +1439,14 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        memcpy (data1, de, len);
        de = (struct ext4_dir_entry_2 *) data1;
        top = data1 + len;
-       while ((char *)(de2 = ext4_next_entry(de)) < top)
+       while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top)
                de = de2;
-       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de);
+       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de,
+                                          blocksize);
        /* Initialize the root; the dot dirents already exist */
        de = (struct ext4_dir_entry_2 *) (&root->dotdot);
-       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2));
+       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2),
+                                          blocksize);
        memset (&root->info, 0, sizeof(root->info));
        root->info.info_length = sizeof(root->info);
        root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
@@ -1488,7 +1527,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                return retval;
        de = (struct ext4_dir_entry_2 *) bh->b_data;
        de->inode = 0;
-       de->rec_len = ext4_rec_len_to_disk(blocksize);
+       de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
        return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
 
@@ -1551,7 +1590,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                        goto cleanup;
                node2 = (struct dx_node *)(bh2->b_data);
                entries2 = node2->entries;
-               node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize);
+               node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize,
+                                                          sb->s_blocksize);
                node2->fake.inode = 0;
                BUFFER_TRACE(frame->bh, "get_write_access");
                err = ext4_journal_get_write_access(handle, frame->bh);
@@ -1639,6 +1679,7 @@ static int ext4_delete_entry(handle_t *handle,
                             struct buffer_head *bh)
 {
        struct ext4_dir_entry_2 *de, *pde;
+       unsigned int blocksize = dir->i_sb->s_blocksize;
        int i;
 
        i = 0;
@@ -1652,8 +1693,11 @@ static int ext4_delete_entry(handle_t *handle,
                        ext4_journal_get_write_access(handle, bh);
                        if (pde)
                                pde->rec_len = ext4_rec_len_to_disk(
-                                       ext4_rec_len_from_disk(pde->rec_len) +
-                                       ext4_rec_len_from_disk(de->rec_len));
+                                       ext4_rec_len_from_disk(pde->rec_len,
+                                                              blocksize) +
+                                       ext4_rec_len_from_disk(de->rec_len,
+                                                              blocksize),
+                                       blocksize);
                        else
                                de->inode = 0;
                        dir->i_version++;
@@ -1661,9 +1705,9 @@ static int ext4_delete_entry(handle_t *handle,
                        ext4_handle_dirty_metadata(handle, dir, bh);
                        return 0;
                }
-               i += ext4_rec_len_from_disk(de->rec_len);
+               i += ext4_rec_len_from_disk(de->rec_len, blocksize);
                pde = de;
-               de = ext4_next_entry(de);
+               de = ext4_next_entry(de, blocksize);
        }
        return -ENOENT;
 }
@@ -1793,6 +1837,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct inode *inode;
        struct buffer_head *dir_block;
        struct ext4_dir_entry_2 *de;
+       unsigned int blocksize = dir->i_sb->s_blocksize;
        int err, retries = 0;
 
        if (EXT4_DIR_LINK_MAX(dir))
@@ -1824,13 +1869,14 @@ retry:
        de = (struct ext4_dir_entry_2 *) dir_block->b_data;
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
-       de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len));
+       de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
+                                          blocksize);
        strcpy(de->name, ".");
        ext4_set_de_type(dir->i_sb, de, S_IFDIR);
-       de = ext4_next_entry(de);
+       de = ext4_next_entry(de, blocksize);
        de->inode = cpu_to_le32(dir->i_ino);
-       de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize -
-                                               EXT4_DIR_REC_LEN(1));
+       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(1),
+                                          blocksize);
        de->name_len = 2;
        strcpy(de->name, "..");
        ext4_set_de_type(dir->i_sb, de, S_IFDIR);
@@ -1885,7 +1931,7 @@ static int empty_dir(struct inode *inode)
                return 1;
        }
        de = (struct ext4_dir_entry_2 *) bh->b_data;
-       de1 = ext4_next_entry(de);
+       de1 = ext4_next_entry(de, sb->s_blocksize);
        if (le32_to_cpu(de->inode) != inode->i_ino ||
                        !le32_to_cpu(de1->inode) ||
                        strcmp(".", de->name) ||
@@ -1896,9 +1942,9 @@ static int empty_dir(struct inode *inode)
                brelse(bh);
                return 1;
        }
-       offset = ext4_rec_len_from_disk(de->rec_len) +
-                ext4_rec_len_from_disk(de1->rec_len);
-       de = ext4_next_entry(de1);
+       offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) +
+                ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
+       de = ext4_next_entry(de1, sb->s_blocksize);
        while (offset < inode->i_size) {
                if (!bh ||
                        (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
@@ -1927,8 +1973,8 @@ static int empty_dir(struct inode *inode)
                        brelse(bh);
                        return 0;
                }
-               offset += ext4_rec_len_from_disk(de->rec_len);
-               de = ext4_next_entry(de);
+               offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
+               de = ext4_next_entry(de, sb->s_blocksize);
        }
        brelse(bh);
        return 1;
@@ -2297,8 +2343,8 @@ retry:
        return err;
 }
 
-#define PARENT_INO(buffer) \
-       (ext4_next_entry((struct ext4_dir_entry_2 *)(buffer))->inode)
+#define PARENT_INO(buffer, size) \
+       (ext4_next_entry((struct ext4_dir_entry_2 *)(buffer), size)->inode)
 
 /*
  * Anybody can rename anything with this: the permission checks are left to the
@@ -2311,7 +2357,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct inode *old_inode, *new_inode;
        struct buffer_head *old_bh, *new_bh, *dir_bh;
        struct ext4_dir_entry_2 *old_de, *new_de;
-       int retval;
+       int retval, force_da_alloc = 0;
 
        old_bh = new_bh = dir_bh = NULL;
 
@@ -2358,7 +2404,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval);
                if (!dir_bh)
                        goto end_rename;
-               if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+               if (le32_to_cpu(PARENT_INO(dir_bh->b_data,
+                               old_dir->i_sb->s_blocksize)) != old_dir->i_ino)
                        goto end_rename;
                retval = -EMLINK;
                if (!new_inode && new_dir != old_dir &&
@@ -2430,7 +2477,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (dir_bh) {
                BUFFER_TRACE(dir_bh, "get_write_access");
                ext4_journal_get_write_access(handle, dir_bh);
-               PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
+               PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) =
+                                               cpu_to_le32(new_dir->i_ino);
                BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
                ext4_handle_dirty_metadata(handle, old_dir, dir_bh);
                ext4_dec_count(handle, old_dir);
@@ -2449,6 +2497,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                ext4_mark_inode_dirty(handle, new_inode);
                if (!new_inode->i_nlink)
                        ext4_orphan_add(handle, new_inode);
+               if (!test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC))
+                       force_da_alloc = 1;
        }
        retval = 0;
 
@@ -2457,6 +2507,8 @@ end_rename:
        brelse(old_bh);
        brelse(new_bh);
        ext4_journal_stop(handle);
+       if (retval == 0 && force_da_alloc)
+               ext4_alloc_da_blocks(old_inode);
        return retval;
 }
 
index c06886abd6588b3c975ee92dd1eb76a88be29e3a..546c7dd869e19176e77cb54278e9bdfc2b520da4 100644 (file)
@@ -938,10 +938,10 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
                ext4_group_t flex_group;
                flex_group = ext4_flex_group(sbi, input->group);
-               sbi->s_flex_groups[flex_group].free_blocks +=
-                       input->free_blocks_count;
-               sbi->s_flex_groups[flex_group].free_inodes +=
-                       EXT4_INODES_PER_GROUP(sb);
+               atomic_add(input->free_blocks_count,
+                          &sbi->s_flex_groups[flex_group].free_blocks);
+               atomic_add(EXT4_INODES_PER_GROUP(sb),
+                          &sbi->s_flex_groups[flex_group].free_inodes);
        }
 
        ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
index f7371a6a923d359480108517c1a3358276a42eb7..9987bba99db3cc62c2faa887b95783676f83b480 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
+#include <linux/ctype.h>
 #include <linux/marker.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
@@ -48,6 +49,7 @@
 #include "group.h"
 
 struct proc_dir_entry *ext4_proc_root;
+static struct kset *ext4_kset;
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
@@ -577,9 +579,9 @@ static void ext4_put_super(struct super_block *sb)
                ext4_commit_super(sb, es, 1);
        }
        if (sbi->s_proc) {
-               remove_proc_entry("inode_readahead_blks", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
+       kobject_del(&sbi->s_kobj);
 
        for (i = 0; i < sbi->s_gdb_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -615,6 +617,17 @@ static void ext4_put_super(struct super_block *sb)
                ext4_blkdev_remove(sbi);
        }
        sb->s_fs_info = NULL;
+       /*
+        * Now that we are completely done shutting down the
+        * superblock, we need to actually destroy the kobject.
+        */
+       unlock_kernel();
+       unlock_super(sb);
+       kobject_put(&sbi->s_kobj);
+       wait_for_completion(&sbi->s_kobj_unregister);
+       lock_super(sb);
+       lock_kernel();
+       kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        return;
 }
@@ -803,8 +816,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
                seq_puts(seq, ",noacl");
 #endif
-       if (!test_opt(sb, RESERVATION))
-               seq_puts(seq, ",noreservation");
        if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
                seq_printf(seq, ",commit=%u",
                           (unsigned) (sbi->s_commit_interval / HZ));
@@ -855,6 +866,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (test_opt(sb, DATA_ERR_ABORT))
                seq_puts(seq, ",data_err=abort");
 
+       if (test_opt(sb, NO_AUTO_DA_ALLOC))
+               seq_puts(seq, ",noauto_da_alloc");
+
        ext4_show_quota_options(seq, sb);
        return 0;
 }
@@ -1004,7 +1018,7 @@ enum {
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
        Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
-       Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
+       Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, Opt_nobh, Opt_bh,
        Opt_commit, Opt_min_batch_time, Opt_max_batch_time,
        Opt_journal_update, Opt_journal_dev,
        Opt_journal_checksum, Opt_journal_async_commit,
@@ -1012,8 +1026,8 @@ enum {
        Opt_data_err_abort, Opt_data_err_ignore,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
-       Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
-       Opt_grpquota, Opt_i_version,
+       Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize,
+       Opt_usrquota, Opt_grpquota, Opt_i_version,
        Opt_stripe, Opt_delalloc, Opt_nodelalloc,
        Opt_inode_readahead_blks, Opt_journal_ioprio
 };
@@ -1039,8 +1053,6 @@ static const match_table_t tokens = {
        {Opt_nouser_xattr, "nouser_xattr"},
        {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
-       {Opt_reservation, "reservation"},
-       {Opt_noreservation, "noreservation"},
        {Opt_noload, "noload"},
        {Opt_nobh, "nobh"},
        {Opt_bh, "bh"},
@@ -1068,6 +1080,8 @@ static const match_table_t tokens = {
        {Opt_quota, "quota"},
        {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
+       {Opt_barrier, "barrier"},
+       {Opt_nobarrier, "nobarrier"},
        {Opt_i_version, "i_version"},
        {Opt_stripe, "stripe=%u"},
        {Opt_resize, "resize"},
@@ -1075,6 +1089,9 @@ static const match_table_t tokens = {
        {Opt_nodelalloc, "nodelalloc"},
        {Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
        {Opt_journal_ioprio, "journal_ioprio=%u"},
+       {Opt_auto_da_alloc, "auto_da_alloc=%u"},
+       {Opt_auto_da_alloc, "auto_da_alloc"},
+       {Opt_noauto_da_alloc, "noauto_da_alloc"},
        {Opt_err, NULL},
 };
 
@@ -1207,12 +1224,6 @@ static int parse_options(char *options, struct super_block *sb,
                               "not supported\n");
                        break;
 #endif
-               case Opt_reservation:
-                       set_opt(sbi->s_mount_opt, RESERVATION);
-                       break;
-               case Opt_noreservation:
-                       clear_opt(sbi->s_mount_opt, RESERVATION);
-                       break;
                case Opt_journal_update:
                        /* @@@ FIXME */
                        /* Eventually we will want to be able to create
@@ -1415,9 +1426,14 @@ set_qf_format:
                case Opt_abort:
                        set_opt(sbi->s_mount_opt, ABORT);
                        break;
+               case Opt_nobarrier:
+                       clear_opt(sbi->s_mount_opt, BARRIER);
+                       break;
                case Opt_barrier:
-                       if (match_int(&args[0], &option))
-                               return 0;
+                       if (match_int(&args[0], &option)) {
+                               set_opt(sbi->s_mount_opt, BARRIER);
+                               break;
+                       }
                        if (option)
                                set_opt(sbi->s_mount_opt, BARRIER);
                        else
@@ -1463,6 +1479,11 @@ set_qf_format:
                                return 0;
                        if (option < 0 || option > (1 << 30))
                                return 0;
+                       if (option & (option - 1)) {
+                               printk(KERN_ERR "EXT4-fs: inode_readahead_blks"
+                                      " must be a power of 2\n");
+                               return 0;
+                       }
                        sbi->s_inode_readahead_blks = option;
                        break;
                case Opt_journal_ioprio:
@@ -1473,6 +1494,19 @@ set_qf_format:
                        *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE,
                                                            option);
                        break;
+               case Opt_noauto_da_alloc:
+                       set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC);
+                       break;
+               case Opt_auto_da_alloc:
+                       if (match_int(&args[0], &option)) {
+                               clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC);
+                               break;
+                       }
+                       if (option)
+                               clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC);
+                       else
+                               set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC);
+                       break;
                default:
                        printk(KERN_ERR
                               "EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1612,10 +1646,12 @@ static int ext4_fill_flex_info(struct super_block *sb)
                gdp = ext4_get_group_desc(sb, i, &bh);
 
                flex_group = ext4_flex_group(sbi, i);
-               sbi->s_flex_groups[flex_group].free_inodes +=
-                       ext4_free_inodes_count(sb, gdp);
-               sbi->s_flex_groups[flex_group].free_blocks +=
-                       ext4_free_blks_count(sb, gdp);
+               atomic_set(&sbi->s_flex_groups[flex_group].free_inodes,
+                          ext4_free_inodes_count(sb, gdp));
+               atomic_set(&sbi->s_flex_groups[flex_group].free_blocks,
+                          ext4_free_blks_count(sb, gdp));
+               atomic_set(&sbi->s_flex_groups[flex_group].used_dirs,
+                          ext4_used_dirs_count(sb, gdp));
        }
 
        return 1;
@@ -1991,6 +2027,181 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
        return 0;
 }
 
+/* sysfs supprt */
+
+struct ext4_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *);
+       ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, 
+                        const char *, size_t);
+       int offset;
+};
+
+static int parse_strtoul(const char *buf,
+               unsigned long max, unsigned long *value)
+{
+       char *endp;
+
+       while (*buf && isspace(*buf))
+               buf++;
+       *value = simple_strtoul(buf, &endp, 0);
+       while (*endp && isspace(*endp))
+               endp++;
+       if (*endp || *value > max)
+               return -EINVAL;
+
+       return 0;
+}
+
+static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a,
+                                             struct ext4_sb_info *sbi,
+                                             char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%llu\n",
+                       (s64) percpu_counter_sum(&sbi->s_dirtyblocks_counter));
+}
+
+static ssize_t session_write_kbytes_show(struct ext4_attr *a,
+                                        struct ext4_sb_info *sbi, char *buf)
+{
+       struct super_block *sb = sbi->s_buddy_cache->i_sb;
+
+       return snprintf(buf, PAGE_SIZE, "%lu\n",
+                       (part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                        sbi->s_sectors_written_start) >> 1);
+}
+
+static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
+                                         struct ext4_sb_info *sbi, char *buf)
+{
+       struct super_block *sb = sbi->s_buddy_cache->i_sb;
+
+       return snprintf(buf, PAGE_SIZE, "%llu\n",
+                       sbi->s_kbytes_written + 
+                       ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                         EXT4_SB(sb)->s_sectors_written_start) >> 1));
+}
+
+static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
+                                         struct ext4_sb_info *sbi,
+                                         const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 0x40000000, &t))
+               return -EINVAL;
+
+       /* inode_readahead_blks must be a power of 2 */
+       if (t & (t-1))
+               return -EINVAL;
+
+       sbi->s_inode_readahead_blks = t;
+       return count;
+}
+
+static ssize_t sbi_ui_show(struct ext4_attr *a,
+                               struct ext4_sb_info *sbi, char *buf)
+{
+       unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
+}
+
+static ssize_t sbi_ui_store(struct ext4_attr *a,
+                           struct ext4_sb_info *sbi,
+                           const char *buf, size_t count)
+{
+       unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
+       unsigned long t;
+
+       if (parse_strtoul(buf, 0xffffffff, &t))
+               return -EINVAL;
+       *ui = t;
+       return count;
+}
+
+#define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \
+static struct ext4_attr ext4_attr_##_name = {                  \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+       .offset = offsetof(struct ext4_sb_info, _elname),       \
+}
+#define EXT4_ATTR(name, mode, show, store) \
+static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
+
+#define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL)
+#define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store)
+#define EXT4_RW_ATTR_SBI_UI(name, elname)      \
+       EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname)
+#define ATTR_LIST(name) &ext4_attr_##name.attr
+
+EXT4_RO_ATTR(delayed_allocation_blocks);
+EXT4_RO_ATTR(session_write_kbytes);
+EXT4_RO_ATTR(lifetime_write_kbytes);
+EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show,
+                inode_readahead_blks_store, s_inode_readahead_blks);
+EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);
+EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);
+EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
+EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
+EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
+EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
+
+static struct attribute *ext4_attrs[] = {
+       ATTR_LIST(delayed_allocation_blocks),
+       ATTR_LIST(session_write_kbytes),
+       ATTR_LIST(lifetime_write_kbytes),
+       ATTR_LIST(inode_readahead_blks),
+       ATTR_LIST(mb_stats),
+       ATTR_LIST(mb_max_to_scan),
+       ATTR_LIST(mb_min_to_scan),
+       ATTR_LIST(mb_order2_req),
+       ATTR_LIST(mb_stream_req),
+       ATTR_LIST(mb_group_prealloc),
+       NULL,
+};
+
+static ssize_t ext4_attr_show(struct kobject *kobj,
+                             struct attribute *attr, char *buf)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
+
+       return a->show ? a->show(a, sbi, buf) : 0;
+}
+
+static ssize_t ext4_attr_store(struct kobject *kobj,
+                              struct attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
+
+       return a->store ? a->store(a, sbi, buf, len) : 0;
+}
+
+static void ext4_sb_release(struct kobject *kobj)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       complete(&sbi->s_kobj_unregister);
+}
+
+
+static struct sysfs_ops ext4_attr_ops = {
+       .show   = ext4_attr_show,
+       .store  = ext4_attr_store,
+};
+
+static struct kobj_type ext4_ktype = {
+       .default_attrs  = ext4_attrs,
+       .sysfs_ops      = &ext4_attr_ops,
+       .release        = ext4_sb_release,
+};
+
 static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                __releases(kernel_lock)
                                __acquires(kernel_lock)
@@ -2021,12 +2232,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
+
+       sbi->s_blockgroup_lock =
+               kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
+       if (!sbi->s_blockgroup_lock) {
+               kfree(sbi);
+               return -ENOMEM;
+       }
        sb->s_fs_info = sbi;
        sbi->s_mount_opt = 0;
        sbi->s_resuid = EXT4_DEF_RESUID;
        sbi->s_resgid = EXT4_DEF_RESGID;
        sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
        sbi->s_sb_block = sb_block;
+       sbi->s_sectors_written_start = part_stat_read(sb->s_bdev->bd_part,
+                                                     sectors[1]);
 
        unlock_kernel();
 
@@ -2064,6 +2284,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_magic = le16_to_cpu(es->s_magic);
        if (sb->s_magic != EXT4_SUPER_MAGIC)
                goto cantfind_ext4;
+       sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);
 
        /* Set defaults before we parse the mount options */
        def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
@@ -2101,7 +2322,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
        sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
 
-       set_opt(sbi->s_mount_opt, RESERVATION);
        set_opt(sbi->s_mount_opt, BARRIER);
 
        /*
@@ -2325,14 +2545,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 #ifdef CONFIG_PROC_FS
        if (ext4_proc_root)
                sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
-
-       if (sbi->s_proc)
-               proc_create_data("inode_readahead_blks", 0644, sbi->s_proc,
-                                &ext4_ui_proc_fops,
-                                &sbi->s_inode_readahead_blks);
 #endif
 
-       bgl_lock_init(&sbi->s_blockgroup_lock);
+       bgl_lock_init(sbi->s_blockgroup_lock);
 
        for (i = 0; i < db_count; i++) {
                block = descriptor_loc(sb, logical_sb_block, i);
@@ -2564,6 +2779,16 @@ no_journal:
                goto failed_mount4;
        }
 
+       sbi->s_kobj.kset = ext4_kset;
+       init_completion(&sbi->s_kobj_unregister);
+       err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL,
+                                  "%s", sb->s_id);
+       if (err) {
+               ext4_mb_release(sb);
+               ext4_ext_release(sb);
+               goto failed_mount4;
+       };
+
        /*
         * akpm: core read_super() calls in here with the superblock locked.
         * That deadlocks, because orphan cleanup needs to lock the superblock
@@ -2618,7 +2843,6 @@ failed_mount2:
        kfree(sbi->s_group_desc);
 failed_mount:
        if (sbi->s_proc) {
-               remove_proc_entry("inode_readahead_blks", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
 #ifdef CONFIG_QUOTA
@@ -2913,6 +3137,10 @@ static int ext4_commit_super(struct super_block *sb,
                set_buffer_uptodate(sbh);
        }
        es->s_wtime = cpu_to_le32(get_seconds());
+       es->s_kbytes_written =
+               cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + 
+                           ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                             EXT4_SB(sb)->s_sectors_written_start) >> 1));
        ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
                                        &EXT4_SB(sb)->s_freeblocks_counter));
        es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
@@ -3647,45 +3875,6 @@ static int ext4_get_sb(struct file_system_type *fs_type,
        return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
 }
 
-#ifdef CONFIG_PROC_FS
-static int ext4_ui_proc_show(struct seq_file *m, void *v)
-{
-       unsigned int *p = m->private;
-
-       seq_printf(m, "%u\n", *p);
-       return 0;
-}
-
-static int ext4_ui_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ext4_ui_proc_show, PDE(inode)->data);
-}
-
-static ssize_t ext4_ui_proc_write(struct file *file, const char __user *buf,
-                              size_t cnt, loff_t *ppos)
-{
-       unsigned long *p = PDE(file->f_path.dentry->d_inode)->data;
-       char str[32];
-
-       if (cnt >= sizeof(str))
-               return -EINVAL;
-       if (copy_from_user(str, buf, cnt))
-               return -EFAULT;
-
-       *p = simple_strtoul(str, NULL, 0);
-       return cnt;
-}
-
-const struct file_operations ext4_ui_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ext4_ui_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = ext4_ui_proc_write,
-};
-#endif
-
 static struct file_system_type ext4_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "ext4",
@@ -3719,6 +3908,9 @@ static int __init init_ext4_fs(void)
 {
        int err;
 
+       ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
+       if (!ext4_kset)
+               return -ENOMEM;
        ext4_proc_root = proc_mkdir("fs/ext4", NULL);
        err = init_ext4_mballoc();
        if (err)
@@ -3760,6 +3952,7 @@ static void __exit exit_ext4_fs(void)
        exit_ext4_xattr();
        exit_ext4_mballoc();
        remove_proc_entry("fs/ext4", NULL);
+       kset_unregister(ext4_kset);
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
index de0004fe6e0049c8a09a494444d19831313da64c..296785a0dec8068471d5e5764fd41cea1bcc9903 100644 (file)
@@ -523,7 +523,9 @@ static int fat_remount(struct super_block *sb, int *flags, char *data)
 
 static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
+       struct super_block *sb = dentry->d_sb;
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        /* If the count of free cluster is still unknown, counts it here. */
        if (sbi->free_clusters == -1 || !sbi->free_clus_valid) {
@@ -537,6 +539,8 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
        buf->f_bfree = sbi->free_clusters;
        buf->f_bavail = sbi->free_clusters;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = sbi->options.isvfat ? 260 : 12;
 
        return 0;
@@ -930,7 +934,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
 
        opts->fs_uid = current_uid();
        opts->fs_gid = current_gid();
-       opts->fs_fmask = opts->fs_dmask = current->fs->umask;
+       opts->fs_fmask = current_umask();
        opts->allow_utime = -1;
        opts->codepage = fat_default_codepage;
        opts->iocharset = fat_default_iocharset;
index b74a8e1da913c95033bc494e39c6c9f0ff87316d..54018fe488403082ac5274e24a3fee9480fa0a16 100644 (file)
@@ -169,7 +169,6 @@ struct file *alloc_file(struct vfsmount *mnt, struct dentry *dentry,
                fmode_t mode, const struct file_operations *fop)
 {
        struct file *file;
-       struct path;
 
        file = get_empty_filp();
        if (!file)
index e3fe9918faafb710446f5bd73445eeca5ce5b0d7..91013ff7dd5319dfd5c200461c3cdc617bb114e5 100644 (file)
@@ -196,7 +196,7 @@ static void redirty_tail(struct inode *inode)
                struct inode *tail_inode;
 
                tail_inode = list_entry(sb->s_dirty.next, struct inode, i_list);
-               if (!time_after_eq(inode->dirtied_when,
+               if (time_before(inode->dirtied_when,
                                tail_inode->dirtied_when))
                        inode->dirtied_when = jiffies;
        }
@@ -220,6 +220,21 @@ static void inode_sync_complete(struct inode *inode)
        wake_up_bit(&inode->i_state, __I_SYNC);
 }
 
+static bool inode_dirtied_after(struct inode *inode, unsigned long t)
+{
+       bool ret = time_after(inode->dirtied_when, t);
+#ifndef CONFIG_64BIT
+       /*
+        * For inodes being constantly redirtied, dirtied_when can get stuck.
+        * It _appears_ to be in the future, but is actually in distant past.
+        * This test is necessary to prevent such wrapped-around relative times
+        * from permanently stopping the whole pdflush writeback.
+        */
+       ret = ret && time_before_eq(inode->dirtied_when, jiffies);
+#endif
+       return ret;
+}
+
 /*
  * Move expired dirty inodes from @delaying_queue to @dispatch_queue.
  */
@@ -231,7 +246,7 @@ static void move_expired_inodes(struct list_head *delaying_queue,
                struct inode *inode = list_entry(delaying_queue->prev,
                                                struct inode, i_list);
                if (older_than_this &&
-                       time_after(inode->dirtied_when, *older_than_this))
+                   inode_dirtied_after(inode, *older_than_this))
                        break;
                list_move(&inode->i_list, dispatch_queue);
        }
@@ -420,7 +435,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
  * If older_than_this is non-NULL, then only write out inodes which
  * had their first dirtying at a time earlier than *older_than_this.
  *
- * If we're a pdlfush thread, then implement pdflush collision avoidance
+ * If we're a pdflush thread, then implement pdflush collision avoidance
  * against the entire list.
  *
  * If `bdi' is non-zero then we're being asked to writeback a specific queue.
@@ -492,8 +507,11 @@ void generic_sync_sb_inodes(struct super_block *sb,
                        continue;               /* blockdev has wrong queue */
                }
 
-               /* Was this inode dirtied after sync_sb_inodes was called? */
-               if (time_after(inode->dirtied_when, start))
+               /*
+                * Was this inode dirtied after sync_sb_inodes was called?
+                * This keeps sync from extra jobs and livelock.
+                */
+               if (inode_dirtied_after(inode, start))
                        break;
 
                /* Is another pdflush already flushing this queue? */
@@ -538,7 +556,8 @@ void generic_sync_sb_inodes(struct super_block *sb,
                list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                        struct address_space *mapping;
 
-                       if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+                       if (inode->i_state &
+                                       (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
                                continue;
                        mapping = inode->i_mapping;
                        if (mapping->nrpages == 0)
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
new file mode 100644 (file)
index 0000000..eee0590
--- /dev/null
@@ -0,0 +1,177 @@
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/path.h>
+#include <linux/slab.h>
+#include <linux/fs_struct.h>
+
+/*
+ * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
+ * It can block.
+ */
+void set_fs_root(struct fs_struct *fs, struct path *path)
+{
+       struct path old_root;
+
+       write_lock(&fs->lock);
+       old_root = fs->root;
+       fs->root = *path;
+       path_get(path);
+       write_unlock(&fs->lock);
+       if (old_root.dentry)
+               path_put(&old_root);
+}
+
+/*
+ * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
+ * It can block.
+ */
+void set_fs_pwd(struct fs_struct *fs, struct path *path)
+{
+       struct path old_pwd;
+
+       write_lock(&fs->lock);
+       old_pwd = fs->pwd;
+       fs->pwd = *path;
+       path_get(path);
+       write_unlock(&fs->lock);
+
+       if (old_pwd.dentry)
+               path_put(&old_pwd);
+}
+
+void chroot_fs_refs(struct path *old_root, struct path *new_root)
+{
+       struct task_struct *g, *p;
+       struct fs_struct *fs;
+       int count = 0;
+
+       read_lock(&tasklist_lock);
+       do_each_thread(g, p) {
+               task_lock(p);
+               fs = p->fs;
+               if (fs) {
+                       write_lock(&fs->lock);
+                       if (fs->root.dentry == old_root->dentry
+                           && fs->root.mnt == old_root->mnt) {
+                               path_get(new_root);
+                               fs->root = *new_root;
+                               count++;
+                       }
+                       if (fs->pwd.dentry == old_root->dentry
+                           && fs->pwd.mnt == old_root->mnt) {
+                               path_get(new_root);
+                               fs->pwd = *new_root;
+                               count++;
+                       }
+                       write_unlock(&fs->lock);
+               }
+               task_unlock(p);
+       } while_each_thread(g, p);
+       read_unlock(&tasklist_lock);
+       while (count--)
+               path_put(old_root);
+}
+
+void free_fs_struct(struct fs_struct *fs)
+{
+       path_put(&fs->root);
+       path_put(&fs->pwd);
+       kmem_cache_free(fs_cachep, fs);
+}
+
+void exit_fs(struct task_struct *tsk)
+{
+       struct fs_struct *fs = tsk->fs;
+
+       if (fs) {
+               int kill;
+               task_lock(tsk);
+               write_lock(&fs->lock);
+               tsk->fs = NULL;
+               kill = !--fs->users;
+               write_unlock(&fs->lock);
+               task_unlock(tsk);
+               if (kill)
+                       free_fs_struct(fs);
+       }
+}
+
+struct fs_struct *copy_fs_struct(struct fs_struct *old)
+{
+       struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
+       /* We don't need to lock fs - think why ;-) */
+       if (fs) {
+               fs->users = 1;
+               fs->in_exec = 0;
+               rwlock_init(&fs->lock);
+               fs->umask = old->umask;
+               read_lock(&old->lock);
+               fs->root = old->root;
+               path_get(&old->root);
+               fs->pwd = old->pwd;
+               path_get(&old->pwd);
+               read_unlock(&old->lock);
+       }
+       return fs;
+}
+
+int unshare_fs_struct(void)
+{
+       struct fs_struct *fs = current->fs;
+       struct fs_struct *new_fs = copy_fs_struct(fs);
+       int kill;
+
+       if (!new_fs)
+               return -ENOMEM;
+
+       task_lock(current);
+       write_lock(&fs->lock);
+       kill = !--fs->users;
+       current->fs = new_fs;
+       write_unlock(&fs->lock);
+       task_unlock(current);
+
+       if (kill)
+               free_fs_struct(fs);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(unshare_fs_struct);
+
+int current_umask(void)
+{
+       return current->fs->umask;
+}
+EXPORT_SYMBOL(current_umask);
+
+/* to be mentioned only in INIT_TASK */
+struct fs_struct init_fs = {
+       .users          = 1,
+       .lock           = __RW_LOCK_UNLOCKED(init_fs.lock),
+       .umask          = 0022,
+};
+
+void daemonize_fs_struct(void)
+{
+       struct fs_struct *fs = current->fs;
+
+       if (fs) {
+               int kill;
+
+               task_lock(current);
+
+               write_lock(&init_fs.lock);
+               init_fs.users++;
+               write_unlock(&init_fs.lock);
+
+               write_lock(&fs->lock);
+               current->fs = &init_fs;
+               kill = !--fs->users;
+               write_unlock(&fs->lock);
+
+               task_unlock(current);
+               if (kill)
+                       free_fs_struct(fs);
+       }
+}
diff --git a/fs/fscache/Kconfig b/fs/fscache/Kconfig
new file mode 100644 (file)
index 0000000..9bbb8ce
--- /dev/null
@@ -0,0 +1,56 @@
+
+config FSCACHE
+       tristate "General filesystem local caching manager"
+       depends on EXPERIMENTAL
+       select SLOW_WORK
+       help
+         This option enables a generic filesystem caching manager that can be
+         used by various network and other filesystems to cache data locally.
+         Different sorts of caches can be plugged in, depending on the
+         resources available.
+
+         See Documentation/filesystems/caching/fscache.txt for more information.
+
+config FSCACHE_STATS
+       bool "Gather statistical information on local caching"
+       depends on FSCACHE && PROC_FS
+       help
+         This option causes statistical information to be gathered on local
+         caching and exported through file:
+
+               /proc/fs/fscache/stats
+
+         The gathering of statistics adds a certain amount of overhead to
+         execution as there are a quite a few stats gathered, and on a
+         multi-CPU system these may be on cachelines that keep bouncing
+         between CPUs.  On the other hand, the stats are very useful for
+         debugging purposes.  Saying 'Y' here is recommended.
+
+         See Documentation/filesystems/caching/fscache.txt for more information.
+
+config FSCACHE_HISTOGRAM
+       bool "Gather latency information on local caching"
+       depends on FSCACHE && PROC_FS
+       help
+         This option causes latency information to be gathered on local
+         caching and exported through file:
+
+               /proc/fs/fscache/histogram
+
+         The generation of this histogram adds a certain amount of overhead to
+         execution as there are a number of points at which data is gathered,
+         and on a multi-CPU system these may be on cachelines that keep
+         bouncing between CPUs.  On the other hand, the histogram may be
+         useful for debugging purposes.  Saying 'N' here is recommended.
+
+         See Documentation/filesystems/caching/fscache.txt for more information.
+
+config FSCACHE_DEBUG
+       bool "Debug FS-Cache"
+       depends on FSCACHE
+       help
+         This permits debugging to be dynamically enabled in the local caching
+         management module.  If this is set, the debugging output may be
+         enabled by setting bits in /sys/modules/fscache/parameter/debug.
+
+         See Documentation/filesystems/caching/fscache.txt for more information.
diff --git a/fs/fscache/Makefile b/fs/fscache/Makefile
new file mode 100644 (file)
index 0000000..91571b9
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for general filesystem caching code
+#
+
+fscache-y := \
+       cache.o \
+       cookie.o \
+       fsdef.o \
+       main.o \
+       netfs.o \
+       object.o \
+       operation.o \
+       page.o
+
+fscache-$(CONFIG_PROC_FS) += proc.o
+fscache-$(CONFIG_FSCACHE_STATS) += stats.o
+fscache-$(CONFIG_FSCACHE_HISTOGRAM) += histogram.o
+
+obj-$(CONFIG_FSCACHE) := fscache.o
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c
new file mode 100644 (file)
index 0000000..e21985b
--- /dev/null
@@ -0,0 +1,415 @@
+/* FS-Cache cache handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#define FSCACHE_DEBUG_LEVEL CACHE
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+LIST_HEAD(fscache_cache_list);
+DECLARE_RWSEM(fscache_addremove_sem);
+DECLARE_WAIT_QUEUE_HEAD(fscache_cache_cleared_wq);
+EXPORT_SYMBOL(fscache_cache_cleared_wq);
+
+static LIST_HEAD(fscache_cache_tag_list);
+
+/*
+ * look up a cache tag
+ */
+struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *name)
+{
+       struct fscache_cache_tag *tag, *xtag;
+
+       /* firstly check for the existence of the tag under read lock */
+       down_read(&fscache_addremove_sem);
+
+       list_for_each_entry(tag, &fscache_cache_tag_list, link) {
+               if (strcmp(tag->name, name) == 0) {
+                       atomic_inc(&tag->usage);
+                       up_read(&fscache_addremove_sem);
+                       return tag;
+               }
+       }
+
+       up_read(&fscache_addremove_sem);
+
+       /* the tag does not exist - create a candidate */
+       xtag = kzalloc(sizeof(*xtag) + strlen(name) + 1, GFP_KERNEL);
+       if (!xtag)
+               /* return a dummy tag if out of memory */
+               return ERR_PTR(-ENOMEM);
+
+       atomic_set(&xtag->usage, 1);
+       strcpy(xtag->name, name);
+
+       /* write lock, search again and add if still not present */
+       down_write(&fscache_addremove_sem);
+
+       list_for_each_entry(tag, &fscache_cache_tag_list, link) {
+               if (strcmp(tag->name, name) == 0) {
+                       atomic_inc(&tag->usage);
+                       up_write(&fscache_addremove_sem);
+                       kfree(xtag);
+                       return tag;
+               }
+       }
+
+       list_add_tail(&xtag->link, &fscache_cache_tag_list);
+       up_write(&fscache_addremove_sem);
+       return xtag;
+}
+
+/*
+ * release a reference to a cache tag
+ */
+void __fscache_release_cache_tag(struct fscache_cache_tag *tag)
+{
+       if (tag != ERR_PTR(-ENOMEM)) {
+               down_write(&fscache_addremove_sem);
+
+               if (atomic_dec_and_test(&tag->usage))
+                       list_del_init(&tag->link);
+               else
+                       tag = NULL;
+
+               up_write(&fscache_addremove_sem);
+
+               kfree(tag);
+       }
+}
+
+/*
+ * select a cache in which to store an object
+ * - the cache addremove semaphore must be at least read-locked by the caller
+ * - the object will never be an index
+ */
+struct fscache_cache *fscache_select_cache_for_object(
+       struct fscache_cookie *cookie)
+{
+       struct fscache_cache_tag *tag;
+       struct fscache_object *object;
+       struct fscache_cache *cache;
+
+       _enter("");
+
+       if (list_empty(&fscache_cache_list)) {
+               _leave(" = NULL [no cache]");
+               return NULL;
+       }
+
+       /* we check the parent to determine the cache to use */
+       spin_lock(&cookie->lock);
+
+       /* the first in the parent's backing list should be the preferred
+        * cache */
+       if (!hlist_empty(&cookie->backing_objects)) {
+               object = hlist_entry(cookie->backing_objects.first,
+                                    struct fscache_object, cookie_link);
+
+               cache = object->cache;
+               if (object->state >= FSCACHE_OBJECT_DYING ||
+                   test_bit(FSCACHE_IOERROR, &cache->flags))
+                       cache = NULL;
+
+               spin_unlock(&cookie->lock);
+               _leave(" = %p [parent]", cache);
+               return cache;
+       }
+
+       /* the parent is unbacked */
+       if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) {
+               /* cookie not an index and is unbacked */
+               spin_unlock(&cookie->lock);
+               _leave(" = NULL [cookie ub,ni]");
+               return NULL;
+       }
+
+       spin_unlock(&cookie->lock);
+
+       if (!cookie->def->select_cache)
+               goto no_preference;
+
+       /* ask the netfs for its preference */
+       tag = cookie->def->select_cache(cookie->parent->netfs_data,
+                                       cookie->netfs_data);
+       if (!tag)
+               goto no_preference;
+
+       if (tag == ERR_PTR(-ENOMEM)) {
+               _leave(" = NULL [nomem tag]");
+               return NULL;
+       }
+
+       if (!tag->cache) {
+               _leave(" = NULL [unbacked tag]");
+               return NULL;
+       }
+
+       if (test_bit(FSCACHE_IOERROR, &tag->cache->flags))
+               return NULL;
+
+       _leave(" = %p [specific]", tag->cache);
+       return tag->cache;
+
+no_preference:
+       /* netfs has no preference - just select first cache */
+       cache = list_entry(fscache_cache_list.next,
+                          struct fscache_cache, link);
+       _leave(" = %p [first]", cache);
+       return cache;
+}
+
+/**
+ * fscache_init_cache - Initialise a cache record
+ * @cache: The cache record to be initialised
+ * @ops: The cache operations to be installed in that record
+ * @idfmt: Format string to define identifier
+ * @...: sprintf-style arguments
+ *
+ * Initialise a record of a cache and fill in the name.
+ *
+ * See Documentation/filesystems/caching/backend-api.txt for a complete
+ * description.
+ */
+void fscache_init_cache(struct fscache_cache *cache,
+                       const struct fscache_cache_ops *ops,
+                       const char *idfmt,
+                       ...)
+{
+       va_list va;
+
+       memset(cache, 0, sizeof(*cache));
+
+       cache->ops = ops;
+
+       va_start(va, idfmt);
+       vsnprintf(cache->identifier, sizeof(cache->identifier), idfmt, va);
+       va_end(va);
+
+       INIT_WORK(&cache->op_gc, fscache_operation_gc);
+       INIT_LIST_HEAD(&cache->link);
+       INIT_LIST_HEAD(&cache->object_list);
+       INIT_LIST_HEAD(&cache->op_gc_list);
+       spin_lock_init(&cache->object_list_lock);
+       spin_lock_init(&cache->op_gc_list_lock);
+}
+EXPORT_SYMBOL(fscache_init_cache);
+
+/**
+ * fscache_add_cache - Declare a cache as being open for business
+ * @cache: The record describing the cache
+ * @ifsdef: The record of the cache object describing the top-level index
+ * @tagname: The tag describing this cache
+ *
+ * Add a cache to the system, making it available for netfs's to use.
+ *
+ * See Documentation/filesystems/caching/backend-api.txt for a complete
+ * description.
+ */
+int fscache_add_cache(struct fscache_cache *cache,
+                     struct fscache_object *ifsdef,
+                     const char *tagname)
+{
+       struct fscache_cache_tag *tag;
+
+       BUG_ON(!cache->ops);
+       BUG_ON(!ifsdef);
+
+       cache->flags = 0;
+       ifsdef->event_mask = ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED);
+       ifsdef->state = FSCACHE_OBJECT_ACTIVE;
+
+       if (!tagname)
+               tagname = cache->identifier;
+
+       BUG_ON(!tagname[0]);
+
+       _enter("{%s.%s},,%s", cache->ops->name, cache->identifier, tagname);
+
+       /* we use the cache tag to uniquely identify caches */
+       tag = __fscache_lookup_cache_tag(tagname);
+       if (IS_ERR(tag))
+               goto nomem;
+
+       if (test_and_set_bit(FSCACHE_TAG_RESERVED, &tag->flags))
+               goto tag_in_use;
+
+       cache->kobj = kobject_create_and_add(tagname, fscache_root);
+       if (!cache->kobj)
+               goto error;
+
+       ifsdef->cookie = &fscache_fsdef_index;
+       ifsdef->cache = cache;
+       cache->fsdef = ifsdef;
+
+       down_write(&fscache_addremove_sem);
+
+       tag->cache = cache;
+       cache->tag = tag;
+
+       /* add the cache to the list */
+       list_add(&cache->link, &fscache_cache_list);
+
+       /* add the cache's netfs definition index object to the cache's
+        * list */
+       spin_lock(&cache->object_list_lock);
+       list_add_tail(&ifsdef->cache_link, &cache->object_list);
+       spin_unlock(&cache->object_list_lock);
+
+       /* add the cache's netfs definition index object to the top level index
+        * cookie as a known backing object */
+       spin_lock(&fscache_fsdef_index.lock);
+
+       hlist_add_head(&ifsdef->cookie_link,
+                      &fscache_fsdef_index.backing_objects);
+
+       atomic_inc(&fscache_fsdef_index.usage);
+
+       /* done */
+       spin_unlock(&fscache_fsdef_index.lock);
+       up_write(&fscache_addremove_sem);
+
+       printk(KERN_NOTICE "FS-Cache: Cache \"%s\" added (type %s)\n",
+              cache->tag->name, cache->ops->name);
+       kobject_uevent(cache->kobj, KOBJ_ADD);
+
+       _leave(" = 0 [%s]", cache->identifier);
+       return 0;
+
+tag_in_use:
+       printk(KERN_ERR "FS-Cache: Cache tag '%s' already in use\n", tagname);
+       __fscache_release_cache_tag(tag);
+       _leave(" = -EXIST");
+       return -EEXIST;
+
+error:
+       __fscache_release_cache_tag(tag);
+       _leave(" = -EINVAL");
+       return -EINVAL;
+
+nomem:
+       _leave(" = -ENOMEM");
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(fscache_add_cache);
+
+/**
+ * fscache_io_error - Note a cache I/O error
+ * @cache: The record describing the cache
+ *
+ * Note that an I/O error occurred in a cache and that it should no longer be
+ * used for anything.  This also reports the error into the kernel log.
+ *
+ * See Documentation/filesystems/caching/backend-api.txt for a complete
+ * description.
+ */
+void fscache_io_error(struct fscache_cache *cache)
+{
+       set_bit(FSCACHE_IOERROR, &cache->flags);
+
+       printk(KERN_ERR "FS-Cache: Cache %s stopped due to I/O error\n",
+              cache->ops->name);
+}
+EXPORT_SYMBOL(fscache_io_error);
+
+/*
+ * request withdrawal of all the objects in a cache
+ * - all the objects being withdrawn are moved onto the supplied list
+ */
+static void fscache_withdraw_all_objects(struct fscache_cache *cache,
+                                        struct list_head *dying_objects)
+{
+       struct fscache_object *object;
+
+       spin_lock(&cache->object_list_lock);
+
+       while (!list_empty(&cache->object_list)) {
+               object = list_entry(cache->object_list.next,
+                                   struct fscache_object, cache_link);
+               list_move_tail(&object->cache_link, dying_objects);
+
+               _debug("withdraw %p", object->cookie);
+
+               spin_lock(&object->lock);
+               spin_unlock(&cache->object_list_lock);
+               fscache_raise_event(object, FSCACHE_OBJECT_EV_WITHDRAW);
+               spin_unlock(&object->lock);
+
+               cond_resched();
+               spin_lock(&cache->object_list_lock);
+       }
+
+       spin_unlock(&cache->object_list_lock);
+}
+
+/**
+ * fscache_withdraw_cache - Withdraw a cache from the active service
+ * @cache: The record describing the cache
+ *
+ * Withdraw a cache from service, unbinding all its cache objects from the
+ * netfs cookies they're currently representing.
+ *
+ * See Documentation/filesystems/caching/backend-api.txt for a complete
+ * description.
+ */
+void fscache_withdraw_cache(struct fscache_cache *cache)
+{
+       LIST_HEAD(dying_objects);
+
+       _enter("");
+
+       printk(KERN_NOTICE "FS-Cache: Withdrawing cache \"%s\"\n",
+              cache->tag->name);
+
+       /* make the cache unavailable for cookie acquisition */
+       if (test_and_set_bit(FSCACHE_CACHE_WITHDRAWN, &cache->flags))
+               BUG();
+
+       down_write(&fscache_addremove_sem);
+       list_del_init(&cache->link);
+       cache->tag->cache = NULL;
+       up_write(&fscache_addremove_sem);
+
+       /* make sure all pages pinned by operations on behalf of the netfs are
+        * written to disk */
+       cache->ops->sync_cache(cache);
+
+       /* dissociate all the netfs pages backed by this cache from the block
+        * mappings in the cache */
+       cache->ops->dissociate_pages(cache);
+
+       /* we now have to destroy all the active objects pertaining to this
+        * cache - which we do by passing them off to thread pool to be
+        * disposed of */
+       _debug("destroy");
+
+       fscache_withdraw_all_objects(cache, &dying_objects);
+
+       /* wait for all extant objects to finish their outstanding operations
+        * and go away */
+       _debug("wait for finish");
+       wait_event(fscache_cache_cleared_wq,
+                  atomic_read(&cache->object_count) == 0);
+       _debug("wait for clearance");
+       wait_event(fscache_cache_cleared_wq,
+                  list_empty(&cache->object_list));
+       _debug("cleared");
+       ASSERT(list_empty(&dying_objects));
+
+       kobject_put(cache->kobj);
+
+       clear_bit(FSCACHE_TAG_RESERVED, &cache->tag->flags);
+       fscache_release_cache_tag(cache->tag);
+       cache->tag = NULL;
+
+       _leave("");
+}
+EXPORT_SYMBOL(fscache_withdraw_cache);
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
new file mode 100644 (file)
index 0000000..72fd18f
--- /dev/null
@@ -0,0 +1,500 @@
+/* netfs cookie management
+ *
+ * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for more information on
+ * the netfs API.
+ */
+
+#define FSCACHE_DEBUG_LEVEL COOKIE
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+struct kmem_cache *fscache_cookie_jar;
+
+static atomic_t fscache_object_debug_id = ATOMIC_INIT(0);
+
+static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie);
+static int fscache_alloc_object(struct fscache_cache *cache,
+                               struct fscache_cookie *cookie);
+static int fscache_attach_object(struct fscache_cookie *cookie,
+                                struct fscache_object *object);
+
+/*
+ * initialise an cookie jar slab element prior to any use
+ */
+void fscache_cookie_init_once(void *_cookie)
+{
+       struct fscache_cookie *cookie = _cookie;
+
+       memset(cookie, 0, sizeof(*cookie));
+       spin_lock_init(&cookie->lock);
+       INIT_HLIST_HEAD(&cookie->backing_objects);
+}
+
+/*
+ * request a cookie to represent an object (index, datafile, xattr, etc)
+ * - parent specifies the parent object
+ *   - the top level index cookie for each netfs is stored in the fscache_netfs
+ *     struct upon registration
+ * - def points to the definition
+ * - the netfs_data will be passed to the functions pointed to in *def
+ * - all attached caches will be searched to see if they contain this object
+ * - index objects aren't stored on disk until there's a dependent file that
+ *   needs storing
+ * - other objects are stored in a selected cache immediately, and all the
+ *   indices forming the path to it are instantiated if necessary
+ * - we never let on to the netfs about errors
+ *   - we may set a negative cookie pointer, but that's okay
+ */
+struct fscache_cookie *__fscache_acquire_cookie(
+       struct fscache_cookie *parent,
+       const struct fscache_cookie_def *def,
+       void *netfs_data)
+{
+       struct fscache_cookie *cookie;
+
+       BUG_ON(!def);
+
+       _enter("{%s},{%s},%p",
+              parent ? (char *) parent->def->name : "<no-parent>",
+              def->name, netfs_data);
+
+       fscache_stat(&fscache_n_acquires);
+
+       /* if there's no parent cookie, then we don't create one here either */
+       if (!parent) {
+               fscache_stat(&fscache_n_acquires_null);
+               _leave(" [no parent]");
+               return NULL;
+       }
+
+       /* validate the definition */
+       BUG_ON(!def->get_key);
+       BUG_ON(!def->name[0]);
+
+       BUG_ON(def->type == FSCACHE_COOKIE_TYPE_INDEX &&
+              parent->def->type != FSCACHE_COOKIE_TYPE_INDEX);
+
+       /* allocate and initialise a cookie */
+       cookie = kmem_cache_alloc(fscache_cookie_jar, GFP_KERNEL);
+       if (!cookie) {
+               fscache_stat(&fscache_n_acquires_oom);
+               _leave(" [ENOMEM]");
+               return NULL;
+       }
+
+       atomic_set(&cookie->usage, 1);
+       atomic_set(&cookie->n_children, 0);
+
+       atomic_inc(&parent->usage);
+       atomic_inc(&parent->n_children);
+
+       cookie->def             = def;
+       cookie->parent          = parent;
+       cookie->netfs_data      = netfs_data;
+       cookie->flags           = 0;
+
+       INIT_RADIX_TREE(&cookie->stores, GFP_NOFS);
+
+       switch (cookie->def->type) {
+       case FSCACHE_COOKIE_TYPE_INDEX:
+               fscache_stat(&fscache_n_cookie_index);
+               break;
+       case FSCACHE_COOKIE_TYPE_DATAFILE:
+               fscache_stat(&fscache_n_cookie_data);
+               break;
+       default:
+               fscache_stat(&fscache_n_cookie_special);
+               break;
+       }
+
+       /* if the object is an index then we need do nothing more here - we
+        * create indices on disk when we need them as an index may exist in
+        * multiple caches */
+       if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) {
+               if (fscache_acquire_non_index_cookie(cookie) < 0) {
+                       atomic_dec(&parent->n_children);
+                       __fscache_cookie_put(cookie);
+                       fscache_stat(&fscache_n_acquires_nobufs);
+                       _leave(" = NULL");
+                       return NULL;
+               }
+       }
+
+       fscache_stat(&fscache_n_acquires_ok);
+       _leave(" = %p", cookie);
+       return cookie;
+}
+EXPORT_SYMBOL(__fscache_acquire_cookie);
+
+/*
+ * acquire a non-index cookie
+ * - this must make sure the index chain is instantiated and instantiate the
+ *   object representation too
+ */
+static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie)
+{
+       struct fscache_object *object;
+       struct fscache_cache *cache;
+       uint64_t i_size;
+       int ret;
+
+       _enter("");
+
+       cookie->flags = 1 << FSCACHE_COOKIE_UNAVAILABLE;
+
+       /* now we need to see whether the backing objects for this cookie yet
+        * exist, if not there'll be nothing to search */
+       down_read(&fscache_addremove_sem);
+
+       if (list_empty(&fscache_cache_list)) {
+               up_read(&fscache_addremove_sem);
+               _leave(" = 0 [no caches]");
+               return 0;
+       }
+
+       /* select a cache in which to store the object */
+       cache = fscache_select_cache_for_object(cookie->parent);
+       if (!cache) {
+               up_read(&fscache_addremove_sem);
+               fscache_stat(&fscache_n_acquires_no_cache);
+               _leave(" = -ENOMEDIUM [no cache]");
+               return -ENOMEDIUM;
+       }
+
+       _debug("cache %s", cache->tag->name);
+
+       cookie->flags =
+               (1 << FSCACHE_COOKIE_LOOKING_UP) |
+               (1 << FSCACHE_COOKIE_CREATING) |
+               (1 << FSCACHE_COOKIE_NO_DATA_YET);
+
+       /* ask the cache to allocate objects for this cookie and its parent
+        * chain */
+       ret = fscache_alloc_object(cache, cookie);
+       if (ret < 0) {
+               up_read(&fscache_addremove_sem);
+               _leave(" = %d", ret);
+               return ret;
+       }
+
+       /* pass on how big the object we're caching is supposed to be */
+       cookie->def->get_attr(cookie->netfs_data, &i_size);
+
+       spin_lock(&cookie->lock);
+       if (hlist_empty(&cookie->backing_objects)) {
+               spin_unlock(&cookie->lock);
+               goto unavailable;
+       }
+
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+
+       fscache_set_store_limit(object, i_size);
+
+       /* initiate the process of looking up all the objects in the chain
+        * (done by fscache_initialise_object()) */
+       fscache_enqueue_object(object);
+
+       spin_unlock(&cookie->lock);
+
+       /* we may be required to wait for lookup to complete at this point */
+       if (!fscache_defer_lookup) {
+               _debug("non-deferred lookup %p", &cookie->flags);
+               wait_on_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP,
+                           fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+               _debug("complete");
+               if (test_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags))
+                       goto unavailable;
+       }
+
+       up_read(&fscache_addremove_sem);
+       _leave(" = 0 [deferred]");
+       return 0;
+
+unavailable:
+       up_read(&fscache_addremove_sem);
+       _leave(" = -ENOBUFS");
+       return -ENOBUFS;
+}
+
+/*
+ * recursively allocate cache object records for a cookie/cache combination
+ * - caller must be holding the addremove sem
+ */
+static int fscache_alloc_object(struct fscache_cache *cache,
+                               struct fscache_cookie *cookie)
+{
+       struct fscache_object *object;
+       struct hlist_node *_n;
+       int ret;
+
+       _enter("%p,%p{%s}", cache, cookie, cookie->def->name);
+
+       spin_lock(&cookie->lock);
+       hlist_for_each_entry(object, _n, &cookie->backing_objects,
+                            cookie_link) {
+               if (object->cache == cache)
+                       goto object_already_extant;
+       }
+       spin_unlock(&cookie->lock);
+
+       /* ask the cache to allocate an object (we may end up with duplicate
+        * objects at this stage, but we sort that out later) */
+       object = cache->ops->alloc_object(cache, cookie);
+       if (IS_ERR(object)) {
+               fscache_stat(&fscache_n_object_no_alloc);
+               ret = PTR_ERR(object);
+               goto error;
+       }
+
+       fscache_stat(&fscache_n_object_alloc);
+
+       object->debug_id = atomic_inc_return(&fscache_object_debug_id);
+
+       _debug("ALLOC OBJ%x: %s {%lx}",
+              object->debug_id, cookie->def->name, object->events);
+
+       ret = fscache_alloc_object(cache, cookie->parent);
+       if (ret < 0)
+               goto error_put;
+
+       /* only attach if we managed to allocate all we needed, otherwise
+        * discard the object we just allocated and instead use the one
+        * attached to the cookie */
+       if (fscache_attach_object(cookie, object) < 0)
+               cache->ops->put_object(object);
+
+       _leave(" = 0");
+       return 0;
+
+object_already_extant:
+       ret = -ENOBUFS;
+       if (object->state >= FSCACHE_OBJECT_DYING) {
+               spin_unlock(&cookie->lock);
+               goto error;
+       }
+       spin_unlock(&cookie->lock);
+       _leave(" = 0 [found]");
+       return 0;
+
+error_put:
+       cache->ops->put_object(object);
+error:
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * attach a cache object to a cookie
+ */
+static int fscache_attach_object(struct fscache_cookie *cookie,
+                                struct fscache_object *object)
+{
+       struct fscache_object *p;
+       struct fscache_cache *cache = object->cache;
+       struct hlist_node *_n;
+       int ret;
+
+       _enter("{%s},{OBJ%x}", cookie->def->name, object->debug_id);
+
+       spin_lock(&cookie->lock);
+
+       /* there may be multiple initial creations of this object, but we only
+        * want one */
+       ret = -EEXIST;
+       hlist_for_each_entry(p, _n, &cookie->backing_objects, cookie_link) {
+               if (p->cache == object->cache) {
+                       if (p->state >= FSCACHE_OBJECT_DYING)
+                               ret = -ENOBUFS;
+                       goto cant_attach_object;
+               }
+       }
+
+       /* pin the parent object */
+       spin_lock_nested(&cookie->parent->lock, 1);
+       hlist_for_each_entry(p, _n, &cookie->parent->backing_objects,
+                            cookie_link) {
+               if (p->cache == object->cache) {
+                       if (p->state >= FSCACHE_OBJECT_DYING) {
+                               ret = -ENOBUFS;
+                               spin_unlock(&cookie->parent->lock);
+                               goto cant_attach_object;
+                       }
+                       object->parent = p;
+                       spin_lock(&p->lock);
+                       p->n_children++;
+                       spin_unlock(&p->lock);
+                       break;
+               }
+       }
+       spin_unlock(&cookie->parent->lock);
+
+       /* attach to the cache's object list */
+       if (list_empty(&object->cache_link)) {
+               spin_lock(&cache->object_list_lock);
+               list_add(&object->cache_link, &cache->object_list);
+               spin_unlock(&cache->object_list_lock);
+       }
+
+       /* attach to the cookie */
+       object->cookie = cookie;
+       atomic_inc(&cookie->usage);
+       hlist_add_head(&object->cookie_link, &cookie->backing_objects);
+       ret = 0;
+
+cant_attach_object:
+       spin_unlock(&cookie->lock);
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * update the index entries backing a cookie
+ */
+void __fscache_update_cookie(struct fscache_cookie *cookie)
+{
+       struct fscache_object *object;
+       struct hlist_node *_p;
+
+       fscache_stat(&fscache_n_updates);
+
+       if (!cookie) {
+               fscache_stat(&fscache_n_updates_null);
+               _leave(" [no cookie]");
+               return;
+       }
+
+       _enter("{%s}", cookie->def->name);
+
+       BUG_ON(!cookie->def->get_aux);
+
+       spin_lock(&cookie->lock);
+
+       /* update the index entry on disk in each cache backing this cookie */
+       hlist_for_each_entry(object, _p,
+                            &cookie->backing_objects, cookie_link) {
+               fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE);
+       }
+
+       spin_unlock(&cookie->lock);
+       _leave("");
+}
+EXPORT_SYMBOL(__fscache_update_cookie);
+
+/*
+ * release a cookie back to the cache
+ * - the object will be marked as recyclable on disk if retire is true
+ * - all dependents of this cookie must have already been unregistered
+ *   (indices/files/pages)
+ */
+void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
+{
+       struct fscache_cache *cache;
+       struct fscache_object *object;
+       unsigned long event;
+
+       fscache_stat(&fscache_n_relinquishes);
+
+       if (!cookie) {
+               fscache_stat(&fscache_n_relinquishes_null);
+               _leave(" [no cookie]");
+               return;
+       }
+
+       _enter("%p{%s,%p},%d",
+              cookie, cookie->def->name, cookie->netfs_data, retire);
+
+       if (atomic_read(&cookie->n_children) != 0) {
+               printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n",
+                      cookie->def->name);
+               BUG();
+       }
+
+       /* wait for the cookie to finish being instantiated (or to fail) */
+       if (test_bit(FSCACHE_COOKIE_CREATING, &cookie->flags)) {
+               fscache_stat(&fscache_n_relinquishes_waitcrt);
+               wait_on_bit(&cookie->flags, FSCACHE_COOKIE_CREATING,
+                           fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+       }
+
+       event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE;
+
+       /* detach pointers back to the netfs */
+       spin_lock(&cookie->lock);
+
+       cookie->netfs_data      = NULL;
+       cookie->def             = NULL;
+
+       /* break links with all the active objects */
+       while (!hlist_empty(&cookie->backing_objects)) {
+               object = hlist_entry(cookie->backing_objects.first,
+                                    struct fscache_object,
+                                    cookie_link);
+
+               _debug("RELEASE OBJ%x", object->debug_id);
+
+               /* detach each cache object from the object cookie */
+               spin_lock(&object->lock);
+               hlist_del_init(&object->cookie_link);
+
+               cache = object->cache;
+               object->cookie = NULL;
+               fscache_raise_event(object, event);
+               spin_unlock(&object->lock);
+
+               if (atomic_dec_and_test(&cookie->usage))
+                       /* the cookie refcount shouldn't be reduced to 0 yet */
+                       BUG();
+       }
+
+       spin_unlock(&cookie->lock);
+
+       if (cookie->parent) {
+               ASSERTCMP(atomic_read(&cookie->parent->usage), >, 0);
+               ASSERTCMP(atomic_read(&cookie->parent->n_children), >, 0);
+               atomic_dec(&cookie->parent->n_children);
+       }
+
+       /* finally dispose of the cookie */
+       ASSERTCMP(atomic_read(&cookie->usage), >, 0);
+       fscache_cookie_put(cookie);
+
+       _leave("");
+}
+EXPORT_SYMBOL(__fscache_relinquish_cookie);
+
+/*
+ * destroy a cookie
+ */
+void __fscache_cookie_put(struct fscache_cookie *cookie)
+{
+       struct fscache_cookie *parent;
+
+       _enter("%p", cookie);
+
+       for (;;) {
+               _debug("FREE COOKIE %p", cookie);
+               parent = cookie->parent;
+               BUG_ON(!hlist_empty(&cookie->backing_objects));
+               kmem_cache_free(fscache_cookie_jar, cookie);
+
+               if (!parent)
+                       break;
+
+               cookie = parent;
+               BUG_ON(atomic_read(&cookie->usage) <= 0);
+               if (!atomic_dec_and_test(&cookie->usage))
+                       break;
+       }
+
+       _leave("");
+}
diff --git a/fs/fscache/fsdef.c b/fs/fscache/fsdef.c
new file mode 100644 (file)
index 0000000..f5b4bae
--- /dev/null
@@ -0,0 +1,144 @@
+/* Filesystem index definition
+ *
+ * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#define FSCACHE_DEBUG_LEVEL CACHE
+#include <linux/module.h>
+#include "internal.h"
+
+static uint16_t fscache_fsdef_netfs_get_key(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t bufmax);
+
+static uint16_t fscache_fsdef_netfs_get_aux(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t bufmax);
+
+static
+enum fscache_checkaux fscache_fsdef_netfs_check_aux(void *cookie_netfs_data,
+                                                   const void *data,
+                                                   uint16_t datalen);
+
+/*
+ * The root index is owned by FS-Cache itself.
+ *
+ * When a netfs requests caching facilities, FS-Cache will, if one doesn't
+ * already exist, create an entry in the root index with the key being the name
+ * of the netfs ("AFS" for example), and the auxiliary data holding the index
+ * structure version supplied by the netfs:
+ *
+ *                                  FSDEF
+ *                                    |
+ *                              +-----------+
+ *                              |           |
+ *                             NFS         AFS
+ *                            [v=1]       [v=1]
+ *
+ * If an entry with the appropriate name does already exist, the version is
+ * compared.  If the version is different, the entire subtree from that entry
+ * will be discarded and a new entry created.
+ *
+ * The new entry will be an index, and a cookie referring to it will be passed
+ * to the netfs.  This is then the root handle by which the netfs accesses the
+ * cache.  It can create whatever objects it likes in that index, including
+ * further indices.
+ */
+static struct fscache_cookie_def fscache_fsdef_index_def = {
+       .name           = ".FS-Cache",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+};
+
+struct fscache_cookie fscache_fsdef_index = {
+       .usage          = ATOMIC_INIT(1),
+       .lock           = __SPIN_LOCK_UNLOCKED(fscache_fsdef_index.lock),
+       .backing_objects = HLIST_HEAD_INIT,
+       .def            = &fscache_fsdef_index_def,
+};
+EXPORT_SYMBOL(fscache_fsdef_index);
+
+/*
+ * Definition of an entry in the root index.  Each entry is an index, keyed to
+ * a specific netfs and only applicable to a particular version of the index
+ * structure used by that netfs.
+ */
+struct fscache_cookie_def fscache_fsdef_netfs_def = {
+       .name           = "FSDEF.netfs",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key        = fscache_fsdef_netfs_get_key,
+       .get_aux        = fscache_fsdef_netfs_get_aux,
+       .check_aux      = fscache_fsdef_netfs_check_aux,
+};
+
+/*
+ * get the key data for an FSDEF index record - this is the name of the netfs
+ * for which this entry is created
+ */
+static uint16_t fscache_fsdef_netfs_get_key(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t bufmax)
+{
+       const struct fscache_netfs *netfs = cookie_netfs_data;
+       unsigned klen;
+
+       _enter("{%s.%u},", netfs->name, netfs->version);
+
+       klen = strlen(netfs->name);
+       if (klen > bufmax)
+               return 0;
+
+       memcpy(buffer, netfs->name, klen);
+       return klen;
+}
+
+/*
+ * get the auxiliary data for an FSDEF index record - this is the index
+ * structure version number of the netfs for which this version is created
+ */
+static uint16_t fscache_fsdef_netfs_get_aux(const void *cookie_netfs_data,
+                                           void *buffer, uint16_t bufmax)
+{
+       const struct fscache_netfs *netfs = cookie_netfs_data;
+       unsigned dlen;
+
+       _enter("{%s.%u},", netfs->name, netfs->version);
+
+       dlen = sizeof(uint32_t);
+       if (dlen > bufmax)
+               return 0;
+
+       memcpy(buffer, &netfs->version, dlen);
+       return dlen;
+}
+
+/*
+ * check that the index structure version number stored in the auxiliary data
+ * matches the one the netfs gave us
+ */
+static enum fscache_checkaux fscache_fsdef_netfs_check_aux(
+       void *cookie_netfs_data,
+       const void *data,
+       uint16_t datalen)
+{
+       struct fscache_netfs *netfs = cookie_netfs_data;
+       uint32_t version;
+
+       _enter("{%s},,%hu", netfs->name, datalen);
+
+       if (datalen != sizeof(version)) {
+               _leave(" = OBSOLETE [dl=%d v=%zu]", datalen, sizeof(version));
+               return FSCACHE_CHECKAUX_OBSOLETE;
+       }
+
+       memcpy(&version, data, sizeof(version));
+       if (version != netfs->version) {
+               _leave(" = OBSOLETE [ver=%x net=%x]", version, netfs->version);
+               return FSCACHE_CHECKAUX_OBSOLETE;
+       }
+
+       _leave(" = OKAY");
+       return FSCACHE_CHECKAUX_OKAY;
+}
diff --git a/fs/fscache/histogram.c b/fs/fscache/histogram.c
new file mode 100644 (file)
index 0000000..bad4967
--- /dev/null
@@ -0,0 +1,109 @@
+/* FS-Cache latency histogram
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define FSCACHE_DEBUG_LEVEL THREAD
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include "internal.h"
+
+atomic_t fscache_obj_instantiate_histogram[HZ];
+atomic_t fscache_objs_histogram[HZ];
+atomic_t fscache_ops_histogram[HZ];
+atomic_t fscache_retrieval_delay_histogram[HZ];
+atomic_t fscache_retrieval_histogram[HZ];
+
+/*
+ * display the time-taken histogram
+ */
+static int fscache_histogram_show(struct seq_file *m, void *v)
+{
+       unsigned long index;
+       unsigned n[5], t;
+
+       switch ((unsigned long) v) {
+       case 1:
+               seq_puts(m, "JIFS  SECS  OBJ INST  OP RUNS   OBJ RUNS "
+                        " RETRV DLY RETRIEVLS\n");
+               return 0;
+       case 2:
+               seq_puts(m, "===== ===== ========= ========= ========="
+                        " ========= =========\n");
+               return 0;
+       default:
+               index = (unsigned long) v - 3;
+               n[0] = atomic_read(&fscache_obj_instantiate_histogram[index]);
+               n[1] = atomic_read(&fscache_ops_histogram[index]);
+               n[2] = atomic_read(&fscache_objs_histogram[index]);
+               n[3] = atomic_read(&fscache_retrieval_delay_histogram[index]);
+               n[4] = atomic_read(&fscache_retrieval_histogram[index]);
+               if (!(n[0] | n[1] | n[2] | n[3] | n[4]))
+                       return 0;
+
+               t = (index * 1000) / HZ;
+
+               seq_printf(m, "%4lu  0.%03u %9u %9u %9u %9u %9u\n",
+                          index, t, n[0], n[1], n[2], n[3], n[4]);
+               return 0;
+       }
+}
+
+/*
+ * set up the iterator to start reading from the first line
+ */
+static void *fscache_histogram_start(struct seq_file *m, loff_t *_pos)
+{
+       if ((unsigned long long)*_pos >= HZ + 2)
+               return NULL;
+       if (*_pos == 0)
+               *_pos = 1;
+       return (void *)(unsigned long) *_pos;
+}
+
+/*
+ * move to the next line
+ */
+static void *fscache_histogram_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return (unsigned long long)*pos > HZ + 2 ?
+               NULL : (void *)(unsigned long) *pos;
+}
+
+/*
+ * clean up after reading
+ */
+static void fscache_histogram_stop(struct seq_file *m, void *v)
+{
+}
+
+static const struct seq_operations fscache_histogram_ops = {
+       .start          = fscache_histogram_start,
+       .stop           = fscache_histogram_stop,
+       .next           = fscache_histogram_next,
+       .show           = fscache_histogram_show,
+};
+
+/*
+ * open "/proc/fs/fscache/histogram" to provide latency data
+ */
+static int fscache_histogram_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &fscache_histogram_ops);
+}
+
+const struct file_operations fscache_histogram_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fscache_histogram_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
new file mode 100644 (file)
index 0000000..e0cbd16
--- /dev/null
@@ -0,0 +1,380 @@
+/* Internal definitions for FS-Cache
+ *
+ * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+/*
+ * Lock order, in the order in which multiple locks should be obtained:
+ * - fscache_addremove_sem
+ * - cookie->lock
+ * - cookie->parent->lock
+ * - cache->object_list_lock
+ * - object->lock
+ * - object->parent->lock
+ * - fscache_thread_lock
+ *
+ */
+
+#include <linux/fscache-cache.h>
+#include <linux/sched.h>
+
+#define FSCACHE_MIN_THREADS    4
+#define FSCACHE_MAX_THREADS    32
+
+/*
+ * fsc-cache.c
+ */
+extern struct list_head fscache_cache_list;
+extern struct rw_semaphore fscache_addremove_sem;
+
+extern struct fscache_cache *fscache_select_cache_for_object(
+       struct fscache_cookie *);
+
+/*
+ * fsc-cookie.c
+ */
+extern struct kmem_cache *fscache_cookie_jar;
+
+extern void fscache_cookie_init_once(void *);
+extern void __fscache_cookie_put(struct fscache_cookie *);
+
+/*
+ * fsc-fsdef.c
+ */
+extern struct fscache_cookie fscache_fsdef_index;
+extern struct fscache_cookie_def fscache_fsdef_netfs_def;
+
+/*
+ * fsc-histogram.c
+ */
+#ifdef CONFIG_FSCACHE_HISTOGRAM
+extern atomic_t fscache_obj_instantiate_histogram[HZ];
+extern atomic_t fscache_objs_histogram[HZ];
+extern atomic_t fscache_ops_histogram[HZ];
+extern atomic_t fscache_retrieval_delay_histogram[HZ];
+extern atomic_t fscache_retrieval_histogram[HZ];
+
+static inline void fscache_hist(atomic_t histogram[], unsigned long start_jif)
+{
+       unsigned long jif = jiffies - start_jif;
+       if (jif >= HZ)
+               jif = HZ - 1;
+       atomic_inc(&histogram[jif]);
+}
+
+extern const struct file_operations fscache_histogram_fops;
+
+#else
+#define fscache_hist(hist, start_jif) do {} while (0)
+#endif
+
+/*
+ * fsc-main.c
+ */
+extern unsigned fscache_defer_lookup;
+extern unsigned fscache_defer_create;
+extern unsigned fscache_debug;
+extern struct kobject *fscache_root;
+
+extern int fscache_wait_bit(void *);
+extern int fscache_wait_bit_interruptible(void *);
+
+/*
+ * fsc-object.c
+ */
+extern void fscache_withdrawing_object(struct fscache_cache *,
+                                      struct fscache_object *);
+extern void fscache_enqueue_object(struct fscache_object *);
+
+/*
+ * fsc-operation.c
+ */
+extern int fscache_submit_exclusive_op(struct fscache_object *,
+                                      struct fscache_operation *);
+extern int fscache_submit_op(struct fscache_object *,
+                            struct fscache_operation *);
+extern void fscache_abort_object(struct fscache_object *);
+extern void fscache_start_operations(struct fscache_object *);
+extern void fscache_operation_gc(struct work_struct *);
+
+/*
+ * fsc-proc.c
+ */
+#ifdef CONFIG_PROC_FS
+extern int __init fscache_proc_init(void);
+extern void fscache_proc_cleanup(void);
+#else
+#define fscache_proc_init()    (0)
+#define fscache_proc_cleanup() do {} while (0)
+#endif
+
+/*
+ * fsc-stats.c
+ */
+#ifdef CONFIG_FSCACHE_STATS
+extern atomic_t fscache_n_ops_processed[FSCACHE_MAX_THREADS];
+extern atomic_t fscache_n_objs_processed[FSCACHE_MAX_THREADS];
+
+extern atomic_t fscache_n_op_pend;
+extern atomic_t fscache_n_op_run;
+extern atomic_t fscache_n_op_enqueue;
+extern atomic_t fscache_n_op_deferred_release;
+extern atomic_t fscache_n_op_release;
+extern atomic_t fscache_n_op_gc;
+
+extern atomic_t fscache_n_attr_changed;
+extern atomic_t fscache_n_attr_changed_ok;
+extern atomic_t fscache_n_attr_changed_nobufs;
+extern atomic_t fscache_n_attr_changed_nomem;
+extern atomic_t fscache_n_attr_changed_calls;
+
+extern atomic_t fscache_n_allocs;
+extern atomic_t fscache_n_allocs_ok;
+extern atomic_t fscache_n_allocs_wait;
+extern atomic_t fscache_n_allocs_nobufs;
+extern atomic_t fscache_n_alloc_ops;
+extern atomic_t fscache_n_alloc_op_waits;
+
+extern atomic_t fscache_n_retrievals;
+extern atomic_t fscache_n_retrievals_ok;
+extern atomic_t fscache_n_retrievals_wait;
+extern atomic_t fscache_n_retrievals_nodata;
+extern atomic_t fscache_n_retrievals_nobufs;
+extern atomic_t fscache_n_retrievals_intr;
+extern atomic_t fscache_n_retrievals_nomem;
+extern atomic_t fscache_n_retrieval_ops;
+extern atomic_t fscache_n_retrieval_op_waits;
+
+extern atomic_t fscache_n_stores;
+extern atomic_t fscache_n_stores_ok;
+extern atomic_t fscache_n_stores_again;
+extern atomic_t fscache_n_stores_nobufs;
+extern atomic_t fscache_n_stores_oom;
+extern atomic_t fscache_n_store_ops;
+extern atomic_t fscache_n_store_calls;
+
+extern atomic_t fscache_n_marks;
+extern atomic_t fscache_n_uncaches;
+
+extern atomic_t fscache_n_acquires;
+extern atomic_t fscache_n_acquires_null;
+extern atomic_t fscache_n_acquires_no_cache;
+extern atomic_t fscache_n_acquires_ok;
+extern atomic_t fscache_n_acquires_nobufs;
+extern atomic_t fscache_n_acquires_oom;
+
+extern atomic_t fscache_n_updates;
+extern atomic_t fscache_n_updates_null;
+extern atomic_t fscache_n_updates_run;
+
+extern atomic_t fscache_n_relinquishes;
+extern atomic_t fscache_n_relinquishes_null;
+extern atomic_t fscache_n_relinquishes_waitcrt;
+
+extern atomic_t fscache_n_cookie_index;
+extern atomic_t fscache_n_cookie_data;
+extern atomic_t fscache_n_cookie_special;
+
+extern atomic_t fscache_n_object_alloc;
+extern atomic_t fscache_n_object_no_alloc;
+extern atomic_t fscache_n_object_lookups;
+extern atomic_t fscache_n_object_lookups_negative;
+extern atomic_t fscache_n_object_lookups_positive;
+extern atomic_t fscache_n_object_created;
+extern atomic_t fscache_n_object_avail;
+extern atomic_t fscache_n_object_dead;
+
+extern atomic_t fscache_n_checkaux_none;
+extern atomic_t fscache_n_checkaux_okay;
+extern atomic_t fscache_n_checkaux_update;
+extern atomic_t fscache_n_checkaux_obsolete;
+
+static inline void fscache_stat(atomic_t *stat)
+{
+       atomic_inc(stat);
+}
+
+extern const struct file_operations fscache_stats_fops;
+#else
+
+#define fscache_stat(stat) do {} while (0)
+#endif
+
+/*
+ * raise an event on an object
+ * - if the event is not masked for that object, then the object is
+ *   queued for attention by the thread pool.
+ */
+static inline void fscache_raise_event(struct fscache_object *object,
+                                      unsigned event)
+{
+       if (!test_and_set_bit(event, &object->events) &&
+           test_bit(event, &object->event_mask))
+               fscache_enqueue_object(object);
+}
+
+/*
+ * drop a reference to a cookie
+ */
+static inline void fscache_cookie_put(struct fscache_cookie *cookie)
+{
+       BUG_ON(atomic_read(&cookie->usage) <= 0);
+       if (atomic_dec_and_test(&cookie->usage))
+               __fscache_cookie_put(cookie);
+}
+
+/*
+ * get an extra reference to a netfs retrieval context
+ */
+static inline
+void *fscache_get_context(struct fscache_cookie *cookie, void *context)
+{
+       if (cookie->def->get_context)
+               cookie->def->get_context(cookie->netfs_data, context);
+       return context;
+}
+
+/*
+ * release a reference to a netfs retrieval context
+ */
+static inline
+void fscache_put_context(struct fscache_cookie *cookie, void *context)
+{
+       if (cookie->def->put_context)
+               cookie->def->put_context(cookie->netfs_data, context);
+}
+
+/*****************************************************************************/
+/*
+ * debug tracing
+ */
+#define dbgprintk(FMT, ...) \
+       printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__)
+
+/* make sure we maintain the format strings, even when debugging is disabled */
+static inline __attribute__((format(printf, 1, 2)))
+void _dbprintk(const char *fmt, ...)
+{
+}
+
+#define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
+#define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__)
+
+#define kjournal(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__)
+
+#ifdef __KDEBUG
+#define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__)
+#define _leave(FMT, ...) kleave(FMT, ##__VA_ARGS__)
+#define _debug(FMT, ...) kdebug(FMT, ##__VA_ARGS__)
+
+#elif defined(CONFIG_FSCACHE_DEBUG)
+#define _enter(FMT, ...)                       \
+do {                                           \
+       if (__do_kdebug(ENTER))                 \
+               kenter(FMT, ##__VA_ARGS__);     \
+} while (0)
+
+#define _leave(FMT, ...)                       \
+do {                                           \
+       if (__do_kdebug(LEAVE))                 \
+               kleave(FMT, ##__VA_ARGS__);     \
+} while (0)
+
+#define _debug(FMT, ...)                       \
+do {                                           \
+       if (__do_kdebug(DEBUG))                 \
+               kdebug(FMT, ##__VA_ARGS__);     \
+} while (0)
+
+#else
+#define _enter(FMT, ...) _dbprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
+#define _leave(FMT, ...) _dbprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
+#define _debug(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__)
+#endif
+
+/*
+ * determine whether a particular optional debugging point should be logged
+ * - we need to go through three steps to persuade cpp to correctly join the
+ *   shorthand in FSCACHE_DEBUG_LEVEL with its prefix
+ */
+#define ____do_kdebug(LEVEL, POINT) \
+       unlikely((fscache_debug & \
+                 (FSCACHE_POINT_##POINT << (FSCACHE_DEBUG_ ## LEVEL * 3))))
+#define ___do_kdebug(LEVEL, POINT) \
+       ____do_kdebug(LEVEL, POINT)
+#define __do_kdebug(POINT) \
+       ___do_kdebug(FSCACHE_DEBUG_LEVEL, POINT)
+
+#define FSCACHE_DEBUG_CACHE    0
+#define FSCACHE_DEBUG_COOKIE   1
+#define FSCACHE_DEBUG_PAGE     2
+#define FSCACHE_DEBUG_OPERATION        3
+
+#define FSCACHE_POINT_ENTER    1
+#define FSCACHE_POINT_LEAVE    2
+#define FSCACHE_POINT_DEBUG    4
+
+#ifndef FSCACHE_DEBUG_LEVEL
+#define FSCACHE_DEBUG_LEVEL CACHE
+#endif
+
+/*
+ * assertions
+ */
+#if 1 /* defined(__KDEBUGALL) */
+
+#define ASSERT(X)                                                      \
+do {                                                                   \
+       if (unlikely(!(X))) {                                           \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "FS-Cache: Assertion failed\n");        \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#define ASSERTCMP(X, OP, Y)                                            \
+do {                                                                   \
+       if (unlikely(!((X) OP (Y)))) {                                  \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "FS-Cache: Assertion failed\n");        \
+               printk(KERN_ERR "%lx " #OP " %lx is false\n",           \
+                      (unsigned long)(X), (unsigned long)(Y));         \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#define ASSERTIF(C, X)                                                 \
+do {                                                                   \
+       if (unlikely((C) && !(X))) {                                    \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "FS-Cache: Assertion failed\n");        \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#define ASSERTIFCMP(C, X, OP, Y)                                       \
+do {                                                                   \
+       if (unlikely((C) && !((X) OP (Y)))) {                           \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "FS-Cache: Assertion failed\n");        \
+               printk(KERN_ERR "%lx " #OP " %lx is false\n",           \
+                      (unsigned long)(X), (unsigned long)(Y));         \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+
+#else
+
+#define ASSERT(X)                      do {} while (0)
+#define ASSERTCMP(X, OP, Y)            do {} while (0)
+#define ASSERTIF(C, X)                 do {} while (0)
+#define ASSERTIFCMP(C, X, OP, Y)       do {} while (0)
+
+#endif /* assert or not */
diff --git a/fs/fscache/main.c b/fs/fscache/main.c
new file mode 100644 (file)
index 0000000..4de41b5
--- /dev/null
@@ -0,0 +1,124 @@
+/* General filesystem local caching manager
+ *
+ * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#define FSCACHE_DEBUG_LEVEL CACHE
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+MODULE_DESCRIPTION("FS Cache Manager");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+unsigned fscache_defer_lookup = 1;
+module_param_named(defer_lookup, fscache_defer_lookup, uint,
+                  S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(fscache_defer_lookup,
+                "Defer cookie lookup to background thread");
+
+unsigned fscache_defer_create = 1;
+module_param_named(defer_create, fscache_defer_create, uint,
+                  S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(fscache_defer_create,
+                "Defer cookie creation to background thread");
+
+unsigned fscache_debug;
+module_param_named(debug, fscache_debug, uint,
+                  S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(fscache_debug,
+                "FS-Cache debugging mask");
+
+struct kobject *fscache_root;
+
+/*
+ * initialise the fs caching module
+ */
+static int __init fscache_init(void)
+{
+       int ret;
+
+       ret = slow_work_register_user();
+       if (ret < 0)
+               goto error_slow_work;
+
+       ret = fscache_proc_init();
+       if (ret < 0)
+               goto error_proc;
+
+       fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar",
+                                              sizeof(struct fscache_cookie),
+                                              0,
+                                              0,
+                                              fscache_cookie_init_once);
+       if (!fscache_cookie_jar) {
+               printk(KERN_NOTICE
+                      "FS-Cache: Failed to allocate a cookie jar\n");
+               ret = -ENOMEM;
+               goto error_cookie_jar;
+       }
+
+       fscache_root = kobject_create_and_add("fscache", kernel_kobj);
+       if (!fscache_root)
+               goto error_kobj;
+
+       printk(KERN_NOTICE "FS-Cache: Loaded\n");
+       return 0;
+
+error_kobj:
+       kmem_cache_destroy(fscache_cookie_jar);
+error_cookie_jar:
+       fscache_proc_cleanup();
+error_proc:
+       slow_work_unregister_user();
+error_slow_work:
+       return ret;
+}
+
+fs_initcall(fscache_init);
+
+/*
+ * clean up on module removal
+ */
+static void __exit fscache_exit(void)
+{
+       _enter("");
+
+       kobject_put(fscache_root);
+       kmem_cache_destroy(fscache_cookie_jar);
+       fscache_proc_cleanup();
+       slow_work_unregister_user();
+       printk(KERN_NOTICE "FS-Cache: Unloaded\n");
+}
+
+module_exit(fscache_exit);
+
+/*
+ * wait_on_bit() sleep function for uninterruptible waiting
+ */
+int fscache_wait_bit(void *flags)
+{
+       schedule();
+       return 0;
+}
+EXPORT_SYMBOL(fscache_wait_bit);
+
+/*
+ * wait_on_bit() sleep function for interruptible waiting
+ */
+int fscache_wait_bit_interruptible(void *flags)
+{
+       schedule();
+       return signal_pending(current);
+}
+EXPORT_SYMBOL(fscache_wait_bit_interruptible);
diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c
new file mode 100644 (file)
index 0000000..e028b8e
--- /dev/null
@@ -0,0 +1,103 @@
+/* FS-Cache netfs (client) registration
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define FSCACHE_DEBUG_LEVEL COOKIE
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+static LIST_HEAD(fscache_netfs_list);
+
+/*
+ * register a network filesystem for caching
+ */
+int __fscache_register_netfs(struct fscache_netfs *netfs)
+{
+       struct fscache_netfs *ptr;
+       int ret;
+
+       _enter("{%s}", netfs->name);
+
+       INIT_LIST_HEAD(&netfs->link);
+
+       /* allocate a cookie for the primary index */
+       netfs->primary_index =
+               kmem_cache_zalloc(fscache_cookie_jar, GFP_KERNEL);
+
+       if (!netfs->primary_index) {
+               _leave(" = -ENOMEM");
+               return -ENOMEM;
+       }
+
+       /* initialise the primary index cookie */
+       atomic_set(&netfs->primary_index->usage, 1);
+       atomic_set(&netfs->primary_index->n_children, 0);
+
+       netfs->primary_index->def               = &fscache_fsdef_netfs_def;
+       netfs->primary_index->parent            = &fscache_fsdef_index;
+       netfs->primary_index->netfs_data        = netfs;
+
+       atomic_inc(&netfs->primary_index->parent->usage);
+       atomic_inc(&netfs->primary_index->parent->n_children);
+
+       spin_lock_init(&netfs->primary_index->lock);
+       INIT_HLIST_HEAD(&netfs->primary_index->backing_objects);
+
+       /* check the netfs type is not already present */
+       down_write(&fscache_addremove_sem);
+
+       ret = -EEXIST;
+       list_for_each_entry(ptr, &fscache_netfs_list, link) {
+               if (strcmp(ptr->name, netfs->name) == 0)
+                       goto already_registered;
+       }
+
+       list_add(&netfs->link, &fscache_netfs_list);
+       ret = 0;
+
+       printk(KERN_NOTICE "FS-Cache: Netfs '%s' registered for caching\n",
+              netfs->name);
+
+already_registered:
+       up_write(&fscache_addremove_sem);
+
+       if (ret < 0) {
+               netfs->primary_index->parent = NULL;
+               __fscache_cookie_put(netfs->primary_index);
+               netfs->primary_index = NULL;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL(__fscache_register_netfs);
+
+/*
+ * unregister a network filesystem from the cache
+ * - all cookies must have been released first
+ */
+void __fscache_unregister_netfs(struct fscache_netfs *netfs)
+{
+       _enter("{%s.%u}", netfs->name, netfs->version);
+
+       down_write(&fscache_addremove_sem);
+
+       list_del(&netfs->link);
+       fscache_relinquish_cookie(netfs->primary_index, 0);
+
+       up_write(&fscache_addremove_sem);
+
+       printk(KERN_NOTICE "FS-Cache: Netfs '%s' unregistered from caching\n",
+              netfs->name);
+
+       _leave("");
+}
+EXPORT_SYMBOL(__fscache_unregister_netfs);
diff --git a/fs/fscache/object.c b/fs/fscache/object.c
new file mode 100644 (file)
index 0000000..392a41b
--- /dev/null
@@ -0,0 +1,810 @@
+/* FS-Cache object state machine handler
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ *
+ * See Documentation/filesystems/caching/object.txt for a description of the
+ * object state machine and the in-kernel representations.
+ */
+
+#define FSCACHE_DEBUG_LEVEL COOKIE
+#include <linux/module.h>
+#include "internal.h"
+
+const char *fscache_object_states[] = {
+       [FSCACHE_OBJECT_INIT]           = "OBJECT_INIT",
+       [FSCACHE_OBJECT_LOOKING_UP]     = "OBJECT_LOOKING_UP",
+       [FSCACHE_OBJECT_CREATING]       = "OBJECT_CREATING",
+       [FSCACHE_OBJECT_AVAILABLE]      = "OBJECT_AVAILABLE",
+       [FSCACHE_OBJECT_ACTIVE]         = "OBJECT_ACTIVE",
+       [FSCACHE_OBJECT_UPDATING]       = "OBJECT_UPDATING",
+       [FSCACHE_OBJECT_DYING]          = "OBJECT_DYING",
+       [FSCACHE_OBJECT_LC_DYING]       = "OBJECT_LC_DYING",
+       [FSCACHE_OBJECT_ABORT_INIT]     = "OBJECT_ABORT_INIT",
+       [FSCACHE_OBJECT_RELEASING]      = "OBJECT_RELEASING",
+       [FSCACHE_OBJECT_RECYCLING]      = "OBJECT_RECYCLING",
+       [FSCACHE_OBJECT_WITHDRAWING]    = "OBJECT_WITHDRAWING",
+       [FSCACHE_OBJECT_DEAD]           = "OBJECT_DEAD",
+};
+EXPORT_SYMBOL(fscache_object_states);
+
+static void fscache_object_slow_work_put_ref(struct slow_work *);
+static int  fscache_object_slow_work_get_ref(struct slow_work *);
+static void fscache_object_slow_work_execute(struct slow_work *);
+static void fscache_initialise_object(struct fscache_object *);
+static void fscache_lookup_object(struct fscache_object *);
+static void fscache_object_available(struct fscache_object *);
+static void fscache_release_object(struct fscache_object *);
+static void fscache_withdraw_object(struct fscache_object *);
+static void fscache_enqueue_dependents(struct fscache_object *);
+static void fscache_dequeue_object(struct fscache_object *);
+
+const struct slow_work_ops fscache_object_slow_work_ops = {
+       .get_ref        = fscache_object_slow_work_get_ref,
+       .put_ref        = fscache_object_slow_work_put_ref,
+       .execute        = fscache_object_slow_work_execute,
+};
+EXPORT_SYMBOL(fscache_object_slow_work_ops);
+
+/*
+ * we need to notify the parent when an op completes that we had outstanding
+ * upon it
+ */
+static inline void fscache_done_parent_op(struct fscache_object *object)
+{
+       struct fscache_object *parent = object->parent;
+
+       _enter("OBJ%x {OBJ%x,%x}",
+              object->debug_id, parent->debug_id, parent->n_ops);
+
+       spin_lock_nested(&parent->lock, 1);
+       parent->n_ops--;
+       parent->n_obj_ops--;
+       if (parent->n_ops == 0)
+               fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED);
+       spin_unlock(&parent->lock);
+}
+
+/*
+ * process events that have been sent to an object's state machine
+ * - initiates parent lookup
+ * - does object lookup
+ * - does object creation
+ * - does object recycling and retirement
+ * - does object withdrawal
+ */
+static void fscache_object_state_machine(struct fscache_object *object)
+{
+       enum fscache_object_state new_state;
+
+       ASSERT(object != NULL);
+
+       _enter("{OBJ%x,%s,%lx}",
+              object->debug_id, fscache_object_states[object->state],
+              object->events);
+
+       switch (object->state) {
+               /* wait for the parent object to become ready */
+       case FSCACHE_OBJECT_INIT:
+               object->event_mask =
+                       ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED);
+               fscache_initialise_object(object);
+               goto done;
+
+               /* look up the object metadata on disk */
+       case FSCACHE_OBJECT_LOOKING_UP:
+               fscache_lookup_object(object);
+               goto lookup_transit;
+
+               /* create the object metadata on disk */
+       case FSCACHE_OBJECT_CREATING:
+               fscache_lookup_object(object);
+               goto lookup_transit;
+
+               /* handle an object becoming available; start pending
+                * operations and queue dependent operations for processing */
+       case FSCACHE_OBJECT_AVAILABLE:
+               fscache_object_available(object);
+               goto active_transit;
+
+               /* normal running state */
+       case FSCACHE_OBJECT_ACTIVE:
+               goto active_transit;
+
+               /* update the object metadata on disk */
+       case FSCACHE_OBJECT_UPDATING:
+               clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events);
+               fscache_stat(&fscache_n_updates_run);
+               object->cache->ops->update_object(object);
+               goto active_transit;
+
+               /* handle an object dying during lookup or creation */
+       case FSCACHE_OBJECT_LC_DYING:
+               object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE);
+               object->cache->ops->lookup_complete(object);
+
+               spin_lock(&object->lock);
+               object->state = FSCACHE_OBJECT_DYING;
+               if (test_and_clear_bit(FSCACHE_COOKIE_CREATING,
+                                      &object->cookie->flags))
+                       wake_up_bit(&object->cookie->flags,
+                                   FSCACHE_COOKIE_CREATING);
+               spin_unlock(&object->lock);
+
+               fscache_done_parent_op(object);
+
+               /* wait for completion of all active operations on this object
+                * and the death of all child objects of this object */
+       case FSCACHE_OBJECT_DYING:
+       dying:
+               clear_bit(FSCACHE_OBJECT_EV_CLEARED, &object->events);
+               spin_lock(&object->lock);
+               _debug("dying OBJ%x {%d,%d}",
+                      object->debug_id, object->n_ops, object->n_children);
+               if (object->n_ops == 0 && object->n_children == 0) {
+                       object->event_mask &=
+                               ~(1 << FSCACHE_OBJECT_EV_CLEARED);
+                       object->event_mask |=
+                               (1 << FSCACHE_OBJECT_EV_WITHDRAW) |
+                               (1 << FSCACHE_OBJECT_EV_RETIRE) |
+                               (1 << FSCACHE_OBJECT_EV_RELEASE) |
+                               (1 << FSCACHE_OBJECT_EV_ERROR);
+               } else {
+                       object->event_mask &=
+                               ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
+                                 (1 << FSCACHE_OBJECT_EV_RETIRE) |
+                                 (1 << FSCACHE_OBJECT_EV_RELEASE) |
+                                 (1 << FSCACHE_OBJECT_EV_ERROR));
+                       object->event_mask |=
+                               1 << FSCACHE_OBJECT_EV_CLEARED;
+               }
+               spin_unlock(&object->lock);
+               fscache_enqueue_dependents(object);
+               goto terminal_transit;
+
+               /* handle an abort during initialisation */
+       case FSCACHE_OBJECT_ABORT_INIT:
+               _debug("handle abort init %lx", object->events);
+               object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE);
+
+               spin_lock(&object->lock);
+               fscache_dequeue_object(object);
+
+               object->state = FSCACHE_OBJECT_DYING;
+               if (test_and_clear_bit(FSCACHE_COOKIE_CREATING,
+                                      &object->cookie->flags))
+                       wake_up_bit(&object->cookie->flags,
+                                   FSCACHE_COOKIE_CREATING);
+               spin_unlock(&object->lock);
+               goto dying;
+
+               /* handle the netfs releasing an object and possibly marking it
+                * obsolete too */
+       case FSCACHE_OBJECT_RELEASING:
+       case FSCACHE_OBJECT_RECYCLING:
+               object->event_mask &=
+                       ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
+                         (1 << FSCACHE_OBJECT_EV_RETIRE) |
+                         (1 << FSCACHE_OBJECT_EV_RELEASE) |
+                         (1 << FSCACHE_OBJECT_EV_ERROR));
+               fscache_release_object(object);
+               spin_lock(&object->lock);
+               object->state = FSCACHE_OBJECT_DEAD;
+               spin_unlock(&object->lock);
+               fscache_stat(&fscache_n_object_dead);
+               goto terminal_transit;
+
+               /* handle the parent cache of this object being withdrawn from
+                * active service */
+       case FSCACHE_OBJECT_WITHDRAWING:
+               object->event_mask &=
+                       ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
+                         (1 << FSCACHE_OBJECT_EV_RETIRE) |
+                         (1 << FSCACHE_OBJECT_EV_RELEASE) |
+                         (1 << FSCACHE_OBJECT_EV_ERROR));
+               fscache_withdraw_object(object);
+               spin_lock(&object->lock);
+               object->state = FSCACHE_OBJECT_DEAD;
+               spin_unlock(&object->lock);
+               fscache_stat(&fscache_n_object_dead);
+               goto terminal_transit;
+
+               /* complain about the object being woken up once it is
+                * deceased */
+       case FSCACHE_OBJECT_DEAD:
+               printk(KERN_ERR "FS-Cache:"
+                      " Unexpected event in dead state %lx\n",
+                      object->events & object->event_mask);
+               BUG();
+
+       default:
+               printk(KERN_ERR "FS-Cache: Unknown object state %u\n",
+                      object->state);
+               BUG();
+       }
+
+       /* determine the transition from a lookup state */
+lookup_transit:
+       switch (fls(object->events & object->event_mask) - 1) {
+       case FSCACHE_OBJECT_EV_WITHDRAW:
+       case FSCACHE_OBJECT_EV_RETIRE:
+       case FSCACHE_OBJECT_EV_RELEASE:
+       case FSCACHE_OBJECT_EV_ERROR:
+               new_state = FSCACHE_OBJECT_LC_DYING;
+               goto change_state;
+       case FSCACHE_OBJECT_EV_REQUEUE:
+               goto done;
+       case -1:
+               goto done; /* sleep until event */
+       default:
+               goto unsupported_event;
+       }
+
+       /* determine the transition from an active state */
+active_transit:
+       switch (fls(object->events & object->event_mask) - 1) {
+       case FSCACHE_OBJECT_EV_WITHDRAW:
+       case FSCACHE_OBJECT_EV_RETIRE:
+       case FSCACHE_OBJECT_EV_RELEASE:
+       case FSCACHE_OBJECT_EV_ERROR:
+               new_state = FSCACHE_OBJECT_DYING;
+               goto change_state;
+       case FSCACHE_OBJECT_EV_UPDATE:
+               new_state = FSCACHE_OBJECT_UPDATING;
+               goto change_state;
+       case -1:
+               new_state = FSCACHE_OBJECT_ACTIVE;
+               goto change_state; /* sleep until event */
+       default:
+               goto unsupported_event;
+       }
+
+       /* determine the transition from a terminal state */
+terminal_transit:
+       switch (fls(object->events & object->event_mask) - 1) {
+       case FSCACHE_OBJECT_EV_WITHDRAW:
+               new_state = FSCACHE_OBJECT_WITHDRAWING;
+               goto change_state;
+       case FSCACHE_OBJECT_EV_RETIRE:
+               new_state = FSCACHE_OBJECT_RECYCLING;
+               goto change_state;
+       case FSCACHE_OBJECT_EV_RELEASE:
+               new_state = FSCACHE_OBJECT_RELEASING;
+               goto change_state;
+       case FSCACHE_OBJECT_EV_ERROR:
+               new_state = FSCACHE_OBJECT_WITHDRAWING;
+               goto change_state;
+       case FSCACHE_OBJECT_EV_CLEARED:
+               new_state = FSCACHE_OBJECT_DYING;
+               goto change_state;
+       case -1:
+               goto done; /* sleep until event */
+       default:
+               goto unsupported_event;
+       }
+
+change_state:
+       spin_lock(&object->lock);
+       object->state = new_state;
+       spin_unlock(&object->lock);
+
+done:
+       _leave(" [->%s]", fscache_object_states[object->state]);
+       return;
+
+unsupported_event:
+       printk(KERN_ERR "FS-Cache:"
+              " Unsupported event %lx [mask %lx] in state %s\n",
+              object->events, object->event_mask,
+              fscache_object_states[object->state]);
+       BUG();
+}
+
+/*
+ * execute an object
+ */
+static void fscache_object_slow_work_execute(struct slow_work *work)
+{
+       struct fscache_object *object =
+               container_of(work, struct fscache_object, work);
+       unsigned long start;
+
+       _enter("{OBJ%x}", object->debug_id);
+
+       clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
+
+       start = jiffies;
+       fscache_object_state_machine(object);
+       fscache_hist(fscache_objs_histogram, start);
+       if (object->events & object->event_mask)
+               fscache_enqueue_object(object);
+}
+
+/*
+ * initialise an object
+ * - check the specified object's parent to see if we can make use of it
+ *   immediately to do a creation
+ * - we may need to start the process of creating a parent and we need to wait
+ *   for the parent's lookup and creation to complete if it's not there yet
+ * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the
+ *   leaf-most cookies of the object and all its children
+ */
+static void fscache_initialise_object(struct fscache_object *object)
+{
+       struct fscache_object *parent;
+
+       _enter("");
+       ASSERT(object->cookie != NULL);
+       ASSERT(object->cookie->parent != NULL);
+       ASSERT(list_empty(&object->work.link));
+
+       if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) |
+                             (1 << FSCACHE_OBJECT_EV_RELEASE) |
+                             (1 << FSCACHE_OBJECT_EV_RETIRE) |
+                             (1 << FSCACHE_OBJECT_EV_WITHDRAW))) {
+               _debug("abort init %lx", object->events);
+               spin_lock(&object->lock);
+               object->state = FSCACHE_OBJECT_ABORT_INIT;
+               spin_unlock(&object->lock);
+               return;
+       }
+
+       spin_lock(&object->cookie->lock);
+       spin_lock_nested(&object->cookie->parent->lock, 1);
+
+       parent = object->parent;
+       if (!parent) {
+               _debug("no parent");
+               set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events);
+       } else {
+               spin_lock(&object->lock);
+               spin_lock_nested(&parent->lock, 1);
+               _debug("parent %s", fscache_object_states[parent->state]);
+
+               if (parent->state >= FSCACHE_OBJECT_DYING) {
+                       _debug("bad parent");
+                       set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events);
+               } else if (parent->state < FSCACHE_OBJECT_AVAILABLE) {
+                       _debug("wait");
+
+                       /* we may get woken up in this state by child objects
+                        * binding on to us, so we need to make sure we don't
+                        * add ourself to the list multiple times */
+                       if (list_empty(&object->dep_link)) {
+                               object->cache->ops->grab_object(object);
+                               list_add(&object->dep_link,
+                                        &parent->dependents);
+
+                               /* fscache_acquire_non_index_cookie() uses this
+                                * to wake the chain up */
+                               if (parent->state == FSCACHE_OBJECT_INIT)
+                                       fscache_enqueue_object(parent);
+                       }
+               } else {
+                       _debug("go");
+                       parent->n_ops++;
+                       parent->n_obj_ops++;
+                       object->lookup_jif = jiffies;
+                       object->state = FSCACHE_OBJECT_LOOKING_UP;
+                       set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
+               }
+
+               spin_unlock(&parent->lock);
+               spin_unlock(&object->lock);
+       }
+
+       spin_unlock(&object->cookie->parent->lock);
+       spin_unlock(&object->cookie->lock);
+       _leave("");
+}
+
+/*
+ * look an object up in the cache from which it was allocated
+ * - we hold an "access lock" on the parent object, so the parent object cannot
+ *   be withdrawn by either party till we've finished
+ * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the
+ *   leaf-most cookies of the object and all its children
+ */
+static void fscache_lookup_object(struct fscache_object *object)
+{
+       struct fscache_cookie *cookie = object->cookie;
+       struct fscache_object *parent;
+
+       _enter("");
+
+       parent = object->parent;
+       ASSERT(parent != NULL);
+       ASSERTCMP(parent->n_ops, >, 0);
+       ASSERTCMP(parent->n_obj_ops, >, 0);
+
+       /* make sure the parent is still available */
+       ASSERTCMP(parent->state, >=, FSCACHE_OBJECT_AVAILABLE);
+
+       if (parent->state >= FSCACHE_OBJECT_DYING ||
+           test_bit(FSCACHE_IOERROR, &object->cache->flags)) {
+               _debug("unavailable");
+               set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events);
+               _leave("");
+               return;
+       }
+
+       _debug("LOOKUP \"%s/%s\" in \"%s\"",
+              parent->cookie->def->name, cookie->def->name,
+              object->cache->tag->name);
+
+       fscache_stat(&fscache_n_object_lookups);
+       object->cache->ops->lookup_object(object);
+
+       if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events))
+               set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags);
+
+       _leave("");
+}
+
+/**
+ * fscache_object_lookup_negative - Note negative cookie lookup
+ * @object: Object pointing to cookie to mark
+ *
+ * Note negative lookup, permitting those waiting to read data from an already
+ * existing backing object to continue as there's no data for them to read.
+ */
+void fscache_object_lookup_negative(struct fscache_object *object)
+{
+       struct fscache_cookie *cookie = object->cookie;
+
+       _enter("{OBJ%x,%s}",
+              object->debug_id, fscache_object_states[object->state]);
+
+       spin_lock(&object->lock);
+       if (object->state == FSCACHE_OBJECT_LOOKING_UP) {
+               fscache_stat(&fscache_n_object_lookups_negative);
+
+               /* transit here to allow write requests to begin stacking up
+                * and read requests to begin returning ENODATA */
+               object->state = FSCACHE_OBJECT_CREATING;
+               spin_unlock(&object->lock);
+
+               set_bit(FSCACHE_COOKIE_PENDING_FILL, &cookie->flags);
+               set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
+
+               _debug("wake up lookup %p", &cookie->flags);
+               smp_mb__before_clear_bit();
+               clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
+               smp_mb__after_clear_bit();
+               wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
+               set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
+       } else {
+               ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING);
+               spin_unlock(&object->lock);
+       }
+
+       _leave("");
+}
+EXPORT_SYMBOL(fscache_object_lookup_negative);
+
+/**
+ * fscache_obtained_object - Note successful object lookup or creation
+ * @object: Object pointing to cookie to mark
+ *
+ * Note successful lookup and/or creation, permitting those waiting to write
+ * data to a backing object to continue.
+ *
+ * Note that after calling this, an object's cookie may be relinquished by the
+ * netfs, and so must be accessed with object lock held.
+ */
+void fscache_obtained_object(struct fscache_object *object)
+{
+       struct fscache_cookie *cookie = object->cookie;
+
+       _enter("{OBJ%x,%s}",
+              object->debug_id, fscache_object_states[object->state]);
+
+       /* if we were still looking up, then we must have a positive lookup
+        * result, in which case there may be data available */
+       spin_lock(&object->lock);
+       if (object->state == FSCACHE_OBJECT_LOOKING_UP) {
+               fscache_stat(&fscache_n_object_lookups_positive);
+
+               clear_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
+
+               object->state = FSCACHE_OBJECT_AVAILABLE;
+               spin_unlock(&object->lock);
+
+               smp_mb__before_clear_bit();
+               clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
+               smp_mb__after_clear_bit();
+               wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
+               set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
+       } else {
+               ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING);
+               fscache_stat(&fscache_n_object_created);
+
+               object->state = FSCACHE_OBJECT_AVAILABLE;
+               spin_unlock(&object->lock);
+               set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
+               smp_wmb();
+       }
+
+       if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, &cookie->flags))
+               wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING);
+
+       _leave("");
+}
+EXPORT_SYMBOL(fscache_obtained_object);
+
+/*
+ * handle an object that has just become available
+ */
+static void fscache_object_available(struct fscache_object *object)
+{
+       _enter("{OBJ%x}", object->debug_id);
+
+       spin_lock(&object->lock);
+
+       if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags))
+               wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING);
+
+       fscache_done_parent_op(object);
+       if (object->n_in_progress == 0) {
+               if (object->n_ops > 0) {
+                       ASSERTCMP(object->n_ops, >=, object->n_obj_ops);
+                       ASSERTIF(object->n_ops > object->n_obj_ops,
+                                !list_empty(&object->pending_ops));
+                       fscache_start_operations(object);
+               } else {
+                       ASSERT(list_empty(&object->pending_ops));
+               }
+       }
+       spin_unlock(&object->lock);
+
+       object->cache->ops->lookup_complete(object);
+       fscache_enqueue_dependents(object);
+
+       fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif);
+       fscache_stat(&fscache_n_object_avail);
+
+       _leave("");
+}
+
+/*
+ * drop an object's attachments
+ */
+static void fscache_drop_object(struct fscache_object *object)
+{
+       struct fscache_object *parent = object->parent;
+       struct fscache_cache *cache = object->cache;
+
+       _enter("{OBJ%x,%d}", object->debug_id, object->n_children);
+
+       spin_lock(&cache->object_list_lock);
+       list_del_init(&object->cache_link);
+       spin_unlock(&cache->object_list_lock);
+
+       cache->ops->drop_object(object);
+
+       if (parent) {
+               _debug("release parent OBJ%x {%d}",
+                      parent->debug_id, parent->n_children);
+
+               spin_lock(&parent->lock);
+               parent->n_children--;
+               if (parent->n_children == 0)
+                       fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED);
+               spin_unlock(&parent->lock);
+               object->parent = NULL;
+       }
+
+       /* this just shifts the object release to the slow work processor */
+       object->cache->ops->put_object(object);
+
+       _leave("");
+}
+
+/*
+ * release or recycle an object that the netfs has discarded
+ */
+static void fscache_release_object(struct fscache_object *object)
+{
+       _enter("");
+
+       fscache_drop_object(object);
+}
+
+/*
+ * withdraw an object from active service
+ */
+static void fscache_withdraw_object(struct fscache_object *object)
+{
+       struct fscache_cookie *cookie;
+       bool detached;
+
+       _enter("");
+
+       spin_lock(&object->lock);
+       cookie = object->cookie;
+       if (cookie) {
+               /* need to get the cookie lock before the object lock, starting
+                * from the object pointer */
+               atomic_inc(&cookie->usage);
+               spin_unlock(&object->lock);
+
+               detached = false;
+               spin_lock(&cookie->lock);
+               spin_lock(&object->lock);
+
+               if (object->cookie == cookie) {
+                       hlist_del_init(&object->cookie_link);
+                       object->cookie = NULL;
+                       detached = true;
+               }
+               spin_unlock(&cookie->lock);
+               fscache_cookie_put(cookie);
+               if (detached)
+                       fscache_cookie_put(cookie);
+       }
+
+       spin_unlock(&object->lock);
+
+       fscache_drop_object(object);
+}
+
+/*
+ * withdraw an object from active service at the behest of the cache
+ * - need break the links to a cached object cookie
+ * - called under two situations:
+ *   (1) recycler decides to reclaim an in-use object
+ *   (2) a cache is unmounted
+ * - have to take care as the cookie can be being relinquished by the netfs
+ *   simultaneously
+ * - the object is pinned by the caller holding a refcount on it
+ */
+void fscache_withdrawing_object(struct fscache_cache *cache,
+                               struct fscache_object *object)
+{
+       bool enqueue = false;
+
+       _enter(",OBJ%x", object->debug_id);
+
+       spin_lock(&object->lock);
+       if (object->state < FSCACHE_OBJECT_WITHDRAWING) {
+               object->state = FSCACHE_OBJECT_WITHDRAWING;
+               enqueue = true;
+       }
+       spin_unlock(&object->lock);
+
+       if (enqueue)
+               fscache_enqueue_object(object);
+
+       _leave("");
+}
+
+/*
+ * allow the slow work item processor to get a ref on an object
+ */
+static int fscache_object_slow_work_get_ref(struct slow_work *work)
+{
+       struct fscache_object *object =
+               container_of(work, struct fscache_object, work);
+
+       return object->cache->ops->grab_object(object) ? 0 : -EAGAIN;
+}
+
+/*
+ * allow the slow work item processor to discard a ref on a work item
+ */
+static void fscache_object_slow_work_put_ref(struct slow_work *work)
+{
+       struct fscache_object *object =
+               container_of(work, struct fscache_object, work);
+
+       return object->cache->ops->put_object(object);
+}
+
+/*
+ * enqueue an object for metadata-type processing
+ */
+void fscache_enqueue_object(struct fscache_object *object)
+{
+       _enter("{OBJ%x}", object->debug_id);
+
+       slow_work_enqueue(&object->work);
+}
+
+/*
+ * enqueue the dependents of an object for metadata-type processing
+ * - the caller must hold the object's lock
+ * - this may cause an already locked object to wind up being processed again
+ */
+static void fscache_enqueue_dependents(struct fscache_object *object)
+{
+       struct fscache_object *dep;
+
+       _enter("{OBJ%x}", object->debug_id);
+
+       if (list_empty(&object->dependents))
+               return;
+
+       spin_lock(&object->lock);
+
+       while (!list_empty(&object->dependents)) {
+               dep = list_entry(object->dependents.next,
+                                struct fscache_object, dep_link);
+               list_del_init(&dep->dep_link);
+
+
+               /* sort onto appropriate lists */
+               fscache_enqueue_object(dep);
+               dep->cache->ops->put_object(dep);
+
+               if (!list_empty(&object->dependents))
+                       cond_resched_lock(&object->lock);
+       }
+
+       spin_unlock(&object->lock);
+}
+
+/*
+ * remove an object from whatever queue it's waiting on
+ * - the caller must hold object->lock
+ */
+void fscache_dequeue_object(struct fscache_object *object)
+{
+       _enter("{OBJ%x}", object->debug_id);
+
+       if (!list_empty(&object->dep_link)) {
+               spin_lock(&object->parent->lock);
+               list_del_init(&object->dep_link);
+               spin_unlock(&object->parent->lock);
+       }
+
+       _leave("");
+}
+
+/**
+ * fscache_check_aux - Ask the netfs whether an object on disk is still valid
+ * @object: The object to ask about
+ * @data: The auxiliary data for the object
+ * @datalen: The size of the auxiliary data
+ *
+ * This function consults the netfs about the coherency state of an object
+ */
+enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
+                                       const void *data, uint16_t datalen)
+{
+       enum fscache_checkaux result;
+
+       if (!object->cookie->def->check_aux) {
+               fscache_stat(&fscache_n_checkaux_none);
+               return FSCACHE_CHECKAUX_OKAY;
+       }
+
+       result = object->cookie->def->check_aux(object->cookie->netfs_data,
+                                               data, datalen);
+       switch (result) {
+               /* entry okay as is */
+       case FSCACHE_CHECKAUX_OKAY:
+               fscache_stat(&fscache_n_checkaux_okay);
+               break;
+
+               /* entry requires update */
+       case FSCACHE_CHECKAUX_NEEDS_UPDATE:
+               fscache_stat(&fscache_n_checkaux_update);
+               break;
+
+               /* entry requires deletion */
+       case FSCACHE_CHECKAUX_OBSOLETE:
+               fscache_stat(&fscache_n_checkaux_obsolete);
+               break;
+
+       default:
+               BUG();
+       }
+
+       return result;
+}
+EXPORT_SYMBOL(fscache_check_aux);
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c
new file mode 100644 (file)
index 0000000..e7f8d53
--- /dev/null
@@ -0,0 +1,459 @@
+/* FS-Cache worker operation management routines
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ *
+ * See Documentation/filesystems/caching/operations.txt
+ */
+
+#define FSCACHE_DEBUG_LEVEL OPERATION
+#include <linux/module.h>
+#include "internal.h"
+
+atomic_t fscache_op_debug_id;
+EXPORT_SYMBOL(fscache_op_debug_id);
+
+/**
+ * fscache_enqueue_operation - Enqueue an operation for processing
+ * @op: The operation to enqueue
+ *
+ * Enqueue an operation for processing by the FS-Cache thread pool.
+ *
+ * This will get its own ref on the object.
+ */
+void fscache_enqueue_operation(struct fscache_operation *op)
+{
+       _enter("{OBJ%x OP%x,%u}",
+              op->object->debug_id, op->debug_id, atomic_read(&op->usage));
+
+       ASSERT(op->processor != NULL);
+       ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE);
+       ASSERTCMP(atomic_read(&op->usage), >, 0);
+
+       if (list_empty(&op->pend_link)) {
+               switch (op->flags & FSCACHE_OP_TYPE) {
+               case FSCACHE_OP_FAST:
+                       _debug("queue fast");
+                       atomic_inc(&op->usage);
+                       if (!schedule_work(&op->fast_work))
+                               fscache_put_operation(op);
+                       break;
+               case FSCACHE_OP_SLOW:
+                       _debug("queue slow");
+                       slow_work_enqueue(&op->slow_work);
+                       break;
+               case FSCACHE_OP_MYTHREAD:
+                       _debug("queue for caller's attention");
+                       break;
+               default:
+                       printk(KERN_ERR "FS-Cache: Unexpected op type %lx",
+                              op->flags);
+                       BUG();
+                       break;
+               }
+               fscache_stat(&fscache_n_op_enqueue);
+       }
+}
+EXPORT_SYMBOL(fscache_enqueue_operation);
+
+/*
+ * start an op running
+ */
+static void fscache_run_op(struct fscache_object *object,
+                          struct fscache_operation *op)
+{
+       object->n_in_progress++;
+       if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
+               wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
+       if (op->processor)
+               fscache_enqueue_operation(op);
+       fscache_stat(&fscache_n_op_run);
+}
+
+/*
+ * submit an exclusive operation for an object
+ * - other ops are excluded from running simultaneously with this one
+ * - this gets any extra refs it needs on an op
+ */
+int fscache_submit_exclusive_op(struct fscache_object *object,
+                               struct fscache_operation *op)
+{
+       int ret;
+
+       _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id);
+
+       spin_lock(&object->lock);
+       ASSERTCMP(object->n_ops, >=, object->n_in_progress);
+       ASSERTCMP(object->n_ops, >=, object->n_exclusive);
+
+       ret = -ENOBUFS;
+       if (fscache_object_is_active(object)) {
+               op->object = object;
+               object->n_ops++;
+               object->n_exclusive++;  /* reads and writes must wait */
+
+               if (object->n_ops > 0) {
+                       atomic_inc(&op->usage);
+                       list_add_tail(&op->pend_link, &object->pending_ops);
+                       fscache_stat(&fscache_n_op_pend);
+               } else if (!list_empty(&object->pending_ops)) {
+                       atomic_inc(&op->usage);
+                       list_add_tail(&op->pend_link, &object->pending_ops);
+                       fscache_stat(&fscache_n_op_pend);
+                       fscache_start_operations(object);
+               } else {
+                       ASSERTCMP(object->n_in_progress, ==, 0);
+                       fscache_run_op(object, op);
+               }
+
+               /* need to issue a new write op after this */
+               clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
+               ret = 0;
+       } else if (object->state == FSCACHE_OBJECT_CREATING) {
+               op->object = object;
+               object->n_ops++;
+               object->n_exclusive++;  /* reads and writes must wait */
+               atomic_inc(&op->usage);
+               list_add_tail(&op->pend_link, &object->pending_ops);
+               fscache_stat(&fscache_n_op_pend);
+               ret = 0;
+       } else {
+               /* not allowed to submit ops in any other state */
+               BUG();
+       }
+
+       spin_unlock(&object->lock);
+       return ret;
+}
+
+/*
+ * report an unexpected submission
+ */
+static void fscache_report_unexpected_submission(struct fscache_object *object,
+                                                struct fscache_operation *op,
+                                                unsigned long ostate)
+{
+       static bool once_only;
+       struct fscache_operation *p;
+       unsigned n;
+
+       if (once_only)
+               return;
+       once_only = true;
+
+       kdebug("unexpected submission OP%x [OBJ%x %s]",
+              op->debug_id, object->debug_id,
+              fscache_object_states[object->state]);
+       kdebug("objstate=%s [%s]",
+              fscache_object_states[object->state],
+              fscache_object_states[ostate]);
+       kdebug("objflags=%lx", object->flags);
+       kdebug("objevent=%lx [%lx]", object->events, object->event_mask);
+       kdebug("ops=%u inp=%u exc=%u",
+              object->n_ops, object->n_in_progress, object->n_exclusive);
+
+       if (!list_empty(&object->pending_ops)) {
+               n = 0;
+               list_for_each_entry(p, &object->pending_ops, pend_link) {
+                       ASSERTCMP(p->object, ==, object);
+                       kdebug("%p %p", op->processor, op->release);
+                       n++;
+               }
+
+               kdebug("n=%u", n);
+       }
+
+       dump_stack();
+}
+
+/*
+ * submit an operation for an object
+ * - objects may be submitted only in the following states:
+ *   - during object creation (write ops may be submitted)
+ *   - whilst the object is active
+ *   - after an I/O error incurred in one of the two above states (op rejected)
+ * - this gets any extra refs it needs on an op
+ */
+int fscache_submit_op(struct fscache_object *object,
+                     struct fscache_operation *op)
+{
+       unsigned long ostate;
+       int ret;
+
+       _enter("{OBJ%x OP%x},{%u}",
+              object->debug_id, op->debug_id, atomic_read(&op->usage));
+
+       ASSERTCMP(atomic_read(&op->usage), >, 0);
+
+       spin_lock(&object->lock);
+       ASSERTCMP(object->n_ops, >=, object->n_in_progress);
+       ASSERTCMP(object->n_ops, >=, object->n_exclusive);
+
+       ostate = object->state;
+       smp_rmb();
+
+       if (fscache_object_is_active(object)) {
+               op->object = object;
+               object->n_ops++;
+
+               if (object->n_exclusive > 0) {
+                       atomic_inc(&op->usage);
+                       list_add_tail(&op->pend_link, &object->pending_ops);
+                       fscache_stat(&fscache_n_op_pend);
+               } else if (!list_empty(&object->pending_ops)) {
+                       atomic_inc(&op->usage);
+                       list_add_tail(&op->pend_link, &object->pending_ops);
+                       fscache_stat(&fscache_n_op_pend);
+                       fscache_start_operations(object);
+               } else {
+                       ASSERTCMP(object->n_exclusive, ==, 0);
+                       fscache_run_op(object, op);
+               }
+               ret = 0;
+       } else if (object->state == FSCACHE_OBJECT_CREATING) {
+               op->object = object;
+               object->n_ops++;
+               atomic_inc(&op->usage);
+               list_add_tail(&op->pend_link, &object->pending_ops);
+               fscache_stat(&fscache_n_op_pend);
+               ret = 0;
+       } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) {
+               fscache_report_unexpected_submission(object, op, ostate);
+               ASSERT(!fscache_object_is_active(object));
+               ret = -ENOBUFS;
+       } else {
+               ret = -ENOBUFS;
+       }
+
+       spin_unlock(&object->lock);
+       return ret;
+}
+
+/*
+ * queue an object for withdrawal on error, aborting all following asynchronous
+ * operations
+ */
+void fscache_abort_object(struct fscache_object *object)
+{
+       _enter("{OBJ%x}", object->debug_id);
+
+       fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
+}
+
+/*
+ * jump start the operation processing on an object
+ * - caller must hold object->lock
+ */
+void fscache_start_operations(struct fscache_object *object)
+{
+       struct fscache_operation *op;
+       bool stop = false;
+
+       while (!list_empty(&object->pending_ops) && !stop) {
+               op = list_entry(object->pending_ops.next,
+                               struct fscache_operation, pend_link);
+
+               if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) {
+                       if (object->n_in_progress > 0)
+                               break;
+                       stop = true;
+               }
+               list_del_init(&op->pend_link);
+               object->n_in_progress++;
+
+               if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
+                       wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
+               if (op->processor)
+                       fscache_enqueue_operation(op);
+
+               /* the pending queue was holding a ref on the object */
+               fscache_put_operation(op);
+       }
+
+       ASSERTCMP(object->n_in_progress, <=, object->n_ops);
+
+       _debug("woke %d ops on OBJ%x",
+              object->n_in_progress, object->debug_id);
+}
+
+/*
+ * release an operation
+ * - queues pending ops if this is the last in-progress op
+ */
+void fscache_put_operation(struct fscache_operation *op)
+{
+       struct fscache_object *object;
+       struct fscache_cache *cache;
+
+       _enter("{OBJ%x OP%x,%d}",
+              op->object->debug_id, op->debug_id, atomic_read(&op->usage));
+
+       ASSERTCMP(atomic_read(&op->usage), >, 0);
+
+       if (!atomic_dec_and_test(&op->usage))
+               return;
+
+       _debug("PUT OP");
+       if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags))
+               BUG();
+
+       fscache_stat(&fscache_n_op_release);
+
+       if (op->release) {
+               op->release(op);
+               op->release = NULL;
+       }
+
+       object = op->object;
+
+       /* now... we may get called with the object spinlock held, so we
+        * complete the cleanup here only if we can immediately acquire the
+        * lock, and defer it otherwise */
+       if (!spin_trylock(&object->lock)) {
+               _debug("defer put");
+               fscache_stat(&fscache_n_op_deferred_release);
+
+               cache = object->cache;
+               spin_lock(&cache->op_gc_list_lock);
+               list_add_tail(&op->pend_link, &cache->op_gc_list);
+               spin_unlock(&cache->op_gc_list_lock);
+               schedule_work(&cache->op_gc);
+               _leave(" [defer]");
+               return;
+       }
+
+       if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) {
+               ASSERTCMP(object->n_exclusive, >, 0);
+               object->n_exclusive--;
+       }
+
+       ASSERTCMP(object->n_in_progress, >, 0);
+       object->n_in_progress--;
+       if (object->n_in_progress == 0)
+               fscache_start_operations(object);
+
+       ASSERTCMP(object->n_ops, >, 0);
+       object->n_ops--;
+       if (object->n_ops == 0)
+               fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED);
+
+       spin_unlock(&object->lock);
+
+       kfree(op);
+       _leave(" [done]");
+}
+EXPORT_SYMBOL(fscache_put_operation);
+
+/*
+ * garbage collect operations that have had their release deferred
+ */
+void fscache_operation_gc(struct work_struct *work)
+{
+       struct fscache_operation *op;
+       struct fscache_object *object;
+       struct fscache_cache *cache =
+               container_of(work, struct fscache_cache, op_gc);
+       int count = 0;
+
+       _enter("");
+
+       do {
+               spin_lock(&cache->op_gc_list_lock);
+               if (list_empty(&cache->op_gc_list)) {
+                       spin_unlock(&cache->op_gc_list_lock);
+                       break;
+               }
+
+               op = list_entry(cache->op_gc_list.next,
+                               struct fscache_operation, pend_link);
+               list_del(&op->pend_link);
+               spin_unlock(&cache->op_gc_list_lock);
+
+               object = op->object;
+
+               _debug("GC DEFERRED REL OBJ%x OP%x",
+                      object->debug_id, op->debug_id);
+               fscache_stat(&fscache_n_op_gc);
+
+               ASSERTCMP(atomic_read(&op->usage), ==, 0);
+
+               spin_lock(&object->lock);
+               if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) {
+                       ASSERTCMP(object->n_exclusive, >, 0);
+                       object->n_exclusive--;
+               }
+
+               ASSERTCMP(object->n_in_progress, >, 0);
+               object->n_in_progress--;
+               if (object->n_in_progress == 0)
+                       fscache_start_operations(object);
+
+               ASSERTCMP(object->n_ops, >, 0);
+               object->n_ops--;
+               if (object->n_ops == 0)
+                       fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED);
+
+               spin_unlock(&object->lock);
+
+       } while (count++ < 20);
+
+       if (!list_empty(&cache->op_gc_list))
+               schedule_work(&cache->op_gc);
+
+       _leave("");
+}
+
+/*
+ * allow the slow work item processor to get a ref on an operation
+ */
+static int fscache_op_get_ref(struct slow_work *work)
+{
+       struct fscache_operation *op =
+               container_of(work, struct fscache_operation, slow_work);
+
+       atomic_inc(&op->usage);
+       return 0;
+}
+
+/*
+ * allow the slow work item processor to discard a ref on an operation
+ */
+static void fscache_op_put_ref(struct slow_work *work)
+{
+       struct fscache_operation *op =
+               container_of(work, struct fscache_operation, slow_work);
+
+       fscache_put_operation(op);
+}
+
+/*
+ * execute an operation using the slow thread pool to provide processing context
+ * - the caller holds a ref to this object, so we don't need to hold one
+ */
+static void fscache_op_execute(struct slow_work *work)
+{
+       struct fscache_operation *op =
+               container_of(work, struct fscache_operation, slow_work);
+       unsigned long start;
+
+       _enter("{OBJ%x OP%x,%d}",
+              op->object->debug_id, op->debug_id, atomic_read(&op->usage));
+
+       ASSERT(op->processor != NULL);
+       start = jiffies;
+       op->processor(op);
+       fscache_hist(fscache_ops_histogram, start);
+
+       _leave("");
+}
+
+const struct slow_work_ops fscache_op_slow_work_ops = {
+       .get_ref        = fscache_op_get_ref,
+       .put_ref        = fscache_op_put_ref,
+       .execute        = fscache_op_execute,
+};
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
new file mode 100644 (file)
index 0000000..2568e0e
--- /dev/null
@@ -0,0 +1,816 @@
+/* Cache page management and data I/O routines
+ *
+ * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#define FSCACHE_DEBUG_LEVEL PAGE
+#include <linux/module.h>
+#include <linux/fscache-cache.h>
+#include <linux/buffer_head.h>
+#include <linux/pagevec.h>
+#include "internal.h"
+
+/*
+ * check to see if a page is being written to the cache
+ */
+bool __fscache_check_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+       void *val;
+
+       rcu_read_lock();
+       val = radix_tree_lookup(&cookie->stores, page->index);
+       rcu_read_unlock();
+
+       return val != NULL;
+}
+EXPORT_SYMBOL(__fscache_check_page_write);
+
+/*
+ * wait for a page to finish being written to the cache
+ */
+void __fscache_wait_on_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+       wait_queue_head_t *wq = bit_waitqueue(&cookie->flags, 0);
+
+       wait_event(*wq, !__fscache_check_page_write(cookie, page));
+}
+EXPORT_SYMBOL(__fscache_wait_on_page_write);
+
+/*
+ * note that a page has finished being written to the cache
+ */
+static void fscache_end_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+       struct page *xpage;
+
+       spin_lock(&cookie->lock);
+       xpage = radix_tree_delete(&cookie->stores, page->index);
+       spin_unlock(&cookie->lock);
+       ASSERT(xpage != NULL);
+
+       wake_up_bit(&cookie->flags, 0);
+}
+
+/*
+ * actually apply the changed attributes to a cache object
+ */
+static void fscache_attr_changed_op(struct fscache_operation *op)
+{
+       struct fscache_object *object = op->object;
+
+       _enter("{OBJ%x OP%x}", object->debug_id, op->debug_id);
+
+       fscache_stat(&fscache_n_attr_changed_calls);
+
+       if (fscache_object_is_active(object) &&
+           object->cache->ops->attr_changed(object) < 0)
+               fscache_abort_object(object);
+
+       _leave("");
+}
+
+/*
+ * notification that the attributes on an object have changed
+ */
+int __fscache_attr_changed(struct fscache_cookie *cookie)
+{
+       struct fscache_operation *op;
+       struct fscache_object *object;
+
+       _enter("%p", cookie);
+
+       ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
+
+       fscache_stat(&fscache_n_attr_changed);
+
+       op = kzalloc(sizeof(*op), GFP_KERNEL);
+       if (!op) {
+               fscache_stat(&fscache_n_attr_changed_nomem);
+               _leave(" = -ENOMEM");
+               return -ENOMEM;
+       }
+
+       fscache_operation_init(op, NULL);
+       fscache_operation_init_slow(op, fscache_attr_changed_op);
+       op->flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_EXCLUSIVE);
+
+       spin_lock(&cookie->lock);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs;
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+
+       if (fscache_submit_exclusive_op(object, op) < 0)
+               goto nobufs;
+       spin_unlock(&cookie->lock);
+       fscache_stat(&fscache_n_attr_changed_ok);
+       fscache_put_operation(op);
+       _leave(" = 0");
+       return 0;
+
+nobufs:
+       spin_unlock(&cookie->lock);
+       kfree(op);
+       fscache_stat(&fscache_n_attr_changed_nobufs);
+       _leave(" = %d", -ENOBUFS);
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(__fscache_attr_changed);
+
+/*
+ * handle secondary execution given to a retrieval op on behalf of the
+ * cache
+ */
+static void fscache_retrieval_work(struct work_struct *work)
+{
+       struct fscache_retrieval *op =
+               container_of(work, struct fscache_retrieval, op.fast_work);
+       unsigned long start;
+
+       _enter("{OP%x}", op->op.debug_id);
+
+       start = jiffies;
+       op->op.processor(&op->op);
+       fscache_hist(fscache_ops_histogram, start);
+       fscache_put_operation(&op->op);
+}
+
+/*
+ * release a retrieval op reference
+ */
+static void fscache_release_retrieval_op(struct fscache_operation *_op)
+{
+       struct fscache_retrieval *op =
+               container_of(_op, struct fscache_retrieval, op);
+
+       _enter("{OP%x}", op->op.debug_id);
+
+       fscache_hist(fscache_retrieval_histogram, op->start_time);
+       if (op->context)
+               fscache_put_context(op->op.object->cookie, op->context);
+
+       _leave("");
+}
+
+/*
+ * allocate a retrieval op
+ */
+static struct fscache_retrieval *fscache_alloc_retrieval(
+       struct address_space *mapping,
+       fscache_rw_complete_t end_io_func,
+       void *context)
+{
+       struct fscache_retrieval *op;
+
+       /* allocate a retrieval operation and attempt to submit it */
+       op = kzalloc(sizeof(*op), GFP_NOIO);
+       if (!op) {
+               fscache_stat(&fscache_n_retrievals_nomem);
+               return NULL;
+       }
+
+       fscache_operation_init(&op->op, fscache_release_retrieval_op);
+       op->op.flags    = FSCACHE_OP_MYTHREAD | (1 << FSCACHE_OP_WAITING);
+       op->mapping     = mapping;
+       op->end_io_func = end_io_func;
+       op->context     = context;
+       op->start_time  = jiffies;
+       INIT_WORK(&op->op.fast_work, fscache_retrieval_work);
+       INIT_LIST_HEAD(&op->to_do);
+       return op;
+}
+
+/*
+ * wait for a deferred lookup to complete
+ */
+static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie)
+{
+       unsigned long jif;
+
+       _enter("");
+
+       if (!test_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags)) {
+               _leave(" = 0 [imm]");
+               return 0;
+       }
+
+       fscache_stat(&fscache_n_retrievals_wait);
+
+       jif = jiffies;
+       if (wait_on_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP,
+                       fscache_wait_bit_interruptible,
+                       TASK_INTERRUPTIBLE) != 0) {
+               fscache_stat(&fscache_n_retrievals_intr);
+               _leave(" = -ERESTARTSYS");
+               return -ERESTARTSYS;
+       }
+
+       ASSERT(!test_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags));
+
+       smp_rmb();
+       fscache_hist(fscache_retrieval_delay_histogram, jif);
+       _leave(" = 0 [dly]");
+       return 0;
+}
+
+/*
+ * read a page from the cache or allocate a block in which to store it
+ * - we return:
+ *   -ENOMEM   - out of memory, nothing done
+ *   -ERESTARTSYS - interrupted
+ *   -ENOBUFS  - no backing object available in which to cache the block
+ *   -ENODATA  - no data available in the backing object for this block
+ *   0         - dispatched a read - it'll call end_io_func() when finished
+ */
+int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
+                                struct page *page,
+                                fscache_rw_complete_t end_io_func,
+                                void *context,
+                                gfp_t gfp)
+{
+       struct fscache_retrieval *op;
+       struct fscache_object *object;
+       int ret;
+
+       _enter("%p,%p,,,", cookie, page);
+
+       fscache_stat(&fscache_n_retrievals);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs;
+
+       ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
+       ASSERTCMP(page, !=, NULL);
+
+       if (fscache_wait_for_deferred_lookup(cookie) < 0)
+               return -ERESTARTSYS;
+
+       op = fscache_alloc_retrieval(page->mapping, end_io_func, context);
+       if (!op) {
+               _leave(" = -ENOMEM");
+               return -ENOMEM;
+       }
+
+       spin_lock(&cookie->lock);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs_unlock;
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+
+       ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP);
+
+       if (fscache_submit_op(object, &op->op) < 0)
+               goto nobufs_unlock;
+       spin_unlock(&cookie->lock);
+
+       fscache_stat(&fscache_n_retrieval_ops);
+
+       /* pin the netfs read context in case we need to do the actual netfs
+        * read because we've encountered a cache read failure */
+       fscache_get_context(object->cookie, op->context);
+
+       /* we wait for the operation to become active, and then process it
+        * *here*, in this thread, and not in the thread pool */
+       if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) {
+               _debug(">>> WT");
+               fscache_stat(&fscache_n_retrieval_op_waits);
+               wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
+                           fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+               _debug("<<< GO");
+       }
+
+       /* ask the cache to honour the operation */
+       if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) {
+               ret = object->cache->ops->allocate_page(op, page, gfp);
+               if (ret == 0)
+                       ret = -ENODATA;
+       } else {
+               ret = object->cache->ops->read_or_alloc_page(op, page, gfp);
+       }
+
+       if (ret == -ENOMEM)
+               fscache_stat(&fscache_n_retrievals_nomem);
+       else if (ret == -ERESTARTSYS)
+               fscache_stat(&fscache_n_retrievals_intr);
+       else if (ret == -ENODATA)
+               fscache_stat(&fscache_n_retrievals_nodata);
+       else if (ret < 0)
+               fscache_stat(&fscache_n_retrievals_nobufs);
+       else
+               fscache_stat(&fscache_n_retrievals_ok);
+
+       fscache_put_retrieval(op);
+       _leave(" = %d", ret);
+       return ret;
+
+nobufs_unlock:
+       spin_unlock(&cookie->lock);
+       kfree(op);
+nobufs:
+       fscache_stat(&fscache_n_retrievals_nobufs);
+       _leave(" = -ENOBUFS");
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(__fscache_read_or_alloc_page);
+
+/*
+ * read a list of page from the cache or allocate a block in which to store
+ * them
+ * - we return:
+ *   -ENOMEM   - out of memory, some pages may be being read
+ *   -ERESTARTSYS - interrupted, some pages may be being read
+ *   -ENOBUFS  - no backing object or space available in which to cache any
+ *                pages not being read
+ *   -ENODATA  - no data available in the backing object for some or all of
+ *                the pages
+ *   0         - dispatched a read on all pages
+ *
+ * end_io_func() will be called for each page read from the cache as it is
+ * finishes being read
+ *
+ * any pages for which a read is dispatched will be removed from pages and
+ * nr_pages
+ */
+int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
+                                 struct address_space *mapping,
+                                 struct list_head *pages,
+                                 unsigned *nr_pages,
+                                 fscache_rw_complete_t end_io_func,
+                                 void *context,
+                                 gfp_t gfp)
+{
+       fscache_pages_retrieval_func_t func;
+       struct fscache_retrieval *op;
+       struct fscache_object *object;
+       int ret;
+
+       _enter("%p,,%d,,,", cookie, *nr_pages);
+
+       fscache_stat(&fscache_n_retrievals);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs;
+
+       ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
+       ASSERTCMP(*nr_pages, >, 0);
+       ASSERT(!list_empty(pages));
+
+       if (fscache_wait_for_deferred_lookup(cookie) < 0)
+               return -ERESTARTSYS;
+
+       op = fscache_alloc_retrieval(mapping, end_io_func, context);
+       if (!op)
+               return -ENOMEM;
+
+       spin_lock(&cookie->lock);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs_unlock;
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+
+       if (fscache_submit_op(object, &op->op) < 0)
+               goto nobufs_unlock;
+       spin_unlock(&cookie->lock);
+
+       fscache_stat(&fscache_n_retrieval_ops);
+
+       /* pin the netfs read context in case we need to do the actual netfs
+        * read because we've encountered a cache read failure */
+       fscache_get_context(object->cookie, op->context);
+
+       /* we wait for the operation to become active, and then process it
+        * *here*, in this thread, and not in the thread pool */
+       if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) {
+               _debug(">>> WT");
+               fscache_stat(&fscache_n_retrieval_op_waits);
+               wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
+                           fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+               _debug("<<< GO");
+       }
+
+       /* ask the cache to honour the operation */
+       if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags))
+               func = object->cache->ops->allocate_pages;
+       else
+               func = object->cache->ops->read_or_alloc_pages;
+       ret = func(op, pages, nr_pages, gfp);
+
+       if (ret == -ENOMEM)
+               fscache_stat(&fscache_n_retrievals_nomem);
+       else if (ret == -ERESTARTSYS)
+               fscache_stat(&fscache_n_retrievals_intr);
+       else if (ret == -ENODATA)
+               fscache_stat(&fscache_n_retrievals_nodata);
+       else if (ret < 0)
+               fscache_stat(&fscache_n_retrievals_nobufs);
+       else
+               fscache_stat(&fscache_n_retrievals_ok);
+
+       fscache_put_retrieval(op);
+       _leave(" = %d", ret);
+       return ret;
+
+nobufs_unlock:
+       spin_unlock(&cookie->lock);
+       kfree(op);
+nobufs:
+       fscache_stat(&fscache_n_retrievals_nobufs);
+       _leave(" = -ENOBUFS");
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(__fscache_read_or_alloc_pages);
+
+/*
+ * allocate a block in the cache on which to store a page
+ * - we return:
+ *   -ENOMEM   - out of memory, nothing done
+ *   -ERESTARTSYS - interrupted
+ *   -ENOBUFS  - no backing object available in which to cache the block
+ *   0         - block allocated
+ */
+int __fscache_alloc_page(struct fscache_cookie *cookie,
+                        struct page *page,
+                        gfp_t gfp)
+{
+       struct fscache_retrieval *op;
+       struct fscache_object *object;
+       int ret;
+
+       _enter("%p,%p,,,", cookie, page);
+
+       fscache_stat(&fscache_n_allocs);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs;
+
+       ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
+       ASSERTCMP(page, !=, NULL);
+
+       if (fscache_wait_for_deferred_lookup(cookie) < 0)
+               return -ERESTARTSYS;
+
+       op = fscache_alloc_retrieval(page->mapping, NULL, NULL);
+       if (!op)
+               return -ENOMEM;
+
+       spin_lock(&cookie->lock);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs_unlock;
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+
+       if (fscache_submit_op(object, &op->op) < 0)
+               goto nobufs_unlock;
+       spin_unlock(&cookie->lock);
+
+       fscache_stat(&fscache_n_alloc_ops);
+
+       if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) {
+               _debug(">>> WT");
+               fscache_stat(&fscache_n_alloc_op_waits);
+               wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
+                           fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+               _debug("<<< GO");
+       }
+
+       /* ask the cache to honour the operation */
+       ret = object->cache->ops->allocate_page(op, page, gfp);
+
+       if (ret < 0)
+               fscache_stat(&fscache_n_allocs_nobufs);
+       else
+               fscache_stat(&fscache_n_allocs_ok);
+
+       fscache_put_retrieval(op);
+       _leave(" = %d", ret);
+       return ret;
+
+nobufs_unlock:
+       spin_unlock(&cookie->lock);
+       kfree(op);
+nobufs:
+       fscache_stat(&fscache_n_allocs_nobufs);
+       _leave(" = -ENOBUFS");
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(__fscache_alloc_page);
+
+/*
+ * release a write op reference
+ */
+static void fscache_release_write_op(struct fscache_operation *_op)
+{
+       _enter("{OP%x}", _op->debug_id);
+}
+
+/*
+ * perform the background storage of a page into the cache
+ */
+static void fscache_write_op(struct fscache_operation *_op)
+{
+       struct fscache_storage *op =
+               container_of(_op, struct fscache_storage, op);
+       struct fscache_object *object = op->op.object;
+       struct fscache_cookie *cookie = object->cookie;
+       struct page *page;
+       unsigned n;
+       void *results[1];
+       int ret;
+
+       _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
+
+       spin_lock(&cookie->lock);
+       spin_lock(&object->lock);
+
+       if (!fscache_object_is_active(object)) {
+               spin_unlock(&object->lock);
+               spin_unlock(&cookie->lock);
+               _leave("");
+               return;
+       }
+
+       fscache_stat(&fscache_n_store_calls);
+
+       /* find a page to store */
+       page = NULL;
+       n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, 1,
+                                      FSCACHE_COOKIE_PENDING_TAG);
+       if (n != 1)
+               goto superseded;
+       page = results[0];
+       _debug("gang %d [%lx]", n, page->index);
+       if (page->index > op->store_limit)
+               goto superseded;
+
+       radix_tree_tag_clear(&cookie->stores, page->index,
+                            FSCACHE_COOKIE_PENDING_TAG);
+
+       spin_unlock(&object->lock);
+       spin_unlock(&cookie->lock);
+
+       if (page) {
+               ret = object->cache->ops->write_page(op, page);
+               fscache_end_page_write(cookie, page);
+               page_cache_release(page);
+               if (ret < 0)
+                       fscache_abort_object(object);
+               else
+                       fscache_enqueue_operation(&op->op);
+       }
+
+       _leave("");
+       return;
+
+superseded:
+       /* this writer is going away and there aren't any more things to
+        * write */
+       _debug("cease");
+       clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
+       spin_unlock(&object->lock);
+       spin_unlock(&cookie->lock);
+       _leave("");
+}
+
+/*
+ * request a page be stored in the cache
+ * - returns:
+ *   -ENOMEM   - out of memory, nothing done
+ *   -ENOBUFS  - no backing object available in which to cache the page
+ *   0         - dispatched a write - it'll call end_io_func() when finished
+ *
+ * if the cookie still has a backing object at this point, that object can be
+ * in one of a few states with respect to storage processing:
+ *
+ *  (1) negative lookup, object not yet created (FSCACHE_COOKIE_CREATING is
+ *      set)
+ *
+ *     (a) no writes yet (set FSCACHE_COOKIE_PENDING_FILL and queue deferred
+ *         fill op)
+ *
+ *     (b) writes deferred till post-creation (mark page for writing and
+ *         return immediately)
+ *
+ *  (2) negative lookup, object created, initial fill being made from netfs
+ *      (FSCACHE_COOKIE_INITIAL_FILL is set)
+ *
+ *     (a) fill point not yet reached this page (mark page for writing and
+ *          return)
+ *
+ *     (b) fill point passed this page (queue op to store this page)
+ *
+ *  (3) object extant (queue op to store this page)
+ *
+ * any other state is invalid
+ */
+int __fscache_write_page(struct fscache_cookie *cookie,
+                        struct page *page,
+                        gfp_t gfp)
+{
+       struct fscache_storage *op;
+       struct fscache_object *object;
+       int ret;
+
+       _enter("%p,%x,", cookie, (u32) page->flags);
+
+       ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
+       ASSERT(PageFsCache(page));
+
+       fscache_stat(&fscache_n_stores);
+
+       op = kzalloc(sizeof(*op), GFP_NOIO);
+       if (!op)
+               goto nomem;
+
+       fscache_operation_init(&op->op, fscache_release_write_op);
+       fscache_operation_init_slow(&op->op, fscache_write_op);
+       op->op.flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_WAITING);
+
+       ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
+       if (ret < 0)
+               goto nomem_free;
+
+       ret = -ENOBUFS;
+       spin_lock(&cookie->lock);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto nobufs;
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+       if (test_bit(FSCACHE_IOERROR, &object->cache->flags))
+               goto nobufs;
+
+       /* add the page to the pending-storage radix tree on the backing
+        * object */
+       spin_lock(&object->lock);
+
+       _debug("store limit %llx", (unsigned long long) object->store_limit);
+
+       ret = radix_tree_insert(&cookie->stores, page->index, page);
+       if (ret < 0) {
+               if (ret == -EEXIST)
+                       goto already_queued;
+               _debug("insert failed %d", ret);
+               goto nobufs_unlock_obj;
+       }
+
+       radix_tree_tag_set(&cookie->stores, page->index,
+                          FSCACHE_COOKIE_PENDING_TAG);
+       page_cache_get(page);
+
+       /* we only want one writer at a time, but we do need to queue new
+        * writers after exclusive ops */
+       if (test_and_set_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags))
+               goto already_pending;
+
+       spin_unlock(&object->lock);
+
+       op->op.debug_id = atomic_inc_return(&fscache_op_debug_id);
+       op->store_limit = object->store_limit;
+
+       if (fscache_submit_op(object, &op->op) < 0)
+               goto submit_failed;
+
+       spin_unlock(&cookie->lock);
+       radix_tree_preload_end();
+       fscache_stat(&fscache_n_store_ops);
+       fscache_stat(&fscache_n_stores_ok);
+
+       /* the slow work queue now carries its own ref on the object */
+       fscache_put_operation(&op->op);
+       _leave(" = 0");
+       return 0;
+
+already_queued:
+       fscache_stat(&fscache_n_stores_again);
+already_pending:
+       spin_unlock(&object->lock);
+       spin_unlock(&cookie->lock);
+       radix_tree_preload_end();
+       kfree(op);
+       fscache_stat(&fscache_n_stores_ok);
+       _leave(" = 0");
+       return 0;
+
+submit_failed:
+       radix_tree_delete(&cookie->stores, page->index);
+       page_cache_release(page);
+       ret = -ENOBUFS;
+       goto nobufs;
+
+nobufs_unlock_obj:
+       spin_unlock(&object->lock);
+nobufs:
+       spin_unlock(&cookie->lock);
+       radix_tree_preload_end();
+       kfree(op);
+       fscache_stat(&fscache_n_stores_nobufs);
+       _leave(" = -ENOBUFS");
+       return -ENOBUFS;
+
+nomem_free:
+       kfree(op);
+nomem:
+       fscache_stat(&fscache_n_stores_oom);
+       _leave(" = -ENOMEM");
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(__fscache_write_page);
+
+/*
+ * remove a page from the cache
+ */
+void __fscache_uncache_page(struct fscache_cookie *cookie, struct page *page)
+{
+       struct fscache_object *object;
+
+       _enter(",%p", page);
+
+       ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
+       ASSERTCMP(page, !=, NULL);
+
+       fscache_stat(&fscache_n_uncaches);
+
+       /* cache withdrawal may beat us to it */
+       if (!PageFsCache(page))
+               goto done;
+
+       /* get the object */
+       spin_lock(&cookie->lock);
+
+       if (hlist_empty(&cookie->backing_objects)) {
+               ClearPageFsCache(page);
+               goto done_unlock;
+       }
+
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+
+       /* there might now be stuff on disk we could read */
+       clear_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
+
+       /* only invoke the cache backend if we managed to mark the page
+        * uncached here; this deals with synchronisation vs withdrawal */
+       if (TestClearPageFsCache(page) &&
+           object->cache->ops->uncache_page) {
+               /* the cache backend releases the cookie lock */
+               object->cache->ops->uncache_page(object, page);
+               goto done;
+       }
+
+done_unlock:
+       spin_unlock(&cookie->lock);
+done:
+       _leave("");
+}
+EXPORT_SYMBOL(__fscache_uncache_page);
+
+/**
+ * fscache_mark_pages_cached - Mark pages as being cached
+ * @op: The retrieval op pages are being marked for
+ * @pagevec: The pages to be marked
+ *
+ * Mark a bunch of netfs pages as being cached.  After this is called,
+ * the netfs must call fscache_uncache_page() to remove the mark.
+ */
+void fscache_mark_pages_cached(struct fscache_retrieval *op,
+                              struct pagevec *pagevec)
+{
+       struct fscache_cookie *cookie = op->op.object->cookie;
+       unsigned long loop;
+
+#ifdef CONFIG_FSCACHE_STATS
+       atomic_add(pagevec->nr, &fscache_n_marks);
+#endif
+
+       for (loop = 0; loop < pagevec->nr; loop++) {
+               struct page *page = pagevec->pages[loop];
+
+               _debug("- mark %p{%lx}", page, page->index);
+               if (TestSetPageFsCache(page)) {
+                       static bool once_only;
+                       if (!once_only) {
+                               once_only = true;
+                               printk(KERN_WARNING "FS-Cache:"
+                                      " Cookie type %s marked page %lx"
+                                      " multiple times\n",
+                                      cookie->def->name, page->index);
+                       }
+               }
+       }
+
+       if (cookie->def->mark_pages_cached)
+               cookie->def->mark_pages_cached(cookie->netfs_data,
+                                              op->mapping, pagevec);
+       pagevec_reinit(pagevec);
+}
+EXPORT_SYMBOL(fscache_mark_pages_cached);
diff --git a/fs/fscache/proc.c b/fs/fscache/proc.c
new file mode 100644 (file)
index 0000000..beeab44
--- /dev/null
@@ -0,0 +1,68 @@
+/* FS-Cache statistics viewing interface
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#define FSCACHE_DEBUG_LEVEL OPERATION
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include "internal.h"
+
+/*
+ * initialise the /proc/fs/fscache/ directory
+ */
+int __init fscache_proc_init(void)
+{
+       _enter("");
+
+       if (!proc_mkdir("fs/fscache", NULL))
+               goto error_dir;
+
+#ifdef CONFIG_FSCACHE_STATS
+       if (!proc_create("fs/fscache/stats", S_IFREG | 0444, NULL,
+                        &fscache_stats_fops))
+               goto error_stats;
+#endif
+
+#ifdef CONFIG_FSCACHE_HISTOGRAM
+       if (!proc_create("fs/fscache/histogram", S_IFREG | 0444, NULL,
+                        &fscache_histogram_fops))
+               goto error_histogram;
+#endif
+
+       _leave(" = 0");
+       return 0;
+
+#ifdef CONFIG_FSCACHE_HISTOGRAM
+error_histogram:
+#endif
+#ifdef CONFIG_FSCACHE_STATS
+       remove_proc_entry("fs/fscache/stats", NULL);
+error_stats:
+#endif
+       remove_proc_entry("fs/fscache", NULL);
+error_dir:
+       _leave(" = -ENOMEM");
+       return -ENOMEM;
+}
+
+/*
+ * clean up the /proc/fs/fscache/ directory
+ */
+void fscache_proc_cleanup(void)
+{
+#ifdef CONFIG_FSCACHE_HISTOGRAM
+       remove_proc_entry("fs/fscache/histogram", NULL);
+#endif
+#ifdef CONFIG_FSCACHE_STATS
+       remove_proc_entry("fs/fscache/stats", NULL);
+#endif
+       remove_proc_entry("fs/fscache", NULL);
+}
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c
new file mode 100644 (file)
index 0000000..65deb99
--- /dev/null
@@ -0,0 +1,212 @@
+/* FS-Cache statistics
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#define FSCACHE_DEBUG_LEVEL THREAD
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include "internal.h"
+
+/*
+ * operation counters
+ */
+atomic_t fscache_n_op_pend;
+atomic_t fscache_n_op_run;
+atomic_t fscache_n_op_enqueue;
+atomic_t fscache_n_op_requeue;
+atomic_t fscache_n_op_deferred_release;
+atomic_t fscache_n_op_release;
+atomic_t fscache_n_op_gc;
+
+atomic_t fscache_n_attr_changed;
+atomic_t fscache_n_attr_changed_ok;
+atomic_t fscache_n_attr_changed_nobufs;
+atomic_t fscache_n_attr_changed_nomem;
+atomic_t fscache_n_attr_changed_calls;
+
+atomic_t fscache_n_allocs;
+atomic_t fscache_n_allocs_ok;
+atomic_t fscache_n_allocs_wait;
+atomic_t fscache_n_allocs_nobufs;
+atomic_t fscache_n_alloc_ops;
+atomic_t fscache_n_alloc_op_waits;
+
+atomic_t fscache_n_retrievals;
+atomic_t fscache_n_retrievals_ok;
+atomic_t fscache_n_retrievals_wait;
+atomic_t fscache_n_retrievals_nodata;
+atomic_t fscache_n_retrievals_nobufs;
+atomic_t fscache_n_retrievals_intr;
+atomic_t fscache_n_retrievals_nomem;
+atomic_t fscache_n_retrieval_ops;
+atomic_t fscache_n_retrieval_op_waits;
+
+atomic_t fscache_n_stores;
+atomic_t fscache_n_stores_ok;
+atomic_t fscache_n_stores_again;
+atomic_t fscache_n_stores_nobufs;
+atomic_t fscache_n_stores_oom;
+atomic_t fscache_n_store_ops;
+atomic_t fscache_n_store_calls;
+
+atomic_t fscache_n_marks;
+atomic_t fscache_n_uncaches;
+
+atomic_t fscache_n_acquires;
+atomic_t fscache_n_acquires_null;
+atomic_t fscache_n_acquires_no_cache;
+atomic_t fscache_n_acquires_ok;
+atomic_t fscache_n_acquires_nobufs;
+atomic_t fscache_n_acquires_oom;
+
+atomic_t fscache_n_updates;
+atomic_t fscache_n_updates_null;
+atomic_t fscache_n_updates_run;
+
+atomic_t fscache_n_relinquishes;
+atomic_t fscache_n_relinquishes_null;
+atomic_t fscache_n_relinquishes_waitcrt;
+
+atomic_t fscache_n_cookie_index;
+atomic_t fscache_n_cookie_data;
+atomic_t fscache_n_cookie_special;
+
+atomic_t fscache_n_object_alloc;
+atomic_t fscache_n_object_no_alloc;
+atomic_t fscache_n_object_lookups;
+atomic_t fscache_n_object_lookups_negative;
+atomic_t fscache_n_object_lookups_positive;
+atomic_t fscache_n_object_created;
+atomic_t fscache_n_object_avail;
+atomic_t fscache_n_object_dead;
+
+atomic_t fscache_n_checkaux_none;
+atomic_t fscache_n_checkaux_okay;
+atomic_t fscache_n_checkaux_update;
+atomic_t fscache_n_checkaux_obsolete;
+
+/*
+ * display the general statistics
+ */
+static int fscache_stats_show(struct seq_file *m, void *v)
+{
+       seq_puts(m, "FS-Cache statistics\n");
+
+       seq_printf(m, "Cookies: idx=%u dat=%u spc=%u\n",
+                  atomic_read(&fscache_n_cookie_index),
+                  atomic_read(&fscache_n_cookie_data),
+                  atomic_read(&fscache_n_cookie_special));
+
+       seq_printf(m, "Objects: alc=%u nal=%u avl=%u ded=%u\n",
+                  atomic_read(&fscache_n_object_alloc),
+                  atomic_read(&fscache_n_object_no_alloc),
+                  atomic_read(&fscache_n_object_avail),
+                  atomic_read(&fscache_n_object_dead));
+       seq_printf(m, "ChkAux : non=%u ok=%u upd=%u obs=%u\n",
+                  atomic_read(&fscache_n_checkaux_none),
+                  atomic_read(&fscache_n_checkaux_okay),
+                  atomic_read(&fscache_n_checkaux_update),
+                  atomic_read(&fscache_n_checkaux_obsolete));
+
+       seq_printf(m, "Pages  : mrk=%u unc=%u\n",
+                  atomic_read(&fscache_n_marks),
+                  atomic_read(&fscache_n_uncaches));
+
+       seq_printf(m, "Acquire: n=%u nul=%u noc=%u ok=%u nbf=%u"
+                  " oom=%u\n",
+                  atomic_read(&fscache_n_acquires),
+                  atomic_read(&fscache_n_acquires_null),
+                  atomic_read(&fscache_n_acquires_no_cache),
+                  atomic_read(&fscache_n_acquires_ok),
+                  atomic_read(&fscache_n_acquires_nobufs),
+                  atomic_read(&fscache_n_acquires_oom));
+
+       seq_printf(m, "Lookups: n=%u neg=%u pos=%u crt=%u\n",
+                  atomic_read(&fscache_n_object_lookups),
+                  atomic_read(&fscache_n_object_lookups_negative),
+                  atomic_read(&fscache_n_object_lookups_positive),
+                  atomic_read(&fscache_n_object_created));
+
+       seq_printf(m, "Updates: n=%u nul=%u run=%u\n",
+                  atomic_read(&fscache_n_updates),
+                  atomic_read(&fscache_n_updates_null),
+                  atomic_read(&fscache_n_updates_run));
+
+       seq_printf(m, "Relinqs: n=%u nul=%u wcr=%u\n",
+                  atomic_read(&fscache_n_relinquishes),
+                  atomic_read(&fscache_n_relinquishes_null),
+                  atomic_read(&fscache_n_relinquishes_waitcrt));
+
+       seq_printf(m, "AttrChg: n=%u ok=%u nbf=%u oom=%u run=%u\n",
+                  atomic_read(&fscache_n_attr_changed),
+                  atomic_read(&fscache_n_attr_changed_ok),
+                  atomic_read(&fscache_n_attr_changed_nobufs),
+                  atomic_read(&fscache_n_attr_changed_nomem),
+                  atomic_read(&fscache_n_attr_changed_calls));
+
+       seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u\n",
+                  atomic_read(&fscache_n_allocs),
+                  atomic_read(&fscache_n_allocs_ok),
+                  atomic_read(&fscache_n_allocs_wait),
+                  atomic_read(&fscache_n_allocs_nobufs));
+       seq_printf(m, "Allocs : ops=%u owt=%u\n",
+                  atomic_read(&fscache_n_alloc_ops),
+                  atomic_read(&fscache_n_alloc_op_waits));
+
+       seq_printf(m, "Retrvls: n=%u ok=%u wt=%u nod=%u nbf=%u"
+                  " int=%u oom=%u\n",
+                  atomic_read(&fscache_n_retrievals),
+                  atomic_read(&fscache_n_retrievals_ok),
+                  atomic_read(&fscache_n_retrievals_wait),
+                  atomic_read(&fscache_n_retrievals_nodata),
+                  atomic_read(&fscache_n_retrievals_nobufs),
+                  atomic_read(&fscache_n_retrievals_intr),
+                  atomic_read(&fscache_n_retrievals_nomem));
+       seq_printf(m, "Retrvls: ops=%u owt=%u\n",
+                  atomic_read(&fscache_n_retrieval_ops),
+                  atomic_read(&fscache_n_retrieval_op_waits));
+
+       seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n",
+                  atomic_read(&fscache_n_stores),
+                  atomic_read(&fscache_n_stores_ok),
+                  atomic_read(&fscache_n_stores_again),
+                  atomic_read(&fscache_n_stores_nobufs),
+                  atomic_read(&fscache_n_stores_oom));
+       seq_printf(m, "Stores : ops=%u run=%u\n",
+                  atomic_read(&fscache_n_store_ops),
+                  atomic_read(&fscache_n_store_calls));
+
+       seq_printf(m, "Ops    : pend=%u run=%u enq=%u\n",
+                  atomic_read(&fscache_n_op_pend),
+                  atomic_read(&fscache_n_op_run),
+                  atomic_read(&fscache_n_op_enqueue));
+       seq_printf(m, "Ops    : dfr=%u rel=%u gc=%u\n",
+                  atomic_read(&fscache_n_op_deferred_release),
+                  atomic_read(&fscache_n_op_release),
+                  atomic_read(&fscache_n_op_gc));
+       return 0;
+}
+
+/*
+ * open "/proc/fs/fscache/stats" allowing provision of a statistical summary
+ */
+static int fscache_stats_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, fscache_stats_show, NULL);
+}
+
+const struct file_operations fscache_stats_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fscache_stats_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
index 06da05261e04a8a314881cee7e9e5988bc09c66a..8b8eebc5614bb1e1f6dcba5ecd0ad1966d831f07 100644 (file)
@@ -1032,6 +1032,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
                fuse_put_request(fc, req);
                return -ENOMEM;
        }
+       req->out.argpages = 1;
        req->num_pages = 1;
        req->pages[0] = page;
        fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
index 821d10f719bd06f6c49f855ace9a5d9a3abe3b41..2b25133524a3d71ce5e80dac7b2f904e9f1599a9 100644 (file)
@@ -386,7 +386,6 @@ void fuse_read_fill(struct fuse_req *req, struct file *file,
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(struct fuse_read_in);
        req->in.args[0].value = inarg;
-       req->out.argpages = 1;
        req->out.argvar = 1;
        req->out.numargs = 1;
        req->out.args[0].size = count;
@@ -453,6 +452,7 @@ static int fuse_readpage(struct file *file, struct page *page)
        attr_ver = fuse_get_attr_version(fc);
 
        req->out.page_zeroing = 1;
+       req->out.argpages = 1;
        req->num_pages = 1;
        req->pages[0] = page;
        num_read = fuse_send_read(req, file, inode, pos, count, NULL);
@@ -510,6 +510,8 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
        struct fuse_conn *fc = get_fuse_conn(inode);
        loff_t pos = page_offset(req->pages[0]);
        size_t count = req->num_pages << PAGE_CACHE_SHIFT;
+
+       req->out.argpages = 1;
        req->out.page_zeroing = 1;
        fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
        req->misc.read.attr_ver = fuse_get_attr_version(fc);
@@ -621,7 +623,6 @@ static void fuse_write_fill(struct fuse_req *req, struct file *file,
        inarg->flags = file ? file->f_flags : 0;
        req->in.h.opcode = FUSE_WRITE;
        req->in.h.nodeid = get_node_id(inode);
-       req->in.argpages = 1;
        req->in.numargs = 2;
        if (fc->minor < 9)
                req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE;
@@ -695,6 +696,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode,
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       req->in.argpages = 1;
        req->num_pages = 1;
        req->pages[0] = page;
        req->page_offset = offset;
@@ -771,6 +773,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
        size_t count = 0;
        int err;
 
+       req->in.argpages = 1;
        req->page_offset = offset;
 
        do {
@@ -935,21 +938,28 @@ static void fuse_release_user_pages(struct fuse_req *req, int write)
 }
 
 static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
-                              unsigned nbytes, int write)
+                              unsigned *nbytesp, int write)
 {
+       unsigned nbytes = *nbytesp;
        unsigned long user_addr = (unsigned long) buf;
        unsigned offset = user_addr & ~PAGE_MASK;
        int npages;
 
-       /* This doesn't work with nfsd */
-       if (!current->mm)
-               return -EPERM;
+       /* Special case for kernel I/O: can copy directly into the buffer */
+       if (segment_eq(get_fs(), KERNEL_DS)) {
+               if (write)
+                       req->in.args[1].value = (void *) user_addr;
+               else
+                       req->out.args[0].value = (void *) user_addr;
+
+               return 0;
+       }
 
        nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
        npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
        npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
        down_read(&current->mm->mmap_sem);
-       npages = get_user_pages(current, current->mm, user_addr, npages, write,
+       npages = get_user_pages(current, current->mm, user_addr, npages, !write,
                                0, req->pages, NULL);
        up_read(&current->mm->mmap_sem);
        if (npages < 0)
@@ -957,6 +967,15 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
 
        req->num_pages = npages;
        req->page_offset = offset;
+
+       if (write)
+               req->in.argpages = 1;
+       else
+               req->out.argpages = 1;
+
+       nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
+       *nbytesp = min(*nbytesp, nbytes);
+
        return 0;
 }
 
@@ -979,15 +998,13 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
 
        while (count) {
                size_t nres;
-               size_t nbytes_limit = min(count, nmax);
-               size_t nbytes;
-               int err = fuse_get_user_pages(req, buf, nbytes_limit, !write);
+               size_t nbytes = min(count, nmax);
+               int err = fuse_get_user_pages(req, buf, &nbytes, write);
                if (err) {
                        res = err;
                        break;
                }
-               nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
-               nbytes = min(nbytes_limit, nbytes);
+
                if (write)
                        nres = fuse_send_write(req, file, inode, pos, nbytes,
                                               current->files);
@@ -1163,6 +1180,7 @@ static int fuse_writepage_locked(struct page *page)
        fuse_write_fill(req, NULL, ff, inode, page_offset(page), 0, 1);
 
        copy_highpage(tmp_page, page);
+       req->in.argpages = 1;
        req->num_pages = 1;
        req->pages[0] = tmp_page;
        req->page_offset = 0;
@@ -1234,8 +1252,9 @@ static void fuse_vma_close(struct vm_area_struct *vma)
  * - sync(2)
  * - try_to_free_pages() with order > PAGE_ALLOC_COSTLY_ORDER
  */
-static int fuse_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int fuse_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        /*
         * Don't use page->mapping as it may become NULL from a
         * concurrent truncate.
@@ -1273,6 +1292,15 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
+static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       /* Can't provide the coherency needed for MAP_SHARED */
+       if (vma->vm_flags & VM_MAYSHARE)
+               return -ENODEV;
+
+       return generic_file_mmap(file, vma);
+}
+
 static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
                                  struct file_lock *fl)
 {
@@ -1907,6 +1935,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
        .llseek         = fuse_file_llseek,
        .read           = fuse_direct_read,
        .write          = fuse_direct_write,
+       .mmap           = fuse_direct_mmap,
        .open           = fuse_open,
        .flush          = fuse_flush,
        .release        = fuse_release,
@@ -1916,7 +1945,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
        .unlocked_ioctl = fuse_file_ioctl,
        .compat_ioctl   = fuse_file_compat_ioctl,
        .poll           = fuse_file_poll,
-       /* no mmap and splice_read */
+       /* no splice_read */
 };
 
 static const struct address_space_operations fuse_file_aops  = {
index 995d63b2e747556c879c52be194375196995b58a..e0b53aa7bbec11037ba8f9c2bd35f33392249ecd 100644 (file)
@@ -134,7 +134,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
        mode_t mode = inode->i_mode;
        int error;
 
-       inode->i_mode = mode & ~current->fs->umask;
+       inode->i_mode = mode & ~current_umask();
        if (!S_ISLNK(inode->i_mode))
                acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
        if (acl) {
index 43764f4fa763a148f8bd0b67ed69b8755fa070be..fa881bdc3d8577647d486aa7772eecc3b72177d3 100644 (file)
@@ -215,7 +215,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
        if (error)
                return error;
        if (!acl) {
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
                if (mode != ip->i_inode.i_mode)
                        error = munge_mode(ip, mode);
                return error;
index 3b9e8de3500be1c40b2fbb798cb8dcdc8d4b51b5..70b9b8548945d92450afc5936eddf72744ecccd7 100644 (file)
@@ -337,8 +337,9 @@ static int gfs2_allocate_page_backing(struct page *page)
  * blocks allocated on disk to back that page.
  */
 
-static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -412,6 +413,8 @@ out_unlock:
        gfs2_glock_dq(&gh);
 out:
        gfs2_holder_uninit(&gh);
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        return ret;
 }
 
index c8b5acf4b0b7c086953e5526677bf30c740272d4..a36bb749926da345772e937e5c9af67388af1c05 100644 (file)
@@ -82,6 +82,7 @@ static void hfs_put_super(struct super_block *sb)
 static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = HFS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
@@ -90,6 +91,8 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = buf->f_bfree;
        buf->f_files = HFS_SB(sb)->fs_ablocks;
        buf->f_ffree = HFS_SB(sb)->free_ablocks;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = HFS_NAMELEN;
 
        return 0;
index bab7f8d1bdfa9f97ad8f3c85786daf9ecbc3c9df..3fcbb0e1f6fc09ea43f1918d4099f695937b0db1 100644 (file)
@@ -48,7 +48,7 @@ void hfsplus_fill_defaults(struct hfsplus_sb_info *opts)
 
        opts->creator = HFSPLUS_DEF_CR_TYPE;
        opts->type = HFSPLUS_DEF_CR_TYPE;
-       opts->umask = current->fs->umask;
+       opts->umask = current_umask();
        opts->uid = current_uid();
        opts->gid = current_gid();
        opts->part = -1;
index eb74531a0a8e267bec8491a18a83ed65b1a8d853..f2a64020f42e1ee855c997bb4c0a713ee0c2f4ee 100644 (file)
@@ -223,6 +223,7 @@ static void hfsplus_put_super(struct super_block *sb)
 static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = HFSPLUS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
@@ -231,6 +232,8 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = buf->f_bfree;
        buf->f_files = 0xFFFFFFFF;
        buf->f_ffree = 0xFFFFFFFF - HFSPLUS_SB(sb).next_cnid;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = HFSPLUS_MAX_STRLEN;
 
        return 0;
index 0d049b8919c42ed1c62871f26815994a5f00e254..fecf402d7b8a42ce7f7bf4b1595e71f51d5b88b5 100644 (file)
@@ -136,6 +136,7 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *s = dentry->d_sb;
        struct hpfs_sb_info *sbi = hpfs_sb(s);
+       u64 id = huge_encode_dev(s->s_bdev->bd_dev);
        lock_kernel();
 
        /*if (sbi->sb_n_free == -1) {*/
@@ -149,6 +150,8 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = sbi->sb_n_free;
        buf->f_files = sbi->sb_dirband_size / 4;
        buf->f_ffree = sbi->sb_n_free_dnodes;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = 254;
 
        unlock_kernel();
@@ -477,7 +480,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
 
        uid = current_uid();
        gid = current_gid();
-       umask = current->fs->umask;
+       umask = current_umask();
        lowercase = 0;
        conv = CONV_BINARY;
        eas = 2;
index b278f7f52024ba556d32604ac61cab01e114f39b..a5089a6dd67a741b79279ffb435d94e2162f510e 100644 (file)
@@ -280,7 +280,12 @@ static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count,
                               "errno = %d\n", err);
                        return err;
                }
-               count = hppfs_read_file(hppfs->host_fd, buf, count);
+               err = hppfs_read_file(hppfs->host_fd, buf, count);
+               if (err < 0) {
+                       printk(KERN_ERR "hppfs_read: read failed: %d\n", err);
+                       return err;
+               }
+               count = err;
                if (count > 0)
                        *ppos += count;
        }
index 9b800d97a68771b2299e978ebfdb003476e1c075..23a3c76711e08bb151f91a84cc3ea5e4f7bb20c8 100644 (file)
@@ -943,14 +943,13 @@ static struct vfsmount *hugetlbfs_vfsmount;
 
 static int can_do_hugetlb_shm(void)
 {
-       return likely(capable(CAP_IPC_LOCK) ||
-                       in_group_p(sysctl_hugetlb_shm_group) ||
-                       can_do_mlock());
+       return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group);
 }
 
 struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag)
 {
        int error = -ENOMEM;
+       int unlock_shm = 0;
        struct file *file;
        struct inode *inode;
        struct dentry *dentry, *root;
@@ -960,11 +959,14 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag)
        if (!hugetlbfs_vfsmount)
                return ERR_PTR(-ENOENT);
 
-       if (!can_do_hugetlb_shm())
-               return ERR_PTR(-EPERM);
-
-       if (!user_shm_lock(size, user))
-               return ERR_PTR(-ENOMEM);
+       if (!can_do_hugetlb_shm()) {
+               if (user_shm_lock(size, user)) {
+                       unlock_shm = 1;
+                       WARN_ONCE(1,
+                         "Using mlock ulimits for SHM_HUGETLB deprecated\n");
+               } else
+                       return ERR_PTR(-EPERM);
+       }
 
        root = hugetlbfs_vfsmount->mnt_root;
        quick_string.name = name;
@@ -1004,7 +1006,8 @@ out_inode:
 out_dentry:
        dput(dentry);
 out_shm_unlock:
-       user_shm_unlock(size, user);
+       if (unlock_shm)
+               user_shm_unlock(size, user);
        return ERR_PTR(error);
 }
 
index 53af885f173243df3a5bf0906b589edccece84db..b4dac4fb6b61fbff06d9357d9c75415bbab0a3ac 100644 (file)
@@ -11,6 +11,7 @@
 
 struct super_block;
 struct linux_binprm;
+struct path;
 
 /*
  * block_dev.c
@@ -43,7 +44,7 @@ extern void __init chrdev_init(void);
 /*
  * exec.c
  */
-extern void check_unsafe_exec(struct linux_binprm *);
+extern int check_unsafe_exec(struct linux_binprm *);
 
 /*
  * namespace.c
@@ -60,3 +61,8 @@ extern void umount_tree(struct vfsmount *, int, struct list_head *);
 extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
 
 extern void __init mnt_init(void);
+
+/*
+ * fs_struct.c
+ */
+extern void chroot_fs_refs(struct path *, struct path *);
index 13d2eddd0692d74b732f6b7b31ca2fbf5fd63014..b4cbe9603c7d9fcd479df7463781afd7328566ef 100644 (file)
@@ -923,6 +923,7 @@ out_freesbi:
 static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = ISOFS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
@@ -932,6 +933,8 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = 0;
        buf->f_files = ISOFS_SB(sb)->s_ninodes;
        buf->f_ffree = 0;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = NAME_MAX;
        return 0;
 }
index 3fbffb1ea7147ff079e5c18788231717a345f332..f8077b9c898160513b1e958a532401653ac96123 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <linux/bio.h>
 
 /*
  * Default IO end handler for temporary BJ_IO buffer_heads.
@@ -171,14 +172,15 @@ static int journal_write_commit_record(journal_t *journal,
        return (ret == -EIO);
 }
 
-static void journal_do_submit_data(struct buffer_head **wbuf, int bufs)
+static void journal_do_submit_data(struct buffer_head **wbuf, int bufs,
+                                  int write_op)
 {
        int i;
 
        for (i = 0; i < bufs; i++) {
                wbuf[i]->b_end_io = end_buffer_write_sync;
                /* We use-up our safety reference in submit_bh() */
-               submit_bh(WRITE, wbuf[i]);
+               submit_bh(write_op, wbuf[i]);
        }
 }
 
@@ -186,7 +188,8 @@ static void journal_do_submit_data(struct buffer_head **wbuf, int bufs)
  *  Submit all the data buffers to disk
  */
 static int journal_submit_data_buffers(journal_t *journal,
-                               transaction_t *commit_transaction)
+                                      transaction_t *commit_transaction,
+                                      int write_op)
 {
        struct journal_head *jh;
        struct buffer_head *bh;
@@ -225,7 +228,7 @@ write_out_data:
                                BUFFER_TRACE(bh, "needs blocking lock");
                                spin_unlock(&journal->j_list_lock);
                                /* Write out all data to prevent deadlocks */
-                               journal_do_submit_data(wbuf, bufs);
+                               journal_do_submit_data(wbuf, bufs, write_op);
                                bufs = 0;
                                lock_buffer(bh);
                                spin_lock(&journal->j_list_lock);
@@ -256,7 +259,7 @@ write_out_data:
                        jbd_unlock_bh_state(bh);
                        if (bufs == journal->j_wbufsize) {
                                spin_unlock(&journal->j_list_lock);
-                               journal_do_submit_data(wbuf, bufs);
+                               journal_do_submit_data(wbuf, bufs, write_op);
                                bufs = 0;
                                goto write_out_data;
                        }
@@ -286,7 +289,7 @@ write_out_data:
                }
        }
        spin_unlock(&journal->j_list_lock);
-       journal_do_submit_data(wbuf, bufs);
+       journal_do_submit_data(wbuf, bufs, write_op);
 
        return err;
 }
@@ -315,6 +318,7 @@ void journal_commit_transaction(journal_t *journal)
        int first_tag = 0;
        int tag_flag;
        int i;
+       int write_op = WRITE;
 
        /*
         * First job: lock down the current transaction and wait for
@@ -347,6 +351,8 @@ void journal_commit_transaction(journal_t *journal)
        spin_lock(&journal->j_state_lock);
        commit_transaction->t_state = T_LOCKED;
 
+       if (commit_transaction->t_synchronous_commit)
+               write_op = WRITE_SYNC;
        spin_lock(&commit_transaction->t_handle_lock);
        while (commit_transaction->t_updates) {
                DEFINE_WAIT(wait);
@@ -431,7 +437,8 @@ void journal_commit_transaction(journal_t *journal)
         * Now start flushing things to disk, in the order they appear
         * on the transaction lists.  Data blocks go first.
         */
-       err = journal_submit_data_buffers(journal, commit_transaction);
+       err = journal_submit_data_buffers(journal, commit_transaction,
+                                         write_op);
 
        /*
         * Wait for all previously submitted IO to complete.
@@ -660,7 +667,7 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(WRITE, bh);
+                               submit_bh(write_op, bh);
                        }
                        cond_resched();
 
index e79c07812afa4d044ec46bc92d77ba8f759aacb4..737f7246a4b5ddc750b4a5198928f4b5afacc193 100644 (file)
@@ -637,6 +637,8 @@ struct journal_head *journal_get_descriptor_buffer(journal_t *journal)
                return NULL;
 
        bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+       if (!bh)
+               return NULL;
        lock_buffer(bh);
        memset(bh->b_data, 0, journal->j_blocksize);
        set_buffer_uptodate(bh);
@@ -733,9 +735,7 @@ journal_t * journal_init_dev(struct block_device *bdev,
        if (!journal->j_wbuf) {
                printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
                        __func__);
-               kfree(journal);
-               journal = NULL;
-               goto out;
+               goto out_err;
        }
        journal->j_dev = bdev;
        journal->j_fs_dev = fs_dev;
@@ -743,11 +743,19 @@ journal_t * journal_init_dev(struct block_device *bdev,
        journal->j_maxlen = len;
 
        bh = __getblk(journal->j_dev, start, journal->j_blocksize);
-       J_ASSERT(bh != NULL);
+       if (!bh) {
+               printk(KERN_ERR
+                      "%s: Cannot get buffer for journal superblock\n",
+                      __func__);
+               goto out_err;
+       }
        journal->j_sb_buffer = bh;
        journal->j_superblock = (journal_superblock_t *)bh->b_data;
-out:
+
        return journal;
+out_err:
+       kfree(journal);
+       return NULL;
 }
 
 /**
@@ -787,8 +795,7 @@ journal_t * journal_init_inode (struct inode *inode)
        if (!journal->j_wbuf) {
                printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
                        __func__);
-               kfree(journal);
-               return NULL;
+               goto out_err;
        }
 
        err = journal_bmap(journal, 0, &blocknr);
@@ -796,16 +803,23 @@ journal_t * journal_init_inode (struct inode *inode)
        if (err) {
                printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
                       __func__);
-               kfree(journal);
-               return NULL;
+               goto out_err;
        }
 
        bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
-       J_ASSERT(bh != NULL);
+       if (!bh) {
+               printk(KERN_ERR
+                      "%s: Cannot get buffer for journal superblock\n",
+                      __func__);
+               goto out_err;
+       }
        journal->j_sb_buffer = bh;
        journal->j_superblock = (journal_superblock_t *)bh->b_data;
 
        return journal;
+out_err:
+       kfree(journal);
+       return NULL;
 }
 
 /*
index e6a117431277129a9a3e23ca93916826e43f842a..ed886e6db399e31a619539b61e6e5765874d2b06 100644 (file)
@@ -1440,6 +1440,8 @@ int journal_stop(handle_t *handle)
                }
        }
 
+       if (handle->h_sync)
+               transaction->t_synchronous_commit = 1;
        current->journal_info = NULL;
        spin_lock(&journal->j_state_lock);
        spin_lock(&transaction->t_handle_lock);
index 62804e57a44caf2f893d16cc481f7ac347efe19a..4ea72377c7a28797b609c77084b03be21485800d 100644 (file)
@@ -367,6 +367,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        int tag_bytes = journal_tag_bytes(journal);
        struct buffer_head *cbh = NULL; /* For transactional checksums */
        __u32 crc32_sum = ~0;
+       int write_op = WRITE;
 
        /*
         * First job: lock down the current transaction and wait for
@@ -401,6 +402,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        spin_lock(&journal->j_state_lock);
        commit_transaction->t_state = T_LOCKED;
 
+       if (commit_transaction->t_synchronous_commit)
+               write_op = WRITE_SYNC;
        stats.u.run.rs_wait = commit_transaction->t_max_wait;
        stats.u.run.rs_locked = jiffies;
        stats.u.run.rs_running = jbd2_time_diff(commit_transaction->t_start,
@@ -680,7 +683,7 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(WRITE, bh);
+                               submit_bh(write_op, bh);
                        }
                        cond_resched();
                        stats.u.run.rs_blocks_logged += bufs;
index 257ff26257655f4573669a5ab6cb7ee817e0371b..bbe6d592d8b3723a17e2ef7be46098e3bdc10ebf 100644 (file)
  *                     need do nothing.
  * RevokeValid set, Revoked set:
  *                     buffer has been revoked.
+ *
+ * Locking rules:
+ * We keep two hash tables of revoke records. One hashtable belongs to the
+ * running transaction (is pointed to by journal->j_revoke), the other one
+ * belongs to the committing transaction. Accesses to the second hash table
+ * happen only from the kjournald and no other thread touches this table.  Also
+ * journal_switch_revoke_table() which switches which hashtable belongs to the
+ * running and which to the committing transaction is called only from
+ * kjournald. Therefore we need no locks when accessing the hashtable belonging
+ * to the committing transaction.
+ *
+ * All users operating on the hash table belonging to the running transaction
+ * have a handle to the transaction. Therefore they are safe from kjournald
+ * switching hash tables under them. For operations on the lists of entries in
+ * the hash table j_revoke_lock is used.
+ *
+ * Finally, also replay code uses the hash tables but at this moment noone else
+ * can touch them (filesystem isn't mounted yet) and hence no locking is
+ * needed.
  */
 
 #ifndef __KERNEL__
@@ -401,8 +420,6 @@ int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
  * the second time we would still have a pending revoke to cancel.  So,
  * do not trust the Revoked bit on buffers unless RevokeValid is also
  * set.
- *
- * The caller must have the journal locked.
  */
 int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
 {
@@ -480,10 +497,7 @@ void jbd2_journal_switch_revoke_table(journal_t *journal)
 /*
  * Write revoke records to the journal for all entries in the current
  * revoke hash, deleting the entries as we go.
- *
- * Called with the journal lock held.
  */
-
 void jbd2_journal_write_revoke_records(journal_t *journal,
                                  transaction_t *transaction)
 {
index 28ce21d8598e11f16182a973d31d7e8bef83c145..996ffda06bf306fde630e833f91332b745107689 100644 (file)
@@ -1315,6 +1315,8 @@ int jbd2_journal_stop(handle_t *handle)
                }
        }
 
+       if (handle->h_sync)
+               transaction->t_synchronous_commit = 1;
        current->journal_info = NULL;
        spin_lock(&journal->j_state_lock);
        spin_lock(&transaction->t_handle_lock);
index d98713777a1b62f2aa12f659dd872616d2dbeb4a..77ccf8cb0823c805ff9af233aba63404d0df01a2 100644 (file)
@@ -336,7 +336,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
                return PTR_ERR(acl);
 
        if (!acl) {
-               *i_mode &= ~current->fs->umask;
+               *i_mode &= ~current_umask();
        } else {
                if (S_ISDIR(*i_mode))
                        jffs2_iset_acl(inode, &f->i_acl_default, acl);
index a166c1669e823823844790f43e04ee13a14a6011..06ca1b8d205459e2a2bbbfb35282d0f576ee788c 100644 (file)
@@ -182,7 +182,7 @@ int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
 cleanup:
                posix_acl_release(acl);
        } else
-               inode->i_mode &= ~current->fs->umask;
+               inode->i_mode &= ~current_umask();
 
        JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
                               inode->i_mode;
index 6a73de84bcef142350ad60f3b3fefe2b172de043..dd824d9b0b1a11877b2c901d335b2c746709bd08 100644 (file)
@@ -90,7 +90,6 @@ void jfs_proc_init(void)
 
        if (!(base = proc_mkdir("fs/jfs", NULL)))
                return;
-       base->owner = THIS_MODULE;
 
        for (i = 0; i < NPROCENT; i++)
                proc_create(Entries[i].name, 0, base, Entries[i].proc_fops);
index aedc47a264c1f8ccf9d00eac8a46c298af58cac6..1f3b0fc0d351de0f6bd6ea7f48e3344e99f1fe56 100644 (file)
@@ -139,55 +139,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
        return 0;
 }
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static const struct in6_addr *nlmclnt_map_v4addr(const struct sockaddr *sap,
-                                                struct in6_addr *addr_mapped)
-{
-       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
-
-       switch (sap->sa_family) {
-       case AF_INET6:
-               return &((const struct sockaddr_in6 *)sap)->sin6_addr;
-       case AF_INET:
-               ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, addr_mapped);
-               return addr_mapped;
-       }
-
-       return NULL;
-}
-
-/*
- * If lockd is using a PF_INET6 listener, all incoming requests appear
- * to come from AF_INET6 remotes.  The address of AF_INET remotes are
- * mapped to AF_INET6 automatically by the network layer.  In case the
- * user passed an AF_INET server address at mount time, ensure both
- * addresses are AF_INET6 before comparing them.
- */
-static int nlmclnt_cmp_addr(const struct nlm_host *host,
-                           const struct sockaddr *sap)
-{
-       const struct in6_addr *addr1;
-       const struct in6_addr *addr2;
-       struct in6_addr addr1_mapped;
-       struct in6_addr addr2_mapped;
-
-       addr1 = nlmclnt_map_v4addr(nlm_addr(host), &addr1_mapped);
-       if (likely(addr1 != NULL)) {
-               addr2 = nlmclnt_map_v4addr(sap, &addr2_mapped);
-               if (likely(addr2 != NULL))
-                       return ipv6_addr_equal(addr1, addr2);
-       }
-
-       return 0;
-}
-#else  /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
-static int nlmclnt_cmp_addr(const struct nlm_host *host,
-                           const struct sockaddr *sap)
-{
-       return nlm_cmp_addr(nlm_addr(host), sap);
-}
-#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
-
 /*
  * The server lockd has called us back to tell us the lock was granted
  */
@@ -215,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
                 */
                if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
                        continue;
-               if (!nlmclnt_cmp_addr(block->b_host, addr))
+               if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
                        continue;
                if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
                        continue;
index 5e2c4d5ac82774011072c05f5f039ec466fca59e..6d5d4a4169e5ae472dcf2ad43e46e0495c20fb05 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
 
+#include <asm/unaligned.h>
+
 #define NLMDBG_FACILITY                NLMDBG_MONITOR
 #define NSM_PROGRAM            100024
 #define NSM_VERSION            1
@@ -274,10 +276,12 @@ static void nsm_init_private(struct nsm_handle *nsm)
 {
        u64 *p = (u64 *)&nsm->sm_priv.data;
        struct timespec ts;
+       s64 ns;
 
        ktime_get_ts(&ts);
-       *p++ = timespec_to_ns(&ts);
-       *p = (unsigned long)nsm;
+       ns = timespec_to_ns(&ts);
+       put_unaligned(ns, p);
+       put_unaligned((unsigned long)nsm, p + 1);
 }
 
 static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
index 64f1c31b58533317d65a256b79e1d5c474620421..abf83881f68a762f736b1a99faa16aff669256af 100644 (file)
@@ -52,17 +52,6 @@ static struct task_struct    *nlmsvc_task;
 static struct svc_rqst         *nlmsvc_rqst;
 unsigned long                  nlmsvc_timeout;
 
-/*
- * If the kernel has IPv6 support available, always listen for
- * both AF_INET and AF_INET6 requests.
- */
-#if (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) && \
-       defined(CONFIG_SUNRPC_REGISTER_V4)
-static const sa_family_t       nlmsvc_family = AF_INET6;
-#else  /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
-static const sa_family_t       nlmsvc_family = AF_INET;
-#endif /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
-
 /*
  * These can be set at insmod time (useful for NFS as root filesystem),
  * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
@@ -204,19 +193,30 @@ lockd(void *vrqstp)
        return 0;
 }
 
-static int create_lockd_listener(struct svc_serv *serv, char *name,
-                                unsigned short port)
+static int create_lockd_listener(struct svc_serv *serv, const char *name,
+                                const int family, const unsigned short port)
 {
        struct svc_xprt *xprt;
 
-       xprt = svc_find_xprt(serv, name, 0, 0);
+       xprt = svc_find_xprt(serv, name, family, 0);
        if (xprt == NULL)
-               return svc_create_xprt(serv, name, port, SVC_SOCK_DEFAULTS);
-
+               return svc_create_xprt(serv, name, family, port,
+                                               SVC_SOCK_DEFAULTS);
        svc_xprt_put(xprt);
        return 0;
 }
 
+static int create_lockd_family(struct svc_serv *serv, const int family)
+{
+       int err;
+
+       err = create_lockd_listener(serv, "udp", family, nlm_udpport);
+       if (err < 0)
+               return err;
+
+       return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
+}
+
 /*
  * Ensure there are active UDP and TCP listeners for lockd.
  *
@@ -232,13 +232,15 @@ static int make_socks(struct svc_serv *serv)
        static int warned;
        int err;
 
-       err = create_lockd_listener(serv, "udp", nlm_udpport);
+       err = create_lockd_family(serv, PF_INET);
        if (err < 0)
                goto out_err;
 
-       err = create_lockd_listener(serv, "tcp", nlm_tcpport);
-       if (err < 0)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       err = create_lockd_family(serv, PF_INET6);
+       if (err < 0 && err != -EAFNOSUPPORT)
                goto out_err;
+#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
 
        warned = 0;
        return 0;
@@ -274,7 +276,7 @@ int lockd_up(void)
                        "lockd_up: no pid, %d users??\n", nlmsvc_users);
 
        error = -ENOMEM;
-       serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, nlmsvc_family, NULL);
+       serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
        if (!serv) {
                printk(KERN_WARNING "lockd_up: create service failed\n");
                goto out;
index 618865b3128ba7534a0971167ad608633591e31b..daad3c2740dbd5d85d7afee2f07c3ffdb8f996f3 100644 (file)
@@ -321,15 +321,20 @@ out:
 
 static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct minix_sb_info *sbi = minix_sb(dentry->d_sb);
-       buf->f_type = dentry->d_sb->s_magic;
-       buf->f_bsize = dentry->d_sb->s_blocksize;
+       struct super_block *sb = dentry->d_sb;
+       struct minix_sb_info *sbi = minix_sb(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+       buf->f_type = sb->s_magic;
+       buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
        buf->f_bfree = minix_count_free_blocks(sbi);
        buf->f_bavail = buf->f_bfree;
        buf->f_files = sbi->s_ninodes;
        buf->f_ffree = minix_count_free_inodes(sbi);
        buf->f_namelen = sbi->s_namelen;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
+
        return 0;
 }
 
index 16c3ef37eae348ed97ad90229d427449699315a3..680ba60863ffb2dee0f81ffbda6974c419c79668 100644 (file)
@@ -82,7 +82,7 @@ static void mpage_end_io_write(struct bio *bio, int err)
        bio_put(bio);
 }
 
-struct bio *mpage_bio_submit(int rw, struct bio *bio)
+static struct bio *mpage_bio_submit(int rw, struct bio *bio)
 {
        bio->bi_end_io = mpage_end_io_read;
        if (rw == WRITE)
@@ -90,7 +90,6 @@ struct bio *mpage_bio_submit(int rw, struct bio *bio)
        submit_bio(rw, bio);
        return NULL;
 }
-EXPORT_SYMBOL(mpage_bio_submit);
 
 static struct bio *
 mpage_alloc(struct block_device *bdev,
@@ -439,7 +438,14 @@ EXPORT_SYMBOL(mpage_readpage);
  * just allocate full-size (16-page) BIOs.
  */
 
-int __mpage_writepage(struct page *page, struct writeback_control *wbc,
+struct mpage_data {
+       struct bio *bio;
+       sector_t last_block_in_bio;
+       get_block_t *get_block;
+       unsigned use_writepage;
+};
+
+static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
                      void *data)
 {
        struct mpage_data *mpd = data;
@@ -648,7 +654,6 @@ out:
        mpd->bio = bio;
        return ret;
 }
-EXPORT_SYMBOL(__mpage_writepage);
 
 /**
  * mpage_writepages - walk the list of dirty pages of the given address space & writepage() all of them
index d040ce11785d6acb115154da5e83a7500909df13..b8433ebfae055424c5d953ff3ff9c96bc7c7a628 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/file.h>
 #include <linux/fcntl.h>
 #include <linux/device_cgroup.h>
+#include <linux/fs_struct.h>
 #include <asm/uaccess.h>
 
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
@@ -1578,7 +1579,7 @@ static int __open_namei_create(struct nameidata *nd, struct path *path,
        struct dentry *dir = nd->path.dentry;
 
        if (!IS_POSIXACL(dir->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
        error = security_path_mknod(&nd->path, path->dentry, mode, 0);
        if (error)
                goto out_unlock;
@@ -1989,7 +1990,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,
                goto out_unlock;
        }
        if (!IS_POSIXACL(nd.path.dentry->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
        error = may_mknod(mode);
        if (error)
                goto out_dput;
@@ -2067,7 +2068,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode)
                goto out_unlock;
 
        if (!IS_POSIXACL(nd.path.dentry->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto out_dput;
@@ -2897,10 +2898,3 @@ EXPORT_SYMBOL(vfs_symlink);
 EXPORT_SYMBOL(vfs_unlink);
 EXPORT_SYMBOL(dentry_unhash);
 EXPORT_SYMBOL(generic_readlink);
-
-/* to be mentioned only in INIT_TASK */
-struct fs_struct init_fs = {
-       .count          = ATOMIC_INIT(1),
-       .lock           = __RW_LOCK_UNLOCKED(init_fs.lock),
-       .umask          = 0022,
-};
index 0a42e0e9602766939a6ac0a2e444df2992adc3f9..c6f54e4c42901f2cf0d91432507962fbc91552b7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/ramfs.h>
 #include <linux/log2.h>
 #include <linux/idr.h>
+#include <linux/fs_struct.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include "pnode.h"
@@ -2092,66 +2093,6 @@ out1:
        return retval;
 }
 
-/*
- * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
- * It can block. Requires the big lock held.
- */
-void set_fs_root(struct fs_struct *fs, struct path *path)
-{
-       struct path old_root;
-
-       write_lock(&fs->lock);
-       old_root = fs->root;
-       fs->root = *path;
-       path_get(path);
-       write_unlock(&fs->lock);
-       if (old_root.dentry)
-               path_put(&old_root);
-}
-
-/*
- * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
- * It can block. Requires the big lock held.
- */
-void set_fs_pwd(struct fs_struct *fs, struct path *path)
-{
-       struct path old_pwd;
-
-       write_lock(&fs->lock);
-       old_pwd = fs->pwd;
-       fs->pwd = *path;
-       path_get(path);
-       write_unlock(&fs->lock);
-
-       if (old_pwd.dentry)
-               path_put(&old_pwd);
-}
-
-static void chroot_fs_refs(struct path *old_root, struct path *new_root)
-{
-       struct task_struct *g, *p;
-       struct fs_struct *fs;
-
-       read_lock(&tasklist_lock);
-       do_each_thread(g, p) {
-               task_lock(p);
-               fs = p->fs;
-               if (fs) {
-                       atomic_inc(&fs->count);
-                       task_unlock(p);
-                       if (fs->root.dentry == old_root->dentry
-                           && fs->root.mnt == old_root->mnt)
-                               set_fs_root(fs, new_root);
-                       if (fs->pwd.dentry == old_root->dentry
-                           && fs->pwd.mnt == old_root->mnt)
-                               set_fs_pwd(fs, new_root);
-                       put_fs_struct(fs);
-               } else
-                       task_unlock(p);
-       } while_each_thread(g, p);
-       read_unlock(&tasklist_lock);
-}
-
 /*
  * pivot_root Semantics:
  * Moves the root file system of the current process to the directory put_old,
index 36fe20d6eba29a10e9a00b411f1afe4473ceff22..e67f3ec0773681c17dcf906e0cddfbd12d9ea1bc 100644 (file)
@@ -84,3 +84,11 @@ config ROOT_NFS
          <file:Documentation/filesystems/nfsroot.txt>.
 
          Most people say N here.
+
+config NFS_FSCACHE
+       bool "Provide NFS client caching support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       depends on NFS_FS=m && FSCACHE || NFS_FS=y && FSCACHE=y
+       help
+         Say Y here if you want NFS data to be cached locally on disc through
+         the general filesystem cache manager
index ac6170c594a37fadd988fd7027f84e66160f302d..845159814de2985869689aa0d033c2fd07b41a5d 100644 (file)
@@ -15,3 +15,4 @@ nfs-$(CONFIG_NFS_V4)  += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
                           callback.o callback_xdr.o callback_proc.o \
                           nfs4namespace.o
 nfs-$(CONFIG_SYSCTL) += sysctl.o
+nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
index 3e634f2a1083cf556e9c3429320e0cd458d3c5b1..a886e692ddd006359aa8b021f053e3b7f9904567 100644 (file)
@@ -38,19 +38,10 @@ static struct svc_program nfs4_callback_program;
 
 unsigned int nfs_callback_set_tcpport;
 unsigned short nfs_callback_tcpport;
+unsigned short nfs_callback_tcpport6;
 static const int nfs_set_port_min = 0;
 static const int nfs_set_port_max = 65535;
 
-/*
- * If the kernel has IPv6 support available, always listen for
- * both AF_INET and AF_INET6 requests.
- */
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static const sa_family_t       nfs_callback_family = AF_INET6;
-#else
-static const sa_family_t       nfs_callback_family = AF_INET;
-#endif
-
 static int param_set_port(const char *val, struct kernel_param *kp)
 {
        char *endp;
@@ -116,19 +107,29 @@ int nfs_callback_up(void)
        mutex_lock(&nfs_callback_mutex);
        if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
                goto out;
-       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
-                               nfs_callback_family, NULL);
+       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
        ret = -ENOMEM;
        if (!serv)
                goto out_err;
 
-       ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
-                             SVC_SOCK_ANONYMOUS);
+       ret = svc_create_xprt(serv, "tcp", PF_INET,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
        if (ret <= 0)
                goto out_err;
        nfs_callback_tcpport = ret;
        dprintk("NFS: Callback listener port = %u (af %u)\n",
-                       nfs_callback_tcpport, nfs_callback_family);
+                       nfs_callback_tcpport, PF_INET);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       ret = svc_create_xprt(serv, "tcp", PF_INET6,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+       if (ret > 0) {
+               nfs_callback_tcpport6 = ret;
+               dprintk("NFS: Callback listener port = %u (af %u)\n",
+                               nfs_callback_tcpport6, PF_INET6);
+       } else if (ret != -EAFNOSUPPORT)
+               goto out_err;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 
        nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
        if (IS_ERR(nfs_callback_info.rqst)) {
index bb25d2135ff1e7e15ead85466b5c36a0de5737cf..e110e286a26217d681b8a26e4165d5fff3a7b75d 100644 (file)
@@ -72,5 +72,6 @@ extern void nfs_callback_down(void);
 
 extern unsigned int nfs_callback_set_tcpport;
 extern unsigned short nfs_callback_tcpport;
+extern unsigned short nfs_callback_tcpport6;
 
 #endif /* __LINUX_FS_NFS_CALLBACK_H */
index 574158ae2398aaeb1151d76f0a85f2b73871b976..75c9cd2aa1194e0f0c4ac754ae2b85e722ce5809 100644 (file)
@@ -45,6 +45,7 @@
 #include "delegation.h"
 #include "iostat.h"
 #include "internal.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
@@ -154,6 +155,8 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
        if (!IS_ERR(cred))
                clp->cl_machine_cred = cred;
 
+       nfs_fscache_get_client_cookie(clp);
+
        return clp;
 
 error_3:
@@ -187,6 +190,8 @@ static void nfs_free_client(struct nfs_client *clp)
 
        nfs4_shutdown_client(clp);
 
+       nfs_fscache_release_client_cookie(clp);
+
        /* -EIO all pending I/O */
        if (!IS_ERR(clp->cl_rpcclient))
                rpc_shutdown_client(clp->cl_rpcclient);
@@ -224,38 +229,6 @@ void nfs_put_client(struct nfs_client *clp)
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped)
-{
-       switch (sa->sa_family) {
-               default:
-                       return NULL;
-               case AF_INET6:
-                       return &((const struct sockaddr_in6 *)sa)->sin6_addr;
-                       break;
-               case AF_INET:
-                       ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr,
-                                       addr_mapped);
-                       return addr_mapped;
-       }
-}
-
-static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
-               const struct sockaddr *sa2)
-{
-       const struct in6_addr *addr1;
-       const struct in6_addr *addr2;
-       struct in6_addr addr1_mapped;
-       struct in6_addr addr2_mapped;
-
-       addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped);
-       if (likely(addr1 != NULL)) {
-               addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped);
-               if (likely(addr2 != NULL))
-                       return ipv6_addr_equal(addr1, addr2);
-       }
-       return 0;
-}
-
 /*
  * Test if two ip6 socket addresses refer to the same socket by
  * comparing relevant fields. The padding bytes specifically, are not
@@ -267,38 +240,21 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
  *
  * The caller should ensure both socket addresses are AF_INET6.
  */
-static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
-                               const struct sockaddr *sa2)
+static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
+                                     const struct sockaddr *sa2)
 {
-       const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1;
-       const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2;
+       const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
+       const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
 
-       if (!ipv6_addr_equal(&saddr1->sin6_addr,
-                            &saddr1->sin6_addr))
-               return 0;
-       if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
-           saddr1->sin6_scope_id != saddr2->sin6_scope_id)
+       if (ipv6_addr_scope(&sin1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
+           sin1->sin6_scope_id != sin2->sin6_scope_id)
                return 0;
-       return saddr1->sin6_port == saddr2->sin6_port;
-}
-#else
-static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
-                                const struct sockaddr_in *sa2)
-{
-       return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
-}
 
-static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
-                                const struct sockaddr *sa2)
-{
-       if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET))
-               return 0;
-       return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
-                       (const struct sockaddr_in *)sa2);
+       return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr);
 }
-
-static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
-                               const struct sockaddr * sa2)
+#else  /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */
+static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
+                                     const struct sockaddr *sa2)
 {
        return 0;
 }
@@ -311,20 +267,57 @@ static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
  *
  * The caller should ensure both socket addresses are AF_INET.
  */
+static int nfs_sockaddr_match_ipaddr4(const struct sockaddr *sa1,
+                                     const struct sockaddr *sa2)
+{
+       const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
+       const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
+
+       return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
+}
+
+static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
+                               const struct sockaddr *sa2)
+{
+       const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
+       const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
+
+       return nfs_sockaddr_match_ipaddr6(sa1, sa2) &&
+               (sin1->sin6_port == sin2->sin6_port);
+}
+
 static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
                                const struct sockaddr *sa2)
 {
-       const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1;
-       const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2;
+       const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
+       const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
 
-       if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr)
+       return nfs_sockaddr_match_ipaddr4(sa1, sa2) &&
+               (sin1->sin_port == sin2->sin_port);
+}
+
+/*
+ * Test if two socket addresses represent the same actual socket,
+ * by comparing (only) relevant fields, excluding the port number.
+ */
+static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
+                                    const struct sockaddr *sa2)
+{
+       if (sa1->sa_family != sa2->sa_family)
                return 0;
-       return saddr1->sin_port == saddr2->sin_port;
+
+       switch (sa1->sa_family) {
+       case AF_INET:
+               return nfs_sockaddr_match_ipaddr4(sa1, sa2);
+       case AF_INET6:
+               return nfs_sockaddr_match_ipaddr6(sa1, sa2);
+       }
+       return 0;
 }
 
 /*
  * Test if two socket addresses represent the same actual socket,
- * by comparing (only) relevant fields.
+ * by comparing (only) relevant fields, including the port number.
  */
 static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
                            const struct sockaddr *sa2)
@@ -772,6 +765,7 @@ static int nfs_init_server(struct nfs_server *server,
 
        /* Initialise the client representation from the mount data */
        server->flags = data->flags;
+       server->options = data->options;
 
        if (data->rsize)
                server->rsize = nfs_block_size(data->rsize, NULL);
@@ -1160,6 +1154,7 @@ static int nfs4_init_server(struct nfs_server *server,
        /* Initialise the client representation from the mount data */
        server->flags = data->flags;
        server->caps |= NFS_CAP_ATOMIC_OPEN;
+       server->options = data->options;
 
        /* Get a client record */
        error = nfs4_set_client(server,
@@ -1571,7 +1566,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
 
        /* display header on line 1 */
        if (v == &nfs_volume_list) {
-               seq_puts(m, "NV SERVER   PORT DEV     FSID\n");
+               seq_puts(m, "NV SERVER   PORT DEV     FSID              FSC\n");
                return 0;
        }
        /* display one transport per line on subsequent lines */
@@ -1585,12 +1580,13 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
                 (unsigned long long) server->fsid.major,
                 (unsigned long long) server->fsid.minor);
 
-       seq_printf(m, "v%u %s %s %-7s %-17s\n",
+       seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
                   clp->rpc_ops->version,
                   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
                   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
                   dev,
-                  fsid);
+                  fsid,
+                  nfs_server_fscache_state(server));
 
        return 0;
 }
@@ -1606,8 +1602,6 @@ int __init nfs_fs_proc_init(void)
        if (!proc_fs_nfs)
                goto error_0;
 
-       proc_fs_nfs->owner = THIS_MODULE;
-
        /* a file of servers with which we're dealing */
        p = proc_create("servers", S_IFREG|S_IRUGO,
                        proc_fs_nfs, &nfs_server_list_fops);
index 78bf72fc1db3a79fe08ae65c77960eff1326443f..370b190a09d1d7ac7d03fe1cd45457ec866749a4 100644 (file)
@@ -1624,8 +1624,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                } else if (atomic_read(&new_dentry->d_count) > 1)
                        /* dentry still busy? */
                        goto out;
-       } else
-               nfs_drop_nlink(new_inode);
+       }
 
 go_ahead:
        /*
@@ -1638,10 +1637,8 @@ go_ahead:
        }
        nfs_inode_return_delegation(old_inode);
 
-       if (new_inode != NULL) {
+       if (new_inode != NULL)
                nfs_inode_return_delegation(new_inode);
-               d_delete(new_dentry);
-       }
 
        error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
                                           new_dir, &new_dentry->d_name);
@@ -1650,6 +1647,8 @@ out:
        if (rehash)
                d_rehash(rehash);
        if (!error) {
+               if (new_inode != NULL)
+                       nfs_drop_nlink(new_inode);
                d_move(old_dentry, new_dentry);
                nfs_set_verifier(new_dentry,
                                        nfs_save_change_attribute(new_dir));
index 90f292b520d25eec248a9728b7d61cf20cd061f9..3523b895eb4b3b598a89399aceca8d77833cb595 100644 (file)
@@ -35,6 +35,7 @@
 #include "delegation.h"
 #include "internal.h"
 #include "iostat.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_FILE
 
@@ -64,11 +65,7 @@ const struct file_operations nfs_file_operations = {
        .write          = do_sync_write,
        .aio_read       = nfs_file_read,
        .aio_write      = nfs_file_write,
-#ifdef CONFIG_MMU
        .mmap           = nfs_file_mmap,
-#else
-       .mmap           = generic_file_mmap,
-#endif
        .open           = nfs_file_open,
        .flush          = nfs_file_flush,
        .release        = nfs_file_release,
@@ -141,9 +138,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
                        dentry->d_parent->d_name.name,
                        dentry->d_name.name);
 
-       /* Ensure that dirty pages are flushed out with the right creds */
-       if (filp->f_mode & FMODE_WRITE)
-               nfs_wb_all(dentry->d_inode);
        nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
        return nfs_release(inode, filp);
 }
@@ -235,7 +229,6 @@ nfs_file_flush(struct file *file, fl_owner_t id)
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct dentry   *dentry = file->f_path.dentry;
        struct inode    *inode = dentry->d_inode;
-       int             status;
 
        dprintk("NFS: flush(%s/%s)\n",
                        dentry->d_parent->d_name.name,
@@ -245,11 +238,8 @@ nfs_file_flush(struct file *file, fl_owner_t id)
                return 0;
        nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
 
-       /* Ensure that data+attribute caches are up to date after close() */
-       status = nfs_do_fsync(ctx, inode);
-       if (!status)
-               nfs_revalidate_inode(NFS_SERVER(inode), inode);
-       return status;
+       /* Flush writes to the server and return any errors */
+       return nfs_do_fsync(ctx, inode);
 }
 
 static ssize_t
@@ -304,11 +294,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
        dprintk("NFS: mmap(%s/%s)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
-       status = nfs_revalidate_mapping(inode, file->f_mapping);
+       /* Note: generic_file_mmap() returns ENOSYS on nommu systems
+        *       so we call that before revalidating the mapping
+        */
+       status = generic_file_mmap(file, vma);
        if (!status) {
                vma->vm_ops = &nfs_file_vm_ops;
-               vma->vm_flags |= VM_CAN_NONLINEAR;
-               file_accessed(file);
+               status = nfs_revalidate_mapping(inode, file->f_mapping);
        }
        return status;
 }
@@ -354,6 +346,15 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
                file->f_path.dentry->d_name.name,
                mapping->host->i_ino, len, (long long) pos);
 
+       /*
+        * Prevent starvation issues if someone is doing a consistency
+        * sync-to-disk
+        */
+       ret = wait_on_bit(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+       if (ret)
+               return ret;
+
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
                return -ENOMEM;
@@ -409,6 +410,13 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
        return copied;
 }
 
+/*
+ * Partially or wholly invalidate a page
+ * - Release the private state associated with a page if undergoing complete
+ *   page invalidation
+ * - Called if either PG_private or PG_fscache is set on the page
+ * - Caller holds page lock
+ */
 static void nfs_invalidate_page(struct page *page, unsigned long offset)
 {
        dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset);
@@ -417,23 +425,43 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
                return;
        /* Cancel any unstarted writes on this page */
        nfs_wb_page_cancel(page->mapping->host, page);
+
+       nfs_fscache_invalidate_page(page, page->mapping->host);
 }
 
+/*
+ * Attempt to release the private state associated with a page
+ * - Called if either PG_private or PG_fscache is set on the page
+ * - Caller holds page lock
+ * - Return true (may release page) or false (may not)
+ */
 static int nfs_release_page(struct page *page, gfp_t gfp)
 {
        dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
 
        /* If PagePrivate() is set, then the page is not freeable */
-       return 0;
+       if (PagePrivate(page))
+               return 0;
+       return nfs_fscache_release_page(page, gfp);
 }
 
+/*
+ * Attempt to clear the private state associated with a page when an error
+ * occurs that requires the cached contents of an inode to be written back or
+ * destroyed
+ * - Called if either PG_private or fscache is set on the page
+ * - Caller holds page lock
+ * - Return 0 if successful, -error otherwise
+ */
 static int nfs_launder_page(struct page *page)
 {
        struct inode *inode = page->mapping->host;
+       struct nfs_inode *nfsi = NFS_I(inode);
 
        dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
                inode->i_ino, (long long)page_offset(page));
 
+       nfs_fscache_wait_on_page_write(nfsi, page);
        return nfs_wb_page(inode, page);
 }
 
@@ -451,8 +479,14 @@ const struct address_space_operations nfs_file_aops = {
        .launder_page = nfs_launder_page,
 };
 
-static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+/*
+ * Notification that a PTE pointing to an NFS page is about to be made
+ * writable, implying that someone is about to modify the page through a
+ * shared-writable mapping
+ */
+static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct file *filp = vma->vm_file;
        struct dentry *dentry = filp->f_path.dentry;
        unsigned pagelen;
@@ -464,6 +498,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
                filp->f_mapping->host->i_ino,
                (long long)page_offset(page));
 
+       /* make sure the cache has finished storing the page */
+       nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page);
+
        lock_page(page);
        mapping = page->mapping;
        if (mapping != dentry->d_inode->i_mapping)
@@ -483,6 +520,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
                ret = pagelen;
 out_unlock:
        unlock_page(page);
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        return ret;
 }
 
diff --git a/fs/nfs/fscache-index.c b/fs/nfs/fscache-index.c
new file mode 100644 (file)
index 0000000..5b10064
--- /dev/null
@@ -0,0 +1,337 @@
+/* NFS FS-Cache index structure definition
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/in6.h>
+
+#include "internal.h"
+#include "fscache.h"
+
+#define NFSDBG_FACILITY                NFSDBG_FSCACHE
+
+/*
+ * Define the NFS filesystem for FS-Cache.  Upon registration FS-Cache sticks
+ * the cookie for the top-level index object for NFS into here.  The top-level
+ * index can than have other cache objects inserted into it.
+ */
+struct fscache_netfs nfs_fscache_netfs = {
+       .name           = "nfs",
+       .version        = 0,
+};
+
+/*
+ * Register NFS for caching
+ */
+int nfs_fscache_register(void)
+{
+       return fscache_register_netfs(&nfs_fscache_netfs);
+}
+
+/*
+ * Unregister NFS for caching
+ */
+void nfs_fscache_unregister(void)
+{
+       fscache_unregister_netfs(&nfs_fscache_netfs);
+}
+
+/*
+ * Layout of the key for an NFS server cache object.
+ */
+struct nfs_server_key {
+       uint16_t        nfsversion;             /* NFS protocol version */
+       uint16_t        family;                 /* address family */
+       uint16_t        port;                   /* IP port */
+       union {
+               struct in_addr  ipv4_addr;      /* IPv4 address */
+               struct in6_addr ipv6_addr;      /* IPv6 address */
+       } addr[0];
+};
+
+/*
+ * Generate a key to describe a server in the main NFS index
+ * - We return the length of the key, or 0 if we can't generate one
+ */
+static uint16_t nfs_server_get_key(const void *cookie_netfs_data,
+                                  void *buffer, uint16_t bufmax)
+{
+       const struct nfs_client *clp = cookie_netfs_data;
+       const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr;
+       const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr;
+       struct nfs_server_key *key = buffer;
+       uint16_t len = sizeof(struct nfs_server_key);
+
+       key->nfsversion = clp->rpc_ops->version;
+       key->family = clp->cl_addr.ss_family;
+
+       memset(key, 0, len);
+
+       switch (clp->cl_addr.ss_family) {
+       case AF_INET:
+               key->port = sin->sin_port;
+               key->addr[0].ipv4_addr = sin->sin_addr;
+               len += sizeof(key->addr[0].ipv4_addr);
+               break;
+
+       case AF_INET6:
+               key->port = sin6->sin6_port;
+               key->addr[0].ipv6_addr = sin6->sin6_addr;
+               len += sizeof(key->addr[0].ipv6_addr);
+               break;
+
+       default:
+               printk(KERN_WARNING "NFS: Unknown network family '%d'\n",
+                      clp->cl_addr.ss_family);
+               len = 0;
+               break;
+       }
+
+       return len;
+}
+
+/*
+ * Define the server object for FS-Cache.  This is used to describe a server
+ * object to fscache_acquire_cookie().  It is keyed by the NFS protocol and
+ * server address parameters.
+ */
+const struct fscache_cookie_def nfs_fscache_server_index_def = {
+       .name           = "NFS.server",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key        = nfs_server_get_key,
+};
+
+/*
+ * Generate a key to describe a superblock key in the main NFS index
+ */
+static uint16_t nfs_super_get_key(const void *cookie_netfs_data,
+                                 void *buffer, uint16_t bufmax)
+{
+       const struct nfs_fscache_key *key;
+       const struct nfs_server *nfss = cookie_netfs_data;
+       uint16_t len;
+
+       key = nfss->fscache_key;
+       len = sizeof(key->key) + key->key.uniq_len;
+       if (len > bufmax) {
+               len = 0;
+       } else {
+               memcpy(buffer, &key->key, sizeof(key->key));
+               memcpy(buffer + sizeof(key->key),
+                      key->key.uniquifier, key->key.uniq_len);
+       }
+
+       return len;
+}
+
+/*
+ * Define the superblock object for FS-Cache.  This is used to describe a
+ * superblock object to fscache_acquire_cookie().  It is keyed by all the NFS
+ * parameters that might cause a separate superblock.
+ */
+const struct fscache_cookie_def nfs_fscache_super_index_def = {
+       .name           = "NFS.super",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key        = nfs_super_get_key,
+};
+
+/*
+ * Definition of the auxiliary data attached to NFS inode storage objects
+ * within the cache.
+ *
+ * The contents of this struct are recorded in the on-disk local cache in the
+ * auxiliary data attached to the data storage object backing an inode.  This
+ * permits coherency to be managed when a new inode binds to an already extant
+ * cache object.
+ */
+struct nfs_fscache_inode_auxdata {
+       struct timespec mtime;
+       struct timespec ctime;
+       loff_t          size;
+       u64             change_attr;
+};
+
+/*
+ * Generate a key to describe an NFS inode in an NFS server's index
+ */
+static uint16_t nfs_fscache_inode_get_key(const void *cookie_netfs_data,
+                                         void *buffer, uint16_t bufmax)
+{
+       const struct nfs_inode *nfsi = cookie_netfs_data;
+       uint16_t nsize;
+
+       /* use the inode's NFS filehandle as the key */
+       nsize = nfsi->fh.size;
+       memcpy(buffer, nfsi->fh.data, nsize);
+       return nsize;
+}
+
+/*
+ * Get certain file attributes from the netfs data
+ * - This function can be absent for an index
+ * - Not permitted to return an error
+ * - The netfs data from the cookie being used as the source is presented
+ */
+static void nfs_fscache_inode_get_attr(const void *cookie_netfs_data,
+                                      uint64_t *size)
+{
+       const struct nfs_inode *nfsi = cookie_netfs_data;
+
+       *size = nfsi->vfs_inode.i_size;
+}
+
+/*
+ * Get the auxiliary data from netfs data
+ * - This function can be absent if the index carries no state data
+ * - Should store the auxiliary data in the buffer
+ * - Should return the amount of amount stored
+ * - Not permitted to return an error
+ * - The netfs data from the cookie being used as the source is presented
+ */
+static uint16_t nfs_fscache_inode_get_aux(const void *cookie_netfs_data,
+                                         void *buffer, uint16_t bufmax)
+{
+       struct nfs_fscache_inode_auxdata auxdata;
+       const struct nfs_inode *nfsi = cookie_netfs_data;
+
+       memset(&auxdata, 0, sizeof(auxdata));
+       auxdata.size = nfsi->vfs_inode.i_size;
+       auxdata.mtime = nfsi->vfs_inode.i_mtime;
+       auxdata.ctime = nfsi->vfs_inode.i_ctime;
+
+       if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
+               auxdata.change_attr = nfsi->change_attr;
+
+       if (bufmax > sizeof(auxdata))
+               bufmax = sizeof(auxdata);
+
+       memcpy(buffer, &auxdata, bufmax);
+       return bufmax;
+}
+
+/*
+ * Consult the netfs about the state of an object
+ * - This function can be absent if the index carries no state data
+ * - The netfs data from the cookie being used as the target is
+ *   presented, as is the auxiliary data
+ */
+static
+enum fscache_checkaux nfs_fscache_inode_check_aux(void *cookie_netfs_data,
+                                                 const void *data,
+                                                 uint16_t datalen)
+{
+       struct nfs_fscache_inode_auxdata auxdata;
+       struct nfs_inode *nfsi = cookie_netfs_data;
+
+       if (datalen != sizeof(auxdata))
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       memset(&auxdata, 0, sizeof(auxdata));
+       auxdata.size = nfsi->vfs_inode.i_size;
+       auxdata.mtime = nfsi->vfs_inode.i_mtime;
+       auxdata.ctime = nfsi->vfs_inode.i_ctime;
+
+       if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
+               auxdata.change_attr = nfsi->change_attr;
+
+       if (memcmp(data, &auxdata, datalen) != 0)
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       return FSCACHE_CHECKAUX_OKAY;
+}
+
+/*
+ * Indication from FS-Cache that the cookie is no longer cached
+ * - This function is called when the backing store currently caching a cookie
+ *   is removed
+ * - The netfs should use this to clean up any markers indicating cached pages
+ * - This is mandatory for any object that may have data
+ */
+static void nfs_fscache_inode_now_uncached(void *cookie_netfs_data)
+{
+       struct nfs_inode *nfsi = cookie_netfs_data;
+       struct pagevec pvec;
+       pgoff_t first;
+       int loop, nr_pages;
+
+       pagevec_init(&pvec, 0);
+       first = 0;
+
+       dprintk("NFS: nfs_inode_now_uncached: nfs_inode 0x%p\n", nfsi);
+
+       for (;;) {
+               /* grab a bunch of pages to unmark */
+               nr_pages = pagevec_lookup(&pvec,
+                                         nfsi->vfs_inode.i_mapping,
+                                         first,
+                                         PAGEVEC_SIZE - pagevec_count(&pvec));
+               if (!nr_pages)
+                       break;
+
+               for (loop = 0; loop < nr_pages; loop++)
+                       ClearPageFsCache(pvec.pages[loop]);
+
+               first = pvec.pages[nr_pages - 1]->index + 1;
+
+               pvec.nr = nr_pages;
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+}
+
+/*
+ * Get an extra reference on a read context.
+ * - This function can be absent if the completion function doesn't require a
+ *   context.
+ * - The read context is passed back to NFS in the event that a data read on the
+ *   cache fails with EIO - in which case the server must be contacted to
+ *   retrieve the data, which requires the read context for security.
+ */
+static void nfs_fh_get_context(void *cookie_netfs_data, void *context)
+{
+       get_nfs_open_context(context);
+}
+
+/*
+ * Release an extra reference on a read context.
+ * - This function can be absent if the completion function doesn't require a
+ *   context.
+ */
+static void nfs_fh_put_context(void *cookie_netfs_data, void *context)
+{
+       if (context)
+               put_nfs_open_context(context);
+}
+
+/*
+ * Define the inode object for FS-Cache.  This is used to describe an inode
+ * object to fscache_acquire_cookie().  It is keyed by the NFS file handle for
+ * an inode.
+ *
+ * Coherency is managed by comparing the copies of i_size, i_mtime and i_ctime
+ * held in the cache auxiliary data for the data storage object with those in
+ * the inode struct in memory.
+ */
+const struct fscache_cookie_def nfs_fscache_inode_object_def = {
+       .name           = "NFS.fh",
+       .type           = FSCACHE_COOKIE_TYPE_DATAFILE,
+       .get_key        = nfs_fscache_inode_get_key,
+       .get_attr       = nfs_fscache_inode_get_attr,
+       .get_aux        = nfs_fscache_inode_get_aux,
+       .check_aux      = nfs_fscache_inode_check_aux,
+       .now_uncached   = nfs_fscache_inode_now_uncached,
+       .get_context    = nfs_fh_get_context,
+       .put_context    = nfs_fh_put_context,
+};
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
new file mode 100644 (file)
index 0000000..379be67
--- /dev/null
@@ -0,0 +1,523 @@
+/* NFS filesystem cache interface
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/in6.h>
+#include <linux/seq_file.h>
+
+#include "internal.h"
+#include "iostat.h"
+#include "fscache.h"
+
+#define NFSDBG_FACILITY                NFSDBG_FSCACHE
+
+static struct rb_root nfs_fscache_keys = RB_ROOT;
+static DEFINE_SPINLOCK(nfs_fscache_keys_lock);
+
+/*
+ * Get the per-client index cookie for an NFS client if the appropriate mount
+ * flag was set
+ * - We always try and get an index cookie for the client, but get filehandle
+ *   cookies on a per-superblock basis, depending on the mount flags
+ */
+void nfs_fscache_get_client_cookie(struct nfs_client *clp)
+{
+       /* create a cache index for looking up filehandles */
+       clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index,
+                                             &nfs_fscache_server_index_def,
+                                             clp);
+       dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n",
+                clp, clp->fscache);
+}
+
+/*
+ * Dispose of a per-client cookie
+ */
+void nfs_fscache_release_client_cookie(struct nfs_client *clp)
+{
+       dfprintk(FSCACHE, "NFS: releasing client cookie (0x%p/0x%p)\n",
+                clp, clp->fscache);
+
+       fscache_relinquish_cookie(clp->fscache, 0);
+       clp->fscache = NULL;
+}
+
+/*
+ * Get the cache cookie for an NFS superblock.  We have to handle
+ * uniquification here because the cache doesn't do it for us.
+ */
+void nfs_fscache_get_super_cookie(struct super_block *sb,
+                                 struct nfs_parsed_mount_data *data)
+{
+       struct nfs_fscache_key *key, *xkey;
+       struct nfs_server *nfss = NFS_SB(sb);
+       struct rb_node **p, *parent;
+       const char *uniq = data->fscache_uniq ?: "";
+       int diff, ulen;
+
+       ulen = strlen(uniq);
+       key = kzalloc(sizeof(*key) + ulen, GFP_KERNEL);
+       if (!key)
+               return;
+
+       key->nfs_client = nfss->nfs_client;
+       key->key.super.s_flags = sb->s_flags & NFS_MS_MASK;
+       key->key.nfs_server.flags = nfss->flags;
+       key->key.nfs_server.rsize = nfss->rsize;
+       key->key.nfs_server.wsize = nfss->wsize;
+       key->key.nfs_server.acregmin = nfss->acregmin;
+       key->key.nfs_server.acregmax = nfss->acregmax;
+       key->key.nfs_server.acdirmin = nfss->acdirmin;
+       key->key.nfs_server.acdirmax = nfss->acdirmax;
+       key->key.nfs_server.fsid = nfss->fsid;
+       key->key.rpc_auth.au_flavor = nfss->client->cl_auth->au_flavor;
+
+       key->key.uniq_len = ulen;
+       memcpy(key->key.uniquifier, uniq, ulen);
+
+       spin_lock(&nfs_fscache_keys_lock);
+       p = &nfs_fscache_keys.rb_node;
+       parent = NULL;
+       while (*p) {
+               parent = *p;
+               xkey = rb_entry(parent, struct nfs_fscache_key, node);
+
+               if (key->nfs_client < xkey->nfs_client)
+                       goto go_left;
+               if (key->nfs_client > xkey->nfs_client)
+                       goto go_right;
+
+               diff = memcmp(&key->key, &xkey->key, sizeof(key->key));
+               if (diff < 0)
+                       goto go_left;
+               if (diff > 0)
+                       goto go_right;
+
+               if (key->key.uniq_len == 0)
+                       goto non_unique;
+               diff = memcmp(key->key.uniquifier,
+                             xkey->key.uniquifier,
+                             key->key.uniq_len);
+               if (diff < 0)
+                       goto go_left;
+               if (diff > 0)
+                       goto go_right;
+               goto non_unique;
+
+       go_left:
+               p = &(*p)->rb_left;
+               continue;
+       go_right:
+               p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&key->node, parent, p);
+       rb_insert_color(&key->node, &nfs_fscache_keys);
+       spin_unlock(&nfs_fscache_keys_lock);
+       nfss->fscache_key = key;
+
+       /* create a cache index for looking up filehandles */
+       nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache,
+                                              &nfs_fscache_super_index_def,
+                                              nfss);
+       dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
+                nfss, nfss->fscache);
+       return;
+
+non_unique:
+       spin_unlock(&nfs_fscache_keys_lock);
+       kfree(key);
+       nfss->fscache_key = NULL;
+       nfss->fscache = NULL;
+       printk(KERN_WARNING "NFS:"
+              " Cache request denied due to non-unique superblock keys\n");
+}
+
+/*
+ * release a per-superblock cookie
+ */
+void nfs_fscache_release_super_cookie(struct super_block *sb)
+{
+       struct nfs_server *nfss = NFS_SB(sb);
+
+       dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n",
+                nfss, nfss->fscache);
+
+       fscache_relinquish_cookie(nfss->fscache, 0);
+       nfss->fscache = NULL;
+
+       if (nfss->fscache_key) {
+               spin_lock(&nfs_fscache_keys_lock);
+               rb_erase(&nfss->fscache_key->node, &nfs_fscache_keys);
+               spin_unlock(&nfs_fscache_keys_lock);
+               kfree(nfss->fscache_key);
+               nfss->fscache_key = NULL;
+       }
+}
+
+/*
+ * Initialise the per-inode cache cookie pointer for an NFS inode.
+ */
+void nfs_fscache_init_inode_cookie(struct inode *inode)
+{
+       NFS_I(inode)->fscache = NULL;
+       if (S_ISREG(inode->i_mode))
+               set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags);
+}
+
+/*
+ * Get the per-inode cache cookie for an NFS inode.
+ */
+static void nfs_fscache_enable_inode_cookie(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       if (nfsi->fscache || !NFS_FSCACHE(inode))
+               return;
+
+       if ((NFS_SB(sb)->options & NFS_OPTION_FSCACHE)) {
+               nfsi->fscache = fscache_acquire_cookie(
+                       NFS_SB(sb)->fscache,
+                       &nfs_fscache_inode_object_def,
+                       nfsi);
+
+               dfprintk(FSCACHE, "NFS: get FH cookie (0x%p/0x%p/0x%p)\n",
+                        sb, nfsi, nfsi->fscache);
+       }
+}
+
+/*
+ * Release a per-inode cookie.
+ */
+void nfs_fscache_release_inode_cookie(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n",
+                nfsi, nfsi->fscache);
+
+       fscache_relinquish_cookie(nfsi->fscache, 0);
+       nfsi->fscache = NULL;
+}
+
+/*
+ * Retire a per-inode cookie, destroying the data attached to it.
+ */
+void nfs_fscache_zap_inode_cookie(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       dfprintk(FSCACHE, "NFS: zapping cookie (0x%p/0x%p)\n",
+                nfsi, nfsi->fscache);
+
+       fscache_relinquish_cookie(nfsi->fscache, 1);
+       nfsi->fscache = NULL;
+}
+
+/*
+ * Turn off the cache with regard to a per-inode cookie if opened for writing,
+ * invalidating all the pages in the page cache relating to the associated
+ * inode to clear the per-page caching.
+ */
+static void nfs_fscache_disable_inode_cookie(struct inode *inode)
+{
+       clear_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags);
+
+       if (NFS_I(inode)->fscache) {
+               dfprintk(FSCACHE,
+                        "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode));
+
+               /* Need to invalidate any mapped pages that were read in before
+                * turning off the cache.
+                */
+               if (inode->i_mapping && inode->i_mapping->nrpages)
+                       invalidate_inode_pages2(inode->i_mapping);
+
+               nfs_fscache_zap_inode_cookie(inode);
+       }
+}
+
+/*
+ * wait_on_bit() sleep function for uninterruptible waiting
+ */
+static int nfs_fscache_wait_bit(void *flags)
+{
+       schedule();
+       return 0;
+}
+
+/*
+ * Lock against someone else trying to also acquire or relinquish a cookie
+ */
+static inline void nfs_fscache_inode_lock(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       while (test_and_set_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags))
+               wait_on_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK,
+                           nfs_fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+}
+
+/*
+ * Unlock cookie management lock
+ */
+static inline void nfs_fscache_inode_unlock(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       smp_mb__before_clear_bit();
+       clear_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK);
+}
+
+/*
+ * Decide if we should enable or disable local caching for this inode.
+ * - For now, with NFS, only regular files that are open read-only will be able
+ *   to use the cache.
+ * - May be invoked multiple times in parallel by parallel nfs_open() functions.
+ */
+void nfs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
+{
+       if (NFS_FSCACHE(inode)) {
+               nfs_fscache_inode_lock(inode);
+               if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
+                       nfs_fscache_disable_inode_cookie(inode);
+               else
+                       nfs_fscache_enable_inode_cookie(inode);
+               nfs_fscache_inode_unlock(inode);
+       }
+}
+
+/*
+ * Replace a per-inode cookie due to revalidation detecting a file having
+ * changed on the server.
+ */
+void nfs_fscache_reset_inode_cookie(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct nfs_server *nfss = NFS_SERVER(inode);
+       struct fscache_cookie *old = nfsi->fscache;
+
+       nfs_fscache_inode_lock(inode);
+       if (nfsi->fscache) {
+               /* retire the current fscache cache and get a new one */
+               fscache_relinquish_cookie(nfsi->fscache, 1);
+
+               nfsi->fscache = fscache_acquire_cookie(
+                       nfss->nfs_client->fscache,
+                       &nfs_fscache_inode_object_def,
+                       nfsi);
+
+               dfprintk(FSCACHE,
+                        "NFS: revalidation new cookie (0x%p/0x%p/0x%p/0x%p)\n",
+                        nfss, nfsi, old, nfsi->fscache);
+       }
+       nfs_fscache_inode_unlock(inode);
+}
+
+/*
+ * Release the caching state associated with a page, if the page isn't busy
+ * interacting with the cache.
+ * - Returns true (can release page) or false (page busy).
+ */
+int nfs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       struct nfs_inode *nfsi = NFS_I(page->mapping->host);
+       struct fscache_cookie *cookie = nfsi->fscache;
+
+       BUG_ON(!cookie);
+
+       if (fscache_check_page_write(cookie, page)) {
+               if (!(gfp & __GFP_WAIT))
+                       return 0;
+               fscache_wait_on_page_write(cookie, page);
+       }
+
+       if (PageFsCache(page)) {
+               dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n",
+                        cookie, page, nfsi);
+
+               fscache_uncache_page(cookie, page);
+               nfs_add_fscache_stats(page->mapping->host,
+                                     NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
+       }
+
+       return 1;
+}
+
+/*
+ * Release the caching state associated with a page if undergoing complete page
+ * invalidation.
+ */
+void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct fscache_cookie *cookie = nfsi->fscache;
+
+       BUG_ON(!cookie);
+
+       dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n",
+                cookie, page, nfsi);
+
+       fscache_wait_on_page_write(cookie, page);
+
+       BUG_ON(!PageLocked(page));
+       fscache_uncache_page(cookie, page);
+       nfs_add_fscache_stats(page->mapping->host,
+                             NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
+}
+
+/*
+ * Handle completion of a page being read from the cache.
+ * - Called in process (keventd) context.
+ */
+static void nfs_readpage_from_fscache_complete(struct page *page,
+                                              void *context,
+                                              int error)
+{
+       dfprintk(FSCACHE,
+                "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n",
+                page, context, error);
+
+       /* if the read completes with an error, we just unlock the page and let
+        * the VM reissue the readpage */
+       if (!error) {
+               SetPageUptodate(page);
+               unlock_page(page);
+       } else {
+               error = nfs_readpage_async(context, page->mapping->host, page);
+               if (error)
+                       unlock_page(page);
+       }
+}
+
+/*
+ * Retrieve a page from fscache
+ */
+int __nfs_readpage_from_fscache(struct nfs_open_context *ctx,
+                               struct inode *inode, struct page *page)
+{
+       int ret;
+
+       dfprintk(FSCACHE,
+                "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n",
+                NFS_I(inode)->fscache, page, page->index, page->flags, inode);
+
+       ret = fscache_read_or_alloc_page(NFS_I(inode)->fscache,
+                                        page,
+                                        nfs_readpage_from_fscache_complete,
+                                        ctx,
+                                        GFP_KERNEL);
+
+       switch (ret) {
+       case 0: /* read BIO submitted (page in fscache) */
+               dfprintk(FSCACHE,
+                        "NFS:    readpage_from_fscache: BIO submitted\n");
+               nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK, 1);
+               return ret;
+
+       case -ENOBUFS: /* inode not in cache */
+       case -ENODATA: /* page not in cache */
+               nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1);
+               dfprintk(FSCACHE,
+                        "NFS:    readpage_from_fscache %d\n", ret);
+               return 1;
+
+       default:
+               dfprintk(FSCACHE, "NFS:    readpage_from_fscache %d\n", ret);
+               nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1);
+       }
+       return ret;
+}
+
+/*
+ * Retrieve a set of pages from fscache
+ */
+int __nfs_readpages_from_fscache(struct nfs_open_context *ctx,
+                                struct inode *inode,
+                                struct address_space *mapping,
+                                struct list_head *pages,
+                                unsigned *nr_pages)
+{
+       int ret, npages = *nr_pages;
+
+       dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n",
+                NFS_I(inode)->fscache, npages, inode);
+
+       ret = fscache_read_or_alloc_pages(NFS_I(inode)->fscache,
+                                         mapping, pages, nr_pages,
+                                         nfs_readpage_from_fscache_complete,
+                                         ctx,
+                                         mapping_gfp_mask(mapping));
+       if (*nr_pages < npages)
+               nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK,
+                                     npages);
+       if (*nr_pages > 0)
+               nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL,
+                                     *nr_pages);
+
+       switch (ret) {
+       case 0: /* read submitted to the cache for all pages */
+               BUG_ON(!list_empty(pages));
+               BUG_ON(*nr_pages != 0);
+               dfprintk(FSCACHE,
+                        "NFS: nfs_getpages_from_fscache: submitted\n");
+
+               return ret;
+
+       case -ENOBUFS: /* some pages aren't cached and can't be */
+       case -ENODATA: /* some pages aren't cached */
+               dfprintk(FSCACHE,
+                        "NFS: nfs_getpages_from_fscache: no page: %d\n", ret);
+               return 1;
+
+       default:
+               dfprintk(FSCACHE,
+                        "NFS: nfs_getpages_from_fscache: ret  %d\n", ret);
+       }
+
+       return ret;
+}
+
+/*
+ * Store a newly fetched page in fscache
+ * - PG_fscache must be set on the page
+ */
+void __nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
+{
+       int ret;
+
+       dfprintk(FSCACHE,
+                "NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx)/%d)\n",
+                NFS_I(inode)->fscache, page, page->index, page->flags, sync);
+
+       ret = fscache_write_page(NFS_I(inode)->fscache, page, GFP_KERNEL);
+       dfprintk(FSCACHE,
+                "NFS:     readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n",
+                page, page->index, page->flags, ret);
+
+       if (ret != 0) {
+               fscache_uncache_page(NFS_I(inode)->fscache, page);
+               nfs_add_fscache_stats(inode,
+                                     NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL, 1);
+               nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
+       } else {
+               nfs_add_fscache_stats(inode,
+                                     NFSIOS_FSCACHE_PAGES_WRITTEN_OK, 1);
+       }
+}
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
new file mode 100644 (file)
index 0000000..6e809bb
--- /dev/null
@@ -0,0 +1,220 @@
+/* NFS filesystem cache interface definitions
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _NFS_FSCACHE_H
+#define _NFS_FSCACHE_H
+
+#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
+#include <linux/fscache.h>
+
+#ifdef CONFIG_NFS_FSCACHE
+
+/*
+ * set of NFS FS-Cache objects that form a superblock key
+ */
+struct nfs_fscache_key {
+       struct rb_node          node;
+       struct nfs_client       *nfs_client;    /* the server */
+
+       /* the elements of the unique key - as used by nfs_compare_super() and
+        * nfs_compare_mount_options() to distinguish superblocks */
+       struct {
+               struct {
+                       unsigned long   s_flags;        /* various flags
+                                                        * (& NFS_MS_MASK) */
+               } super;
+
+               struct {
+                       struct nfs_fsid fsid;
+                       int             flags;
+                       unsigned int    rsize;          /* read size */
+                       unsigned int    wsize;          /* write size */
+                       unsigned int    acregmin;       /* attr cache timeouts */
+                       unsigned int    acregmax;
+                       unsigned int    acdirmin;
+                       unsigned int    acdirmax;
+               } nfs_server;
+
+               struct {
+                       rpc_authflavor_t au_flavor;
+               } rpc_auth;
+
+               /* uniquifier - can be used if nfs_server.flags includes
+                * NFS_MOUNT_UNSHARED  */
+               u8 uniq_len;
+               char uniquifier[0];
+       } key;
+};
+
+/*
+ * fscache-index.c
+ */
+extern struct fscache_netfs nfs_fscache_netfs;
+extern const struct fscache_cookie_def nfs_fscache_server_index_def;
+extern const struct fscache_cookie_def nfs_fscache_super_index_def;
+extern const struct fscache_cookie_def nfs_fscache_inode_object_def;
+
+extern int nfs_fscache_register(void);
+extern void nfs_fscache_unregister(void);
+
+/*
+ * fscache.c
+ */
+extern void nfs_fscache_get_client_cookie(struct nfs_client *);
+extern void nfs_fscache_release_client_cookie(struct nfs_client *);
+
+extern void nfs_fscache_get_super_cookie(struct super_block *,
+                                        struct nfs_parsed_mount_data *);
+extern void nfs_fscache_release_super_cookie(struct super_block *);
+
+extern void nfs_fscache_init_inode_cookie(struct inode *);
+extern void nfs_fscache_release_inode_cookie(struct inode *);
+extern void nfs_fscache_zap_inode_cookie(struct inode *);
+extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *);
+extern void nfs_fscache_reset_inode_cookie(struct inode *);
+
+extern void __nfs_fscache_invalidate_page(struct page *, struct inode *);
+extern int nfs_fscache_release_page(struct page *, gfp_t);
+
+extern int __nfs_readpage_from_fscache(struct nfs_open_context *,
+                                      struct inode *, struct page *);
+extern int __nfs_readpages_from_fscache(struct nfs_open_context *,
+                                       struct inode *, struct address_space *,
+                                       struct list_head *, unsigned *);
+extern void __nfs_readpage_to_fscache(struct inode *, struct page *, int);
+
+/*
+ * wait for a page to complete writing to the cache
+ */
+static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
+                                                 struct page *page)
+{
+       if (PageFsCache(page))
+               fscache_wait_on_page_write(nfsi->fscache, page);
+}
+
+/*
+ * release the caching state associated with a page if undergoing complete page
+ * invalidation
+ */
+static inline void nfs_fscache_invalidate_page(struct page *page,
+                                              struct inode *inode)
+{
+       if (PageFsCache(page))
+               __nfs_fscache_invalidate_page(page, inode);
+}
+
+/*
+ * Retrieve a page from an inode data storage object.
+ */
+static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx,
+                                           struct inode *inode,
+                                           struct page *page)
+{
+       if (NFS_I(inode)->fscache)
+               return __nfs_readpage_from_fscache(ctx, inode, page);
+       return -ENOBUFS;
+}
+
+/*
+ * Retrieve a set of pages from an inode data storage object.
+ */
+static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx,
+                                            struct inode *inode,
+                                            struct address_space *mapping,
+                                            struct list_head *pages,
+                                            unsigned *nr_pages)
+{
+       if (NFS_I(inode)->fscache)
+               return __nfs_readpages_from_fscache(ctx, inode, mapping, pages,
+                                                   nr_pages);
+       return -ENOBUFS;
+}
+
+/*
+ * Store a page newly fetched from the server in an inode data storage object
+ * in the cache.
+ */
+static inline void nfs_readpage_to_fscache(struct inode *inode,
+                                          struct page *page,
+                                          int sync)
+{
+       if (PageFsCache(page))
+               __nfs_readpage_to_fscache(inode, page, sync);
+}
+
+/*
+ * indicate the client caching state as readable text
+ */
+static inline const char *nfs_server_fscache_state(struct nfs_server *server)
+{
+       if (server->fscache && (server->options & NFS_OPTION_FSCACHE))
+               return "yes";
+       return "no ";
+}
+
+
+#else /* CONFIG_NFS_FSCACHE */
+static inline int nfs_fscache_register(void) { return 0; }
+static inline void nfs_fscache_unregister(void) {}
+
+static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {}
+static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {}
+
+static inline void nfs_fscache_get_super_cookie(
+       struct super_block *sb,
+       struct nfs_parsed_mount_data *data)
+{
+}
+static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {}
+
+static inline void nfs_fscache_init_inode_cookie(struct inode *inode) {}
+static inline void nfs_fscache_release_inode_cookie(struct inode *inode) {}
+static inline void nfs_fscache_zap_inode_cookie(struct inode *inode) {}
+static inline void nfs_fscache_set_inode_cookie(struct inode *inode,
+                                               struct file *filp) {}
+static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {}
+
+static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       return 1; /* True: may release page */
+}
+static inline void nfs_fscache_invalidate_page(struct page *page,
+                                              struct inode *inode) {}
+static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
+                                                 struct page *page) {}
+
+static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx,
+                                           struct inode *inode,
+                                           struct page *page)
+{
+       return -ENOBUFS;
+}
+static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx,
+                                            struct inode *inode,
+                                            struct address_space *mapping,
+                                            struct list_head *pages,
+                                            unsigned *nr_pages)
+{
+       return -ENOBUFS;
+}
+static inline void nfs_readpage_to_fscache(struct inode *inode,
+                                          struct page *page, int sync) {}
+
+static inline const char *nfs_server_fscache_state(struct nfs_server *server)
+{
+       return "no ";
+}
+
+#endif /* CONFIG_NFS_FSCACHE */
+#endif /* _NFS_FSCACHE_H */
index b7c9b2df1f299dd15d30b81d533b602d8ae09572..46177cb8706402cff250c18a7b10640deee0b38f 100644 (file)
@@ -156,7 +156,7 @@ int nfs4_path_walk(struct nfs_server *server,
                return ret;
        }
 
-       if (fattr.type != NFDIR) {
+       if (!S_ISDIR(fattr.mode)) {
                printk(KERN_ERR "nfs4_get_root:"
                       " getroot encountered non-directory\n");
                return -ENOTDIR;
@@ -213,7 +213,7 @@ eat_dot_dir:
                return ret;
        }
 
-       if (fattr.type != NFDIR) {
+       if (!S_ISDIR(fattr.mode)) {
                printk(KERN_ERR "nfs4_get_root:"
                       " lookupfh encountered non-directory\n");
                return -ENOTDIR;
index 0c381686171e30cc1eab1f71128bce7837bd22dd..64f87194d3907620709c5413f23c95324b23afd9 100644 (file)
@@ -46,6 +46,7 @@
 #include "delegation.h"
 #include "iostat.h"
 #include "internal.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
@@ -65,6 +66,18 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
        return nfs_fileid_to_ino_t(fattr->fileid);
 }
 
+/**
+ * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
+ * @word: long word containing the bit lock
+ */
+int nfs_wait_bit_killable(void *word)
+{
+       if (fatal_signal_pending(current))
+               return -ERESTARTSYS;
+       schedule();
+       return 0;
+}
+
 /**
  * nfs_compat_user_ino64 - returns the user-visible inode number
  * @fileid: 64-bit fileid
@@ -109,6 +122,7 @@ void nfs_clear_inode(struct inode *inode)
        BUG_ON(!list_empty(&NFS_I(inode)->open_files));
        nfs_zap_acl_cache(inode);
        nfs_access_zap_cache(inode);
+       nfs_fscache_release_inode_cookie(inode);
 }
 
 /**
@@ -249,13 +263,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
        struct inode *inode = ERR_PTR(-ENOENT);
        unsigned long hash;
 
-       if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
                goto out_no_inode;
-
-       if (!fattr->nlink) {
-               printk("NFS: Buggy server - nlink == 0!\n");
+       if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
                goto out_no_inode;
-       }
 
        hash = nfs_fattr_to_ino_t(fattr);
 
@@ -291,7 +302,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                            && fattr->size <= NFS_LIMIT_READDIRPLUS)
                                set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        /* Deal with crossing mountpoints */
-                       if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
+                       if ((fattr->valid & NFS_ATTR_FATTR_FSID)
+                                       && !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
                                if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
                                        inode->i_op = &nfs_referral_inode_operations;
                                else
@@ -304,30 +316,49 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                else
                        init_special_inode(inode, inode->i_mode, fattr->rdev);
 
+               memset(&inode->i_atime, 0, sizeof(inode->i_atime));
+               memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
+               memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
+               nfsi->change_attr = 0;
+               inode->i_size = 0;
+               inode->i_nlink = 0;
+               inode->i_uid = -2;
+               inode->i_gid = -2;
+               inode->i_blocks = 0;
+               memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
+
                nfsi->read_cache_jiffies = fattr->time_start;
                nfsi->attr_gencount = fattr->gencount;
-               inode->i_atime = fattr->atime;
-               inode->i_mtime = fattr->mtime;
-               inode->i_ctime = fattr->ctime;
-               if (fattr->valid & NFS_ATTR_FATTR_V4)
+               if (fattr->valid & NFS_ATTR_FATTR_ATIME)
+                       inode->i_atime = fattr->atime;
+               if (fattr->valid & NFS_ATTR_FATTR_MTIME)
+                       inode->i_mtime = fattr->mtime;
+               if (fattr->valid & NFS_ATTR_FATTR_CTIME)
+                       inode->i_ctime = fattr->ctime;
+               if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        nfsi->change_attr = fattr->change_attr;
-               inode->i_size = nfs_size_to_loff_t(fattr->size);
-               inode->i_nlink = fattr->nlink;
-               inode->i_uid = fattr->uid;
-               inode->i_gid = fattr->gid;
-               if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
+               if (fattr->valid & NFS_ATTR_FATTR_SIZE)
+                       inode->i_size = nfs_size_to_loff_t(fattr->size);
+               if (fattr->valid & NFS_ATTR_FATTR_NLINK)
+                       inode->i_nlink = fattr->nlink;
+               if (fattr->valid & NFS_ATTR_FATTR_OWNER)
+                       inode->i_uid = fattr->uid;
+               if (fattr->valid & NFS_ATTR_FATTR_GROUP)
+                       inode->i_gid = fattr->gid;
+               if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
+                       inode->i_blocks = fattr->du.nfs2.blocks;
+               if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
                        /*
                         * report the blocks in 512byte units
                         */
                        inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
-               } else {
-                       inode->i_blocks = fattr->du.nfs2.blocks;
                }
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
-               memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
                nfsi->access_cache = RB_ROOT;
 
+               nfs_fscache_init_inode_cookie(inode);
+
                unlock_new_inode(inode);
        } else
                nfs_refresh_inode(inode, fattr);
@@ -514,6 +545,32 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        return err;
 }
 
+/**
+ * nfs_close_context - Common close_context() routine NFSv2/v3
+ * @ctx: pointer to context
+ * @is_sync: is this a synchronous close
+ *
+ * always ensure that the attributes are up to date if we're mounted
+ * with close-to-open semantics
+ */
+void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
+{
+       struct inode *inode;
+       struct nfs_server *server;
+
+       if (!(ctx->mode & FMODE_WRITE))
+               return;
+       if (!is_sync)
+               return;
+       inode = ctx->path.dentry->d_inode;
+       if (!list_empty(&NFS_I(inode)->open_files))
+               return;
+       server = NFS_SERVER(inode);
+       if (server->flags & NFS_MOUNT_NOCTO)
+               return;
+       nfs_revalidate_inode(server, inode);
+}
+
 static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred)
 {
        struct nfs_open_context *ctx;
@@ -540,24 +597,15 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
        return ctx;
 }
 
-static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
+static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
 {
-       struct inode *inode;
-
-       if (ctx == NULL)
-               return;
+       struct inode *inode = ctx->path.dentry->d_inode;
 
-       inode = ctx->path.dentry->d_inode;
        if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
                return;
        list_del(&ctx->list);
        spin_unlock(&inode->i_lock);
-       if (ctx->state != NULL) {
-               if (wait)
-                       nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
-               else
-                       nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
-       }
+       NFS_PROTO(inode)->close_context(ctx, is_sync);
        if (ctx->cred != NULL)
                put_rpccred(ctx->cred);
        path_put(&ctx->path);
@@ -642,6 +690,7 @@ int nfs_open(struct inode *inode, struct file *filp)
        ctx->mode = filp->f_mode;
        nfs_file_set_open_context(filp, ctx);
        put_nfs_open_context(ctx);
+       nfs_fscache_set_inode_cookie(inode, filp);
        return 0;
 }
 
@@ -670,9 +719,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        if (NFS_STALE(inode))
                goto out;
 
-       if (NFS_STALE(inode))
-               goto out;
-
        nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
        status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
        if (status != 0) {
@@ -745,6 +791,7 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa
                memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
        spin_unlock(&inode->i_lock);
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
+       nfs_fscache_reset_inode_cookie(inode);
        dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
                        inode->i_sb->s_id, (long long)NFS_FILEID(inode));
        return 0;
@@ -815,25 +862,31 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
-                       nfsi->change_attr == fattr->pre_change_attr) {
+       if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
+                       && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
+                       && nfsi->change_attr == fattr->pre_change_attr) {
                nfsi->change_attr = fattr->change_attr;
                if (S_ISDIR(inode->i_mode))
                        nfsi->cache_validity |= NFS_INO_INVALID_DATA;
        }
        /* If we have atomic WCC data, we may update some attributes */
-       if ((fattr->valid & NFS_ATTR_WCC) != 0) {
-               if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
+       if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
+                       && (fattr->valid & NFS_ATTR_FATTR_CTIME)
+                       && timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
                        memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-               if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
+
+       if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
+                       && (fattr->valid & NFS_ATTR_FATTR_MTIME)
+                       && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
                        memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
                        if (S_ISDIR(inode->i_mode))
                                nfsi->cache_validity |= NFS_INO_INVALID_DATA;
-               }
-               if (i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) &&
-                   nfsi->npages == 0)
-                       i_size_write(inode, nfs_size_to_loff_t(fattr->size));
        }
+       if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
+                       && (fattr->valid & NFS_ATTR_FATTR_SIZE)
+                       && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
+                       && nfsi->npages == 0)
+                       i_size_write(inode, nfs_size_to_loff_t(fattr->size));
 }
 
 /**
@@ -853,35 +906,39 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
 
 
        /* Has the inode gone and changed behind our back? */
-       if (nfsi->fileid != fattr->fileid
-                       || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
+       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
+               return -EIO;
+       if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
                return -EIO;
-       }
 
-       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+       if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
                        nfsi->change_attr != fattr->change_attr)
                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
        /* Verify a few of the more important attributes */
-       if (!timespec_equal(&inode->i_mtime, &fattr->mtime))
+       if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
-       cur_size = i_size_read(inode);
-       new_isize = nfs_size_to_loff_t(fattr->size);
-       if (cur_size != new_isize && nfsi->npages == 0)
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+       if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
+               cur_size = i_size_read(inode);
+               new_isize = nfs_size_to_loff_t(fattr->size);
+               if (cur_size != new_isize && nfsi->npages == 0)
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+       }
 
        /* Have any file permissions changed? */
-       if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
-                       || inode->i_uid != fattr->uid
-                       || inode->i_gid != fattr->gid)
+       if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
+               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+       if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid)
+               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+       if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid)
                invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
 
        /* Has the link count changed? */
-       if (inode->i_nlink != fattr->nlink)
+       if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
                invalid |= NFS_INO_INVALID_ATTR;
 
-       if (!timespec_equal(&inode->i_atime, &fattr->atime))
+       if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
                invalid |= NFS_INO_INVALID_ATIME;
 
        if (invalid != 0)
@@ -893,11 +950,15 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
 
 static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
 {
+       if (!(fattr->valid & NFS_ATTR_FATTR_CTIME))
+               return 0;
        return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
 }
 
 static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
 {
+       if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
+               return 0;
        return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
 }
 
@@ -975,6 +1036,7 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
        spin_lock(&inode->i_lock);
        status = nfs_refresh_inode_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
+
        return status;
 }
 
@@ -1033,20 +1095,31 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
        /* Don't do a WCC update if these attributes are already stale */
        if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
                        !nfs_inode_attrs_need_update(inode, fattr)) {
-               fattr->valid &= ~(NFS_ATTR_WCC_V4|NFS_ATTR_WCC);
+               fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
+                               | NFS_ATTR_FATTR_PRESIZE
+                               | NFS_ATTR_FATTR_PREMTIME
+                               | NFS_ATTR_FATTR_PRECTIME);
                goto out_noforce;
        }
-       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
-                       (fattr->valid & NFS_ATTR_WCC_V4) == 0) {
+       if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
                fattr->pre_change_attr = NFS_I(inode)->change_attr;
-               fattr->valid |= NFS_ATTR_WCC_V4;
+               fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
        }
-       if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
-                       (fattr->valid & NFS_ATTR_WCC) == 0) {
+       if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
                memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
+               fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
+       }
+       if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
                memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
+               fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
+       }
+       if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
+                       (fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
                fattr->pre_size = i_size_read(inode);
-               fattr->valid |= NFS_ATTR_WCC;
+               fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
        }
 out_noforce:
        status = nfs_post_op_update_inode_locked(inode, fattr);
@@ -1078,18 +1151,18 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        __func__, inode->i_sb->s_id, inode->i_ino,
                        atomic_read(&inode->i_count), fattr->valid);
 
-       if (nfsi->fileid != fattr->fileid)
+       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
                goto out_fileid;
 
        /*
         * Make sure the inode's type hasn't changed.
         */
-       if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
+       if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
                goto out_changed;
 
        server = NFS_SERVER(inode);
        /* Update the fsid? */
-       if (S_ISDIR(inode->i_mode) &&
+       if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
                        !nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
                        !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
                server->fsid = fattr->fsid;
@@ -1099,14 +1172,27 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
         */
        nfsi->read_cache_jiffies = fattr->time_start;
 
-       nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME
-                       | NFS_INO_REVAL_PAGECACHE);
+       if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME)))
+           nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
+                   | NFS_INO_INVALID_ATIME
+                   | NFS_INO_REVAL_PAGECACHE);
 
        /* Do atomic weak cache consistency updates */
        nfs_wcc_update_inode(inode, fattr);
 
        /* More cache consistency checks */
-       if (!(fattr->valid & NFS_ATTR_FATTR_V4)) {
+       if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
+               if (nfsi->change_attr != fattr->change_attr) {
+                       dprintk("NFS: change_attr change on server for file %s/%ld\n",
+                                       inode->i_sb->s_id, inode->i_ino);
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       if (S_ISDIR(inode->i_mode))
+                               nfs_force_lookup_revalidate(inode);
+                       nfsi->change_attr = fattr->change_attr;
+               }
+       }
+
+       if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
                /* NFSv2/v3: Check if the mtime agrees */
                if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
                        dprintk("NFS: mtime change on server for file %s/%ld\n",
@@ -1114,59 +1200,80 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                        if (S_ISDIR(inode->i_mode))
                                nfs_force_lookup_revalidate(inode);
+                       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
                }
+       }
+       if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
                /* If ctime has changed we should definitely clear access+acl caches */
-               if (!timespec_equal(&inode->i_ctime, &fattr->ctime))
+               if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-       } else if (nfsi->change_attr != fattr->change_attr) {
-               dprintk("NFS: change_attr change on server for file %s/%ld\n",
-                               inode->i_sb->s_id, inode->i_ino);
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-               if (S_ISDIR(inode->i_mode))
-                       nfs_force_lookup_revalidate(inode);
+                       /* and probably clear data for a directory too as utimes can cause
+                        * havoc with our cache.
+                        */
+                       if (S_ISDIR(inode->i_mode)) {
+                               invalid |= NFS_INO_INVALID_DATA;
+                               nfs_force_lookup_revalidate(inode);
+                       }
+                       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+               }
        }
 
        /* Check if our cached file size is stale */
-       new_isize = nfs_size_to_loff_t(fattr->size);
-       cur_isize = i_size_read(inode);
-       if (new_isize != cur_isize) {
-               /* Do we perhaps have any outstanding writes, or has
-                * the file grown beyond our last write? */
-               if (nfsi->npages == 0 || new_isize > cur_isize) {
-                       i_size_write(inode, new_isize);
-                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+       if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
+               new_isize = nfs_size_to_loff_t(fattr->size);
+               cur_isize = i_size_read(inode);
+               if (new_isize != cur_isize) {
+                       /* Do we perhaps have any outstanding writes, or has
+                        * the file grown beyond our last write? */
+                       if (nfsi->npages == 0 || new_isize > cur_isize) {
+                               i_size_write(inode, new_isize);
+                               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+                       }
+                       dprintk("NFS: isize change on server for file %s/%ld\n",
+                                       inode->i_sb->s_id, inode->i_ino);
                }
-               dprintk("NFS: isize change on server for file %s/%ld\n",
-                               inode->i_sb->s_id, inode->i_ino);
        }
 
 
-       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-       memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
-       nfsi->change_attr = fattr->change_attr;
-
-       if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
-           inode->i_uid != fattr->uid ||
-           inode->i_gid != fattr->gid)
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+       if (fattr->valid & NFS_ATTR_FATTR_ATIME)
+               memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
 
-       if (inode->i_nlink != fattr->nlink)
-               invalid |= NFS_INO_INVALID_ATTR;
+       if (fattr->valid & NFS_ATTR_FATTR_MODE) {
+               if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       inode->i_mode = fattr->mode;
+               }
+       }
+       if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
+               if (inode->i_uid != fattr->uid) {
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       inode->i_uid = fattr->uid;
+               }
+       }
+       if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
+               if (inode->i_gid != fattr->gid) {
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+                       inode->i_gid = fattr->gid;
+               }
+       }
 
-       inode->i_mode = fattr->mode;
-       inode->i_nlink = fattr->nlink;
-       inode->i_uid = fattr->uid;
-       inode->i_gid = fattr->gid;
+       if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
+               if (inode->i_nlink != fattr->nlink) {
+                       invalid |= NFS_INO_INVALID_ATTR;
+                       if (S_ISDIR(inode->i_mode))
+                               invalid |= NFS_INO_INVALID_DATA;
+                       inode->i_nlink = fattr->nlink;
+               }
+       }
 
-       if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
+       if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
                /*
                 * report the blocks in 512byte units
                 */
                inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
-       } else {
-               inode->i_blocks = fattr->du.nfs2.blocks;
        }
+       if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
+               inode->i_blocks = fattr->du.nfs2.blocks;
 
        /* Update attrtimeo value if we're out of the unstable period */
        if (invalid & NFS_INO_INVALID_ATTR) {
@@ -1274,7 +1381,6 @@ static void init_once(void *foo)
        INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
        INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
        INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
-       nfsi->ncommit = 0;
        nfsi->npages = 0;
        atomic_set(&nfsi->silly_count, 1);
        INIT_HLIST_HEAD(&nfsi->silly_list);
@@ -1337,6 +1443,10 @@ static int __init init_nfs_fs(void)
 {
        int err;
 
+       err = nfs_fscache_register();
+       if (err < 0)
+               goto out7;
+
        err = nfsiod_start();
        if (err)
                goto out6;
@@ -1389,6 +1499,8 @@ out4:
 out5:
        nfsiod_stop();
 out6:
+       nfs_fscache_unregister();
+out7:
        return err;
 }
 
@@ -1399,6 +1511,7 @@ static void __exit exit_nfs_fs(void)
        nfs_destroy_readpagecache();
        nfs_destroy_inodecache();
        nfs_destroy_nfspagecache();
+       nfs_fscache_unregister();
 #ifdef CONFIG_PROC_FS
        rpc_proc_unregister("nfs");
 #endif
index 340ede8f608fe3402952890e7d82f26c004cbb65..e4d6a8348adf5178a8d7d63b85a96fe22e0d129b 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/mount.h>
 #include <linux/security.h>
 
+#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
+
 struct nfs_string;
 
 /* Maximum number of readahead requests
@@ -37,10 +39,12 @@ struct nfs_parsed_mount_data {
        int                     acregmin, acregmax,
                                acdirmin, acdirmax;
        int                     namlen;
+       unsigned int            options;
        unsigned int            bsize;
        unsigned int            auth_flavor_len;
        rpc_authflavor_t        auth_flavors[1];
        char                    *client_address;
+       char                    *fscache_uniq;
 
        struct {
                struct sockaddr_storage address;
@@ -152,6 +156,9 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
 #endif
 
+/* proc.c */
+void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
+
 /* dir.c */
 extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
 
@@ -165,6 +172,7 @@ extern void nfs_clear_inode(struct inode *);
 extern void nfs4_clear_inode(struct inode *);
 #endif
 void nfs_zap_acl_cache(struct inode *inode);
+extern int nfs_wait_bit_killable(void *word);
 
 /* super.c */
 void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *);
index a36952810032f8c492acb4e1f4f96c7494250b3f..a2ab2529b5ca4ee1c1ac2b8e3889e4651bb8f1ac 100644 (file)
@@ -16,6 +16,9 @@
 
 struct nfs_iostats {
        unsigned long long      bytes[__NFSIOS_BYTESMAX];
+#ifdef CONFIG_NFS_FSCACHE
+       unsigned long long      fscache[__NFSIOS_FSCACHEMAX];
+#endif
        unsigned long           events[__NFSIOS_COUNTSMAX];
 } ____cacheline_aligned;
 
@@ -57,6 +60,21 @@ static inline void nfs_add_stats(const struct inode *inode,
        nfs_add_server_stats(NFS_SERVER(inode), stat, addend);
 }
 
+#ifdef CONFIG_NFS_FSCACHE
+static inline void nfs_add_fscache_stats(struct inode *inode,
+                                        enum nfs_stat_fscachecounters stat,
+                                        unsigned long addend)
+{
+       struct nfs_iostats *iostats;
+       int cpu;
+
+       cpu = get_cpu();
+       iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu);
+       iostats->fscache[stat] += addend;
+       put_cpu_no_resched();
+}
+#endif
+
 static inline struct nfs_iostats *nfs_alloc_iostats(void)
 {
        return alloc_percpu(struct nfs_iostats);
index 28bab67d1519bc23b1db1d190713e7971fe79d94..c862c9340f9a4598d3391c44d557187ec5b06871 100644 (file)
@@ -120,8 +120,8 @@ xdr_decode_time(__be32 *p, struct timespec *timep)
 static __be32 *
 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 {
-       u32 rdev;
-       fattr->type = (enum nfs_ftype) ntohl(*p++);
+       u32 rdev, type;
+       type = ntohl(*p++);
        fattr->mode = ntohl(*p++);
        fattr->nlink = ntohl(*p++);
        fattr->uid = ntohl(*p++);
@@ -136,10 +136,9 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
        p = xdr_decode_time(p, &fattr->atime);
        p = xdr_decode_time(p, &fattr->mtime);
        p = xdr_decode_time(p, &fattr->ctime);
-       fattr->valid |= NFS_ATTR_FATTR;
+       fattr->valid |= NFS_ATTR_FATTR_V2;
        fattr->rdev = new_decode_dev(rdev);
-       if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
-               fattr->type = NFFIFO;
+       if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
                fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
                fattr->rdev = 0;
        }
index c55be7a7679e27f6c011766add0b2bf8e9cfc447..d0cc5ce0edfe8ada1d9598143e291c3683882393 100644 (file)
@@ -328,7 +328,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                data->arg.create.verifier[1] = current->pid;
        }
 
-       sattr->ia_mode &= ~current->fs->umask;
+       sattr->ia_mode &= ~current_umask();
 
        for (;;) {
                status = nfs3_do_create(dir, dentry, data);
@@ -528,7 +528,7 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 
        dprintk("NFS call  mkdir %s\n", dentry->d_name.name);
 
-       sattr->ia_mode &= ~current->fs->umask;
+       sattr->ia_mode &= ~current_umask();
 
        data = nfs3_alloc_createdata();
        if (data == NULL)
@@ -639,7 +639,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        dprintk("NFS call  mknod %s %u:%u\n", dentry->d_name.name,
                        MAJOR(rdev), MINOR(rdev));
 
-       sattr->ia_mode &= ~current->fs->umask;
+       sattr->ia_mode &= ~current_umask();
 
        data = nfs3_alloc_createdata();
        if (data == NULL)
@@ -834,4 +834,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .commit_done    = nfs3_commit_done,
        .lock           = nfs3_proc_lock,
        .clear_acl_cache = nfs3_forget_cached_acls,
+       .close_context  = nfs_close_context,
 };
index 6cdeacffde469143045588c6b20e6cff72cc586a..e6a1932c7110a245d77b0595d7ad57778ee3aad6 100644 (file)
 /*
  * Map file type to S_IFMT bits
  */
-static struct {
-       unsigned int    mode;
-       unsigned int    nfs2type;
-} nfs_type2fmt[] = {
-      { 0,             NFNON   },
-      { S_IFREG,       NFREG   },
-      { S_IFDIR,       NFDIR   },
-      { S_IFBLK,       NFBLK   },
-      { S_IFCHR,       NFCHR   },
-      { S_IFLNK,       NFLNK   },
-      { S_IFSOCK,      NFSOCK  },
-      { S_IFIFO,       NFFIFO  },
-      { 0,             NFBAD   }
+static const umode_t nfs_type2fmt[] = {
+       [NF3BAD] = 0,
+       [NF3REG] = S_IFREG,
+       [NF3DIR] = S_IFDIR,
+       [NF3BLK] = S_IFBLK,
+       [NF3CHR] = S_IFCHR,
+       [NF3LNK] = S_IFLNK,
+       [NF3SOCK] = S_IFSOCK,
+       [NF3FIFO] = S_IFIFO,
 };
 
 /*
@@ -148,13 +144,12 @@ static __be32 *
 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 {
        unsigned int    type, major, minor;
-       int             fmode;
+       umode_t         fmode;
 
        type = ntohl(*p++);
-       if (type >= NF3BAD)
-               type = NF3BAD;
-       fmode = nfs_type2fmt[type].mode;
-       fattr->type = nfs_type2fmt[type].nfs2type;
+       if (type > NF3FIFO)
+               type = NF3NON;
+       fmode = nfs_type2fmt[type];
        fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
        fattr->nlink = ntohl(*p++);
        fattr->uid = ntohl(*p++);
@@ -177,7 +172,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
        p = xdr_decode_time3(p, &fattr->ctime);
 
        /* Update the mode bits */
-       fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
+       fattr->valid |= NFS_ATTR_FATTR_V3;
        return p;
 }
 
@@ -233,7 +228,9 @@ xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
        p = xdr_decode_hyper(p, &fattr->pre_size);
        p = xdr_decode_time3(p, &fattr->pre_mtime);
        p = xdr_decode_time3(p, &fattr->pre_ctime);
-       fattr->valid |= NFS_ATTR_WCC;
+       fattr->valid |= NFS_ATTR_FATTR_PRESIZE
+               | NFS_ATTR_FATTR_PREMTIME
+               | NFS_ATTR_FATTR_PRECTIME;
        return p;
 }
 
index 8dde84b988d9cd349604eb4663a70fc4333fe367..a4d242680299fa91795fc43ffe7492c63cf4dedf 100644 (file)
@@ -193,14 +193,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
        kunmap_atomic(start, KM_USER0);
 }
 
-static int nfs4_wait_bit_killable(void *word)
-{
-       if (fatal_signal_pending(current))
-               return -ERESTARTSYS;
-       schedule();
-       return 0;
-}
-
 static int nfs4_wait_clnt_recover(struct nfs_client *clp)
 {
        int res;
@@ -208,7 +200,7 @@ static int nfs4_wait_clnt_recover(struct nfs_client *clp)
        might_sleep();
 
        res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
-                       nfs4_wait_bit_killable, TASK_KILLABLE);
+                       nfs_wait_bit_killable, TASK_KILLABLE);
        return res;
 }
 
@@ -1439,7 +1431,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
        if (calldata->arg.seqid == NULL)
                goto out_free_calldata;
        calldata->arg.fmode = 0;
-       calldata->arg.bitmask = server->attr_bitmask;
+       calldata->arg.bitmask = server->cache_consistency_bitmask;
        calldata->res.fattr = &calldata->fattr;
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
@@ -1509,7 +1501,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
                attr.ia_mode = nd->intent.open.create_mode;
                attr.ia_valid = ATTR_MODE;
                if (!IS_POSIXACL(dir))
-                       attr.ia_mode &= ~current->fs->umask;
+                       attr.ia_mode &= ~current_umask();
        } else {
                attr.ia_valid = 0;
                BUG_ON(nd->intent.open.flags & O_CREAT);
@@ -1580,6 +1572,15 @@ out_drop:
        return 0;
 }
 
+void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
+{
+       if (ctx->state == NULL)
+               return;
+       if (is_sync)
+               nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
+       else
+               nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
+}
 
 static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 {
@@ -1600,6 +1601,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                        server->caps |= NFS_CAP_HARDLINKS;
                if (res.has_symlinks != 0)
                        server->caps |= NFS_CAP_SYMLINKS;
+               memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
+               server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
+               server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
                server->acl_bitmask = res.acl_bitmask;
        }
        return status;
@@ -2079,7 +2083,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
        struct nfs_removeargs *args = msg->rpc_argp;
        struct nfs_removeres *res = msg->rpc_resp;
 
-       args->bitmask = server->attr_bitmask;
+       args->bitmask = server->cache_consistency_bitmask;
        res->server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
 }
@@ -2323,7 +2327,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
                .pages = &page,
                .pgbase = 0,
                .count = count,
-               .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
+               .bitmask = NFS_SERVER(dentry->d_inode)->cache_consistency_bitmask,
        };
        struct nfs4_readdir_res res;
        struct rpc_message msg = {
@@ -2552,7 +2556,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 {
        struct nfs_server *server = NFS_SERVER(data->inode);
 
-       data->args.bitmask = server->attr_bitmask;
+       data->args.bitmask = server->cache_consistency_bitmask;
        data->res.server = server;
        data->timestamp   = jiffies;
 
@@ -2575,7 +2579,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
 {
        struct nfs_server *server = NFS_SERVER(data->inode);
        
-       data->args.bitmask = server->attr_bitmask;
+       data->args.bitmask = server->cache_consistency_bitmask;
        data->res.server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
 }
@@ -3678,6 +3682,19 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
        return len;
 }
 
+static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
+{
+       if (!((fattr->valid & NFS_ATTR_FATTR_FILEID) &&
+               (fattr->valid & NFS_ATTR_FATTR_FSID) &&
+               (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
+               return;
+
+       fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
+               NFS_ATTR_FATTR_NLINK;
+       fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+       fattr->nlink = 2;
+}
+
 int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
                struct nfs4_fs_locations *fs_locations, struct page *page)
 {
@@ -3704,6 +3721,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
        fs_locations->server = server;
        fs_locations->nlocations = 0;
        status = rpc_call_sync(server->client, &msg, 0);
+       nfs_fixup_referral_attributes(&fs_locations->fattr);
        dprintk("%s: returned status = %d\n", __func__, status);
        return status;
 }
@@ -3767,6 +3785,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .commit_done    = nfs4_commit_done,
        .lock           = nfs4_proc_lock,
        .clear_acl_cache = nfs4_zap_acl_attr,
+       .close_context  = nfs4_close_context,
 };
 
 /*
index 2022fe47966f52d641496fe633ad0d0b98b15fc7..0298e909559fdc67f0bc5e7bab885595743e90a1 100644 (file)
@@ -62,8 +62,14 @@ static LIST_HEAD(nfs4_clientid_list);
 
 static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
 {
-       int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
-                       nfs_callback_tcpport, cred);
+       unsigned short port;
+       int status;
+
+       port = nfs_callback_tcpport;
+       if (clp->cl_addr.ss_family == AF_INET6)
+               port = nfs_callback_tcpport6;
+
+       status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred);
        if (status == 0)
                status = nfs4_proc_setclientid_confirm(clp, cred);
        if (status == 0)
index d1e4c8f8a0a9e8b5106564cf71986579340efa77..1690f0e44b9169bf0d0277b98f1a43776b0bd18a 100644 (file)
@@ -522,20 +522,17 @@ static int nfs4_stat_to_errno(int);
                                 decode_lookup_maxsz + \
                                 decode_fs_locations_maxsz)
 
-static struct {
-       unsigned int    mode;
-       unsigned int    nfs2type;
-} nfs_type2fmt[] = {
-       { 0,            NFNON        },
-       { S_IFREG,      NFREG        },
-       { S_IFDIR,      NFDIR        },
-       { S_IFBLK,      NFBLK        },
-       { S_IFCHR,      NFCHR        },
-       { S_IFLNK,      NFLNK        },
-       { S_IFSOCK,     NFSOCK       },
-       { S_IFIFO,      NFFIFO       },
-       { 0,            NFNON        },
-       { 0,            NFNON        },
+static const umode_t nfs_type2fmt[] = {
+       [NF4BAD] = 0,
+       [NF4REG] = S_IFREG,
+       [NF4DIR] = S_IFDIR,
+       [NF4BLK] = S_IFBLK,
+       [NF4CHR] = S_IFCHR,
+       [NF4LNK] = S_IFLNK,
+       [NF4SOCK] = S_IFSOCK,
+       [NF4FIFO] = S_IFIFO,
+       [NF4ATTRDIR] = 0,
+       [NF4NAMEDATTR] = 0,
 };
 
 struct compound_hdr {
@@ -2160,6 +2157,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
 static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
 {
        __be32 *p;
+       int ret = 0;
 
        *type = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
@@ -2172,14 +2170,16 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
                        return -EIO;
                }
                bitmap[0] &= ~FATTR4_WORD0_TYPE;
+               ret = NFS_ATTR_FATTR_TYPE;
        }
-       dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type].nfs2type);
-       return 0;
+       dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
+       return ret;
 }
 
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
        __be32 *p;
+       int ret = 0;
 
        *change = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
@@ -2188,15 +2188,17 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
                READ_BUF(8);
                READ64(*change);
                bitmap[0] &= ~FATTR4_WORD0_CHANGE;
+               ret = NFS_ATTR_FATTR_CHANGE;
        }
        dprintk("%s: change attribute=%Lu\n", __func__,
                        (unsigned long long)*change);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
 {
        __be32 *p;
+       int ret = 0;
 
        *size = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
@@ -2205,9 +2207,10 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *
                READ_BUF(8);
                READ64(*size);
                bitmap[0] &= ~FATTR4_WORD0_SIZE;
+               ret = NFS_ATTR_FATTR_SIZE;
        }
        dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
@@ -2245,6 +2248,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
 static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
 {
        __be32 *p;
+       int ret = 0;
 
        fsid->major = 0;
        fsid->minor = 0;
@@ -2255,11 +2259,12 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs
                READ64(fsid->major);
                READ64(fsid->minor);
                bitmap[0] &= ~FATTR4_WORD0_FSID;
+               ret = NFS_ATTR_FATTR_FSID;
        }
        dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
                        (unsigned long long)fsid->major,
                        (unsigned long long)fsid->minor);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
@@ -2297,6 +2302,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
 static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
+       int ret = 0;
 
        *fileid = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
@@ -2305,14 +2311,16 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
                READ_BUF(8);
                READ64(*fileid);
                bitmap[0] &= ~FATTR4_WORD0_FILEID;
+               ret = NFS_ATTR_FATTR_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
+       int ret = 0;
 
        *fileid = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
@@ -2321,9 +2329,10 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
                READ_BUF(8);
                READ64(*fileid);
                bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+               ret = NFS_ATTR_FATTR_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
@@ -2479,6 +2488,8 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
                if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
                        res->nlocations++;
        }
+       if (res->nlocations != 0)
+               status = NFS_ATTR_FATTR_V4_REFERRAL;
 out:
        dprintk("%s: fs_locations done, error = %d\n", __func__, status);
        return status;
@@ -2580,26 +2591,30 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32
        return status;
 }
 
-static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
+static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
 {
+       uint32_t tmp;
        __be32 *p;
+       int ret = 0;
 
        *mode = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
                READ_BUF(4);
-               READ32(*mode);
-               *mode &= ~S_IFMT;
+               READ32(tmp);
+               *mode = tmp & ~S_IFMT;
                bitmap[1] &= ~FATTR4_WORD1_MODE;
+               ret = NFS_ATTR_FATTR_MODE;
        }
        dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
 {
        __be32 *p;
+       int ret = 0;
 
        *nlink = 1;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
@@ -2608,15 +2623,17 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
                READ_BUF(4);
                READ32(*nlink);
                bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
+               ret = NFS_ATTR_FATTR_NLINK;
        }
        dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid)
 {
        uint32_t len;
        __be32 *p;
+       int ret = 0;
 
        *uid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
@@ -2626,7 +2643,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                READ32(len);
                READ_BUF(len);
                if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0)
+                       if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
+                               ret = NFS_ATTR_FATTR_OWNER;
+                       else
                                dprintk("%s: nfs_map_name_to_uid failed!\n",
                                                __func__);
                } else
@@ -2635,13 +2654,14 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                bitmap[1] &= ~FATTR4_WORD1_OWNER;
        }
        dprintk("%s: uid=%d\n", __func__, (int)*uid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid)
 {
        uint32_t len;
        __be32 *p;
+       int ret = 0;
 
        *gid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
@@ -2651,7 +2671,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                READ32(len);
                READ_BUF(len);
                if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0)
+                       if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
+                               ret = NFS_ATTR_FATTR_GROUP;
+                       else
                                dprintk("%s: nfs_map_group_to_gid failed!\n",
                                                __func__);
                } else
@@ -2660,13 +2682,14 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
        }
        dprintk("%s: gid=%d\n", __func__, (int)*gid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
 {
        uint32_t major = 0, minor = 0;
        __be32 *p;
+       int ret = 0;
 
        *rdev = MKDEV(0,0);
        if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
@@ -2681,9 +2704,10 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde
                if (MAJOR(tmp) == major && MINOR(tmp) == minor)
                        *rdev = tmp;
                bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
+               ret = NFS_ATTR_FATTR_RDEV;
        }
        dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
@@ -2740,6 +2764,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
 static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
 {
        __be32 *p;
+       int ret = 0;
 
        *used = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
@@ -2748,10 +2773,11 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint
                READ_BUF(8);
                READ64(*used);
                bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
+               ret = NFS_ATTR_FATTR_SPACE_USED;
        }
        dprintk("%s: space used=%Lu\n", __func__,
                        (unsigned long long)*used);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
@@ -2778,6 +2804,8 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_ATIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
        }
        dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
@@ -2794,6 +2822,8 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_CTIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
        }
        dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
@@ -2810,6 +2840,8 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_MTIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
        }
        dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
@@ -2994,63 +3026,116 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
        uint32_t attrlen,
                 bitmap[2] = {0},
                 type;
-       int status, fmode = 0;
+       int status;
+       umode_t fmode = 0;
        uint64_t fileid;
 
-       if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
-               goto xdr_error;
-       if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+       status = decode_op_hdr(xdr, OP_GETATTR);
+       if (status < 0)
                goto xdr_error;
 
-       fattr->bitmap[0] = bitmap[0];
-       fattr->bitmap[1] = bitmap[1];
+       status = decode_attr_bitmap(xdr, bitmap);
+       if (status < 0)
+               goto xdr_error;
 
-       if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+       status = decode_attr_length(xdr, &attrlen, &savep);
+       if (status < 0)
                goto xdr_error;
 
 
-       if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
+       status = decode_attr_type(xdr, bitmap, &type);
+       if (status < 0)
                goto xdr_error;
-       fattr->type = nfs_type2fmt[type].nfs2type;
-       fmode = nfs_type2fmt[type].mode;
+       fattr->mode = 0;
+       if (status != 0) {
+               fattr->mode |= nfs_type2fmt[type];
+               fattr->valid |= status;
+       }
 
-       if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
+       status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_size(xdr, bitmap, &fattr->size);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
+       fattr->valid |= status;
+
+       status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
                                                struct nfs4_fs_locations,
-                                               fattr))) != 0)
+                                               fattr));
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_mode(xdr, bitmap, &fmode);
+       if (status < 0)
                goto xdr_error;
-       fattr->mode |= fmode;
-       if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
+       if (status != 0) {
+               fattr->mode |= fmode;
+               fattr->valid |= status;
+       }
+
+       status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
+       if (status < 0)
                goto xdr_error;
-       if (fattr->fileid == 0 && fileid != 0)
+       if (status != 0 && !(fattr->valid & status)) {
                fattr->fileid = fileid;
-       if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
-               fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
+               fattr->valid |= status;
+       }
+
+       status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
        dprintk("%s: xdr returned %d\n", __func__, -status);
        return status;
@@ -4078,9 +4163,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se
        status = decode_setattr(&xdr, res);
        if (status)
                goto out;
-       status = decode_getfattr(&xdr, res->fattr, res->server);
-       if (status == NFS4ERR_DELAY)
-               status = 0;
+       decode_getfattr(&xdr, res->fattr, res->server);
 out:
        return status;
 }
index 7f079209d70a91ff79f036dbec62ace856023913..e2975939126abe4b949e3e7f0d09f8790ba81260 100644 (file)
@@ -176,17 +176,6 @@ void nfs_release_request(struct nfs_page *req)
        kref_put(&req->wb_kref, nfs_free_request);
 }
 
-static int nfs_wait_bit_killable(void *word)
-{
-       int ret = 0;
-
-       if (fatal_signal_pending(current))
-               ret = -ERESTARTSYS;
-       else
-               schedule();
-       return ret;
-}
-
 /**
  * nfs_wait_on_request - Wait for a request to complete.
  * @req: request to wait upon.
index 193465210d7cdeec5548f7fbb2fbe0ccfecf2375..7be72d90d49de3191899c8be4626d7cfc385d148 100644 (file)
@@ -663,4 +663,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .commit_setup   = nfs_proc_commit_setup,
        .lock           = nfs_proc_lock,
        .lock_check_bounds = nfs_lock_check_bounds,
+       .close_context  = nfs_close_context,
 };
index f856004bb7fa3c8ed4bfe99c3c61ccd6d5729861..4ace3c50a8ebae5dc010084b7dc479cc8664e834 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "internal.h"
 #include "iostat.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
@@ -111,8 +112,8 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
        }
 }
 
-static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
-               struct page *page)
+int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
+                      struct page *page)
 {
        LIST_HEAD(one_request);
        struct nfs_page *new;
@@ -139,6 +140,11 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
 
 static void nfs_readpage_release(struct nfs_page *req)
 {
+       struct inode *d_inode = req->wb_context->path.dentry->d_inode;
+
+       if (PageUptodate(req->wb_page))
+               nfs_readpage_to_fscache(d_inode, req->wb_page, 0);
+
        unlock_page(req->wb_page);
 
        dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
@@ -510,8 +516,15 @@ int nfs_readpage(struct file *file, struct page *page)
        } else
                ctx = get_nfs_open_context(nfs_file_open_context(file));
 
+       if (!IS_SYNC(inode)) {
+               error = nfs_readpage_from_fscache(ctx, inode, page);
+               if (error == 0)
+                       goto out;
+       }
+
        error = nfs_readpage_async(ctx, inode, page);
 
+out:
        put_nfs_open_context(ctx);
        return error;
 out_unlock:
@@ -584,6 +597,15 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
                        return -EBADF;
        } else
                desc.ctx = get_nfs_open_context(nfs_file_open_context(filp));
+
+       /* attempt to read as many of the pages as possible from the cache
+        * - this returns -ENOBUFS immediately if the cookie is negative
+        */
+       ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping,
+                                        pages, &nr_pages);
+       if (ret == 0)
+               goto read_complete; /* all pages were read */
+
        if (rsize < PAGE_CACHE_SIZE)
                nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
        else
@@ -594,6 +616,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        nfs_pageio_complete(&pgio);
        npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        nfs_add_stats(inode, NFSIOS_READPAGES, npages);
+read_complete:
        put_nfs_open_context(desc.ctx);
 out:
        return ret;
index d6686f4786dc55b5d5f06afe913e2930f2b45b96..82eaadbff40872f6fbae90e52a8acf28bca52d7c 100644 (file)
@@ -60,6 +60,7 @@
 #include "delegation.h"
 #include "iostat.h"
 #include "internal.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
@@ -76,6 +77,7 @@ enum {
        Opt_rdirplus, Opt_nordirplus,
        Opt_sharecache, Opt_nosharecache,
        Opt_resvport, Opt_noresvport,
+       Opt_fscache, Opt_nofscache,
 
        /* Mount options that take integer arguments */
        Opt_port,
@@ -93,6 +95,7 @@ enum {
        Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
        Opt_addr, Opt_mountaddr, Opt_clientaddr,
        Opt_lookupcache,
+       Opt_fscache_uniq,
 
        /* Special mount options */
        Opt_userspace, Opt_deprecated, Opt_sloppy,
@@ -132,6 +135,9 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_nosharecache, "nosharecache" },
        { Opt_resvport, "resvport" },
        { Opt_noresvport, "noresvport" },
+       { Opt_fscache, "fsc" },
+       { Opt_fscache_uniq, "fsc=%s" },
+       { Opt_nofscache, "nofsc" },
 
        { Opt_port, "port=%u" },
        { Opt_rsize, "rsize=%u" },
@@ -563,6 +569,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        if (clp->rpc_ops->version == 4)
                seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
 #endif
+       if (nfss->options & NFS_OPTION_FSCACHE)
+               seq_printf(m, ",fsc");
 }
 
 /*
@@ -641,6 +649,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
                        totals.events[i] += stats->events[i];
                for (i = 0; i < __NFSIOS_BYTESMAX; i++)
                        totals.bytes[i] += stats->bytes[i];
+#ifdef CONFIG_NFS_FSCACHE
+               for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
+                       totals.fscache[i] += stats->fscache[i];
+#endif
 
                preempt_enable();
        }
@@ -651,6 +663,13 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
        seq_printf(m, "\n\tbytes:\t");
        for (i = 0; i < __NFSIOS_BYTESMAX; i++)
                seq_printf(m, "%Lu ", totals.bytes[i]);
+#ifdef CONFIG_NFS_FSCACHE
+       if (nfss->options & NFS_OPTION_FSCACHE) {
+               seq_printf(m, "\n\tfsc:\t");
+               for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
+                       seq_printf(m, "%Lu ", totals.bytes[i]);
+       }
+#endif
        seq_printf(m, "\n");
 
        rpc_print_iostats(m, nfss->client);
@@ -1018,6 +1037,7 @@ static int nfs_parse_mount_options(char *raw,
                case Opt_rdma:
                        mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
                        mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                       xprt_load_transport(p);
                        break;
                case Opt_acl:
                        mnt->flags &= ~NFS_MOUNT_NOACL;
@@ -1043,6 +1063,24 @@ static int nfs_parse_mount_options(char *raw,
                case Opt_noresvport:
                        mnt->flags |= NFS_MOUNT_NORESVPORT;
                        break;
+               case Opt_fscache:
+                       mnt->options |= NFS_OPTION_FSCACHE;
+                       kfree(mnt->fscache_uniq);
+                       mnt->fscache_uniq = NULL;
+                       break;
+               case Opt_nofscache:
+                       mnt->options &= ~NFS_OPTION_FSCACHE;
+                       kfree(mnt->fscache_uniq);
+                       mnt->fscache_uniq = NULL;
+                       break;
+               case Opt_fscache_uniq:
+                       string = match_strdup(args);
+                       if (!string)
+                               goto out_nomem;
+                       kfree(mnt->fscache_uniq);
+                       mnt->fscache_uniq = string;
+                       mnt->options |= NFS_OPTION_FSCACHE;
+                       break;
 
                /*
                 * options that take numeric values
@@ -1205,12 +1243,14 @@ static int nfs_parse_mount_options(char *raw,
                                /* vector side protocols to TCP */
                                mnt->flags |= NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                               xprt_load_transport(string);
                                break;
                        default:
                                errors++;
                                dfprintk(MOUNT, "NFS:   unrecognized "
                                                "transport protocol\n");
                        }
+                       kfree(string);
                        break;
                case Opt_mountproto:
                        string = match_strdup(args);
@@ -1218,7 +1258,6 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        token = match_token(string,
                                            nfs_xprt_protocol_tokens, args);
-                       kfree(string);
 
                        switch (token) {
                        case Opt_xprt_udp:
@@ -1868,8 +1907,6 @@ static void nfs_clone_super(struct super_block *sb,
        nfs_initialise_sb(sb);
 }
 
-#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
-
 static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
 {
        const struct nfs_server *a = s->s_fs_info;
@@ -2034,6 +2071,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs_fill_super(s, data);
+               nfs_fscache_get_super_cookie(s, data);
        }
 
        mntroot = nfs_get_root(s, mntfh);
@@ -2054,6 +2092,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
 out:
        kfree(data->nfs_server.hostname);
        kfree(data->mount_server.hostname);
+       kfree(data->fscache_uniq);
        security_free_mnt_opts(&data->lsm_opts);
 out_free_fh:
        kfree(mntfh);
@@ -2081,6 +2120,7 @@ static void nfs_kill_super(struct super_block *s)
 
        bdi_unregister(&server->backing_dev_info);
        kill_anon_super(s);
+       nfs_fscache_release_super_cookie(s);
        nfs_free_server(server);
 }
 
@@ -2388,6 +2428,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs4_fill_super(s);
+               nfs_fscache_get_super_cookie(s, data);
        }
 
        mntroot = nfs4_get_root(s, mntfh);
@@ -2409,6 +2450,7 @@ out:
        kfree(data->client_address);
        kfree(data->nfs_server.export_path);
        kfree(data->nfs_server.hostname);
+       kfree(data->fscache_uniq);
        security_free_mnt_opts(&data->lsm_opts);
 out_free_fh:
        kfree(mntfh);
@@ -2435,6 +2477,7 @@ static void nfs4_kill_super(struct super_block *sb)
        kill_anon_super(sb);
 
        nfs4_renewd_prepare_shutdown(server);
+       nfs_fscache_release_super_cookie(sb);
        nfs_free_server(server);
 }
 
index 9f9845859fc1805627c317bc18963473427cbdd2..e560a78995a3cf5027a01df5168060183ef49547 100644 (file)
@@ -313,19 +313,34 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
 int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
        struct inode *inode = mapping->host;
+       unsigned long *bitlock = &NFS_I(inode)->flags;
        struct nfs_pageio_descriptor pgio;
        int err;
 
+       /* Stop dirtying of new pages while we sync */
+       err = wait_on_bit_lock(bitlock, NFS_INO_FLUSHING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+       if (err)
+               goto out_err;
+
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
        nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
        err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
        nfs_pageio_complete(&pgio);
+
+       clear_bit_unlock(NFS_INO_FLUSHING, bitlock);
+       smp_mb__after_clear_bit();
+       wake_up_bit(bitlock, NFS_INO_FLUSHING);
+
        if (err < 0)
-               return err;
-       if (pgio.pg_error < 0)
-               return pgio.pg_error;
+               goto out_err;
+       err = pgio.pg_error;
+       if (err < 0)
+               goto out_err;
        return 0;
+out_err:
+       return err;
 }
 
 /*
@@ -404,7 +419,6 @@ nfs_mark_request_commit(struct nfs_page *req)
        struct nfs_inode *nfsi = NFS_I(inode);
 
        spin_lock(&inode->i_lock);
-       nfsi->ncommit++;
        set_bit(PG_CLEAN, &(req)->wb_flags);
        radix_tree_tag_set(&nfsi->nfs_page_tree,
                        req->wb_index,
@@ -524,6 +538,12 @@ static void nfs_cancel_commit_list(struct list_head *head)
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+static int
+nfs_need_commit(struct nfs_inode *nfsi)
+{
+       return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
+}
+
 /*
  * nfs_scan_commit - Scan an inode for commit requests
  * @inode: NFS inode to scan
@@ -538,16 +558,18 @@ static int
 nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       int res = 0;
 
-       if (nfsi->ncommit != 0) {
-               res = nfs_scan_list(nfsi, dst, idx_start, npages,
-                               NFS_PAGE_TAG_COMMIT);
-               nfsi->ncommit -= res;
-       }
-       return res;
+       if (!nfs_need_commit(nfsi))
+               return 0;
+
+       return nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
 }
 #else
+static inline int nfs_need_commit(struct nfs_inode *nfsi)
+{
+       return 0;
+}
+
 static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
        return 0;
@@ -820,7 +842,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
        data->args.stable  = NFS_UNSTABLE;
        if (how & FLUSH_STABLE) {
                data->args.stable = NFS_DATA_SYNC;
-               if (!NFS_I(inode)->ncommit)
+               if (!nfs_need_commit(NFS_I(inode)))
                        data->args.stable = NFS_FILE_SYNC;
        }
 
@@ -1425,18 +1447,13 @@ static int nfs_write_mapping(struct address_space *mapping, int how)
 {
        struct writeback_control wbc = {
                .bdi = mapping->backing_dev_info,
-               .sync_mode = WB_SYNC_NONE,
+               .sync_mode = WB_SYNC_ALL,
                .nr_to_write = LONG_MAX,
                .range_start = 0,
                .range_end = LLONG_MAX,
                .for_writepages = 1,
        };
-       int ret;
 
-       ret = __nfs_write_mapping(mapping, &wbc, how);
-       if (ret < 0)
-               return ret;
-       wbc.sync_mode = WB_SYNC_ALL;
        return __nfs_write_mapping(mapping, &wbc, how);
 }
 
index 3d93b2064ce5e83b4e8d8672a84684414daf9e65..a4ed8644d69c0f5050d8e11cc6b66686b7804084 100644 (file)
@@ -938,10 +938,12 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
                char transport[16];
                int port;
                if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
+                       if (port < 1 || port > 65535)
+                               return -EINVAL;
                        err = nfsd_create_serv();
                        if (!err) {
                                err = svc_create_xprt(nfsd_serv,
-                                                     transport, port,
+                                                     transport, PF_INET, port,
                                                      SVC_SOCK_ANONYMOUS);
                                if (err == -ENOENT)
                                        /* Give a reasonable perror msg for
@@ -960,7 +962,7 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
                char transport[16];
                int port;
                if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
-                       if (port == 0)
+                       if (port < 1 || port > 65535)
                                return -EINVAL;
                        if (nfsd_serv) {
                                xprt = svc_find_xprt(nfsd_serv, transport,
index 07e4f5d7baa8c63f3639cfee85cb043d0ae8cd84..7c09852be713b91ef9de1f507aafb04ad61a35a9 100644 (file)
@@ -229,7 +229,6 @@ int nfsd_create_serv(void)
 
        atomic_set(&nfsd_busy, 0);
        nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
-                                     AF_INET,
                                      nfsd_last_thread, nfsd, THIS_MODULE);
        if (nfsd_serv == NULL)
                err = -ENOMEM;
@@ -244,7 +243,7 @@ static int nfsd_init_socks(int port)
        if (!list_empty(&nfsd_serv->sv_permsocks))
                return 0;
 
-       error = svc_create_xprt(nfsd_serv, "udp", port,
+       error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
@@ -253,7 +252,7 @@ static int nfsd_init_socks(int port)
        if (error < 0)
                return error;
 
-       error = svc_create_xprt(nfsd_serv, "tcp", port,
+       error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
@@ -404,7 +403,6 @@ static int
 nfsd(void *vrqstp)
 {
        struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
-       struct fs_struct *fsp;
        int err, preverr = 0;
 
        /* Lock module and set up kernel thread */
@@ -413,13 +411,11 @@ nfsd(void *vrqstp)
        /* At this point, the thread shares current->fs
         * with the init process. We need to create files with a
         * umask of 0 instead of init's umask. */
-       fsp = copy_fs_struct(current->fs);
-       if (!fsp) {
+       if (unshare_fs_struct() < 0) {
                printk("Unable to start nfsd thread: out of memory\n");
                goto out;
        }
-       exit_fs(current);
-       current->fs = fsp;
+
        current->fs->umask = 0;
 
        /*
index 34314b33dbd409f379df4874894625553edc2880..5a9e34475e37951eb03be7ae62d8c55666b53c48 100644 (file)
@@ -32,8 +32,8 @@
 /**
  * The little endian Unicode string $I30 as a global constant.
  */
-ntfschar I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
-               const_cpu_to_le16('3'), const_cpu_to_le16('0'), 0 };
+ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
+               cpu_to_le16('3'),       cpu_to_le16('0'), 0 };
 
 /**
  * ntfs_lookup_inode_by_name - find an inode in a directory given its name
index 86bef156cf0a15b277d879021b24138a333d4eeb..82c5085559c6796332f97bfe3064861c5cc46aad 100644 (file)
@@ -1975,8 +1975,7 @@ int ntfs_read_inode_mount(struct inode *vi)
                                goto em_put_err_out;
                        next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
                                        le16_to_cpu(al_entry->length));
-                       if (le32_to_cpu(al_entry->type) >
-                                       const_le32_to_cpu(AT_DATA))
+                       if (le32_to_cpu(al_entry->type) > le32_to_cpu(AT_DATA))
                                goto em_put_err_out;
                        if (AT_DATA != al_entry->type)
                                continue;
index 1e383328eceb769c778b2694dbed5a86f200e150..50931b1ce4b9bac7a7089a4f97c1dd93af21c9d0 100644 (file)
 
 #include "types.h"
 
-/*
- * Constant endianness conversion defines.
- */
-#define const_le16_to_cpu(x)   __constant_le16_to_cpu(x)
-#define const_le32_to_cpu(x)   __constant_le32_to_cpu(x)
-#define const_le64_to_cpu(x)   __constant_le64_to_cpu(x)
-
-#define const_cpu_to_le16(x)   __constant_cpu_to_le16(x)
-#define const_cpu_to_le32(x)   __constant_cpu_to_le32(x)
-#define const_cpu_to_le64(x)   __constant_cpu_to_le64(x)
-
 /* The NTFS oem_id "NTFS    " */
-#define magicNTFS      const_cpu_to_le64(0x202020205346544eULL)
+#define magicNTFS      cpu_to_le64(0x202020205346544eULL)
 
 /*
  * Location of bootsector on partition:
@@ -114,25 +103,25 @@ typedef struct {
  */
 enum {
        /* Found in $MFT/$DATA. */
-       magic_FILE = const_cpu_to_le32(0x454c4946), /* Mft entry. */
-       magic_INDX = const_cpu_to_le32(0x58444e49), /* Index buffer. */
-       magic_HOLE = const_cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
+       magic_FILE = cpu_to_le32(0x454c4946), /* Mft entry. */
+       magic_INDX = cpu_to_le32(0x58444e49), /* Index buffer. */
+       magic_HOLE = cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
 
        /* Found in $LogFile/$DATA. */
-       magic_RSTR = const_cpu_to_le32(0x52545352), /* Restart page. */
-       magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */
+       magic_RSTR = cpu_to_le32(0x52545352), /* Restart page. */
+       magic_RCRD = cpu_to_le32(0x44524352), /* Log record page. */
 
        /* Found in $LogFile/$DATA.  (May be found in $MFT/$DATA, also?) */
-       magic_CHKD = const_cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
+       magic_CHKD = cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
 
        /* Found in all ntfs record containing records. */
-       magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector
+       magic_BAAD = cpu_to_le32(0x44414142), /* Failed multi sector
                                                       transfer was detected. */
        /*
         * Found in $LogFile/$DATA when a page is full of 0xff bytes and is
         * thus not initialized.  Page must be initialized before using it.
         */
-       magic_empty = const_cpu_to_le32(0xffffffff) /* Record is empty. */
+       magic_empty = cpu_to_le32(0xffffffff) /* Record is empty. */
 };
 
 typedef le32 NTFS_RECORD_TYPE;
@@ -258,8 +247,8 @@ typedef enum {
  * information about the mft record in which they are present.
  */
 enum {
-       MFT_RECORD_IN_USE       = const_cpu_to_le16(0x0001),
-       MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16(0x0002),
+       MFT_RECORD_IN_USE       = cpu_to_le16(0x0001),
+       MFT_RECORD_IS_DIRECTORY = cpu_to_le16(0x0002),
 } __attribute__ ((__packed__));
 
 typedef le16 MFT_RECORD_FLAGS;
@@ -309,7 +298,7 @@ typedef le16 MFT_RECORD_FLAGS;
  * Note: The _LE versions will return a CPU endian formatted value!
  */
 #define MFT_REF_MASK_CPU 0x0000ffffffffffffULL
-#define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU)
+#define MFT_REF_MASK_LE cpu_to_le64(MFT_REF_MASK_CPU)
 
 typedef u64 MFT_REF;
 typedef le64 leMFT_REF;
@@ -477,25 +466,25 @@ typedef struct {
  * a revealing choice of symbol I do not know what is... (-;
  */
 enum {
-       AT_UNUSED                       = const_cpu_to_le32(         0),
-       AT_STANDARD_INFORMATION         = const_cpu_to_le32(      0x10),
-       AT_ATTRIBUTE_LIST               = const_cpu_to_le32(      0x20),
-       AT_FILE_NAME                    = const_cpu_to_le32(      0x30),
-       AT_OBJECT_ID                    = const_cpu_to_le32(      0x40),
-       AT_SECURITY_DESCRIPTOR          = const_cpu_to_le32(      0x50),
-       AT_VOLUME_NAME                  = const_cpu_to_le32(      0x60),
-       AT_VOLUME_INFORMATION           = const_cpu_to_le32(      0x70),
-       AT_DATA                         = const_cpu_to_le32(      0x80),
-       AT_INDEX_ROOT                   = const_cpu_to_le32(      0x90),
-       AT_INDEX_ALLOCATION             = const_cpu_to_le32(      0xa0),
-       AT_BITMAP                       = const_cpu_to_le32(      0xb0),
-       AT_REPARSE_POINT                = const_cpu_to_le32(      0xc0),
-       AT_EA_INFORMATION               = const_cpu_to_le32(      0xd0),
-       AT_EA                           = const_cpu_to_le32(      0xe0),
-       AT_PROPERTY_SET                 = const_cpu_to_le32(      0xf0),
-       AT_LOGGED_UTILITY_STREAM        = const_cpu_to_le32(     0x100),
-       AT_FIRST_USER_DEFINED_ATTRIBUTE = const_cpu_to_le32(    0x1000),
-       AT_END                          = const_cpu_to_le32(0xffffffff)
+       AT_UNUSED                       = cpu_to_le32(         0),
+       AT_STANDARD_INFORMATION         = cpu_to_le32(      0x10),
+       AT_ATTRIBUTE_LIST               = cpu_to_le32(      0x20),
+       AT_FILE_NAME                    = cpu_to_le32(      0x30),
+       AT_OBJECT_ID                    = cpu_to_le32(      0x40),
+       AT_SECURITY_DESCRIPTOR          = cpu_to_le32(      0x50),
+       AT_VOLUME_NAME                  = cpu_to_le32(      0x60),
+       AT_VOLUME_INFORMATION           = cpu_to_le32(      0x70),
+       AT_DATA                         = cpu_to_le32(      0x80),
+       AT_INDEX_ROOT                   = cpu_to_le32(      0x90),
+       AT_INDEX_ALLOCATION             = cpu_to_le32(      0xa0),
+       AT_BITMAP                       = cpu_to_le32(      0xb0),
+       AT_REPARSE_POINT                = cpu_to_le32(      0xc0),
+       AT_EA_INFORMATION               = cpu_to_le32(      0xd0),
+       AT_EA                           = cpu_to_le32(      0xe0),
+       AT_PROPERTY_SET                 = cpu_to_le32(      0xf0),
+       AT_LOGGED_UTILITY_STREAM        = cpu_to_le32(     0x100),
+       AT_FIRST_USER_DEFINED_ATTRIBUTE = cpu_to_le32(    0x1000),
+       AT_END                          = cpu_to_le32(0xffffffff)
 };
 
 typedef le32 ATTR_TYPE;
@@ -539,13 +528,13 @@ typedef le32 ATTR_TYPE;
  *     equal then the second le32 values would be compared, etc.
  */
 enum {
-       COLLATION_BINARY                = const_cpu_to_le32(0x00),
-       COLLATION_FILE_NAME             = const_cpu_to_le32(0x01),
-       COLLATION_UNICODE_STRING        = const_cpu_to_le32(0x02),
-       COLLATION_NTOFS_ULONG           = const_cpu_to_le32(0x10),
-       COLLATION_NTOFS_SID             = const_cpu_to_le32(0x11),
-       COLLATION_NTOFS_SECURITY_HASH   = const_cpu_to_le32(0x12),
-       COLLATION_NTOFS_ULONGS          = const_cpu_to_le32(0x13),
+       COLLATION_BINARY                = cpu_to_le32(0x00),
+       COLLATION_FILE_NAME             = cpu_to_le32(0x01),
+       COLLATION_UNICODE_STRING        = cpu_to_le32(0x02),
+       COLLATION_NTOFS_ULONG           = cpu_to_le32(0x10),
+       COLLATION_NTOFS_SID             = cpu_to_le32(0x11),
+       COLLATION_NTOFS_SECURITY_HASH   = cpu_to_le32(0x12),
+       COLLATION_NTOFS_ULONGS          = cpu_to_le32(0x13),
 };
 
 typedef le32 COLLATION_RULE;
@@ -559,25 +548,25 @@ typedef le32 COLLATION_RULE;
  * NT4.
  */
 enum {
-       ATTR_DEF_INDEXABLE      = const_cpu_to_le32(0x02), /* Attribute can be
+       ATTR_DEF_INDEXABLE      = cpu_to_le32(0x02), /* Attribute can be
                                        indexed. */
-       ATTR_DEF_MULTIPLE       = const_cpu_to_le32(0x04), /* Attribute type
+       ATTR_DEF_MULTIPLE       = cpu_to_le32(0x04), /* Attribute type
                                        can be present multiple times in the
                                        mft records of an inode. */
-       ATTR_DEF_NOT_ZERO       = const_cpu_to_le32(0x08), /* Attribute value
+       ATTR_DEF_NOT_ZERO       = cpu_to_le32(0x08), /* Attribute value
                                        must contain at least one non-zero
                                        byte. */
-       ATTR_DEF_INDEXED_UNIQUE = const_cpu_to_le32(0x10), /* Attribute must be
+       ATTR_DEF_INDEXED_UNIQUE = cpu_to_le32(0x10), /* Attribute must be
                                        indexed and the attribute value must be
                                        unique for the attribute type in all of
                                        the mft records of an inode. */
-       ATTR_DEF_NAMED_UNIQUE   = const_cpu_to_le32(0x20), /* Attribute must be
+       ATTR_DEF_NAMED_UNIQUE   = cpu_to_le32(0x20), /* Attribute must be
                                        named and the name must be unique for
                                        the attribute type in all of the mft
                                        records of an inode. */
-       ATTR_DEF_RESIDENT       = const_cpu_to_le32(0x40), /* Attribute must be
+       ATTR_DEF_RESIDENT       = cpu_to_le32(0x40), /* Attribute must be
                                        resident. */
-       ATTR_DEF_ALWAYS_LOG     = const_cpu_to_le32(0x80), /* Always log
+       ATTR_DEF_ALWAYS_LOG     = cpu_to_le32(0x80), /* Always log
                                        modifications to this attribute,
                                        regardless of whether it is resident or
                                        non-resident.  Without this, only log
@@ -614,12 +603,12 @@ typedef struct {
  * Attribute flags (16-bit).
  */
 enum {
-       ATTR_IS_COMPRESSED    = const_cpu_to_le16(0x0001),
-       ATTR_COMPRESSION_MASK = const_cpu_to_le16(0x00ff), /* Compression method
+       ATTR_IS_COMPRESSED    = cpu_to_le16(0x0001),
+       ATTR_COMPRESSION_MASK = cpu_to_le16(0x00ff), /* Compression method
                                                              mask.  Also, first
                                                              illegal value. */
-       ATTR_IS_ENCRYPTED     = const_cpu_to_le16(0x4000),
-       ATTR_IS_SPARSE        = const_cpu_to_le16(0x8000),
+       ATTR_IS_ENCRYPTED     = cpu_to_le16(0x4000),
+       ATTR_IS_SPARSE        = cpu_to_le16(0x8000),
 } __attribute__ ((__packed__));
 
 typedef le16 ATTR_FLAGS;
@@ -811,32 +800,32 @@ typedef ATTR_RECORD ATTR_REC;
  * flags appear in all of the above.
  */
 enum {
-       FILE_ATTR_READONLY              = const_cpu_to_le32(0x00000001),
-       FILE_ATTR_HIDDEN                = const_cpu_to_le32(0x00000002),
-       FILE_ATTR_SYSTEM                = const_cpu_to_le32(0x00000004),
-       /* Old DOS volid. Unused in NT. = const_cpu_to_le32(0x00000008), */
+       FILE_ATTR_READONLY              = cpu_to_le32(0x00000001),
+       FILE_ATTR_HIDDEN                = cpu_to_le32(0x00000002),
+       FILE_ATTR_SYSTEM                = cpu_to_le32(0x00000004),
+       /* Old DOS volid. Unused in NT. = cpu_to_le32(0x00000008), */
 
-       FILE_ATTR_DIRECTORY             = const_cpu_to_le32(0x00000010),
+       FILE_ATTR_DIRECTORY             = cpu_to_le32(0x00000010),
        /* Note, FILE_ATTR_DIRECTORY is not considered valid in NT.  It is
           reserved for the DOS SUBDIRECTORY flag. */
-       FILE_ATTR_ARCHIVE               = const_cpu_to_le32(0x00000020),
-       FILE_ATTR_DEVICE                = const_cpu_to_le32(0x00000040),
-       FILE_ATTR_NORMAL                = const_cpu_to_le32(0x00000080),
+       FILE_ATTR_ARCHIVE               = cpu_to_le32(0x00000020),
+       FILE_ATTR_DEVICE                = cpu_to_le32(0x00000040),
+       FILE_ATTR_NORMAL                = cpu_to_le32(0x00000080),
 
-       FILE_ATTR_TEMPORARY             = const_cpu_to_le32(0x00000100),
-       FILE_ATTR_SPARSE_FILE           = const_cpu_to_le32(0x00000200),
-       FILE_ATTR_REPARSE_POINT         = const_cpu_to_le32(0x00000400),
-       FILE_ATTR_COMPRESSED            = const_cpu_to_le32(0x00000800),
+       FILE_ATTR_TEMPORARY             = cpu_to_le32(0x00000100),
+       FILE_ATTR_SPARSE_FILE           = cpu_to_le32(0x00000200),
+       FILE_ATTR_REPARSE_POINT         = cpu_to_le32(0x00000400),
+       FILE_ATTR_COMPRESSED            = cpu_to_le32(0x00000800),
 
-       FILE_ATTR_OFFLINE               = const_cpu_to_le32(0x00001000),
-       FILE_ATTR_NOT_CONTENT_INDEXED   = const_cpu_to_le32(0x00002000),
-       FILE_ATTR_ENCRYPTED             = const_cpu_to_le32(0x00004000),
+       FILE_ATTR_OFFLINE               = cpu_to_le32(0x00001000),
+       FILE_ATTR_NOT_CONTENT_INDEXED   = cpu_to_le32(0x00002000),
+       FILE_ATTR_ENCRYPTED             = cpu_to_le32(0x00004000),
 
-       FILE_ATTR_VALID_FLAGS           = const_cpu_to_le32(0x00007fb7),
+       FILE_ATTR_VALID_FLAGS           = cpu_to_le32(0x00007fb7),
        /* Note, FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the
           FILE_ATTR_DEVICE and preserves everything else.  This mask is used
           to obtain all flags that are valid for reading. */
-       FILE_ATTR_VALID_SET_FLAGS       = const_cpu_to_le32(0x000031a7),
+       FILE_ATTR_VALID_SET_FLAGS       = cpu_to_le32(0x000031a7),
        /* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
           F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT,
           F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest.  This mask
@@ -846,11 +835,11 @@ enum {
         * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
         * attribute of an mft record.
         */
-       FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT   = const_cpu_to_le32(0x10000000),
+       FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT   = cpu_to_le32(0x10000000),
        /* Note, this is a copy of the corresponding bit from the mft record,
           telling us whether this is a directory or not, i.e. whether it has
           an index root attribute or not. */
-       FILE_ATTR_DUP_VIEW_INDEX_PRESENT        = const_cpu_to_le32(0x20000000),
+       FILE_ATTR_DUP_VIEW_INDEX_PRESENT        = cpu_to_le32(0x20000000),
        /* Note, this is a copy of the corresponding bit from the mft record,
           telling us whether this file has a view index present (eg. object id
           index, quota index, one of the security indexes or the encrypting
@@ -1446,42 +1435,42 @@ enum {
        /* Specific rights for files and directories are as follows: */
 
        /* Right to read data from the file. (FILE) */
-       FILE_READ_DATA                  = const_cpu_to_le32(0x00000001),
+       FILE_READ_DATA                  = cpu_to_le32(0x00000001),
        /* Right to list contents of a directory. (DIRECTORY) */
-       FILE_LIST_DIRECTORY             = const_cpu_to_le32(0x00000001),
+       FILE_LIST_DIRECTORY             = cpu_to_le32(0x00000001),
 
        /* Right to write data to the file. (FILE) */
-       FILE_WRITE_DATA                 = const_cpu_to_le32(0x00000002),
+       FILE_WRITE_DATA                 = cpu_to_le32(0x00000002),
        /* Right to create a file in the directory. (DIRECTORY) */
-       FILE_ADD_FILE                   = const_cpu_to_le32(0x00000002),
+       FILE_ADD_FILE                   = cpu_to_le32(0x00000002),
 
        /* Right to append data to the file. (FILE) */
-       FILE_APPEND_DATA                = const_cpu_to_le32(0x00000004),
+       FILE_APPEND_DATA                = cpu_to_le32(0x00000004),
        /* Right to create a subdirectory. (DIRECTORY) */
-       FILE_ADD_SUBDIRECTORY           = const_cpu_to_le32(0x00000004),
+       FILE_ADD_SUBDIRECTORY           = cpu_to_le32(0x00000004),
 
        /* Right to read extended attributes. (FILE/DIRECTORY) */
-       FILE_READ_EA                    = const_cpu_to_le32(0x00000008),
+       FILE_READ_EA                    = cpu_to_le32(0x00000008),
 
        /* Right to write extended attributes. (FILE/DIRECTORY) */
-       FILE_WRITE_EA                   = const_cpu_to_le32(0x00000010),
+       FILE_WRITE_EA                   = cpu_to_le32(0x00000010),
 
        /* Right to execute a file. (FILE) */
-       FILE_EXECUTE                    = const_cpu_to_le32(0x00000020),
+       FILE_EXECUTE                    = cpu_to_le32(0x00000020),
        /* Right to traverse the directory. (DIRECTORY) */
-       FILE_TRAVERSE                   = const_cpu_to_le32(0x00000020),
+       FILE_TRAVERSE                   = cpu_to_le32(0x00000020),
 
        /*
         * Right to delete a directory and all the files it contains (its
         * children), even if the files are read-only. (DIRECTORY)
         */
-       FILE_DELETE_CHILD               = const_cpu_to_le32(0x00000040),
+       FILE_DELETE_CHILD               = cpu_to_le32(0x00000040),
 
        /* Right to read file attributes. (FILE/DIRECTORY) */
-       FILE_READ_ATTRIBUTES            = const_cpu_to_le32(0x00000080),
+       FILE_READ_ATTRIBUTES            = cpu_to_le32(0x00000080),
 
        /* Right to change file attributes. (FILE/DIRECTORY) */
-       FILE_WRITE_ATTRIBUTES           = const_cpu_to_le32(0x00000100),
+       FILE_WRITE_ATTRIBUTES           = cpu_to_le32(0x00000100),
 
        /*
         * The standard rights (bits 16 to 23).  These are independent of the
@@ -1489,27 +1478,27 @@ enum {
         */
 
        /* Right to delete the object. */
-       DELETE                          = const_cpu_to_le32(0x00010000),
+       DELETE                          = cpu_to_le32(0x00010000),
 
        /*
         * Right to read the information in the object's security descriptor,
         * not including the information in the SACL, i.e. right to read the
         * security descriptor and owner.
         */
-       READ_CONTROL                    = const_cpu_to_le32(0x00020000),
+       READ_CONTROL                    = cpu_to_le32(0x00020000),
 
        /* Right to modify the DACL in the object's security descriptor. */
-       WRITE_DAC                       = const_cpu_to_le32(0x00040000),
+       WRITE_DAC                       = cpu_to_le32(0x00040000),
 
        /* Right to change the owner in the object's security descriptor. */
-       WRITE_OWNER                     = const_cpu_to_le32(0x00080000),
+       WRITE_OWNER                     = cpu_to_le32(0x00080000),
 
        /*
         * Right to use the object for synchronization.  Enables a process to
         * wait until the object is in the signalled state.  Some object types
         * do not support this access right.
         */
-       SYNCHRONIZE                     = const_cpu_to_le32(0x00100000),
+       SYNCHRONIZE                     = cpu_to_le32(0x00100000),
 
        /*
         * The following STANDARD_RIGHTS_* are combinations of the above for
@@ -1517,25 +1506,25 @@ enum {
         */
 
        /* These are currently defined to READ_CONTROL. */
-       STANDARD_RIGHTS_READ            = const_cpu_to_le32(0x00020000),
-       STANDARD_RIGHTS_WRITE           = const_cpu_to_le32(0x00020000),
-       STANDARD_RIGHTS_EXECUTE         = const_cpu_to_le32(0x00020000),
+       STANDARD_RIGHTS_READ            = cpu_to_le32(0x00020000),
+       STANDARD_RIGHTS_WRITE           = cpu_to_le32(0x00020000),
+       STANDARD_RIGHTS_EXECUTE         = cpu_to_le32(0x00020000),
 
        /* Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access. */
-       STANDARD_RIGHTS_REQUIRED        = const_cpu_to_le32(0x000f0000),
+       STANDARD_RIGHTS_REQUIRED        = cpu_to_le32(0x000f0000),
 
        /*
         * Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and
         * SYNCHRONIZE access.
         */
-       STANDARD_RIGHTS_ALL             = const_cpu_to_le32(0x001f0000),
+       STANDARD_RIGHTS_ALL             = cpu_to_le32(0x001f0000),
 
        /*
         * The access system ACL and maximum allowed access types (bits 24 to
         * 25, bits 26 to 27 are reserved).
         */
-       ACCESS_SYSTEM_SECURITY          = const_cpu_to_le32(0x01000000),
-       MAXIMUM_ALLOWED                 = const_cpu_to_le32(0x02000000),
+       ACCESS_SYSTEM_SECURITY          = cpu_to_le32(0x01000000),
+       MAXIMUM_ALLOWED                 = cpu_to_le32(0x02000000),
 
        /*
         * The generic rights (bits 28 to 31).  These map onto the standard and
@@ -1543,10 +1532,10 @@ enum {
         */
 
        /* Read, write, and execute access. */
-       GENERIC_ALL                     = const_cpu_to_le32(0x10000000),
+       GENERIC_ALL                     = cpu_to_le32(0x10000000),
 
        /* Execute access. */
-       GENERIC_EXECUTE                 = const_cpu_to_le32(0x20000000),
+       GENERIC_EXECUTE                 = cpu_to_le32(0x20000000),
 
        /*
         * Write access.  For files, this maps onto:
@@ -1555,7 +1544,7 @@ enum {
         * For directories, the mapping has the same numerical value.  See
         * above for the descriptions of the rights granted.
         */
-       GENERIC_WRITE                   = const_cpu_to_le32(0x40000000),
+       GENERIC_WRITE                   = cpu_to_le32(0x40000000),
 
        /*
         * Read access.  For files, this maps onto:
@@ -1564,7 +1553,7 @@ enum {
         * For directories, the mapping has the same numberical value.  See
         * above for the descriptions of the rights granted.
         */
-       GENERIC_READ                    = const_cpu_to_le32(0x80000000),
+       GENERIC_READ                    = cpu_to_le32(0x80000000),
 };
 
 typedef le32 ACCESS_MASK;
@@ -1604,8 +1593,8 @@ typedef struct {
  * The object ACE flags (32-bit).
  */
 enum {
-       ACE_OBJECT_TYPE_PRESENT                 = const_cpu_to_le32(1),
-       ACE_INHERITED_OBJECT_TYPE_PRESENT       = const_cpu_to_le32(2),
+       ACE_OBJECT_TYPE_PRESENT                 = cpu_to_le32(1),
+       ACE_INHERITED_OBJECT_TYPE_PRESENT       = cpu_to_le32(2),
 };
 
 typedef le32 OBJECT_ACE_FLAGS;
@@ -1706,23 +1695,23 @@ typedef enum {
  *     expressed as offsets from the beginning of the security descriptor.
  */
 enum {
-       SE_OWNER_DEFAULTED              = const_cpu_to_le16(0x0001),
-       SE_GROUP_DEFAULTED              = const_cpu_to_le16(0x0002),
-       SE_DACL_PRESENT                 = const_cpu_to_le16(0x0004),
-       SE_DACL_DEFAULTED               = const_cpu_to_le16(0x0008),
-
-       SE_SACL_PRESENT                 = const_cpu_to_le16(0x0010),
-       SE_SACL_DEFAULTED               = const_cpu_to_le16(0x0020),
-
-       SE_DACL_AUTO_INHERIT_REQ        = const_cpu_to_le16(0x0100),
-       SE_SACL_AUTO_INHERIT_REQ        = const_cpu_to_le16(0x0200),
-       SE_DACL_AUTO_INHERITED          = const_cpu_to_le16(0x0400),
-       SE_SACL_AUTO_INHERITED          = const_cpu_to_le16(0x0800),
-
-       SE_DACL_PROTECTED               = const_cpu_to_le16(0x1000),
-       SE_SACL_PROTECTED               = const_cpu_to_le16(0x2000),
-       SE_RM_CONTROL_VALID             = const_cpu_to_le16(0x4000),
-       SE_SELF_RELATIVE                = const_cpu_to_le16(0x8000)
+       SE_OWNER_DEFAULTED              = cpu_to_le16(0x0001),
+       SE_GROUP_DEFAULTED              = cpu_to_le16(0x0002),
+       SE_DACL_PRESENT                 = cpu_to_le16(0x0004),
+       SE_DACL_DEFAULTED               = cpu_to_le16(0x0008),
+
+       SE_SACL_PRESENT                 = cpu_to_le16(0x0010),
+       SE_SACL_DEFAULTED               = cpu_to_le16(0x0020),
+
+       SE_DACL_AUTO_INHERIT_REQ        = cpu_to_le16(0x0100),
+       SE_SACL_AUTO_INHERIT_REQ        = cpu_to_le16(0x0200),
+       SE_DACL_AUTO_INHERITED          = cpu_to_le16(0x0400),
+       SE_SACL_AUTO_INHERITED          = cpu_to_le16(0x0800),
+
+       SE_DACL_PROTECTED               = cpu_to_le16(0x1000),
+       SE_SACL_PROTECTED               = cpu_to_le16(0x2000),
+       SE_RM_CONTROL_VALID             = cpu_to_le16(0x4000),
+       SE_SELF_RELATIVE                = cpu_to_le16(0x8000)
 } __attribute__ ((__packed__));
 
 typedef le16 SECURITY_DESCRIPTOR_CONTROL;
@@ -1910,21 +1899,21 @@ typedef struct {
  * Possible flags for the volume (16-bit).
  */
 enum {
-       VOLUME_IS_DIRTY                 = const_cpu_to_le16(0x0001),
-       VOLUME_RESIZE_LOG_FILE          = const_cpu_to_le16(0x0002),
-       VOLUME_UPGRADE_ON_MOUNT         = const_cpu_to_le16(0x0004),
-       VOLUME_MOUNTED_ON_NT4           = const_cpu_to_le16(0x0008),
+       VOLUME_IS_DIRTY                 = cpu_to_le16(0x0001),
+       VOLUME_RESIZE_LOG_FILE          = cpu_to_le16(0x0002),
+       VOLUME_UPGRADE_ON_MOUNT         = cpu_to_le16(0x0004),
+       VOLUME_MOUNTED_ON_NT4           = cpu_to_le16(0x0008),
 
-       VOLUME_DELETE_USN_UNDERWAY      = const_cpu_to_le16(0x0010),
-       VOLUME_REPAIR_OBJECT_ID         = const_cpu_to_le16(0x0020),
+       VOLUME_DELETE_USN_UNDERWAY      = cpu_to_le16(0x0010),
+       VOLUME_REPAIR_OBJECT_ID         = cpu_to_le16(0x0020),
 
-       VOLUME_CHKDSK_UNDERWAY          = const_cpu_to_le16(0x4000),
-       VOLUME_MODIFIED_BY_CHKDSK       = const_cpu_to_le16(0x8000),
+       VOLUME_CHKDSK_UNDERWAY          = cpu_to_le16(0x4000),
+       VOLUME_MODIFIED_BY_CHKDSK       = cpu_to_le16(0x8000),
 
-       VOLUME_FLAGS_MASK               = const_cpu_to_le16(0xc03f),
+       VOLUME_FLAGS_MASK               = cpu_to_le16(0xc03f),
 
        /* To make our life easier when checking if we must mount read-only. */
-       VOLUME_MUST_MOUNT_RO_MASK       = const_cpu_to_le16(0xc027),
+       VOLUME_MUST_MOUNT_RO_MASK       = cpu_to_le16(0xc027),
 } __attribute__ ((__packed__));
 
 typedef le16 VOLUME_FLAGS;
@@ -2109,26 +2098,26 @@ typedef struct {
  * The user quota flags.  Names explain meaning.
  */
 enum {
-       QUOTA_FLAG_DEFAULT_LIMITS       = const_cpu_to_le32(0x00000001),
-       QUOTA_FLAG_LIMIT_REACHED        = const_cpu_to_le32(0x00000002),
-       QUOTA_FLAG_ID_DELETED           = const_cpu_to_le32(0x00000004),
+       QUOTA_FLAG_DEFAULT_LIMITS       = cpu_to_le32(0x00000001),
+       QUOTA_FLAG_LIMIT_REACHED        = cpu_to_le32(0x00000002),
+       QUOTA_FLAG_ID_DELETED           = cpu_to_le32(0x00000004),
 
-       QUOTA_FLAG_USER_MASK            = const_cpu_to_le32(0x00000007),
+       QUOTA_FLAG_USER_MASK            = cpu_to_le32(0x00000007),
        /* This is a bit mask for the user quota flags. */
 
        /*
         * These flags are only present in the quota defaults index entry, i.e.
         * in the entry where owner_id = QUOTA_DEFAULTS_ID.
         */
-       QUOTA_FLAG_TRACKING_ENABLED     = const_cpu_to_le32(0x00000010),
-       QUOTA_FLAG_ENFORCEMENT_ENABLED  = const_cpu_to_le32(0x00000020),
-       QUOTA_FLAG_TRACKING_REQUESTED   = const_cpu_to_le32(0x00000040),
-       QUOTA_FLAG_LOG_THRESHOLD        = const_cpu_to_le32(0x00000080),
-
-       QUOTA_FLAG_LOG_LIMIT            = const_cpu_to_le32(0x00000100),
-       QUOTA_FLAG_OUT_OF_DATE          = const_cpu_to_le32(0x00000200),
-       QUOTA_FLAG_CORRUPT              = const_cpu_to_le32(0x00000400),
-       QUOTA_FLAG_PENDING_DELETES      = const_cpu_to_le32(0x00000800),
+       QUOTA_FLAG_TRACKING_ENABLED     = cpu_to_le32(0x00000010),
+       QUOTA_FLAG_ENFORCEMENT_ENABLED  = cpu_to_le32(0x00000020),
+       QUOTA_FLAG_TRACKING_REQUESTED   = cpu_to_le32(0x00000040),
+       QUOTA_FLAG_LOG_THRESHOLD        = cpu_to_le32(0x00000080),
+
+       QUOTA_FLAG_LOG_LIMIT            = cpu_to_le32(0x00000100),
+       QUOTA_FLAG_OUT_OF_DATE          = cpu_to_le32(0x00000200),
+       QUOTA_FLAG_CORRUPT              = cpu_to_le32(0x00000400),
+       QUOTA_FLAG_PENDING_DELETES      = cpu_to_le32(0x00000800),
 };
 
 typedef le32 QUOTA_FLAGS;
@@ -2172,9 +2161,9 @@ typedef struct {
  * Predefined owner_id values (32-bit).
  */
 enum {
-       QUOTA_INVALID_ID        = const_cpu_to_le32(0x00000000),
-       QUOTA_DEFAULTS_ID       = const_cpu_to_le32(0x00000001),
-       QUOTA_FIRST_USER_ID     = const_cpu_to_le32(0x00000100),
+       QUOTA_INVALID_ID        = cpu_to_le32(0x00000000),
+       QUOTA_DEFAULTS_ID       = cpu_to_le32(0x00000001),
+       QUOTA_FIRST_USER_ID     = cpu_to_le32(0x00000100),
 };
 
 /*
@@ -2189,14 +2178,14 @@ typedef enum {
  * Index entry flags (16-bit).
  */
 enum {
-       INDEX_ENTRY_NODE = const_cpu_to_le16(1), /* This entry contains a
+       INDEX_ENTRY_NODE = cpu_to_le16(1), /* This entry contains a
                        sub-node, i.e. a reference to an index block in form of
                        a virtual cluster number (see below). */
-       INDEX_ENTRY_END  = const_cpu_to_le16(2), /* This signifies the last
+       INDEX_ENTRY_END  = cpu_to_le16(2), /* This signifies the last
                        entry in an index block.  The index entry does not
                        represent a file but it can point to a sub-node. */
 
-       INDEX_ENTRY_SPACE_FILLER = const_cpu_to_le16(0xffff), /* gcc: Force
+       INDEX_ENTRY_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force
                        enum bit width to 16-bit. */
 } __attribute__ ((__packed__));
 
@@ -2334,26 +2323,26 @@ typedef struct {
  * These are the predefined reparse point tags:
  */
 enum {
-       IO_REPARSE_TAG_IS_ALIAS         = const_cpu_to_le32(0x20000000),
-       IO_REPARSE_TAG_IS_HIGH_LATENCY  = const_cpu_to_le32(0x40000000),
-       IO_REPARSE_TAG_IS_MICROSOFT     = const_cpu_to_le32(0x80000000),
+       IO_REPARSE_TAG_IS_ALIAS         = cpu_to_le32(0x20000000),
+       IO_REPARSE_TAG_IS_HIGH_LATENCY  = cpu_to_le32(0x40000000),
+       IO_REPARSE_TAG_IS_MICROSOFT     = cpu_to_le32(0x80000000),
 
-       IO_REPARSE_TAG_RESERVED_ZERO    = const_cpu_to_le32(0x00000000),
-       IO_REPARSE_TAG_RESERVED_ONE     = const_cpu_to_le32(0x00000001),
-       IO_REPARSE_TAG_RESERVED_RANGE   = const_cpu_to_le32(0x00000001),
+       IO_REPARSE_TAG_RESERVED_ZERO    = cpu_to_le32(0x00000000),
+       IO_REPARSE_TAG_RESERVED_ONE     = cpu_to_le32(0x00000001),
+       IO_REPARSE_TAG_RESERVED_RANGE   = cpu_to_le32(0x00000001),
 
-       IO_REPARSE_TAG_NSS              = const_cpu_to_le32(0x68000005),
-       IO_REPARSE_TAG_NSS_RECOVER      = const_cpu_to_le32(0x68000006),
-       IO_REPARSE_TAG_SIS              = const_cpu_to_le32(0x68000007),
-       IO_REPARSE_TAG_DFS              = const_cpu_to_le32(0x68000008),
+       IO_REPARSE_TAG_NSS              = cpu_to_le32(0x68000005),
+       IO_REPARSE_TAG_NSS_RECOVER      = cpu_to_le32(0x68000006),
+       IO_REPARSE_TAG_SIS              = cpu_to_le32(0x68000007),
+       IO_REPARSE_TAG_DFS              = cpu_to_le32(0x68000008),
 
-       IO_REPARSE_TAG_MOUNT_POINT      = const_cpu_to_le32(0x88000003),
+       IO_REPARSE_TAG_MOUNT_POINT      = cpu_to_le32(0x88000003),
 
-       IO_REPARSE_TAG_HSM              = const_cpu_to_le32(0xa8000004),
+       IO_REPARSE_TAG_HSM              = cpu_to_le32(0xa8000004),
 
-       IO_REPARSE_TAG_SYMBOLIC_LINK    = const_cpu_to_le32(0xe8000000),
+       IO_REPARSE_TAG_SYMBOLIC_LINK    = cpu_to_le32(0xe8000000),
 
-       IO_REPARSE_TAG_VALID_VALUES     = const_cpu_to_le32(0xe000ffff),
+       IO_REPARSE_TAG_VALID_VALUES     = cpu_to_le32(0xe000ffff),
 };
 
 /*
index 9468e1c45ae305dae0a5a626d38de952da914d7b..b5a6f08bd35c8b9010f75cce7358cb723e108c6c 100644 (file)
@@ -104,7 +104,7 @@ typedef struct {
  * in this particular client array.  Also inside the client records themselves,
  * this means that there are no client records preceding or following this one.
  */
-#define LOGFILE_NO_CLIENT      const_cpu_to_le16(0xffff)
+#define LOGFILE_NO_CLIENT      cpu_to_le16(0xffff)
 #define LOGFILE_NO_CLIENT_CPU  0xffff
 
 /*
@@ -112,8 +112,8 @@ typedef struct {
  * information about the log file in which they are present.
  */
 enum {
-       RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002),
-       RESTART_SPACE_FILLER    = const_cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */
+       RESTART_VOLUME_IS_CLEAN = cpu_to_le16(0x0002),
+       RESTART_SPACE_FILLER    = cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */
 } __attribute__ ((__packed__));
 
 typedef le16 RESTART_AREA_FLAGS;
index 17d32ca6bc35b7dc5036033e1afa8b91e5ee4d38..23bf68453d7dec8f16e5691d17dadbbe9776e1b2 100644 (file)
@@ -2839,7 +2839,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
         */
 
        /* Mark the mft record as not in use. */
-       m->flags &= const_cpu_to_le16(~const_le16_to_cpu(MFT_RECORD_IN_USE));
+       m->flags &= ~MFT_RECORD_IN_USE;
 
        /* Increment the sequence number, skipping zero, if it is not zero. */
        old_seq_no = m->sequence_number;
index 4a46743b5077a5e98e59d8f2b0205a4bc20e75a5..f76951dcd4a6e984f2469b06df80dd0aa9e96891 100644 (file)
@@ -618,7 +618,7 @@ static bool is_boot_sector_ntfs(const struct super_block *sb,
         * many BIOSes will refuse to boot from a bootsector if the magic is
         * incorrect, so we emit a warning.
         */
-       if (!silent && b->end_of_sector_marker != const_cpu_to_le16(0xaa55))
+       if (!silent && b->end_of_sector_marker != cpu_to_le16(0xaa55))
                ntfs_warning(sb, "Invalid end of sector marker.");
        return true;
 not_ntfs:
@@ -1242,13 +1242,13 @@ static int check_windows_hibernation_status(ntfs_volume *vol)
        u32 *kaddr, *kend;
        ntfs_name *name = NULL;
        int ret = 1;
-       static const ntfschar hiberfil[13] = { const_cpu_to_le16('h'),
-                       const_cpu_to_le16('i'), const_cpu_to_le16('b'),
-                       const_cpu_to_le16('e'), const_cpu_to_le16('r'),
-                       const_cpu_to_le16('f'), const_cpu_to_le16('i'),
-                       const_cpu_to_le16('l'), const_cpu_to_le16('.'),
-                       const_cpu_to_le16('s'), const_cpu_to_le16('y'),
-                       const_cpu_to_le16('s'), 0 };
+       static const ntfschar hiberfil[13] = { cpu_to_le16('h'),
+                       cpu_to_le16('i'), cpu_to_le16('b'),
+                       cpu_to_le16('e'), cpu_to_le16('r'),
+                       cpu_to_le16('f'), cpu_to_le16('i'),
+                       cpu_to_le16('l'), cpu_to_le16('.'),
+                       cpu_to_le16('s'), cpu_to_le16('y'),
+                       cpu_to_le16('s'), 0 };
 
        ntfs_debug("Entering.");
        /*
@@ -1296,7 +1296,7 @@ static int check_windows_hibernation_status(ntfs_volume *vol)
                goto iput_out;
        }
        kaddr = (u32*)page_address(page);
-       if (*(le32*)kaddr == const_cpu_to_le32(0x72626968)/*'hibr'*/) {
+       if (*(le32*)kaddr == cpu_to_le32(0x72626968)/*'hibr'*/) {
                ntfs_debug("Magic \"hibr\" found in hiberfil.sys.  Windows is "
                                "hibernated on the volume.  This is the "
                                "system volume.");
@@ -1337,12 +1337,12 @@ static bool load_and_init_quota(ntfs_volume *vol)
        MFT_REF mref;
        struct inode *tmp_ino;
        ntfs_name *name = NULL;
-       static const ntfschar Quota[7] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('Q'), const_cpu_to_le16('u'),
-                       const_cpu_to_le16('o'), const_cpu_to_le16('t'),
-                       const_cpu_to_le16('a'), 0 };
-       static ntfschar Q[3] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('Q'), 0 };
+       static const ntfschar Quota[7] = { cpu_to_le16('$'),
+                       cpu_to_le16('Q'), cpu_to_le16('u'),
+                       cpu_to_le16('o'), cpu_to_le16('t'),
+                       cpu_to_le16('a'), 0 };
+       static ntfschar Q[3] = { cpu_to_le16('$'),
+                       cpu_to_le16('Q'), 0 };
 
        ntfs_debug("Entering.");
        /*
@@ -1416,16 +1416,16 @@ static bool load_and_init_usnjrnl(ntfs_volume *vol)
        struct page *page;
        ntfs_name *name = NULL;
        USN_HEADER *uh;
-       static const ntfschar UsnJrnl[9] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('U'), const_cpu_to_le16('s'),
-                       const_cpu_to_le16('n'), const_cpu_to_le16('J'),
-                       const_cpu_to_le16('r'), const_cpu_to_le16('n'),
-                       const_cpu_to_le16('l'), 0 };
-       static ntfschar Max[5] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('M'), const_cpu_to_le16('a'),
-                       const_cpu_to_le16('x'), 0 };
-       static ntfschar J[3] = { const_cpu_to_le16('$'),
-                       const_cpu_to_le16('J'), 0 };
+       static const ntfschar UsnJrnl[9] = { cpu_to_le16('$'),
+                       cpu_to_le16('U'), cpu_to_le16('s'),
+                       cpu_to_le16('n'), cpu_to_le16('J'),
+                       cpu_to_le16('r'), cpu_to_le16('n'),
+                       cpu_to_le16('l'), 0 };
+       static ntfschar Max[5] = { cpu_to_le16('$'),
+                       cpu_to_le16('M'), cpu_to_le16('a'),
+                       cpu_to_le16('x'), 0 };
+       static ntfschar J[3] = { cpu_to_le16('$'),
+                       cpu_to_le16('J'), 0 };
 
        ntfs_debug("Entering.");
        /*
index 4087fbdac327e19a586576aa6bc5bf95d307f96d..00d8e6bd7c369d1f124dc0c13c2b511bfb57cfd5 100644 (file)
@@ -116,27 +116,27 @@ typedef struct {
  * documentation: http://www.linux-ntfs.org/
  */
 enum {
-       USN_REASON_DATA_OVERWRITE       = const_cpu_to_le32(0x00000001),
-       USN_REASON_DATA_EXTEND          = const_cpu_to_le32(0x00000002),
-       USN_REASON_DATA_TRUNCATION      = const_cpu_to_le32(0x00000004),
-       USN_REASON_NAMED_DATA_OVERWRITE = const_cpu_to_le32(0x00000010),
-       USN_REASON_NAMED_DATA_EXTEND    = const_cpu_to_le32(0x00000020),
-       USN_REASON_NAMED_DATA_TRUNCATION= const_cpu_to_le32(0x00000040),
-       USN_REASON_FILE_CREATE          = const_cpu_to_le32(0x00000100),
-       USN_REASON_FILE_DELETE          = const_cpu_to_le32(0x00000200),
-       USN_REASON_EA_CHANGE            = const_cpu_to_le32(0x00000400),
-       USN_REASON_SECURITY_CHANGE      = const_cpu_to_le32(0x00000800),
-       USN_REASON_RENAME_OLD_NAME      = const_cpu_to_le32(0x00001000),
-       USN_REASON_RENAME_NEW_NAME      = const_cpu_to_le32(0x00002000),
-       USN_REASON_INDEXABLE_CHANGE     = const_cpu_to_le32(0x00004000),
-       USN_REASON_BASIC_INFO_CHANGE    = const_cpu_to_le32(0x00008000),
-       USN_REASON_HARD_LINK_CHANGE     = const_cpu_to_le32(0x00010000),
-       USN_REASON_COMPRESSION_CHANGE   = const_cpu_to_le32(0x00020000),
-       USN_REASON_ENCRYPTION_CHANGE    = const_cpu_to_le32(0x00040000),
-       USN_REASON_OBJECT_ID_CHANGE     = const_cpu_to_le32(0x00080000),
-       USN_REASON_REPARSE_POINT_CHANGE = const_cpu_to_le32(0x00100000),
-       USN_REASON_STREAM_CHANGE        = const_cpu_to_le32(0x00200000),
-       USN_REASON_CLOSE                = const_cpu_to_le32(0x80000000),
+       USN_REASON_DATA_OVERWRITE       = cpu_to_le32(0x00000001),
+       USN_REASON_DATA_EXTEND          = cpu_to_le32(0x00000002),
+       USN_REASON_DATA_TRUNCATION      = cpu_to_le32(0x00000004),
+       USN_REASON_NAMED_DATA_OVERWRITE = cpu_to_le32(0x00000010),
+       USN_REASON_NAMED_DATA_EXTEND    = cpu_to_le32(0x00000020),
+       USN_REASON_NAMED_DATA_TRUNCATION= cpu_to_le32(0x00000040),
+       USN_REASON_FILE_CREATE          = cpu_to_le32(0x00000100),
+       USN_REASON_FILE_DELETE          = cpu_to_le32(0x00000200),
+       USN_REASON_EA_CHANGE            = cpu_to_le32(0x00000400),
+       USN_REASON_SECURITY_CHANGE      = cpu_to_le32(0x00000800),
+       USN_REASON_RENAME_OLD_NAME      = cpu_to_le32(0x00001000),
+       USN_REASON_RENAME_NEW_NAME      = cpu_to_le32(0x00002000),
+       USN_REASON_INDEXABLE_CHANGE     = cpu_to_le32(0x00004000),
+       USN_REASON_BASIC_INFO_CHANGE    = cpu_to_le32(0x00008000),
+       USN_REASON_HARD_LINK_CHANGE     = cpu_to_le32(0x00010000),
+       USN_REASON_COMPRESSION_CHANGE   = cpu_to_le32(0x00020000),
+       USN_REASON_ENCRYPTION_CHANGE    = cpu_to_le32(0x00040000),
+       USN_REASON_OBJECT_ID_CHANGE     = cpu_to_le32(0x00080000),
+       USN_REASON_REPARSE_POINT_CHANGE = cpu_to_le32(0x00100000),
+       USN_REASON_STREAM_CHANGE        = cpu_to_le32(0x00200000),
+       USN_REASON_CLOSE                = cpu_to_le32(0x80000000),
 };
 
 typedef le32 USN_REASON_FLAGS;
@@ -148,9 +148,9 @@ typedef le32 USN_REASON_FLAGS;
  *     http://www.linux-ntfs.org/
  */
 enum {
-       USN_SOURCE_DATA_MANAGEMENT        = const_cpu_to_le32(0x00000001),
-       USN_SOURCE_AUXILIARY_DATA         = const_cpu_to_le32(0x00000002),
-       USN_SOURCE_REPLICATION_MANAGEMENT = const_cpu_to_le32(0x00000004),
+       USN_SOURCE_DATA_MANAGEMENT        = cpu_to_le32(0x00000001),
+       USN_SOURCE_AUXILIARY_DATA         = cpu_to_le32(0x00000002),
+       USN_SOURCE_REPLICATION_MANAGEMENT = cpu_to_le32(0x00000004),
 };
 
 typedef le32 USN_SOURCE_INFO_FLAGS;
index 12dfb44c22e57d3e82e8ed038de231008e926c9a..fbeaec762103a91eacd396f47a999244303954ee 100644 (file)
@@ -296,7 +296,7 @@ int ocfs2_init_acl(handle_t *handle,
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
                struct posix_acl *clone;
index 19e3a96aa02c00f67b281ea2c3ce0cbd4e0e4b29..678a067d9251f12424ee9486cc81960749bc33ec 100644 (file)
@@ -294,6 +294,55 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = {
        .eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters,
 };
 
+static void ocfs2_dx_root_set_last_eb_blk(struct ocfs2_extent_tree *et,
+                                         u64 blkno)
+{
+       struct ocfs2_dx_root_block *dx_root = et->et_object;
+
+       dx_root->dr_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_dx_root_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_dx_root_block *dx_root = et->et_object;
+
+       return le64_to_cpu(dx_root->dr_last_eb_blk);
+}
+
+static void ocfs2_dx_root_update_clusters(struct inode *inode,
+                                         struct ocfs2_extent_tree *et,
+                                         u32 clusters)
+{
+       struct ocfs2_dx_root_block *dx_root = et->et_object;
+
+       le32_add_cpu(&dx_root->dr_clusters, clusters);
+}
+
+static int ocfs2_dx_root_sanity_check(struct inode *inode,
+                                     struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_dx_root_block *dx_root = et->et_object;
+
+       BUG_ON(!OCFS2_IS_VALID_DX_ROOT(dx_root));
+
+       return 0;
+}
+
+static void ocfs2_dx_root_fill_root_el(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_dx_root_block *dx_root = et->et_object;
+
+       et->et_root_el = &dx_root->dr_list;
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_dx_root_et_ops = {
+       .eo_set_last_eb_blk     = ocfs2_dx_root_set_last_eb_blk,
+       .eo_get_last_eb_blk     = ocfs2_dx_root_get_last_eb_blk,
+       .eo_update_clusters     = ocfs2_dx_root_update_clusters,
+       .eo_sanity_check        = ocfs2_dx_root_sanity_check,
+       .eo_fill_root_el        = ocfs2_dx_root_fill_root_el,
+};
+
 static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et,
                                     struct inode *inode,
                                     struct buffer_head *bh,
@@ -339,6 +388,14 @@ void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
                                 &ocfs2_xattr_value_et_ops);
 }
 
+void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et,
+                                   struct inode *inode,
+                                   struct buffer_head *bh)
+{
+       __ocfs2_init_extent_tree(et, inode, bh, ocfs2_journal_access_dr,
+                                NULL, &ocfs2_dx_root_et_ops);
+}
+
 static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et,
                                            u64 new_last_eb_blk)
 {
index cceff5c37f47c5872284d5ab43fafab9f9e27db1..353254ba29e15ca2c3625d6537128eed590d182e 100644 (file)
@@ -75,6 +75,9 @@ struct ocfs2_xattr_value_buf;
 void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
                                        struct inode *inode,
                                        struct ocfs2_xattr_value_buf *vb);
+void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et,
+                                   struct inode *inode,
+                                   struct buffer_head *bh);
 
 /*
  * Read an extent block into *bh.  If *bh is NULL, a bh will be
index 8e1709a679b724aaaf323671308e1cd32399cf4d..b2c52b3a1484f1c57c4b098bf9706fe21c186ac0 100644 (file)
@@ -1956,15 +1956,16 @@ static int ocfs2_write_end(struct file *file, struct address_space *mapping,
 }
 
 const struct address_space_operations ocfs2_aops = {
-       .readpage       = ocfs2_readpage,
-       .readpages      = ocfs2_readpages,
-       .writepage      = ocfs2_writepage,
-       .write_begin    = ocfs2_write_begin,
-       .write_end      = ocfs2_write_end,
-       .bmap           = ocfs2_bmap,
-       .sync_page      = block_sync_page,
-       .direct_IO      = ocfs2_direct_IO,
-       .invalidatepage = ocfs2_invalidatepage,
-       .releasepage    = ocfs2_releasepage,
-       .migratepage    = buffer_migrate_page,
+       .readpage               = ocfs2_readpage,
+       .readpages              = ocfs2_readpages,
+       .writepage              = ocfs2_writepage,
+       .write_begin            = ocfs2_write_begin,
+       .write_end              = ocfs2_write_end,
+       .bmap                   = ocfs2_bmap,
+       .sync_page              = block_sync_page,
+       .direct_IO              = ocfs2_direct_IO,
+       .invalidatepage         = ocfs2_invalidatepage,
+       .releasepage            = ocfs2_releasepage,
+       .migratepage            = buffer_migrate_page,
+       .is_partially_uptodate  = block_is_partially_uptodate,
 };
index 04697ba7f73e6be8ef79904b6f21e70b70ccb287..4f85eceab376015596adbafae5b9eb774211e2b1 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/random.h>
 #include <linux/crc32.h>
 #include <linux/time.h>
+#include <linux/debugfs.h>
 
 #include "heartbeat.h"
 #include "tcp.h"
@@ -60,6 +61,11 @@ static unsigned long o2hb_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
 static LIST_HEAD(o2hb_node_events);
 static DECLARE_WAIT_QUEUE_HEAD(o2hb_steady_queue);
 
+#define O2HB_DEBUG_DIR                 "o2hb"
+#define O2HB_DEBUG_LIVENODES           "livenodes"
+static struct dentry *o2hb_debug_dir;
+static struct dentry *o2hb_debug_livenodes;
+
 static LIST_HEAD(o2hb_all_regions);
 
 static struct o2hb_callback {
@@ -905,7 +911,77 @@ static int o2hb_thread(void *data)
        return 0;
 }
 
-void o2hb_init(void)
+#ifdef CONFIG_DEBUG_FS
+static int o2hb_debug_open(struct inode *inode, struct file *file)
+{
+       unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
+       char *buf = NULL;
+       int i = -1;
+       int out = 0;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               goto bail;
+
+       o2hb_fill_node_map(map, sizeof(map));
+
+       while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
+               out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i);
+       out += snprintf(buf + out, PAGE_SIZE - out, "\n");
+
+       i_size_write(inode, out);
+
+       file->private_data = buf;
+
+       return 0;
+bail:
+       return -ENOMEM;
+}
+
+static int o2hb_debug_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
+static ssize_t o2hb_debug_read(struct file *file, char __user *buf,
+                                size_t nbytes, loff_t *ppos)
+{
+       return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
+                                      i_size_read(file->f_mapping->host));
+}
+#else
+static int o2hb_debug_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+static int o2hb_debug_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+static ssize_t o2hb_debug_read(struct file *file, char __user *buf,
+                              size_t nbytes, loff_t *ppos)
+{
+       return 0;
+}
+#endif  /* CONFIG_DEBUG_FS */
+
+static struct file_operations o2hb_debug_fops = {
+       .open =         o2hb_debug_open,
+       .release =      o2hb_debug_release,
+       .read =         o2hb_debug_read,
+       .llseek =       generic_file_llseek,
+};
+
+void o2hb_exit(void)
+{
+       if (o2hb_debug_livenodes)
+               debugfs_remove(o2hb_debug_livenodes);
+       if (o2hb_debug_dir)
+               debugfs_remove(o2hb_debug_dir);
+}
+
+int o2hb_init(void)
 {
        int i;
 
@@ -918,6 +994,24 @@ void o2hb_init(void)
        INIT_LIST_HEAD(&o2hb_node_events);
 
        memset(o2hb_live_node_bitmap, 0, sizeof(o2hb_live_node_bitmap));
+
+       o2hb_debug_dir = debugfs_create_dir(O2HB_DEBUG_DIR, NULL);
+       if (!o2hb_debug_dir) {
+               mlog_errno(-ENOMEM);
+               return -ENOMEM;
+       }
+
+       o2hb_debug_livenodes = debugfs_create_file(O2HB_DEBUG_LIVENODES,
+                                                  S_IFREG|S_IRUSR,
+                                                  o2hb_debug_dir, NULL,
+                                                  &o2hb_debug_fops);
+       if (!o2hb_debug_livenodes) {
+               mlog_errno(-ENOMEM);
+               debugfs_remove(o2hb_debug_dir);
+               return -ENOMEM;
+       }
+
+       return 0;
 }
 
 /* if we're already in a callback then we're already serialized by the sem */
index e511339886b31040e5597695726692b91be07e11..2f1649253b497bed42fc14ef87685e59377dc2be 100644 (file)
@@ -75,7 +75,8 @@ void o2hb_unregister_callback(const char *region_uuid,
                              struct o2hb_callback_func *hc);
 void o2hb_fill_node_map(unsigned long *map,
                        unsigned bytes);
-void o2hb_init(void);
+void o2hb_exit(void);
+int o2hb_init(void);
 int o2hb_check_node_heartbeating(u8 node_num);
 int o2hb_check_node_heartbeating_from_callback(u8 node_num);
 int o2hb_check_local_node_heartbeating(void);
index 70e8fa9e2539cdf210676778770e0de4405713e2..7ee6188bc79a76ebc939b738bcfc3914c99b3ef6 100644 (file)
@@ -881,6 +881,7 @@ static void __exit exit_o2nm(void)
        o2cb_sys_shutdown();
 
        o2net_exit();
+       o2hb_exit();
 }
 
 static int __init init_o2nm(void)
@@ -889,11 +890,13 @@ static int __init init_o2nm(void)
 
        cluster_print_version();
 
-       o2hb_init();
+       ret = o2hb_init();
+       if (ret)
+               goto out;
 
        ret = o2net_init();
        if (ret)
-               goto out;
+               goto out_o2hb;
 
        ret = o2net_register_hb_callbacks();
        if (ret)
@@ -916,6 +919,8 @@ out_callbacks:
        o2net_unregister_hb_callbacks();
 out_o2net:
        o2net_exit();
+out_o2hb:
+       o2hb_exit();
 out:
        return ret;
 }
index f2c4098cf337fd077b1d77835144cc454ce5e8dc..e71160cda1100a1d5b9c840fbbbe784058a682fe 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/quotaops.h>
+#include <linux/sort.h>
 
 #define MLOG_MASK_PREFIX ML_NAMEI
 #include <cluster/masklog.h>
@@ -58,6 +59,7 @@
 #include "namei.h"
 #include "suballoc.h"
 #include "super.h"
+#include "sysfile.h"
 #include "uptodate.h"
 
 #include "buffer_head_io.h"
@@ -71,11 +73,6 @@ static unsigned char ocfs2_filetype_table[] = {
        DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
 
-static int ocfs2_extend_dir(struct ocfs2_super *osb,
-                           struct inode *dir,
-                           struct buffer_head *parent_fe_bh,
-                           unsigned int blocks_wanted,
-                           struct buffer_head **new_de_bh);
 static int ocfs2_do_extend_dir(struct super_block *sb,
                               handle_t *handle,
                               struct inode *dir,
@@ -83,22 +80,36 @@ static int ocfs2_do_extend_dir(struct super_block *sb,
                               struct ocfs2_alloc_context *data_ac,
                               struct ocfs2_alloc_context *meta_ac,
                               struct buffer_head **new_bh);
+static int ocfs2_dir_indexed(struct inode *inode);
 
 /*
  * These are distinct checks because future versions of the file system will
  * want to have a trailing dirent structure independent of indexing.
  */
-static int ocfs2_dir_has_trailer(struct inode *dir)
+static int ocfs2_supports_dir_trailer(struct inode *dir)
 {
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+
        if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
                return 0;
 
-       return ocfs2_meta_ecc(OCFS2_SB(dir->i_sb));
+       return ocfs2_meta_ecc(osb) || ocfs2_dir_indexed(dir);
 }
 
-static int ocfs2_supports_dir_trailer(struct ocfs2_super *osb)
+/*
+ * "new' here refers to the point at which we're creating a new
+ * directory via "mkdir()", but also when we're expanding an inline
+ * directory. In either case, we don't yet have the indexing bit set
+ * on the directory, so the standard checks will fail in when metaecc
+ * is turned off. Only directory-initialization type functions should
+ * use this then. Everything else wants ocfs2_supports_dir_trailer()
+ */
+static int ocfs2_new_dir_wants_trailer(struct inode *dir)
 {
-       return ocfs2_meta_ecc(osb);
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+
+       return ocfs2_meta_ecc(osb) ||
+               ocfs2_supports_indexed_dirs(osb);
 }
 
 static inline unsigned int ocfs2_dir_trailer_blk_off(struct super_block *sb)
@@ -130,7 +141,7 @@ static int ocfs2_skip_dir_trailer(struct inode *dir,
 {
        unsigned long toff = blklen - sizeof(struct ocfs2_dir_block_trailer);
 
-       if (!ocfs2_dir_has_trailer(dir))
+       if (!ocfs2_supports_dir_trailer(dir))
                return 0;
 
        if (offset != toff)
@@ -140,7 +151,7 @@ static int ocfs2_skip_dir_trailer(struct inode *dir,
 }
 
 static void ocfs2_init_dir_trailer(struct inode *inode,
-                                  struct buffer_head *bh)
+                                  struct buffer_head *bh, u16 rec_len)
 {
        struct ocfs2_dir_block_trailer *trailer;
 
@@ -150,6 +161,153 @@ static void ocfs2_init_dir_trailer(struct inode *inode,
                        cpu_to_le16(sizeof(struct ocfs2_dir_block_trailer));
        trailer->db_parent_dinode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
        trailer->db_blkno = cpu_to_le64(bh->b_blocknr);
+       trailer->db_free_rec_len = cpu_to_le16(rec_len);
+}
+/*
+ * Link an unindexed block with a dir trailer structure into the index free
+ * list. This function will modify dirdata_bh, but assumes you've already
+ * passed it to the journal.
+ */
+static int ocfs2_dx_dir_link_trailer(struct inode *dir, handle_t *handle,
+                                    struct buffer_head *dx_root_bh,
+                                    struct buffer_head *dirdata_bh)
+{
+       int ret;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dir_block_trailer *trailer;
+
+       ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+       trailer = ocfs2_trailer_from_bh(dirdata_bh, dir->i_sb);
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+
+       trailer->db_free_next = dx_root->dr_free_blk;
+       dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr);
+
+       ocfs2_journal_dirty(handle, dx_root_bh);
+
+out:
+       return ret;
+}
+
+static int ocfs2_free_list_at_root(struct ocfs2_dir_lookup_result *res)
+{
+       return res->dl_prev_leaf_bh == NULL;
+}
+
+void ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res)
+{
+       brelse(res->dl_dx_root_bh);
+       brelse(res->dl_leaf_bh);
+       brelse(res->dl_dx_leaf_bh);
+       brelse(res->dl_prev_leaf_bh);
+}
+
+static int ocfs2_dir_indexed(struct inode *inode)
+{
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INDEXED_DIR_FL)
+               return 1;
+       return 0;
+}
+
+static inline int ocfs2_dx_root_inline(struct ocfs2_dx_root_block *dx_root)
+{
+       return dx_root->dr_flags & OCFS2_DX_FLAG_INLINE;
+}
+
+/*
+ * Hashing code adapted from ext3
+ */
+#define DELTA 0x9E3779B9
+
+static void TEA_transform(__u32 buf[4], __u32 const in[])
+{
+       __u32   sum = 0;
+       __u32   b0 = buf[0], b1 = buf[1];
+       __u32   a = in[0], b = in[1], c = in[2], d = in[3];
+       int     n = 16;
+
+       do {
+               sum += DELTA;
+               b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
+               b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
+       } while (--n);
+
+       buf[0] += b0;
+       buf[1] += b1;
+}
+
+static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
+{
+       __u32   pad, val;
+       int     i;
+
+       pad = (__u32)len | ((__u32)len << 8);
+       pad |= pad << 16;
+
+       val = pad;
+       if (len > num*4)
+               len = num * 4;
+       for (i = 0; i < len; i++) {
+               if ((i % 4) == 0)
+                       val = pad;
+               val = msg[i] + (val << 8);
+               if ((i % 4) == 3) {
+                       *buf++ = val;
+                       val = pad;
+                       num--;
+               }
+       }
+       if (--num >= 0)
+               *buf++ = val;
+       while (--num >= 0)
+               *buf++ = pad;
+}
+
+static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len,
+                                  struct ocfs2_dx_hinfo *hinfo)
+{
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       const char      *p;
+       __u32           in[8], buf[4];
+
+       /*
+        * XXX: Is this really necessary, if the index is never looked
+        * at by readdir? Is a hash value of '0' a bad idea?
+        */
+       if ((len == 1 && !strncmp(".", name, 1)) ||
+           (len == 2 && !strncmp("..", name, 2))) {
+               buf[0] = buf[1] = 0;
+               goto out;
+       }
+
+#ifdef OCFS2_DEBUG_DX_DIRS
+       /*
+        * This makes it very easy to debug indexing problems. We
+        * should never allow this to be selected without hand editing
+        * this file though.
+        */
+       buf[0] = buf[1] = len;
+       goto out;
+#endif
+
+       memcpy(buf, osb->osb_dx_seed, sizeof(buf));
+
+       p = name;
+       while (len > 0) {
+               str2hashbuf(p, len, in, 4);
+               TEA_transform(buf, in);
+               len -= 16;
+               p += 16;
+       }
+
+out:
+       hinfo->major_hash = buf[0];
+       hinfo->minor_hash = buf[1];
 }
 
 /*
@@ -311,6 +469,52 @@ static int ocfs2_validate_dir_block(struct super_block *sb,
        return rc;
 }
 
+/*
+ * Validate a directory trailer.
+ *
+ * We check the trailer here rather than in ocfs2_validate_dir_block()
+ * because that function doesn't have the inode to test.
+ */
+static int ocfs2_check_dir_trailer(struct inode *dir, struct buffer_head *bh)
+{
+       int rc = 0;
+       struct ocfs2_dir_block_trailer *trailer;
+
+       trailer = ocfs2_trailer_from_bh(bh, dir->i_sb);
+       if (!OCFS2_IS_VALID_DIR_TRAILER(trailer)) {
+               rc = -EINVAL;
+               ocfs2_error(dir->i_sb,
+                           "Invalid dirblock #%llu: "
+                           "signature = %.*s\n",
+                           (unsigned long long)bh->b_blocknr, 7,
+                           trailer->db_signature);
+               goto out;
+       }
+       if (le64_to_cpu(trailer->db_blkno) != bh->b_blocknr) {
+               rc = -EINVAL;
+               ocfs2_error(dir->i_sb,
+                           "Directory block #%llu has an invalid "
+                           "db_blkno of %llu",
+                           (unsigned long long)bh->b_blocknr,
+                           (unsigned long long)le64_to_cpu(trailer->db_blkno));
+               goto out;
+       }
+       if (le64_to_cpu(trailer->db_parent_dinode) !=
+           OCFS2_I(dir)->ip_blkno) {
+               rc = -EINVAL;
+               ocfs2_error(dir->i_sb,
+                           "Directory block #%llu on dinode "
+                           "#%llu has an invalid parent_dinode "
+                           "of %llu",
+                           (unsigned long long)bh->b_blocknr,
+                           (unsigned long long)OCFS2_I(dir)->ip_blkno,
+                           (unsigned long long)le64_to_cpu(trailer->db_blkno));
+               goto out;
+       }
+out:
+       return rc;
+}
+
 /*
  * This function forces all errors to -EIO for consistency with its
  * predecessor, ocfs2_bread().  We haven't audited what returning the
@@ -322,7 +526,6 @@ static int ocfs2_read_dir_block(struct inode *inode, u64 v_block,
 {
        int rc = 0;
        struct buffer_head *tmp = *bh;
-       struct ocfs2_dir_block_trailer *trailer;
 
        rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, flags,
                                    ocfs2_validate_dir_block);
@@ -331,42 +534,13 @@ static int ocfs2_read_dir_block(struct inode *inode, u64 v_block,
                goto out;
        }
 
-       /*
-        * We check the trailer here rather than in
-        * ocfs2_validate_dir_block() because that function doesn't have
-        * the inode to test.
-        */
        if (!(flags & OCFS2_BH_READAHEAD) &&
-           ocfs2_dir_has_trailer(inode)) {
-               trailer = ocfs2_trailer_from_bh(tmp, inode->i_sb);
-               if (!OCFS2_IS_VALID_DIR_TRAILER(trailer)) {
-                       rc = -EINVAL;
-                       ocfs2_error(inode->i_sb,
-                                   "Invalid dirblock #%llu: "
-                                   "signature = %.*s\n",
-                                   (unsigned long long)tmp->b_blocknr, 7,
-                                   trailer->db_signature);
-                       goto out;
-               }
-               if (le64_to_cpu(trailer->db_blkno) != tmp->b_blocknr) {
-                       rc = -EINVAL;
-                       ocfs2_error(inode->i_sb,
-                                   "Directory block #%llu has an invalid "
-                                   "db_blkno of %llu",
-                                   (unsigned long long)tmp->b_blocknr,
-                                   (unsigned long long)le64_to_cpu(trailer->db_blkno));
-                       goto out;
-               }
-               if (le64_to_cpu(trailer->db_parent_dinode) !=
-                   OCFS2_I(inode)->ip_blkno) {
-                       rc = -EINVAL;
-                       ocfs2_error(inode->i_sb,
-                                   "Directory block #%llu on dinode "
-                                   "#%llu has an invalid parent_dinode "
-                                   "of %llu",
-                                   (unsigned long long)tmp->b_blocknr,
-                                   (unsigned long long)OCFS2_I(inode)->ip_blkno,
-                                   (unsigned long long)le64_to_cpu(trailer->db_blkno));
+           ocfs2_supports_dir_trailer(inode)) {
+               rc = ocfs2_check_dir_trailer(inode, tmp);
+               if (rc) {
+                       if (!*bh)
+                               brelse(tmp);
+                       mlog_errno(rc);
                        goto out;
                }
        }
@@ -379,6 +553,141 @@ out:
        return rc ? -EIO : 0;
 }
 
+/*
+ * Read the block at 'phys' which belongs to this directory
+ * inode. This function does no virtual->physical block translation -
+ * what's passed in is assumed to be a valid directory block.
+ */
+static int ocfs2_read_dir_block_direct(struct inode *dir, u64 phys,
+                                      struct buffer_head **bh)
+{
+       int ret;
+       struct buffer_head *tmp = *bh;
+
+       ret = ocfs2_read_block(dir, phys, &tmp, ocfs2_validate_dir_block);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (ocfs2_supports_dir_trailer(dir)) {
+               ret = ocfs2_check_dir_trailer(dir, tmp);
+               if (ret) {
+                       if (!*bh)
+                               brelse(tmp);
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       if (!ret && !*bh)
+               *bh = tmp;
+out:
+       return ret;
+}
+
+static int ocfs2_validate_dx_root(struct super_block *sb,
+                                 struct buffer_head *bh)
+{
+       int ret;
+       struct ocfs2_dx_root_block *dx_root;
+
+       BUG_ON(!buffer_uptodate(bh));
+
+       dx_root = (struct ocfs2_dx_root_block *) bh->b_data;
+
+       ret = ocfs2_validate_meta_ecc(sb, bh->b_data, &dx_root->dr_check);
+       if (ret) {
+               mlog(ML_ERROR,
+                    "Checksum failed for dir index root block %llu\n",
+                    (unsigned long long)bh->b_blocknr);
+               return ret;
+       }
+
+       if (!OCFS2_IS_VALID_DX_ROOT(dx_root)) {
+               ocfs2_error(sb,
+                           "Dir Index Root # %llu has bad signature %.*s",
+                           (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
+                           7, dx_root->dr_signature);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ocfs2_read_dx_root(struct inode *dir, struct ocfs2_dinode *di,
+                             struct buffer_head **dx_root_bh)
+{
+       int ret;
+       u64 blkno = le64_to_cpu(di->i_dx_root);
+       struct buffer_head *tmp = *dx_root_bh;
+
+       ret = ocfs2_read_block(dir, blkno, &tmp, ocfs2_validate_dx_root);
+
+       /* If ocfs2_read_block() got us a new bh, pass it up. */
+       if (!ret && !*dx_root_bh)
+               *dx_root_bh = tmp;
+
+       return ret;
+}
+
+static int ocfs2_validate_dx_leaf(struct super_block *sb,
+                                 struct buffer_head *bh)
+{
+       int ret;
+       struct ocfs2_dx_leaf *dx_leaf = (struct ocfs2_dx_leaf *)bh->b_data;
+
+       BUG_ON(!buffer_uptodate(bh));
+
+       ret = ocfs2_validate_meta_ecc(sb, bh->b_data, &dx_leaf->dl_check);
+       if (ret) {
+               mlog(ML_ERROR,
+                    "Checksum failed for dir index leaf block %llu\n",
+                    (unsigned long long)bh->b_blocknr);
+               return ret;
+       }
+
+       if (!OCFS2_IS_VALID_DX_LEAF(dx_leaf)) {
+               ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s",
+                           7, dx_leaf->dl_signature);
+               return -EROFS;
+       }
+
+       return 0;
+}
+
+static int ocfs2_read_dx_leaf(struct inode *dir, u64 blkno,
+                             struct buffer_head **dx_leaf_bh)
+{
+       int ret;
+       struct buffer_head *tmp = *dx_leaf_bh;
+
+       ret = ocfs2_read_block(dir, blkno, &tmp, ocfs2_validate_dx_leaf);
+
+       /* If ocfs2_read_block() got us a new bh, pass it up. */
+       if (!ret && !*dx_leaf_bh)
+               *dx_leaf_bh = tmp;
+
+       return ret;
+}
+
+/*
+ * Read a series of dx_leaf blocks. This expects all buffer_head
+ * pointers to be NULL on function entry.
+ */
+static int ocfs2_read_dx_leaves(struct inode *dir, u64 start, int num,
+                               struct buffer_head **dx_leaf_bhs)
+{
+       int ret;
+
+       ret = ocfs2_read_blocks(dir, start, num, dx_leaf_bhs, 0,
+                               ocfs2_validate_dx_leaf);
+       if (ret)
+               mlog_errno(ret);
+
+       return ret;
+}
+
 static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen,
                                               struct inode *dir,
                                               struct ocfs2_dir_entry **res_dir)
@@ -480,87 +789,392 @@ cleanup_and_exit:
        return ret;
 }
 
-/*
- * Try to find an entry of the provided name within 'dir'.
- *
- * If nothing was found, NULL is returned. Otherwise, a buffer_head
- * and pointer to the dir entry are passed back.
- *
- * Caller can NOT assume anything about the contents of the
- * buffer_head - it is passed back only so that it can be passed into
- * any one of the manipulation functions (add entry, delete entry,
- * etc). As an example, bh in the extent directory case is a data
- * block, in the inline-data case it actually points to an inode.
- */
-struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
-                                    struct inode *dir,
-                                    struct ocfs2_dir_entry **res_dir)
+static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
+                                  struct ocfs2_extent_list *el,
+                                  u32 major_hash,
+                                  u32 *ret_cpos,
+                                  u64 *ret_phys_blkno,
+                                  unsigned int *ret_clen)
 {
-       *res_dir = NULL;
+       int ret = 0, i, found;
+       struct buffer_head *eb_bh = NULL;
+       struct ocfs2_extent_block *eb;
+       struct ocfs2_extent_rec *rec = NULL;
 
-       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-               return ocfs2_find_entry_id(name, namelen, dir, res_dir);
+       if (el->l_tree_depth) {
+               ret = ocfs2_find_leaf(inode, el, major_hash, &eb_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+               el = &eb->h_list;
+
+               if (el->l_tree_depth) {
+                       ocfs2_error(inode->i_sb,
+                                   "Inode %lu has non zero tree depth in "
+                                   "btree tree block %llu\n", inode->i_ino,
+                                   (unsigned long long)eb_bh->b_blocknr);
+                       ret = -EROFS;
+                       goto out;
+               }
+       }
+
+       found = 0;
+       for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
+               rec = &el->l_recs[i];
+
+               if (le32_to_cpu(rec->e_cpos) <= major_hash) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+                           "record (%u, %u, 0) in btree", inode->i_ino,
+                           le32_to_cpu(rec->e_cpos),
+                           ocfs2_rec_clusters(el, rec));
+               ret = -EROFS;
+               goto out;
+       }
+
+       if (ret_phys_blkno)
+               *ret_phys_blkno = le64_to_cpu(rec->e_blkno);
+       if (ret_cpos)
+               *ret_cpos = le32_to_cpu(rec->e_cpos);
+       if (ret_clen)
+               *ret_clen = le16_to_cpu(rec->e_leaf_clusters);
 
-       return ocfs2_find_entry_el(name, namelen, dir, res_dir);
+out:
+       brelse(eb_bh);
+       return ret;
 }
 
 /*
- * Update inode number and type of a previously found directory entry.
+ * Returns the block index, from the start of the cluster which this
+ * hash belongs too.
  */
-int ocfs2_update_entry(struct inode *dir, handle_t *handle,
-                      struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
-                      struct inode *new_entry_inode)
+static inline unsigned int __ocfs2_dx_dir_hash_idx(struct ocfs2_super *osb,
+                                                  u32 minor_hash)
 {
-       int ret;
-       ocfs2_journal_access_func access = ocfs2_journal_access_db;
+       return minor_hash & osb->osb_dx_mask;
+}
 
-       /*
-        * The same code works fine for both inline-data and extent
-        * based directories, so no need to split this up.  The only
-        * difference is the journal_access function.
-        */
+static inline unsigned int ocfs2_dx_dir_hash_idx(struct ocfs2_super *osb,
+                                         struct ocfs2_dx_hinfo *hinfo)
+{
+       return __ocfs2_dx_dir_hash_idx(osb, hinfo->minor_hash);
+}
 
-       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-               access = ocfs2_journal_access_di;
+static int ocfs2_dx_dir_lookup(struct inode *inode,
+                              struct ocfs2_extent_list *el,
+                              struct ocfs2_dx_hinfo *hinfo,
+                              u32 *ret_cpos,
+                              u64 *ret_phys_blkno)
+{
+       int ret = 0;
+       unsigned int cend, uninitialized_var(clen);
+       u32 uninitialized_var(cpos);
+       u64 uninitialized_var(blkno);
+       u32 name_hash = hinfo->major_hash;
 
-       ret = access(handle, dir, de_bh, OCFS2_JOURNAL_ACCESS_WRITE);
+       ret = ocfs2_dx_dir_lookup_rec(inode, el, name_hash, &cpos, &blkno,
+                                     &clen);
        if (ret) {
                mlog_errno(ret);
                goto out;
        }
 
-       de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno);
-       ocfs2_set_de_type(de, new_entry_inode->i_mode);
+       cend = cpos + clen;
+       if (name_hash >= cend) {
+               /* We want the last cluster */
+               blkno += ocfs2_clusters_to_blocks(inode->i_sb, clen - 1);
+               cpos += clen - 1;
+       } else {
+               blkno += ocfs2_clusters_to_blocks(inode->i_sb,
+                                                 name_hash - cpos);
+               cpos = name_hash;
+       }
 
-       ocfs2_journal_dirty(handle, de_bh);
+       /*
+        * We now have the cluster which should hold our entry. To
+        * find the exact block from the start of the cluster to
+        * search, we take the lower bits of the hash.
+        */
+       blkno += ocfs2_dx_dir_hash_idx(OCFS2_SB(inode->i_sb), hinfo);
+
+       if (ret_phys_blkno)
+               *ret_phys_blkno = blkno;
+       if (ret_cpos)
+               *ret_cpos = cpos;
 
 out:
+
        return ret;
 }
 
-static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
-                               struct ocfs2_dir_entry *de_del,
-                               struct buffer_head *bh, char *first_de,
-                               unsigned int bytes)
+static int ocfs2_dx_dir_search(const char *name, int namelen,
+                              struct inode *dir,
+                              struct ocfs2_dx_root_block *dx_root,
+                              struct ocfs2_dir_lookup_result *res)
 {
-       struct ocfs2_dir_entry *de, *pde;
-       int i, status = -ENOENT;
-       ocfs2_journal_access_func access = ocfs2_journal_access_db;
+       int ret, i, found;
+       u64 uninitialized_var(phys);
+       struct buffer_head *dx_leaf_bh = NULL;
+       struct ocfs2_dx_leaf *dx_leaf;
+       struct ocfs2_dx_entry *dx_entry = NULL;
+       struct buffer_head *dir_ent_bh = NULL;
+       struct ocfs2_dir_entry *dir_ent = NULL;
+       struct ocfs2_dx_hinfo *hinfo = &res->dl_hinfo;
+       struct ocfs2_extent_list *dr_el;
+       struct ocfs2_dx_entry_list *entry_list;
+
+       ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo);
+
+       if (ocfs2_dx_root_inline(dx_root)) {
+               entry_list = &dx_root->dr_entries;
+               goto search;
+       }
 
-       mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
+       dr_el = &dx_root->dr_list;
 
-       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-               access = ocfs2_journal_access_di;
+       ret = ocfs2_dx_dir_lookup(dir, dr_el, hinfo, NULL, &phys);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
 
-       i = 0;
-       pde = NULL;
-       de = (struct ocfs2_dir_entry *) first_de;
-       while (i < bytes) {
-               if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
-                       status = -EIO;
-                       mlog_errno(status);
-                       goto bail;
-               }
+       mlog(0, "Dir %llu: name: \"%.*s\", lookup of hash: %u.0x%x "
+            "returns: %llu\n",
+            (unsigned long long)OCFS2_I(dir)->ip_blkno,
+            namelen, name, hinfo->major_hash, hinfo->minor_hash,
+            (unsigned long long)phys);
+
+       ret = ocfs2_read_dx_leaf(dir, phys, &dx_leaf_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       dx_leaf = (struct ocfs2_dx_leaf *) dx_leaf_bh->b_data;
+
+       mlog(0, "leaf info: num_used: %d, count: %d\n",
+            le16_to_cpu(dx_leaf->dl_list.de_num_used),
+            le16_to_cpu(dx_leaf->dl_list.de_count));
+
+       entry_list = &dx_leaf->dl_list;
+
+search:
+       /*
+        * Empty leaf is legal, so no need to check for that.
+        */
+       found = 0;
+       for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++) {
+               dx_entry = &entry_list->de_entries[i];
+
+               if (hinfo->major_hash != le32_to_cpu(dx_entry->dx_major_hash)
+                   || hinfo->minor_hash != le32_to_cpu(dx_entry->dx_minor_hash))
+                       continue;
+
+               /*
+                * Search unindexed leaf block now. We're not
+                * guaranteed to find anything.
+                */
+               ret = ocfs2_read_dir_block_direct(dir,
+                                         le64_to_cpu(dx_entry->dx_dirent_blk),
+                                         &dir_ent_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               /*
+                * XXX: We should check the unindexed block here,
+                * before using it.
+                */
+
+               found = ocfs2_search_dirblock(dir_ent_bh, dir, name, namelen,
+                                             0, dir_ent_bh->b_data,
+                                             dir->i_sb->s_blocksize, &dir_ent);
+               if (found == 1)
+                       break;
+
+               if (found == -1) {
+                       /* This means we found a bad directory entry. */
+                       ret = -EIO;
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               brelse(dir_ent_bh);
+               dir_ent_bh = NULL;
+       }
+
+       if (found <= 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       res->dl_leaf_bh = dir_ent_bh;
+       res->dl_entry = dir_ent;
+       res->dl_dx_leaf_bh = dx_leaf_bh;
+       res->dl_dx_entry = dx_entry;
+
+       ret = 0;
+out:
+       if (ret) {
+               brelse(dx_leaf_bh);
+               brelse(dir_ent_bh);
+       }
+       return ret;
+}
+
+static int ocfs2_find_entry_dx(const char *name, int namelen,
+                              struct inode *dir,
+                              struct ocfs2_dir_lookup_result *lookup)
+{
+       int ret;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dinode *di;
+       struct buffer_head *dx_root_bh = NULL;
+       struct ocfs2_dx_root_block *dx_root;
+
+       ret = ocfs2_read_inode_block(dir, &di_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       ret = ocfs2_read_dx_root(dir, di, &dx_root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+       dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data;
+
+       ret = ocfs2_dx_dir_search(name, namelen, dir, dx_root, lookup);
+       if (ret) {
+               if (ret != -ENOENT)
+                       mlog_errno(ret);
+               goto out;
+       }
+
+       lookup->dl_dx_root_bh = dx_root_bh;
+       dx_root_bh = NULL;
+out:
+       brelse(di_bh);
+       brelse(dx_root_bh);
+       return ret;
+}
+
+/*
+ * Try to find an entry of the provided name within 'dir'.
+ *
+ * If nothing was found, -ENOENT is returned. Otherwise, zero is
+ * returned and the struct 'res' will contain information useful to
+ * other directory manipulation functions.
+ *
+ * Caller can NOT assume anything about the contents of the
+ * buffer_heads - they are passed back only so that it can be passed
+ * into any one of the manipulation functions (add entry, delete
+ * entry, etc). As an example, bh in the extent directory case is a
+ * data block, in the inline-data case it actually points to an inode,
+ * in the indexed directory case, multiple buffers are involved.
+ */
+int ocfs2_find_entry(const char *name, int namelen,
+                    struct inode *dir, struct ocfs2_dir_lookup_result *lookup)
+{
+       struct buffer_head *bh;
+       struct ocfs2_dir_entry *res_dir = NULL;
+
+       if (ocfs2_dir_indexed(dir))
+               return ocfs2_find_entry_dx(name, namelen, dir, lookup);
+
+       /*
+        * The unindexed dir code only uses part of the lookup
+        * structure, so there's no reason to push it down further
+        * than this.
+        */
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               bh = ocfs2_find_entry_id(name, namelen, dir, &res_dir);
+       else
+               bh = ocfs2_find_entry_el(name, namelen, dir, &res_dir);
+
+       if (bh == NULL)
+               return -ENOENT;
+
+       lookup->dl_leaf_bh = bh;
+       lookup->dl_entry = res_dir;
+       return 0;
+}
+
+/*
+ * Update inode number and type of a previously found directory entry.
+ */
+int ocfs2_update_entry(struct inode *dir, handle_t *handle,
+                      struct ocfs2_dir_lookup_result *res,
+                      struct inode *new_entry_inode)
+{
+       int ret;
+       ocfs2_journal_access_func access = ocfs2_journal_access_db;
+       struct ocfs2_dir_entry *de = res->dl_entry;
+       struct buffer_head *de_bh = res->dl_leaf_bh;
+
+       /*
+        * The same code works fine for both inline-data and extent
+        * based directories, so no need to split this up.  The only
+        * difference is the journal_access function.
+        */
+
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               access = ocfs2_journal_access_di;
+
+       ret = access(handle, dir, de_bh, OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno);
+       ocfs2_set_de_type(de, new_entry_inode->i_mode);
+
+       ocfs2_journal_dirty(handle, de_bh);
+
+out:
+       return ret;
+}
+
+/*
+ * __ocfs2_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
+                               struct ocfs2_dir_entry *de_del,
+                               struct buffer_head *bh, char *first_de,
+                               unsigned int bytes)
+{
+       struct ocfs2_dir_entry *de, *pde;
+       int i, status = -ENOENT;
+       ocfs2_journal_access_func access = ocfs2_journal_access_db;
+
+       mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
+
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               access = ocfs2_journal_access_di;
+
+       i = 0;
+       pde = NULL;
+       de = (struct ocfs2_dir_entry *) first_de;
+       while (i < bytes) {
+               if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
+                       status = -EIO;
+                       mlog_errno(status);
+                       goto bail;
+               }
                if (de == de_del)  {
                        status = access(handle, dir, bh,
                                        OCFS2_JOURNAL_ACCESS_WRITE);
@@ -587,6 +1201,181 @@ bail:
        return status;
 }
 
+static unsigned int ocfs2_figure_dirent_hole(struct ocfs2_dir_entry *de)
+{
+       unsigned int hole;
+
+       if (le64_to_cpu(de->inode) == 0)
+               hole = le16_to_cpu(de->rec_len);
+       else
+               hole = le16_to_cpu(de->rec_len) -
+                       OCFS2_DIR_REC_LEN(de->name_len);
+
+       return hole;
+}
+
+static int ocfs2_find_max_rec_len(struct super_block *sb,
+                                 struct buffer_head *dirblock_bh)
+{
+       int size, this_hole, largest_hole = 0;
+       char *trailer, *de_buf, *limit, *start = dirblock_bh->b_data;
+       struct ocfs2_dir_entry *de;
+
+       trailer = (char *)ocfs2_trailer_from_bh(dirblock_bh, sb);
+       size = ocfs2_dir_trailer_blk_off(sb);
+       limit = start + size;
+       de_buf = start;
+       de = (struct ocfs2_dir_entry *)de_buf;
+       do {
+               if (de_buf != trailer) {
+                       this_hole = ocfs2_figure_dirent_hole(de);
+                       if (this_hole > largest_hole)
+                               largest_hole = this_hole;
+               }
+
+               de_buf += le16_to_cpu(de->rec_len);
+               de = (struct ocfs2_dir_entry *)de_buf;
+       } while (de_buf < limit);
+
+       if (largest_hole >= OCFS2_DIR_MIN_REC_LEN)
+               return largest_hole;
+       return 0;
+}
+
+static void ocfs2_dx_list_remove_entry(struct ocfs2_dx_entry_list *entry_list,
+                                      int index)
+{
+       int num_used = le16_to_cpu(entry_list->de_num_used);
+
+       if (num_used == 1 || index == (num_used - 1))
+               goto clear;
+
+       memmove(&entry_list->de_entries[index],
+               &entry_list->de_entries[index + 1],
+               (num_used - index - 1)*sizeof(struct ocfs2_dx_entry));
+clear:
+       num_used--;
+       memset(&entry_list->de_entries[num_used], 0,
+              sizeof(struct ocfs2_dx_entry));
+       entry_list->de_num_used = cpu_to_le16(num_used);
+}
+
+static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir,
+                                struct ocfs2_dir_lookup_result *lookup)
+{
+       int ret, index, max_rec_len, add_to_free_list = 0;
+       struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh;
+       struct buffer_head *leaf_bh = lookup->dl_leaf_bh;
+       struct ocfs2_dx_leaf *dx_leaf;
+       struct ocfs2_dx_entry *dx_entry = lookup->dl_dx_entry;
+       struct ocfs2_dir_block_trailer *trailer;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dx_entry_list *entry_list;
+
+       /*
+        * This function gets a bit messy because we might have to
+        * modify the root block, regardless of whether the indexed
+        * entries are stored inline.
+        */
+
+       /*
+        * *Only* set 'entry_list' here, based on where we're looking
+        * for the indexed entries. Later, we might still want to
+        * journal both blocks, based on free list state.
+        */
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+       if (ocfs2_dx_root_inline(dx_root)) {
+               entry_list = &dx_root->dr_entries;
+       } else {
+               dx_leaf = (struct ocfs2_dx_leaf *) lookup->dl_dx_leaf_bh->b_data;
+               entry_list = &dx_leaf->dl_list;
+       }
+
+       /* Neither of these are a disk corruption - that should have
+        * been caught by lookup, before we got here. */
+       BUG_ON(le16_to_cpu(entry_list->de_count) <= 0);
+       BUG_ON(le16_to_cpu(entry_list->de_num_used) <= 0);
+
+       index = (char *)dx_entry - (char *)entry_list->de_entries;
+       index /= sizeof(*dx_entry);
+
+       if (index >= le16_to_cpu(entry_list->de_num_used)) {
+               mlog(ML_ERROR, "Dir %llu: Bad dx_entry ptr idx %d, (%p, %p)\n",
+                    (unsigned long long)OCFS2_I(dir)->ip_blkno, index,
+                    entry_list, dx_entry);
+               return -EIO;
+       }
+
+       /*
+        * We know that removal of this dirent will leave enough room
+        * for a new one, so add this block to the free list if it
+        * isn't already there.
+        */
+       trailer = ocfs2_trailer_from_bh(leaf_bh, dir->i_sb);
+       if (trailer->db_free_rec_len == 0)
+               add_to_free_list = 1;
+
+       /*
+        * Add the block holding our index into the journal before
+        * removing the unindexed entry. If we get an error return
+        * from __ocfs2_delete_entry(), then it hasn't removed the
+        * entry yet. Likewise, successful return means we *must*
+        * remove the indexed entry.
+        *
+        * We're also careful to journal the root tree block here as
+        * the entry count needs to be updated. Also, we might be
+        * adding to the start of the free list.
+        */
+       ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (!ocfs2_dx_root_inline(dx_root)) {
+               ret = ocfs2_journal_access_dl(handle, dir,
+                                             lookup->dl_dx_leaf_bh,
+                                             OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       mlog(0, "Dir %llu: delete entry at index: %d\n",
+            (unsigned long long)OCFS2_I(dir)->ip_blkno, index);
+
+       ret = __ocfs2_delete_entry(handle, dir, lookup->dl_entry,
+                                  leaf_bh, leaf_bh->b_data, leaf_bh->b_size);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       max_rec_len = ocfs2_find_max_rec_len(dir->i_sb, leaf_bh);
+       trailer->db_free_rec_len = cpu_to_le16(max_rec_len);
+       if (add_to_free_list) {
+               trailer->db_free_next = dx_root->dr_free_blk;
+               dx_root->dr_free_blk = cpu_to_le64(leaf_bh->b_blocknr);
+               ocfs2_journal_dirty(handle, dx_root_bh);
+       }
+
+       /* leaf_bh was journal_accessed for us in __ocfs2_delete_entry */
+       ocfs2_journal_dirty(handle, leaf_bh);
+
+       le32_add_cpu(&dx_root->dr_num_entries, -1);
+       ocfs2_journal_dirty(handle, dx_root_bh);
+
+       ocfs2_dx_list_remove_entry(entry_list, index);
+
+       if (!ocfs2_dx_root_inline(dx_root))
+               ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh);
+
+out:
+       return ret;
+}
+
 static inline int ocfs2_delete_entry_id(handle_t *handle,
                                        struct inode *dir,
                                        struct ocfs2_dir_entry *de_del,
@@ -624,18 +1413,22 @@ static inline int ocfs2_delete_entry_el(handle_t *handle,
 }
 
 /*
- * ocfs2_delete_entry deletes a directory entry by merging it with the
- * previous entry
+ * Delete a directory entry. Hide the details of directory
+ * implementation from the caller.
  */
 int ocfs2_delete_entry(handle_t *handle,
                       struct inode *dir,
-                      struct ocfs2_dir_entry *de_del,
-                      struct buffer_head *bh)
+                      struct ocfs2_dir_lookup_result *res)
 {
+       if (ocfs2_dir_indexed(dir))
+               return ocfs2_delete_entry_dx(handle, dir, res);
+
        if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-               return ocfs2_delete_entry_id(handle, dir, de_del, bh);
+               return ocfs2_delete_entry_id(handle, dir, res->dl_entry,
+                                            res->dl_leaf_bh);
 
-       return ocfs2_delete_entry_el(handle, dir, de_del, bh);
+       return ocfs2_delete_entry_el(handle, dir, res->dl_entry,
+                                    res->dl_leaf_bh);
 }
 
 /*
@@ -663,45 +1456,218 @@ static inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de,
        return 0;
 }
 
-/* we don't always have a dentry for what we want to add, so people
- * like orphan dir can call this instead.
- *
- * If you pass me insert_bh, I'll skip the search of the other dir
- * blocks and put the record in there.
- */
-int __ocfs2_add_entry(handle_t *handle,
-                     struct inode *dir,
-                     const char *name, int namelen,
-                     struct inode *inode, u64 blkno,
-                     struct buffer_head *parent_fe_bh,
-                     struct buffer_head *insert_bh)
+static void ocfs2_dx_dir_leaf_insert_tail(struct ocfs2_dx_leaf *dx_leaf,
+                                         struct ocfs2_dx_entry *dx_new_entry)
 {
-       unsigned long offset;
-       unsigned short rec_len;
-       struct ocfs2_dir_entry *de, *de1;
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data;
-       struct super_block *sb = dir->i_sb;
-       int retval, status;
-       unsigned int size = sb->s_blocksize;
-       char *data_start = insert_bh->b_data;
+       int i;
 
-       mlog_entry_void();
+       i = le16_to_cpu(dx_leaf->dl_list.de_num_used);
+       dx_leaf->dl_list.de_entries[i] = *dx_new_entry;
 
-       if (!namelen)
-               return -EINVAL;
+       le16_add_cpu(&dx_leaf->dl_list.de_num_used, 1);
+}
 
-       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
-               data_start = di->id2.i_data.id_data;
-               size = i_size_read(dir);
+static void ocfs2_dx_entry_list_insert(struct ocfs2_dx_entry_list *entry_list,
+                                      struct ocfs2_dx_hinfo *hinfo,
+                                      u64 dirent_blk)
+{
+       int i;
+       struct ocfs2_dx_entry *dx_entry;
 
-               BUG_ON(insert_bh != parent_fe_bh);
-       }
+       i = le16_to_cpu(entry_list->de_num_used);
+       dx_entry = &entry_list->de_entries[i];
 
-       rec_len = OCFS2_DIR_REC_LEN(namelen);
-       offset = 0;
-       de = (struct ocfs2_dir_entry *) data_start;
-       while (1) {
-               BUG_ON((char *)de >= (size + data_start));
+       memset(dx_entry, 0, sizeof(*dx_entry));
+       dx_entry->dx_major_hash = cpu_to_le32(hinfo->major_hash);
+       dx_entry->dx_minor_hash = cpu_to_le32(hinfo->minor_hash);
+       dx_entry->dx_dirent_blk = cpu_to_le64(dirent_blk);
+
+       le16_add_cpu(&entry_list->de_num_used, 1);
+}
+
+static int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle,
+                                     struct ocfs2_dx_hinfo *hinfo,
+                                     u64 dirent_blk,
+                                     struct buffer_head *dx_leaf_bh)
+{
+       int ret;
+       struct ocfs2_dx_leaf *dx_leaf;
+
+       ret = ocfs2_journal_access_dl(handle, dir, dx_leaf_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data;
+       ocfs2_dx_entry_list_insert(&dx_leaf->dl_list, hinfo, dirent_blk);
+       ocfs2_journal_dirty(handle, dx_leaf_bh);
+
+out:
+       return ret;
+}
+
+static void ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle,
+                                       struct ocfs2_dx_hinfo *hinfo,
+                                       u64 dirent_blk,
+                                       struct ocfs2_dx_root_block *dx_root)
+{
+       ocfs2_dx_entry_list_insert(&dx_root->dr_entries, hinfo, dirent_blk);
+}
+
+static int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle,
+                              struct ocfs2_dir_lookup_result *lookup)
+{
+       int ret = 0;
+       struct ocfs2_dx_root_block *dx_root;
+       struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh;
+
+       ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       dx_root = (struct ocfs2_dx_root_block *)lookup->dl_dx_root_bh->b_data;
+       if (ocfs2_dx_root_inline(dx_root)) {
+               ocfs2_dx_inline_root_insert(dir, handle,
+                                           &lookup->dl_hinfo,
+                                           lookup->dl_leaf_bh->b_blocknr,
+                                           dx_root);
+       } else {
+               ret = __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo,
+                                                lookup->dl_leaf_bh->b_blocknr,
+                                                lookup->dl_dx_leaf_bh);
+               if (ret)
+                       goto out;
+       }
+
+       le32_add_cpu(&dx_root->dr_num_entries, 1);
+       ocfs2_journal_dirty(handle, dx_root_bh);
+
+out:
+       return ret;
+}
+
+static void ocfs2_remove_block_from_free_list(struct inode *dir,
+                                      handle_t *handle,
+                                      struct ocfs2_dir_lookup_result *lookup)
+{
+       struct ocfs2_dir_block_trailer *trailer, *prev;
+       struct ocfs2_dx_root_block *dx_root;
+       struct buffer_head *bh;
+
+       trailer = ocfs2_trailer_from_bh(lookup->dl_leaf_bh, dir->i_sb);
+
+       if (ocfs2_free_list_at_root(lookup)) {
+               bh = lookup->dl_dx_root_bh;
+               dx_root = (struct ocfs2_dx_root_block *)bh->b_data;
+               dx_root->dr_free_blk = trailer->db_free_next;
+       } else {
+               bh = lookup->dl_prev_leaf_bh;
+               prev = ocfs2_trailer_from_bh(bh, dir->i_sb);
+               prev->db_free_next = trailer->db_free_next;
+       }
+
+       trailer->db_free_rec_len = cpu_to_le16(0);
+       trailer->db_free_next = cpu_to_le64(0);
+
+       ocfs2_journal_dirty(handle, bh);
+       ocfs2_journal_dirty(handle, lookup->dl_leaf_bh);
+}
+
+/*
+ * This expects that a journal write has been reserved on
+ * lookup->dl_prev_leaf_bh or lookup->dl_dx_root_bh
+ */
+static void ocfs2_recalc_free_list(struct inode *dir, handle_t *handle,
+                                  struct ocfs2_dir_lookup_result *lookup)
+{
+       int max_rec_len;
+       struct ocfs2_dir_block_trailer *trailer;
+
+       /* Walk dl_leaf_bh to figure out what the new free rec_len is. */
+       max_rec_len = ocfs2_find_max_rec_len(dir->i_sb, lookup->dl_leaf_bh);
+       if (max_rec_len) {
+               /*
+                * There's still room in this block, so no need to remove it
+                * from the free list. In this case, we just want to update
+                * the rec len accounting.
+                */
+               trailer = ocfs2_trailer_from_bh(lookup->dl_leaf_bh, dir->i_sb);
+               trailer->db_free_rec_len = cpu_to_le16(max_rec_len);
+               ocfs2_journal_dirty(handle, lookup->dl_leaf_bh);
+       } else {
+               ocfs2_remove_block_from_free_list(dir, handle, lookup);
+       }
+}
+
+/* we don't always have a dentry for what we want to add, so people
+ * like orphan dir can call this instead.
+ *
+ * The lookup context must have been filled from
+ * ocfs2_prepare_dir_for_insert.
+ */
+int __ocfs2_add_entry(handle_t *handle,
+                     struct inode *dir,
+                     const char *name, int namelen,
+                     struct inode *inode, u64 blkno,
+                     struct buffer_head *parent_fe_bh,
+                     struct ocfs2_dir_lookup_result *lookup)
+{
+       unsigned long offset;
+       unsigned short rec_len;
+       struct ocfs2_dir_entry *de, *de1;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data;
+       struct super_block *sb = dir->i_sb;
+       int retval, status;
+       unsigned int size = sb->s_blocksize;
+       struct buffer_head *insert_bh = lookup->dl_leaf_bh;
+       char *data_start = insert_bh->b_data;
+
+       mlog_entry_void();
+
+       if (!namelen)
+               return -EINVAL;
+
+       if (ocfs2_dir_indexed(dir)) {
+               struct buffer_head *bh;
+
+               /*
+                * An indexed dir may require that we update the free space
+                * list. Reserve a write to the previous node in the list so
+                * that we don't fail later.
+                *
+                * XXX: This can be either a dx_root_block, or an unindexed
+                * directory tree leaf block.
+                */
+               if (ocfs2_free_list_at_root(lookup)) {
+                       bh = lookup->dl_dx_root_bh;
+                       retval = ocfs2_journal_access_dr(handle, dir, bh,
+                                                OCFS2_JOURNAL_ACCESS_WRITE);
+               } else {
+                       bh = lookup->dl_prev_leaf_bh;
+                       retval = ocfs2_journal_access_db(handle, dir, bh,
+                                                OCFS2_JOURNAL_ACCESS_WRITE);
+               }
+               if (retval) {
+                       mlog_errno(retval);
+                       return retval;
+               }
+       } else if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               data_start = di->id2.i_data.id_data;
+               size = i_size_read(dir);
+
+               BUG_ON(insert_bh != parent_fe_bh);
+       }
+
+       rec_len = OCFS2_DIR_REC_LEN(namelen);
+       offset = 0;
+       de = (struct ocfs2_dir_entry *) data_start;
+       while (1) {
+               BUG_ON((char *)de >= (size + data_start));
 
                /* These checks should've already been passed by the
                 * prepare function, but I guess we can leave them
@@ -737,10 +1703,22 @@ int __ocfs2_add_entry(handle_t *handle,
                                status = ocfs2_journal_access_di(handle, dir,
                                                                 insert_bh,
                                                                 OCFS2_JOURNAL_ACCESS_WRITE);
-                       else
+                       else {
                                status = ocfs2_journal_access_db(handle, dir,
                                                                 insert_bh,
-                                                                OCFS2_JOURNAL_ACCESS_WRITE);
+                                             OCFS2_JOURNAL_ACCESS_WRITE);
+
+                               if (ocfs2_dir_indexed(dir)) {
+                                       status = ocfs2_dx_dir_insert(dir,
+                                                               handle,
+                                                               lookup);
+                                       if (status) {
+                                               mlog_errno(status);
+                                               goto bail;
+                                       }
+                               }
+                       }
+
                        /* By now the buffer is marked for journaling */
                        offset += le16_to_cpu(de->rec_len);
                        if (le64_to_cpu(de->inode)) {
@@ -761,6 +1739,9 @@ int __ocfs2_add_entry(handle_t *handle,
                        de->name_len = namelen;
                        memcpy(de->name, name, namelen);
 
+                       if (ocfs2_dir_indexed(dir))
+                               ocfs2_recalc_free_list(dir, handle, lookup);
+
                        dir->i_version++;
                        status = ocfs2_journal_dirty(handle, insert_bh);
                        retval = 0;
@@ -870,6 +1851,10 @@ out:
        return 0;
 }
 
+/*
+ * NOTE: This function can be called against unindexed directories,
+ * and indexed ones.
+ */
 static int ocfs2_dir_foreach_blk_el(struct inode *inode,
                                    u64 *f_version,
                                    loff_t *f_pos, void *priv,
@@ -1071,31 +2056,22 @@ int ocfs2_find_files_on_disk(const char *name,
                             int namelen,
                             u64 *blkno,
                             struct inode *inode,
-                            struct buffer_head **dirent_bh,
-                            struct ocfs2_dir_entry **dirent)
+                            struct ocfs2_dir_lookup_result *lookup)
 {
        int status = -ENOENT;
 
-       mlog_entry("(name=%.*s, blkno=%p, inode=%p, dirent_bh=%p, dirent=%p)\n",
-                  namelen, name, blkno, inode, dirent_bh, dirent);
+       mlog(0, "name=%.*s, blkno=%p, inode=%llu\n", namelen, name, blkno,
+            (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
-       *dirent_bh = ocfs2_find_entry(name, namelen, inode, dirent);
-       if (!*dirent_bh || !*dirent) {
-               status = -ENOENT;
+       status = ocfs2_find_entry(name, namelen, inode, lookup);
+       if (status)
                goto leave;
-       }
 
-       *blkno = le64_to_cpu((*dirent)->inode);
+       *blkno = le64_to_cpu(lookup->dl_entry->inode);
 
        status = 0;
 leave:
-       if (status < 0) {
-               *dirent = NULL;
-               brelse(*dirent_bh);
-               *dirent_bh = NULL;
-       }
 
-       mlog_exit(status);
        return status;
 }
 
@@ -1107,11 +2083,10 @@ int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
                               int namelen, u64 *blkno)
 {
        int ret;
-       struct buffer_head *bh = NULL;
-       struct ocfs2_dir_entry *dirent = NULL;
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
 
-       ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent);
-       brelse(bh);
+       ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &lookup);
+       ocfs2_free_dir_lookup_result(&lookup);
 
        return ret;
 }
@@ -1128,20 +2103,18 @@ int ocfs2_check_dir_for_entry(struct inode *dir,
                              int namelen)
 {
        int ret;
-       struct buffer_head *dirent_bh = NULL;
-       struct ocfs2_dir_entry *dirent = NULL;
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
 
        mlog_entry("dir %llu, name '%.*s'\n",
                   (unsigned long long)OCFS2_I(dir)->ip_blkno, namelen, name);
 
        ret = -EEXIST;
-       dirent_bh = ocfs2_find_entry(name, namelen, dir, &dirent);
-       if (dirent_bh)
+       if (ocfs2_find_entry(name, namelen, dir, &lookup) == 0)
                goto bail;
 
        ret = 0;
 bail:
-       brelse(dirent_bh);
+       ocfs2_free_dir_lookup_result(&lookup);
 
        mlog_exit(ret);
        return ret;
@@ -1151,6 +2124,7 @@ struct ocfs2_empty_dir_priv {
        unsigned seen_dot;
        unsigned seen_dot_dot;
        unsigned seen_other;
+       unsigned dx_dir;
 };
 static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
                                   loff_t pos, u64 ino, unsigned type)
@@ -1160,6 +2134,13 @@ static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
        /*
         * Check the positions of "." and ".." records to be sure
         * they're in the correct place.
+        *
+        * Indexed directories don't need to proceed past the first
+        * two entries, so we end the scan after seeing '..'. Despite
+        * that, we allow the scan to proceed In the event that we
+        * have a corrupted indexed directory (no dot or dot dot
+        * entries). This allows us to double check for existing
+        * entries which might not have been found in the index.
         */
        if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) {
                p->seen_dot = 1;
@@ -1169,16 +2150,57 @@ static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
        if (name_len == 2 && !strncmp("..", name, 2) &&
            pos == OCFS2_DIR_REC_LEN(1)) {
                p->seen_dot_dot = 1;
+
+               if (p->dx_dir && p->seen_dot)
+                       return 1;
+
                return 0;
        }
 
        p->seen_other = 1;
        return 1;
 }
+
+static int ocfs2_empty_dir_dx(struct inode *inode,
+                             struct ocfs2_empty_dir_priv *priv)
+{
+       int ret;
+       struct buffer_head *di_bh = NULL;
+       struct buffer_head *dx_root_bh = NULL;
+       struct ocfs2_dinode *di;
+       struct ocfs2_dx_root_block *dx_root;
+
+       priv->dx_dir = 1;
+
+       ret = ocfs2_read_inode_block(inode, &di_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       ret = ocfs2_read_dx_root(inode, di, &dx_root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+
+       if (le32_to_cpu(dx_root->dr_num_entries) != 2)
+               priv->seen_other = 1;
+
+out:
+       brelse(di_bh);
+       brelse(dx_root_bh);
+       return ret;
+}
+
 /*
  * routine to check that the specified directory is empty (for rmdir)
  *
  * Returns 1 if dir is empty, zero otherwise.
+ *
+ * XXX: This is a performance problem for unindexed directories.
  */
 int ocfs2_empty_dir(struct inode *inode)
 {
@@ -1188,6 +2210,16 @@ int ocfs2_empty_dir(struct inode *inode)
 
        memset(&priv, 0, sizeof(priv));
 
+       if (ocfs2_dir_indexed(inode)) {
+               ret = ocfs2_empty_dir_dx(inode, &priv);
+               if (ret)
+                       mlog_errno(ret);
+               /*
+                * We still run ocfs2_dir_foreach to get the checks
+                * for "." and "..".
+                */
+       }
+
        ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir);
        if (ret)
                mlog_errno(ret);
@@ -1280,7 +2312,8 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
                                 struct inode *parent,
                                 struct inode *inode,
                                 struct buffer_head *fe_bh,
-                                struct ocfs2_alloc_context *data_ac)
+                                struct ocfs2_alloc_context *data_ac,
+                                struct buffer_head **ret_new_bh)
 {
        int status;
        unsigned int size = osb->sb->s_blocksize;
@@ -1289,7 +2322,7 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
 
        mlog_entry_void();
 
-       if (ocfs2_supports_dir_trailer(osb))
+       if (ocfs2_new_dir_wants_trailer(inode))
                size = ocfs2_dir_trailer_blk_off(parent->i_sb);
 
        status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
@@ -1310,8 +2343,19 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
        memset(new_bh->b_data, 0, osb->sb->s_blocksize);
 
        de = ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data, size);
-       if (ocfs2_supports_dir_trailer(osb))
-               ocfs2_init_dir_trailer(inode, new_bh);
+       if (ocfs2_new_dir_wants_trailer(inode)) {
+               int size = le16_to_cpu(de->rec_len);
+
+               /*
+                * Figure out the size of the hole left over after
+                * insertion of '.' and '..'. The trailer wants this
+                * information.
+                */
+               size -= OCFS2_DIR_REC_LEN(2);
+               size -= sizeof(struct ocfs2_dir_block_trailer);
+
+               ocfs2_init_dir_trailer(inode, new_bh, size);
+       }
 
        status = ocfs2_journal_dirty(handle, new_bh);
        if (status < 0) {
@@ -1329,6 +2373,10 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
        }
 
        status = 0;
+       if (ret_new_bh) {
+               *ret_new_bh = new_bh;
+               new_bh = NULL;
+       }
 bail:
        brelse(new_bh);
 
@@ -1336,646 +2384,1981 @@ bail:
        return status;
 }
 
-int ocfs2_fill_new_dir(struct ocfs2_super *osb,
-                      handle_t *handle,
-                      struct inode *parent,
-                      struct inode *inode,
-                      struct buffer_head *fe_bh,
-                      struct ocfs2_alloc_context *data_ac)
-{
-       BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL);
-
-       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-               return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh);
-
-       return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh,
-                                    data_ac);
-}
-
-/*
- * Expand rec_len of the rightmost dirent in a directory block so that it
- * contains the end of our valid space for dirents. We do this during
- * expansion from an inline directory to one with extents. The first dir block
- * in that case is taken from the inline data portion of the inode block.
- *
- * We add the dir trailer if this filesystem wants it.
- */
-static void ocfs2_expand_last_dirent(char *start, unsigned int old_size,
-                                    struct super_block *sb)
+static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb,
+                                    handle_t *handle, struct inode *dir,
+                                    struct buffer_head *di_bh,
+                                    struct buffer_head *dirdata_bh,
+                                    struct ocfs2_alloc_context *meta_ac,
+                                    int dx_inline, u32 num_entries,
+                                    struct buffer_head **ret_dx_root_bh)
 {
-       struct ocfs2_dir_entry *de;
-       struct ocfs2_dir_entry *prev_de;
-       char *de_buf, *limit;
-       unsigned int new_size = sb->s_blocksize;
-       unsigned int bytes;
-
-       if (ocfs2_supports_dir_trailer(OCFS2_SB(sb)))
-               new_size = ocfs2_dir_trailer_blk_off(sb);
+       int ret;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
+       u16 dr_suballoc_bit;
+       u64 dr_blkno;
+       unsigned int num_bits;
+       struct buffer_head *dx_root_bh = NULL;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dir_block_trailer *trailer =
+               ocfs2_trailer_from_bh(dirdata_bh, dir->i_sb);
 
-       bytes = new_size - old_size;
+       ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1, &dr_suballoc_bit,
+                                  &num_bits, &dr_blkno);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
 
-       limit = start + old_size;
-       de_buf = start;
-       de = (struct ocfs2_dir_entry *)de_buf;
-       do {
-               prev_de = de;
-               de_buf += le16_to_cpu(de->rec_len);
-               de = (struct ocfs2_dir_entry *)de_buf;
-       } while (de_buf < limit);
+       mlog(0, "Dir %llu, attach new index block: %llu\n",
+            (unsigned long long)OCFS2_I(dir)->ip_blkno,
+            (unsigned long long)dr_blkno);
 
-       le16_add_cpu(&prev_de->rec_len, bytes);
-}
+       dx_root_bh = sb_getblk(osb->sb, dr_blkno);
+       if (dx_root_bh == NULL) {
+               ret = -EIO;
+               goto out;
+       }
+       ocfs2_set_new_buffer_uptodate(dir, dx_root_bh);
 
-/*
- * We allocate enough clusters to fulfill "blocks_wanted", but set
- * i_size to exactly one block. Ocfs2_extend_dir() will handle the
- * rest automatically for us.
- *
- * *first_block_bh is a pointer to the 1st data block allocated to the
- *  directory.
- */
-static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
-                                  unsigned int blocks_wanted,
-                                  struct buffer_head **first_block_bh)
-{
-       u32 alloc, bit_off, len;
-       struct super_block *sb = dir->i_sb;
-       int ret, credits = ocfs2_inline_to_extents_credits(sb);
-       u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits;
-       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
-       struct ocfs2_inode_info *oi = OCFS2_I(dir);
-       struct ocfs2_alloc_context *data_ac;
-       struct buffer_head *dirdata_bh = NULL;
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
-       handle_t *handle;
-       struct ocfs2_extent_tree et;
-       int did_quota = 0;
+       ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
+                                     OCFS2_JOURNAL_ACCESS_CREATE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
 
-       ocfs2_init_dinode_extent_tree(&et, dir, di_bh);
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+       memset(dx_root, 0, osb->sb->s_blocksize);
+       strcpy(dx_root->dr_signature, OCFS2_DX_ROOT_SIGNATURE);
+       dx_root->dr_suballoc_slot = cpu_to_le16(osb->slot_num);
+       dx_root->dr_suballoc_bit = cpu_to_le16(dr_suballoc_bit);
+       dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation);
+       dx_root->dr_blkno = cpu_to_le64(dr_blkno);
+       dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno);
+       dx_root->dr_num_entries = cpu_to_le32(num_entries);
+       if (le16_to_cpu(trailer->db_free_rec_len))
+               dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr);
+       else
+               dx_root->dr_free_blk = cpu_to_le64(0);
 
-       alloc = ocfs2_clusters_for_bytes(sb, bytes);
+       if (dx_inline) {
+               dx_root->dr_flags |= OCFS2_DX_FLAG_INLINE;
+               dx_root->dr_entries.de_count =
+                       cpu_to_le16(ocfs2_dx_entries_per_root(osb->sb));
+       } else {
+               dx_root->dr_list.l_count =
+                       cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb));
+       }
 
-       /*
-        * We should never need more than 2 clusters for this -
-        * maximum dirent size is far less than one block. In fact,
-        * the only time we'd need more than one cluster is if
-        * blocksize == clustersize and the dirent won't fit in the
-        * extra space that the expansion to a single block gives. As
-        * of today, that only happens on 4k/4k file systems.
-        */
-       BUG_ON(alloc > 2);
+       ret = ocfs2_journal_dirty(handle, dx_root_bh);
+       if (ret)
+               mlog_errno(ret);
 
-       ret = ocfs2_reserve_clusters(osb, alloc, &data_ac);
+       ret = ocfs2_journal_access_di(handle, dir, di_bh,
+                                     OCFS2_JOURNAL_ACCESS_CREATE);
        if (ret) {
                mlog_errno(ret);
                goto out;
        }
 
-       down_write(&oi->ip_alloc_sem);
+       di->i_dx_root = cpu_to_le64(dr_blkno);
 
-       /*
-        * Prepare for worst case allocation scenario of two separate
-        * extents.
-        */
-       if (alloc == 2)
-               credits += OCFS2_SUBALLOC_ALLOC;
+       OCFS2_I(dir)->ip_dyn_features |= OCFS2_INDEXED_DIR_FL;
+       di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features);
 
-       handle = ocfs2_start_trans(osb, credits);
-       if (IS_ERR(handle)) {
-               ret = PTR_ERR(handle);
+       ret = ocfs2_journal_dirty(handle, di_bh);
+       if (ret)
                mlog_errno(ret);
-               goto out_sem;
-       }
 
-       if (vfs_dq_alloc_space_nodirty(dir,
-                               ocfs2_clusters_to_bytes(osb->sb, alloc))) {
-               ret = -EDQUOT;
-               goto out_commit;
+       *ret_dx_root_bh = dx_root_bh;
+       dx_root_bh = NULL;
+
+out:
+       brelse(dx_root_bh);
+       return ret;
+}
+
+static int ocfs2_dx_dir_format_cluster(struct ocfs2_super *osb,
+                                      handle_t *handle, struct inode *dir,
+                                      struct buffer_head **dx_leaves,
+                                      int num_dx_leaves, u64 start_blk)
+{
+       int ret, i;
+       struct ocfs2_dx_leaf *dx_leaf;
+       struct buffer_head *bh;
+
+       for (i = 0; i < num_dx_leaves; i++) {
+               bh = sb_getblk(osb->sb, start_blk + i);
+               if (bh == NULL) {
+                       ret = -EIO;
+                       goto out;
+               }
+               dx_leaves[i] = bh;
+
+               ocfs2_set_new_buffer_uptodate(dir, bh);
+
+               ret = ocfs2_journal_access_dl(handle, dir, bh,
+                                             OCFS2_JOURNAL_ACCESS_CREATE);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               dx_leaf = (struct ocfs2_dx_leaf *) bh->b_data;
+
+               memset(dx_leaf, 0, osb->sb->s_blocksize);
+               strcpy(dx_leaf->dl_signature, OCFS2_DX_LEAF_SIGNATURE);
+               dx_leaf->dl_fs_generation = cpu_to_le32(osb->fs_generation);
+               dx_leaf->dl_blkno = cpu_to_le64(bh->b_blocknr);
+               dx_leaf->dl_list.de_count =
+                       cpu_to_le16(ocfs2_dx_entries_per_leaf(osb->sb));
+
+               mlog(0,
+                    "Dir %llu, format dx_leaf: %llu, entry count: %u\n",
+                    (unsigned long long)OCFS2_I(dir)->ip_blkno,
+                    (unsigned long long)bh->b_blocknr,
+                    le16_to_cpu(dx_leaf->dl_list.de_count));
+
+               ocfs2_journal_dirty(handle, bh);
        }
-       did_quota = 1;
+
+       ret = 0;
+out:
+       return ret;
+}
+
+/*
+ * Allocates and formats a new cluster for use in an indexed dir
+ * leaf. This version will not do the extent insert, so that it can be
+ * used by operations which need careful ordering.
+ */
+static int __ocfs2_dx_dir_new_cluster(struct inode *dir,
+                                     u32 cpos, handle_t *handle,
+                                     struct ocfs2_alloc_context *data_ac,
+                                     struct buffer_head **dx_leaves,
+                                     int num_dx_leaves, u64 *ret_phys_blkno)
+{
+       int ret;
+       u32 phys, num;
+       u64 phys_blkno;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+
        /*
-        * Try to claim as many clusters as the bitmap can give though
-        * if we only get one now, that's enough to continue. The rest
-        * will be claimed after the conversion to extents.
+        * XXX: For create, this should claim cluster for the index
+        * *before* the unindexed insert so that we have a better
+        * chance of contiguousness as the directory grows in number
+        * of entries.
         */
-       ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+       ret = __ocfs2_claim_clusters(osb, handle, data_ac, 1, 1, &phys, &num);
        if (ret) {
                mlog_errno(ret);
-               goto out_commit;
+               goto out;
        }
 
        /*
-        * Operations are carefully ordered so that we set up the new
-        * data block first. The conversion from inline data to
-        * extents follows.
+        * Format the new cluster first. That way, we're inserting
+        * valid data.
         */
-       blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
-       dirdata_bh = sb_getblk(sb, blkno);
-       if (!dirdata_bh) {
-               ret = -EIO;
-               mlog_errno(ret);
-               goto out_commit;
-       }
-
-       ocfs2_set_new_buffer_uptodate(dir, dirdata_bh);
-
-       ret = ocfs2_journal_access_db(handle, dir, dirdata_bh,
-                                     OCFS2_JOURNAL_ACCESS_CREATE);
+       phys_blkno = ocfs2_clusters_to_blocks(osb->sb, phys);
+       ret = ocfs2_dx_dir_format_cluster(osb, handle, dir, dx_leaves,
+                                         num_dx_leaves, phys_blkno);
        if (ret) {
                mlog_errno(ret);
-               goto out_commit;
+               goto out;
        }
 
-       memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir));
-       memset(dirdata_bh->b_data + i_size_read(dir), 0,
-              sb->s_blocksize - i_size_read(dir));
-       ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir), sb);
-       if (ocfs2_supports_dir_trailer(osb))
-               ocfs2_init_dir_trailer(dir, dirdata_bh);
+       *ret_phys_blkno = phys_blkno;
+out:
+       return ret;
+}
 
-       ret = ocfs2_journal_dirty(handle, dirdata_bh);
+static int ocfs2_dx_dir_new_cluster(struct inode *dir,
+                                   struct ocfs2_extent_tree *et,
+                                   u32 cpos, handle_t *handle,
+                                   struct ocfs2_alloc_context *data_ac,
+                                   struct ocfs2_alloc_context *meta_ac,
+                                   struct buffer_head **dx_leaves,
+                                   int num_dx_leaves)
+{
+       int ret;
+       u64 phys_blkno;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+
+       ret = __ocfs2_dx_dir_new_cluster(dir, cpos, handle, data_ac, dx_leaves,
+                                        num_dx_leaves, &phys_blkno);
        if (ret) {
                mlog_errno(ret);
-               goto out_commit;
+               goto out;
        }
 
-       /*
-        * Set extent, i_size, etc on the directory. After this, the
-        * inode should contain the same exact dirents as before and
-        * be fully accessible from system calls.
-        *
-        * We let the later dirent insert modify c/mtime - to the user
-        * the data hasn't changed.
-        */
-       ret = ocfs2_journal_access_di(handle, dir, di_bh,
-                                     OCFS2_JOURNAL_ACCESS_CREATE);
-       if (ret) {
+       ret = ocfs2_insert_extent(osb, handle, dir, et, cpos, phys_blkno, 1, 0,
+                                 meta_ac);
+       if (ret)
                mlog_errno(ret);
-               goto out_commit;
-       }
+out:
+       return ret;
+}
 
-       spin_lock(&oi->ip_lock);
-       oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
-       di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
-       spin_unlock(&oi->ip_lock);
+static struct buffer_head **ocfs2_dx_dir_kmalloc_leaves(struct super_block *sb,
+                                                       int *ret_num_leaves)
+{
+       int num_dx_leaves = ocfs2_clusters_to_blocks(sb, 1);
+       struct buffer_head **dx_leaves;
 
-       ocfs2_dinode_new_extent_list(dir, di);
+       dx_leaves = kcalloc(num_dx_leaves, sizeof(struct buffer_head *),
+                           GFP_NOFS);
+       if (dx_leaves && ret_num_leaves)
+               *ret_num_leaves = num_dx_leaves;
 
-       i_size_write(dir, sb->s_blocksize);
-       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       return dx_leaves;
+}
 
-       di->i_size = cpu_to_le64(sb->s_blocksize);
-       di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec);
-       di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec);
+static int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb,
+                                handle_t *handle,
+                                struct inode *parent,
+                                struct inode *inode,
+                                struct buffer_head *di_bh,
+                                struct ocfs2_alloc_context *data_ac,
+                                struct ocfs2_alloc_context *meta_ac)
+{
+       int ret;
+       struct buffer_head *leaf_bh = NULL;
+       struct buffer_head *dx_root_bh = NULL;
+       struct ocfs2_dx_hinfo hinfo;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dx_entry_list *entry_list;
 
        /*
-        * This should never fail as our extent list is empty and all
-        * related blocks have been journaled already.
+        * Our strategy is to create the directory as though it were
+        * unindexed, then add the index block. This works with very
+        * little complication since the state of a new directory is a
+        * very well known quantity.
+        *
+        * Essentially, we have two dirents ("." and ".."), in the 1st
+        * block which need indexing. These are easily inserted into
+        * the index block.
         */
-       ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, blkno, len,
-                                 0, NULL);
+
+       ret = ocfs2_fill_new_dir_el(osb, handle, parent, inode, di_bh,
+                                   data_ac, &leaf_bh);
        if (ret) {
                mlog_errno(ret);
-               goto out_commit;
+               goto out;
        }
 
-       /*
-        * Set i_blocks after the extent insert for the most up to
-        * date ip_clusters value.
-        */
-       dir->i_blocks = ocfs2_inode_sector_count(dir);
-
-       ret = ocfs2_journal_dirty(handle, di_bh);
+       ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, leaf_bh,
+                                       meta_ac, 1, 2, &dx_root_bh);
        if (ret) {
                mlog_errno(ret);
-               goto out_commit;
+               goto out;
        }
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+       entry_list = &dx_root->dr_entries;
 
-       /*
-        * We asked for two clusters, but only got one in the 1st
-        * pass. Claim the 2nd cluster as a separate extent.
-        */
-       if (alloc > len) {
-               ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
-                                          &len);
-               if (ret) {
-                       mlog_errno(ret);
-                       goto out_commit;
-               }
-               blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+       /* Buffer has been journaled for us by ocfs2_dx_dir_attach_index */
+       ocfs2_dx_dir_name_hash(inode, ".", 1, &hinfo);
+       ocfs2_dx_entry_list_insert(entry_list, &hinfo, leaf_bh->b_blocknr);
 
-               ret = ocfs2_insert_extent(osb, handle, dir, &et, 1,
-                                         blkno, len, 0, NULL);
-               if (ret) {
-                       mlog_errno(ret);
-                       goto out_commit;
-               }
-       }
+       ocfs2_dx_dir_name_hash(inode, "..", 2, &hinfo);
+       ocfs2_dx_entry_list_insert(entry_list, &hinfo, leaf_bh->b_blocknr);
 
-       *first_block_bh = dirdata_bh;
-       dirdata_bh = NULL;
+out:
+       brelse(dx_root_bh);
+       brelse(leaf_bh);
+       return ret;
+}
 
-out_commit:
-       if (ret < 0 && did_quota)
-               vfs_dq_free_space_nodirty(dir,
-                       ocfs2_clusters_to_bytes(osb->sb, 2));
-       ocfs2_commit_trans(osb, handle);
+int ocfs2_fill_new_dir(struct ocfs2_super *osb,
+                      handle_t *handle,
+                      struct inode *parent,
+                      struct inode *inode,
+                      struct buffer_head *fe_bh,
+                      struct ocfs2_alloc_context *data_ac,
+                      struct ocfs2_alloc_context *meta_ac)
 
-out_sem:
-       up_write(&oi->ip_alloc_sem);
+{
+       BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL);
 
-out:
-       if (data_ac)
-               ocfs2_free_alloc_context(data_ac);
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh);
 
-       brelse(dirdata_bh);
+       if (ocfs2_supports_indexed_dirs(osb))
+               return ocfs2_fill_new_dir_dx(osb, handle, parent, inode, fe_bh,
+                                            data_ac, meta_ac);
 
-       return ret;
+       return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh,
+                                    data_ac, NULL);
 }
 
-/* returns a bh of the 1st new block in the allocation. */
-static int ocfs2_do_extend_dir(struct super_block *sb,
-                              handle_t *handle,
-                              struct inode *dir,
-                              struct buffer_head *parent_fe_bh,
-                              struct ocfs2_alloc_context *data_ac,
-                              struct ocfs2_alloc_context *meta_ac,
-                              struct buffer_head **new_bh)
+static int ocfs2_dx_dir_index_block(struct inode *dir,
+                                   handle_t *handle,
+                                   struct buffer_head **dx_leaves,
+                                   int num_dx_leaves,
+                                   u32 *num_dx_entries,
+                                   struct buffer_head *dirent_bh)
 {
-       int status;
-       int extend, did_quota = 0;
-       u64 p_blkno, v_blkno;
+       int ret, namelen, i;
+       char *de_buf, *limit;
+       struct ocfs2_dir_entry *de;
+       struct buffer_head *dx_leaf_bh;
+       struct ocfs2_dx_hinfo hinfo;
+       u64 dirent_blk = dirent_bh->b_blocknr;
 
-       spin_lock(&OCFS2_I(dir)->ip_lock);
-       extend = (i_size_read(dir) == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters));
-       spin_unlock(&OCFS2_I(dir)->ip_lock);
+       de_buf = dirent_bh->b_data;
+       limit = de_buf + dir->i_sb->s_blocksize;
 
-       if (extend) {
-               u32 offset = OCFS2_I(dir)->ip_clusters;
+       while (de_buf < limit) {
+               de = (struct ocfs2_dir_entry *)de_buf;
 
-               if (vfs_dq_alloc_space_nodirty(dir,
-                                       ocfs2_clusters_to_bytes(sb, 1))) {
-                       status = -EDQUOT;
-                       goto bail;
-               }
-               did_quota = 1;
+               namelen = de->name_len;
+               if (!namelen || !de->inode)
+                       goto inc;
 
-               status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset,
-                                             1, 0, parent_fe_bh, handle,
-                                             data_ac, meta_ac, NULL);
-               BUG_ON(status == -EAGAIN);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
+               ocfs2_dx_dir_name_hash(dir, de->name, namelen, &hinfo);
+
+               i = ocfs2_dx_dir_hash_idx(OCFS2_SB(dir->i_sb), &hinfo);
+               dx_leaf_bh = dx_leaves[i];
+
+               ret = __ocfs2_dx_dir_leaf_insert(dir, handle, &hinfo,
+                                                dirent_blk, dx_leaf_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
                }
-       }
 
-       v_blkno = ocfs2_blocks_for_bytes(sb, i_size_read(dir));
-       status = ocfs2_extent_map_get_blocks(dir, v_blkno, &p_blkno, NULL, NULL);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
+               *num_dx_entries = *num_dx_entries + 1;
 
-       *new_bh = sb_getblk(sb, p_blkno);
-       if (!*new_bh) {
-               status = -EIO;
-               mlog_errno(status);
-               goto bail;
+inc:
+               de_buf += le16_to_cpu(de->rec_len);
        }
-       status = 0;
-bail:
-       if (did_quota && status < 0)
-               vfs_dq_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1));
-       mlog_exit(status);
-       return status;
+
+out:
+       return ret;
 }
 
 /*
- * Assumes you already have a cluster lock on the directory.
- *
- * 'blocks_wanted' is only used if we have an inline directory which
- * is to be turned into an extent based one. The size of the dirent to
- * insert might be larger than the space gained by growing to just one
- * block, so we may have to grow the inode by two blocks in that case.
+ * XXX: This expects dx_root_bh to already be part of the transaction.
  */
-static int ocfs2_extend_dir(struct ocfs2_super *osb,
-                           struct inode *dir,
-                           struct buffer_head *parent_fe_bh,
-                           unsigned int blocks_wanted,
-                           struct buffer_head **new_de_bh)
+static void ocfs2_dx_dir_index_root_block(struct inode *dir,
+                                        struct buffer_head *dx_root_bh,
+                                        struct buffer_head *dirent_bh)
 {
-       int status = 0;
-       int credits, num_free_extents, drop_alloc_sem = 0;
-       loff_t dir_i_size;
-       struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
-       struct ocfs2_extent_list *el = &fe->id2.i_list;
-       struct ocfs2_alloc_context *data_ac = NULL;
-       struct ocfs2_alloc_context *meta_ac = NULL;
-       handle_t *handle = NULL;
-       struct buffer_head *new_bh = NULL;
-       struct ocfs2_dir_entry * de;
-       struct super_block *sb = osb->sb;
-       struct ocfs2_extent_tree et;
+       char *de_buf, *limit;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dir_entry *de;
+       struct ocfs2_dx_hinfo hinfo;
+       u64 dirent_blk = dirent_bh->b_blocknr;
 
-       mlog_entry_void();
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
 
-       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
-               status = ocfs2_expand_inline_dir(dir, parent_fe_bh,
-                                                blocks_wanted, &new_bh);
-               if (status) {
-                       mlog_errno(status);
-                       goto bail;
+       de_buf = dirent_bh->b_data;
+       limit = de_buf + dir->i_sb->s_blocksize;
+
+       while (de_buf < limit) {
+               de = (struct ocfs2_dir_entry *)de_buf;
+
+               if (!de->name_len || !de->inode)
+                       goto inc;
+
+               ocfs2_dx_dir_name_hash(dir, de->name, de->name_len, &hinfo);
+
+               mlog(0,
+                    "dir: %llu, major: 0x%x minor: 0x%x, index: %u, name: %.*s\n",
+                    (unsigned long long)dir->i_ino, hinfo.major_hash,
+                    hinfo.minor_hash,
+                    le16_to_cpu(dx_root->dr_entries.de_num_used),
+                    de->name_len, de->name);
+
+               ocfs2_dx_entry_list_insert(&dx_root->dr_entries, &hinfo,
+                                          dirent_blk);
+
+               le32_add_cpu(&dx_root->dr_num_entries, 1);
+inc:
+               de_buf += le16_to_cpu(de->rec_len);
+       }
+}
+
+/*
+ * Count the number of inline directory entries in di_bh and compare
+ * them against the number of entries we can hold in an inline dx root
+ * block.
+ */
+static int ocfs2_new_dx_should_be_inline(struct inode *dir,
+                                        struct buffer_head *di_bh)
+{
+       int dirent_count = 0;
+       char *de_buf, *limit;
+       struct ocfs2_dir_entry *de;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       de_buf = di->id2.i_data.id_data;
+       limit = de_buf + i_size_read(dir);
+
+       while (de_buf < limit) {
+               de = (struct ocfs2_dir_entry *)de_buf;
+
+               if (de->name_len && de->inode)
+                       dirent_count++;
+
+               de_buf += le16_to_cpu(de->rec_len);
+       }
+
+       /* We are careful to leave room for one extra record. */
+       return dirent_count < ocfs2_dx_entries_per_root(dir->i_sb);
+}
+
+/*
+ * Expand rec_len of the rightmost dirent in a directory block so that it
+ * contains the end of our valid space for dirents. We do this during
+ * expansion from an inline directory to one with extents. The first dir block
+ * in that case is taken from the inline data portion of the inode block.
+ *
+ * This will also return the largest amount of contiguous space for a dirent
+ * in the block. That value is *not* necessarily the last dirent, even after
+ * expansion. The directory indexing code wants this value for free space
+ * accounting. We do this here since we're already walking the entire dir
+ * block.
+ *
+ * We add the dir trailer if this filesystem wants it.
+ */
+static unsigned int ocfs2_expand_last_dirent(char *start, unsigned int old_size,
+                                            struct inode *dir)
+{
+       struct super_block *sb = dir->i_sb;
+       struct ocfs2_dir_entry *de;
+       struct ocfs2_dir_entry *prev_de;
+       char *de_buf, *limit;
+       unsigned int new_size = sb->s_blocksize;
+       unsigned int bytes, this_hole;
+       unsigned int largest_hole = 0;
+
+       if (ocfs2_new_dir_wants_trailer(dir))
+               new_size = ocfs2_dir_trailer_blk_off(sb);
+
+       bytes = new_size - old_size;
+
+       limit = start + old_size;
+       de_buf = start;
+       de = (struct ocfs2_dir_entry *)de_buf;
+       do {
+               this_hole = ocfs2_figure_dirent_hole(de);
+               if (this_hole > largest_hole)
+                       largest_hole = this_hole;
+
+               prev_de = de;
+               de_buf += le16_to_cpu(de->rec_len);
+               de = (struct ocfs2_dir_entry *)de_buf;
+       } while (de_buf < limit);
+
+       le16_add_cpu(&prev_de->rec_len, bytes);
+
+       /* We need to double check this after modification of the final
+        * dirent. */
+       this_hole = ocfs2_figure_dirent_hole(prev_de);
+       if (this_hole > largest_hole)
+               largest_hole = this_hole;
+
+       if (largest_hole >= OCFS2_DIR_MIN_REC_LEN)
+               return largest_hole;
+       return 0;
+}
+
+/*
+ * We allocate enough clusters to fulfill "blocks_wanted", but set
+ * i_size to exactly one block. Ocfs2_extend_dir() will handle the
+ * rest automatically for us.
+ *
+ * *first_block_bh is a pointer to the 1st data block allocated to the
+ *  directory.
+ */
+static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
+                                  unsigned int blocks_wanted,
+                                  struct ocfs2_dir_lookup_result *lookup,
+                                  struct buffer_head **first_block_bh)
+{
+       u32 alloc, dx_alloc, bit_off, len, num_dx_entries = 0;
+       struct super_block *sb = dir->i_sb;
+       int ret, i, num_dx_leaves = 0, dx_inline = 0,
+               credits = ocfs2_inline_to_extents_credits(sb);
+       u64 dx_insert_blkno, blkno,
+               bytes = blocks_wanted << sb->s_blocksize_bits;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct ocfs2_inode_info *oi = OCFS2_I(dir);
+       struct ocfs2_alloc_context *data_ac;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       struct buffer_head *dirdata_bh = NULL;
+       struct buffer_head *dx_root_bh = NULL;
+       struct buffer_head **dx_leaves = NULL;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       handle_t *handle;
+       struct ocfs2_extent_tree et;
+       struct ocfs2_extent_tree dx_et;
+       int did_quota = 0, bytes_allocated = 0;
+
+       ocfs2_init_dinode_extent_tree(&et, dir, di_bh);
+
+       alloc = ocfs2_clusters_for_bytes(sb, bytes);
+       dx_alloc = 0;
+
+       if (ocfs2_supports_indexed_dirs(osb)) {
+               credits += ocfs2_add_dir_index_credits(sb);
+
+               dx_inline = ocfs2_new_dx_should_be_inline(dir, di_bh);
+               if (!dx_inline) {
+                       /* Add one more cluster for an index leaf */
+                       dx_alloc++;
+                       dx_leaves = ocfs2_dx_dir_kmalloc_leaves(sb,
+                                                               &num_dx_leaves);
+                       if (!dx_leaves) {
+                               ret = -ENOMEM;
+                               mlog_errno(ret);
+                               goto out;
+                       }
+               }
+
+               /* This gets us the dx_root */
+               ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       /*
+        * We should never need more than 2 clusters for the unindexed
+        * tree - maximum dirent size is far less than one block. In
+        * fact, the only time we'd need more than one cluster is if
+        * blocksize == clustersize and the dirent won't fit in the
+        * extra space that the expansion to a single block gives. As
+        * of today, that only happens on 4k/4k file systems.
+        */
+       BUG_ON(alloc > 2);
+
+       ret = ocfs2_reserve_clusters(osb, alloc, &data_ac);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       down_write(&oi->ip_alloc_sem);
+
+       /*
+        * Prepare for worst case allocation scenario of two separate
+        * extents in the unindexed tree.
+        */
+       if (alloc == 2)
+               credits += OCFS2_SUBALLOC_ALLOC;
+
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_sem;
+       }
+
+       if (vfs_dq_alloc_space_nodirty(dir,
+                               ocfs2_clusters_to_bytes(osb->sb,
+                                                       alloc + dx_alloc))) {
+               ret = -EDQUOT;
+               goto out_commit;
+       }
+       did_quota = 1;
+
+       if (ocfs2_supports_indexed_dirs(osb) && !dx_inline) {
+               /*
+                * Allocate our index cluster first, to maximize the
+                * possibility that unindexed leaves grow
+                * contiguously.
+                */
+               ret = __ocfs2_dx_dir_new_cluster(dir, 0, handle, data_ac,
+                                                dx_leaves, num_dx_leaves,
+                                                &dx_insert_blkno);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+               bytes_allocated += ocfs2_clusters_to_bytes(dir->i_sb, 1);
+       }
+
+       /*
+        * Try to claim as many clusters as the bitmap can give though
+        * if we only get one now, that's enough to continue. The rest
+        * will be claimed after the conversion to extents.
+        */
+       ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+       bytes_allocated += ocfs2_clusters_to_bytes(dir->i_sb, 1);
+
+       /*
+        * Operations are carefully ordered so that we set up the new
+        * data block first. The conversion from inline data to
+        * extents follows.
+        */
+       blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+       dirdata_bh = sb_getblk(sb, blkno);
+       if (!dirdata_bh) {
+               ret = -EIO;
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ocfs2_set_new_buffer_uptodate(dir, dirdata_bh);
+
+       ret = ocfs2_journal_access_db(handle, dir, dirdata_bh,
+                                     OCFS2_JOURNAL_ACCESS_CREATE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir));
+       memset(dirdata_bh->b_data + i_size_read(dir), 0,
+              sb->s_blocksize - i_size_read(dir));
+       i = ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir), dir);
+       if (ocfs2_new_dir_wants_trailer(dir)) {
+               /*
+                * Prepare the dir trailer up front. It will otherwise look
+                * like a valid dirent. Even if inserting the index fails
+                * (unlikely), then all we'll have done is given first dir
+                * block a small amount of fragmentation.
+                */
+               ocfs2_init_dir_trailer(dir, dirdata_bh, i);
+       }
+
+       ret = ocfs2_journal_dirty(handle, dirdata_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       if (ocfs2_supports_indexed_dirs(osb) && !dx_inline) {
+               /*
+                * Dx dirs with an external cluster need to do this up
+                * front. Inline dx root's get handled later, after
+                * we've allocated our root block. We get passed back
+                * a total number of items so that dr_num_entries can
+                * be correctly set once the dx_root has been
+                * allocated.
+                */
+               ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves,
+                                              num_dx_leaves, &num_dx_entries,
+                                              dirdata_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+       }
+
+       /*
+        * Set extent, i_size, etc on the directory. After this, the
+        * inode should contain the same exact dirents as before and
+        * be fully accessible from system calls.
+        *
+        * We let the later dirent insert modify c/mtime - to the user
+        * the data hasn't changed.
+        */
+       ret = ocfs2_journal_access_di(handle, dir, di_bh,
+                                     OCFS2_JOURNAL_ACCESS_CREATE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       spin_lock(&oi->ip_lock);
+       oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+       di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+       spin_unlock(&oi->ip_lock);
+
+       ocfs2_dinode_new_extent_list(dir, di);
+
+       i_size_write(dir, sb->s_blocksize);
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+
+       di->i_size = cpu_to_le64(sb->s_blocksize);
+       di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec);
+       di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec);
+
+       /*
+        * This should never fail as our extent list is empty and all
+        * related blocks have been journaled already.
+        */
+       ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, blkno, len,
+                                 0, NULL);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * Set i_blocks after the extent insert for the most up to
+        * date ip_clusters value.
+        */
+       dir->i_blocks = ocfs2_inode_sector_count(dir);
+
+       ret = ocfs2_journal_dirty(handle, di_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       if (ocfs2_supports_indexed_dirs(osb)) {
+               ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh,
+                                               dirdata_bh, meta_ac, dx_inline,
+                                               num_dx_entries, &dx_root_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               if (dx_inline) {
+                       ocfs2_dx_dir_index_root_block(dir, dx_root_bh,
+                                                     dirdata_bh);
+               } else {
+                       ocfs2_init_dx_root_extent_tree(&dx_et, dir, dx_root_bh);
+                       ret = ocfs2_insert_extent(osb, handle, dir, &dx_et, 0,
+                                                 dx_insert_blkno, 1, 0, NULL);
+                       if (ret)
+                               mlog_errno(ret);
+               }
+       }
+
+       /*
+        * We asked for two clusters, but only got one in the 1st
+        * pass. Claim the 2nd cluster as a separate extent.
+        */
+       if (alloc > len) {
+               ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+                                          &len);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+               blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+
+               ret = ocfs2_insert_extent(osb, handle, dir, &et, 1,
+                                         blkno, len, 0, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+               bytes_allocated += ocfs2_clusters_to_bytes(dir->i_sb, 1);
+       }
+
+       *first_block_bh = dirdata_bh;
+       dirdata_bh = NULL;
+       if (ocfs2_supports_indexed_dirs(osb)) {
+               unsigned int off;
+
+               if (!dx_inline) {
+                       /*
+                        * We need to return the correct block within the
+                        * cluster which should hold our entry.
+                        */
+                       off = ocfs2_dx_dir_hash_idx(OCFS2_SB(dir->i_sb),
+                                                   &lookup->dl_hinfo);
+                       get_bh(dx_leaves[off]);
+                       lookup->dl_dx_leaf_bh = dx_leaves[off];
+               }
+               lookup->dl_dx_root_bh = dx_root_bh;
+               dx_root_bh = NULL;
+       }
+
+out_commit:
+       if (ret < 0 && did_quota)
+               vfs_dq_free_space_nodirty(dir, bytes_allocated);
+
+       ocfs2_commit_trans(osb, handle);
+
+out_sem:
+       up_write(&oi->ip_alloc_sem);
+
+out:
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+
+       if (dx_leaves) {
+               for (i = 0; i < num_dx_leaves; i++)
+                       brelse(dx_leaves[i]);
+               kfree(dx_leaves);
+       }
+
+       brelse(dirdata_bh);
+       brelse(dx_root_bh);
+
+       return ret;
+}
+
+/* returns a bh of the 1st new block in the allocation. */
+static int ocfs2_do_extend_dir(struct super_block *sb,
+                              handle_t *handle,
+                              struct inode *dir,
+                              struct buffer_head *parent_fe_bh,
+                              struct ocfs2_alloc_context *data_ac,
+                              struct ocfs2_alloc_context *meta_ac,
+                              struct buffer_head **new_bh)
+{
+       int status;
+       int extend, did_quota = 0;
+       u64 p_blkno, v_blkno;
+
+       spin_lock(&OCFS2_I(dir)->ip_lock);
+       extend = (i_size_read(dir) == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters));
+       spin_unlock(&OCFS2_I(dir)->ip_lock);
+
+       if (extend) {
+               u32 offset = OCFS2_I(dir)->ip_clusters;
+
+               if (vfs_dq_alloc_space_nodirty(dir,
+                                       ocfs2_clusters_to_bytes(sb, 1))) {
+                       status = -EDQUOT;
+                       goto bail;
+               }
+               did_quota = 1;
+
+               status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset,
+                                             1, 0, parent_fe_bh, handle,
+                                             data_ac, meta_ac, NULL);
+               BUG_ON(status == -EAGAIN);
+               if (status < 0) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+       }
+
+       v_blkno = ocfs2_blocks_for_bytes(sb, i_size_read(dir));
+       status = ocfs2_extent_map_get_blocks(dir, v_blkno, &p_blkno, NULL, NULL);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       *new_bh = sb_getblk(sb, p_blkno);
+       if (!*new_bh) {
+               status = -EIO;
+               mlog_errno(status);
+               goto bail;
+       }
+       status = 0;
+bail:
+       if (did_quota && status < 0)
+               vfs_dq_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1));
+       mlog_exit(status);
+       return status;
+}
+
+/*
+ * Assumes you already have a cluster lock on the directory.
+ *
+ * 'blocks_wanted' is only used if we have an inline directory which
+ * is to be turned into an extent based one. The size of the dirent to
+ * insert might be larger than the space gained by growing to just one
+ * block, so we may have to grow the inode by two blocks in that case.
+ *
+ * If the directory is already indexed, dx_root_bh must be provided.
+ */
+static int ocfs2_extend_dir(struct ocfs2_super *osb,
+                           struct inode *dir,
+                           struct buffer_head *parent_fe_bh,
+                           unsigned int blocks_wanted,
+                           struct ocfs2_dir_lookup_result *lookup,
+                           struct buffer_head **new_de_bh)
+{
+       int status = 0;
+       int credits, num_free_extents, drop_alloc_sem = 0;
+       loff_t dir_i_size;
+       struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
+       struct ocfs2_extent_list *el = &fe->id2.i_list;
+       struct ocfs2_alloc_context *data_ac = NULL;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       handle_t *handle = NULL;
+       struct buffer_head *new_bh = NULL;
+       struct ocfs2_dir_entry * de;
+       struct super_block *sb = osb->sb;
+       struct ocfs2_extent_tree et;
+       struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh;
+
+       mlog_entry_void();
+
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               /*
+                * This would be a code error as an inline directory should
+                * never have an index root.
+                */
+               BUG_ON(dx_root_bh);
+
+               status = ocfs2_expand_inline_dir(dir, parent_fe_bh,
+                                                blocks_wanted, lookup,
+                                                &new_bh);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+
+               /* Expansion from inline to an indexed directory will
+                * have given us this. */
+               dx_root_bh = lookup->dl_dx_root_bh;
+
+               if (blocks_wanted == 1) {
+                       /*
+                        * If the new dirent will fit inside the space
+                        * created by pushing out to one block, then
+                        * we can complete the operation
+                        * here. Otherwise we have to expand i_size
+                        * and format the 2nd block below.
+                        */
+                       BUG_ON(new_bh == NULL);
+                       goto bail_bh;
+               }
+
+               /*
+                * Get rid of 'new_bh' - we want to format the 2nd
+                * data block and return that instead.
+                */
+               brelse(new_bh);
+               new_bh = NULL;
+
+               dir_i_size = i_size_read(dir);
+               credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
+               goto do_extend;
+       }
+
+       dir_i_size = i_size_read(dir);
+       mlog(0, "extending dir %llu (i_size = %lld)\n",
+            (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
+
+       /* dir->i_size is always block aligned. */
+       spin_lock(&OCFS2_I(dir)->ip_lock);
+       if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) {
+               spin_unlock(&OCFS2_I(dir)->ip_lock);
+               ocfs2_init_dinode_extent_tree(&et, dir, parent_fe_bh);
+               num_free_extents = ocfs2_num_free_extents(osb, dir, &et);
+               if (num_free_extents < 0) {
+                       status = num_free_extents;
+                       mlog_errno(status);
+                       goto bail;
+               }
+
+               if (!num_free_extents) {
+                       status = ocfs2_reserve_new_metadata(osb, el, &meta_ac);
+                       if (status < 0) {
+                               if (status != -ENOSPC)
+                                       mlog_errno(status);
+                               goto bail;
+                       }
+               }
+
+               status = ocfs2_reserve_clusters(osb, 1, &data_ac);
+               if (status < 0) {
+                       if (status != -ENOSPC)
+                               mlog_errno(status);
+                       goto bail;
+               }
+
+               credits = ocfs2_calc_extend_credits(sb, el, 1);
+       } else {
+               spin_unlock(&OCFS2_I(dir)->ip_lock);
+               credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
+       }
+
+do_extend:
+       if (ocfs2_dir_indexed(dir))
+               credits++; /* For attaching the new dirent block to the
+                           * dx_root */
+
+       down_write(&OCFS2_I(dir)->ip_alloc_sem);
+       drop_alloc_sem = 1;
+
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(status);
+               goto bail;
+       }
+
+       status = ocfs2_do_extend_dir(osb->sb, handle, dir, parent_fe_bh,
+                                    data_ac, meta_ac, &new_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       ocfs2_set_new_buffer_uptodate(dir, new_bh);
+
+       status = ocfs2_journal_access_db(handle, dir, new_bh,
+                                        OCFS2_JOURNAL_ACCESS_CREATE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+       memset(new_bh->b_data, 0, sb->s_blocksize);
+
+       de = (struct ocfs2_dir_entry *) new_bh->b_data;
+       de->inode = 0;
+       if (ocfs2_supports_dir_trailer(dir)) {
+               de->rec_len = cpu_to_le16(ocfs2_dir_trailer_blk_off(sb));
+
+               ocfs2_init_dir_trailer(dir, new_bh, le16_to_cpu(de->rec_len));
+
+               if (ocfs2_dir_indexed(dir)) {
+                       status = ocfs2_dx_dir_link_trailer(dir, handle,
+                                                          dx_root_bh, new_bh);
+                       if (status) {
+                               mlog_errno(status);
+                               goto bail;
+                       }
+               }
+       } else {
+               de->rec_len = cpu_to_le16(sb->s_blocksize);
+       }
+       status = ocfs2_journal_dirty(handle, new_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       dir_i_size += dir->i_sb->s_blocksize;
+       i_size_write(dir, dir_i_size);
+       dir->i_blocks = ocfs2_inode_sector_count(dir);
+       status = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+bail_bh:
+       *new_de_bh = new_bh;
+       get_bh(*new_de_bh);
+bail:
+       if (drop_alloc_sem)
+               up_write(&OCFS2_I(dir)->ip_alloc_sem);
+       if (handle)
+               ocfs2_commit_trans(osb, handle);
+
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+
+       brelse(new_bh);
+
+       mlog_exit(status);
+       return status;
+}
+
+static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
+                                  const char *name, int namelen,
+                                  struct buffer_head **ret_de_bh,
+                                  unsigned int *blocks_wanted)
+{
+       int ret;
+       struct super_block *sb = dir->i_sb;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_dir_entry *de, *last_de = NULL;
+       char *de_buf, *limit;
+       unsigned long offset = 0;
+       unsigned int rec_len, new_rec_len, free_space = dir->i_sb->s_blocksize;
+
+       /*
+        * This calculates how many free bytes we'd have in block zero, should
+        * this function force expansion to an extent tree.
+        */
+       if (ocfs2_new_dir_wants_trailer(dir))
+               free_space = ocfs2_dir_trailer_blk_off(sb) - i_size_read(dir);
+       else
+               free_space = dir->i_sb->s_blocksize - i_size_read(dir);
+
+       de_buf = di->id2.i_data.id_data;
+       limit = de_buf + i_size_read(dir);
+       rec_len = OCFS2_DIR_REC_LEN(namelen);
+
+       while (de_buf < limit) {
+               de = (struct ocfs2_dir_entry *)de_buf;
+
+               if (!ocfs2_check_dir_entry(dir, de, di_bh, offset)) {
+                       ret = -ENOENT;
+                       goto out;
+               }
+               if (ocfs2_match(namelen, name, de)) {
+                       ret = -EEXIST;
+                       goto out;
+               }
+               /*
+                * No need to check for a trailing dirent record here as
+                * they're not used for inline dirs.
+                */
+
+               if (ocfs2_dirent_would_fit(de, rec_len)) {
+                       /* Ok, we found a spot. Return this bh and let
+                        * the caller actually fill it in. */
+                       *ret_de_bh = di_bh;
+                       get_bh(*ret_de_bh);
+                       ret = 0;
+                       goto out;
+               }
+
+               last_de = de;
+               de_buf += le16_to_cpu(de->rec_len);
+               offset += le16_to_cpu(de->rec_len);
+       }
+
+       /*
+        * We're going to require expansion of the directory - figure
+        * out how many blocks we'll need so that a place for the
+        * dirent can be found.
+        */
+       *blocks_wanted = 1;
+       new_rec_len = le16_to_cpu(last_de->rec_len) + free_space;
+       if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len)))
+               *blocks_wanted = 2;
+
+       ret = -ENOSPC;
+out:
+       return ret;
+}
+
+static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
+                                  int namelen, struct buffer_head **ret_de_bh)
+{
+       unsigned long offset;
+       struct buffer_head *bh = NULL;
+       unsigned short rec_len;
+       struct ocfs2_dir_entry *de;
+       struct super_block *sb = dir->i_sb;
+       int status;
+       int blocksize = dir->i_sb->s_blocksize;
+
+       status = ocfs2_read_dir_block(dir, 0, &bh, 0);
+       if (status) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       rec_len = OCFS2_DIR_REC_LEN(namelen);
+       offset = 0;
+       de = (struct ocfs2_dir_entry *) bh->b_data;
+       while (1) {
+               if ((char *)de >= sb->s_blocksize + bh->b_data) {
+                       brelse(bh);
+                       bh = NULL;
+
+                       if (i_size_read(dir) <= offset) {
+                               /*
+                                * Caller will have to expand this
+                                * directory.
+                                */
+                               status = -ENOSPC;
+                               goto bail;
+                       }
+                       status = ocfs2_read_dir_block(dir,
+                                            offset >> sb->s_blocksize_bits,
+                                            &bh, 0);
+                       if (status) {
+                               mlog_errno(status);
+                               goto bail;
+                       }
+                       /* move to next block */
+                       de = (struct ocfs2_dir_entry *) bh->b_data;
+               }
+               if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
+                       status = -ENOENT;
+                       goto bail;
+               }
+               if (ocfs2_match(namelen, name, de)) {
+                       status = -EEXIST;
+                       goto bail;
+               }
+
+               if (ocfs2_skip_dir_trailer(dir, de, offset % blocksize,
+                                          blocksize))
+                       goto next;
+
+               if (ocfs2_dirent_would_fit(de, rec_len)) {
+                       /* Ok, we found a spot. Return this bh and let
+                        * the caller actually fill it in. */
+                       *ret_de_bh = bh;
+                       get_bh(*ret_de_bh);
+                       status = 0;
+                       goto bail;
+               }
+next:
+               offset += le16_to_cpu(de->rec_len);
+               de = (struct ocfs2_dir_entry *)((char *) de + le16_to_cpu(de->rec_len));
+       }
+
+       status = 0;
+bail:
+       brelse(bh);
+
+       mlog_exit(status);
+       return status;
+}
+
+static int dx_leaf_sort_cmp(const void *a, const void *b)
+{
+       const struct ocfs2_dx_entry *entry1 = a;
+       const struct ocfs2_dx_entry *entry2 = b;
+       u32 major_hash1 = le32_to_cpu(entry1->dx_major_hash);
+       u32 major_hash2 = le32_to_cpu(entry2->dx_major_hash);
+       u32 minor_hash1 = le32_to_cpu(entry1->dx_minor_hash);
+       u32 minor_hash2 = le32_to_cpu(entry2->dx_minor_hash);
+
+       if (major_hash1 > major_hash2)
+               return 1;
+       if (major_hash1 < major_hash2)
+               return -1;
+
+       /*
+        * It is not strictly necessary to sort by minor
+        */
+       if (minor_hash1 > minor_hash2)
+               return 1;
+       if (minor_hash1 < minor_hash2)
+               return -1;
+       return 0;
+}
+
+static void dx_leaf_sort_swap(void *a, void *b, int size)
+{
+       struct ocfs2_dx_entry *entry1 = a;
+       struct ocfs2_dx_entry *entry2 = b;
+       struct ocfs2_dx_entry tmp;
+
+       BUG_ON(size != sizeof(*entry1));
+
+       tmp = *entry1;
+       *entry1 = *entry2;
+       *entry2 = tmp;
+}
+
+static int ocfs2_dx_leaf_same_major(struct ocfs2_dx_leaf *dx_leaf)
+{
+       struct ocfs2_dx_entry_list *dl_list = &dx_leaf->dl_list;
+       int i, num = le16_to_cpu(dl_list->de_num_used);
+
+       for (i = 0; i < (num - 1); i++) {
+               if (le32_to_cpu(dl_list->de_entries[i].dx_major_hash) !=
+                   le32_to_cpu(dl_list->de_entries[i + 1].dx_major_hash))
+                       return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Find the optimal value to split this leaf on. This expects the leaf
+ * entries to be in sorted order.
+ *
+ * leaf_cpos is the cpos of the leaf we're splitting. insert_hash is
+ * the hash we want to insert.
+ *
+ * This function is only concerned with the major hash - that which
+ * determines which cluster an item belongs to.
+ */
+static int ocfs2_dx_dir_find_leaf_split(struct ocfs2_dx_leaf *dx_leaf,
+                                       u32 leaf_cpos, u32 insert_hash,
+                                       u32 *split_hash)
+{
+       struct ocfs2_dx_entry_list *dl_list = &dx_leaf->dl_list;
+       int i, num_used = le16_to_cpu(dl_list->de_num_used);
+       int allsame;
+
+       /*
+        * There's a couple rare, but nasty corner cases we have to
+        * check for here. All of them involve a leaf where all value
+        * have the same hash, which is what we look for first.
+        *
+        * Most of the time, all of the above is false, and we simply
+        * pick the median value for a split.
+        */
+       allsame = ocfs2_dx_leaf_same_major(dx_leaf);
+       if (allsame) {
+               u32 val = le32_to_cpu(dl_list->de_entries[0].dx_major_hash);
+
+               if (val == insert_hash) {
+                       /*
+                        * No matter where we would choose to split,
+                        * the new entry would want to occupy the same
+                        * block as these. Since there's no space left
+                        * in their existing block, we know there
+                        * won't be space after the split.
+                        */
+                       return -ENOSPC;
+               }
+
+               if (val == leaf_cpos) {
+                       /*
+                        * Because val is the same as leaf_cpos (which
+                        * is the smallest value this leaf can have),
+                        * yet is not equal to insert_hash, then we
+                        * know that insert_hash *must* be larger than
+                        * val (and leaf_cpos). At least cpos+1 in value.
+                        *
+                        * We also know then, that there cannot be an
+                        * adjacent extent (otherwise we'd be looking
+                        * at it). Choosing this value gives us a
+                        * chance to get some contiguousness.
+                        */
+                       *split_hash = leaf_cpos + 1;
+                       return 0;
+               }
+
+               if (val > insert_hash) {
+                       /*
+                        * val can not be the same as insert hash, and
+                        * also must be larger than leaf_cpos. Also,
+                        * we know that there can't be a leaf between
+                        * cpos and val, otherwise the entries with
+                        * hash 'val' would be there.
+                        */
+                       *split_hash = val;
+                       return 0;
+               }
+
+               *split_hash = insert_hash;
+               return 0;
+       }
+
+       /*
+        * Since the records are sorted and the checks above
+        * guaranteed that not all records in this block are the same,
+        * we simple travel forward, from the median, and pick the 1st
+        * record whose value is larger than leaf_cpos.
+        */
+       for (i = (num_used / 2); i < num_used; i++)
+               if (le32_to_cpu(dl_list->de_entries[i].dx_major_hash) >
+                   leaf_cpos)
+                       break;
+
+       BUG_ON(i == num_used); /* Should be impossible */
+       *split_hash = le32_to_cpu(dl_list->de_entries[i].dx_major_hash);
+       return 0;
+}
+
+/*
+ * Transfer all entries in orig_dx_leaves whose major hash is equal to or
+ * larger than split_hash into new_dx_leaves. We use a temporary
+ * buffer (tmp_dx_leaf) to make the changes to the original leaf blocks.
+ *
+ * Since the block offset inside a leaf (cluster) is a constant mask
+ * of minor_hash, we can optimize - an item at block offset X within
+ * the original cluster, will be at offset X within the new cluster.
+ */
+static void ocfs2_dx_dir_transfer_leaf(struct inode *dir, u32 split_hash,
+                                      handle_t *handle,
+                                      struct ocfs2_dx_leaf *tmp_dx_leaf,
+                                      struct buffer_head **orig_dx_leaves,
+                                      struct buffer_head **new_dx_leaves,
+                                      int num_dx_leaves)
+{
+       int i, j, num_used;
+       u32 major_hash;
+       struct ocfs2_dx_leaf *orig_dx_leaf, *new_dx_leaf;
+       struct ocfs2_dx_entry_list *orig_list, *new_list, *tmp_list;
+       struct ocfs2_dx_entry *dx_entry;
+
+       tmp_list = &tmp_dx_leaf->dl_list;
+
+       for (i = 0; i < num_dx_leaves; i++) {
+               orig_dx_leaf = (struct ocfs2_dx_leaf *) orig_dx_leaves[i]->b_data;
+               orig_list = &orig_dx_leaf->dl_list;
+               new_dx_leaf = (struct ocfs2_dx_leaf *) new_dx_leaves[i]->b_data;
+               new_list = &new_dx_leaf->dl_list;
+
+               num_used = le16_to_cpu(orig_list->de_num_used);
+
+               memcpy(tmp_dx_leaf, orig_dx_leaf, dir->i_sb->s_blocksize);
+               tmp_list->de_num_used = cpu_to_le16(0);
+               memset(&tmp_list->de_entries, 0, sizeof(*dx_entry)*num_used);
+
+               for (j = 0; j < num_used; j++) {
+                       dx_entry = &orig_list->de_entries[j];
+                       major_hash = le32_to_cpu(dx_entry->dx_major_hash);
+                       if (major_hash >= split_hash)
+                               ocfs2_dx_dir_leaf_insert_tail(new_dx_leaf,
+                                                             dx_entry);
+                       else
+                               ocfs2_dx_dir_leaf_insert_tail(tmp_dx_leaf,
+                                                             dx_entry);
+               }
+               memcpy(orig_dx_leaf, tmp_dx_leaf, dir->i_sb->s_blocksize);
+
+               ocfs2_journal_dirty(handle, orig_dx_leaves[i]);
+               ocfs2_journal_dirty(handle, new_dx_leaves[i]);
+       }
+}
+
+static int ocfs2_dx_dir_rebalance_credits(struct ocfs2_super *osb,
+                                         struct ocfs2_dx_root_block *dx_root)
+{
+       int credits = ocfs2_clusters_to_blocks(osb->sb, 2);
+
+       credits += ocfs2_calc_extend_credits(osb->sb, &dx_root->dr_list, 1);
+       credits += ocfs2_quota_trans_credits(osb->sb);
+       return credits;
+}
+
+/*
+ * Find the median value in dx_leaf_bh and allocate a new leaf to move
+ * half our entries into.
+ */
+static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir,
+                                 struct buffer_head *dx_root_bh,
+                                 struct buffer_head *dx_leaf_bh,
+                                 struct ocfs2_dx_hinfo *hinfo, u32 leaf_cpos,
+                                 u64 leaf_blkno)
+{
+       struct ocfs2_dx_leaf *dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data;
+       int credits, ret, i, num_used, did_quota = 0;
+       u32 cpos, split_hash, insert_hash = hinfo->major_hash;
+       u64 orig_leaves_start;
+       int num_dx_leaves;
+       struct buffer_head **orig_dx_leaves = NULL;
+       struct buffer_head **new_dx_leaves = NULL;
+       struct ocfs2_alloc_context *data_ac = NULL, *meta_ac = NULL;
+       struct ocfs2_extent_tree et;
+       handle_t *handle = NULL;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dx_leaf *tmp_dx_leaf = NULL;
+
+       mlog(0, "DX Dir: %llu, rebalance leaf leaf_blkno: %llu insert: %u\n",
+            (unsigned long long)OCFS2_I(dir)->ip_blkno,
+            (unsigned long long)leaf_blkno, insert_hash);
+
+       ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh);
+
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+       /*
+        * XXX: This is a rather large limit. We should use a more
+        * realistic value.
+        */
+       if (le32_to_cpu(dx_root->dr_clusters) == UINT_MAX)
+               return -ENOSPC;
+
+       num_used = le16_to_cpu(dx_leaf->dl_list.de_num_used);
+       if (num_used < le16_to_cpu(dx_leaf->dl_list.de_count)) {
+               mlog(ML_ERROR, "DX Dir: %llu, Asked to rebalance empty leaf: "
+                    "%llu, %d\n", (unsigned long long)OCFS2_I(dir)->ip_blkno,
+                    (unsigned long long)leaf_blkno, num_used);
+               ret = -EIO;
+               goto out;
+       }
+
+       orig_dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, &num_dx_leaves);
+       if (!orig_dx_leaves) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       new_dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, NULL);
+       if (!new_dx_leaves) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_lock_allocators(dir, &et, 1, 0, &data_ac, &meta_ac);
+       if (ret) {
+               if (ret != -ENOSPC)
+                       mlog_errno(ret);
+               goto out;
+       }
+
+       credits = ocfs2_dx_dir_rebalance_credits(osb, dx_root);
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (vfs_dq_alloc_space_nodirty(dir,
+                                      ocfs2_clusters_to_bytes(dir->i_sb, 1))) {
+               ret = -EDQUOT;
+               goto out_commit;
+       }
+       did_quota = 1;
+
+       ret = ocfs2_journal_access_dl(handle, dir, dx_leaf_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * This block is changing anyway, so we can sort it in place.
+        */
+       sort(dx_leaf->dl_list.de_entries, num_used,
+            sizeof(struct ocfs2_dx_entry), dx_leaf_sort_cmp,
+            dx_leaf_sort_swap);
+
+       ret = ocfs2_journal_dirty(handle, dx_leaf_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_dx_dir_find_leaf_split(dx_leaf, leaf_cpos, insert_hash,
+                                          &split_hash);
+       if (ret) {
+               mlog_errno(ret);
+               goto  out_commit;
+       }
+
+       mlog(0, "Split leaf (%u) at %u, insert major hash is %u\n",
+            leaf_cpos, split_hash, insert_hash);
+
+       /*
+        * We have to carefully order operations here. There are items
+        * which want to be in the new cluster before insert, but in
+        * order to put those items in the new cluster, we alter the
+        * old cluster. A failure to insert gets nasty.
+        *
+        * So, start by reserving writes to the old
+        * cluster. ocfs2_dx_dir_new_cluster will reserve writes on
+        * the new cluster for us, before inserting it. The insert
+        * won't happen if there's an error before that. Once the
+        * insert is done then, we can transfer from one leaf into the
+        * other without fear of hitting any error.
+        */
+
+       /*
+        * The leaf transfer wants some scratch space so that we don't
+        * wind up doing a bunch of expensive memmove().
+        */
+       tmp_dx_leaf = kmalloc(osb->sb->s_blocksize, GFP_NOFS);
+       if (!tmp_dx_leaf) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       orig_leaves_start = ocfs2_block_to_cluster_start(dir->i_sb, leaf_blkno);
+       ret = ocfs2_read_dx_leaves(dir, orig_leaves_start, num_dx_leaves,
+                                  orig_dx_leaves);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       for (i = 0; i < num_dx_leaves; i++) {
+               ret = ocfs2_journal_access_dl(handle, dir, orig_dx_leaves[i],
+                                             OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
                }
+       }
 
-               if (blocks_wanted == 1) {
+       cpos = split_hash;
+       ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle,
+                                      data_ac, meta_ac, new_dx_leaves,
+                                      num_dx_leaves);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf,
+                                  orig_dx_leaves, new_dx_leaves, num_dx_leaves);
+
+out_commit:
+       if (ret < 0 && did_quota)
+               vfs_dq_free_space_nodirty(dir,
+                               ocfs2_clusters_to_bytes(dir->i_sb, 1));
+
+       ocfs2_commit_trans(osb, handle);
+
+out:
+       if (orig_dx_leaves || new_dx_leaves) {
+               for (i = 0; i < num_dx_leaves; i++) {
+                       if (orig_dx_leaves)
+                               brelse(orig_dx_leaves[i]);
+                       if (new_dx_leaves)
+                               brelse(new_dx_leaves[i]);
+               }
+               kfree(orig_dx_leaves);
+               kfree(new_dx_leaves);
+       }
+
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+
+       kfree(tmp_dx_leaf);
+       return ret;
+}
+
+static int ocfs2_find_dir_space_dx(struct ocfs2_super *osb, struct inode *dir,
+                                  struct buffer_head *di_bh,
+                                  struct buffer_head *dx_root_bh,
+                                  const char *name, int namelen,
+                                  struct ocfs2_dir_lookup_result *lookup)
+{
+       int ret, rebalanced = 0;
+       struct ocfs2_dx_root_block *dx_root;
+       struct buffer_head *dx_leaf_bh = NULL;
+       struct ocfs2_dx_leaf *dx_leaf;
+       u64 blkno;
+       u32 leaf_cpos;
+
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+
+restart_search:
+       ret = ocfs2_dx_dir_lookup(dir, &dx_root->dr_list, &lookup->dl_hinfo,
+                                 &leaf_cpos, &blkno);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_read_dx_leaf(dir, blkno, &dx_leaf_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data;
+
+       if (le16_to_cpu(dx_leaf->dl_list.de_num_used) >=
+           le16_to_cpu(dx_leaf->dl_list.de_count)) {
+               if (rebalanced) {
                        /*
-                        * If the new dirent will fit inside the space
-                        * created by pushing out to one block, then
-                        * we can complete the operation
-                        * here. Otherwise we have to expand i_size
-                        * and format the 2nd block below.
+                        * Rebalancing should have provided us with
+                        * space in an appropriate leaf.
+                        *
+                        * XXX: Is this an abnormal condition then?
+                        * Should we print a message here?
                         */
-                       BUG_ON(new_bh == NULL);
-                       goto bail_bh;
+                       ret = -ENOSPC;
+                       goto out;
+               }
+
+               ret = ocfs2_dx_dir_rebalance(osb, dir, dx_root_bh, dx_leaf_bh,
+                                            &lookup->dl_hinfo, leaf_cpos,
+                                            blkno);
+               if (ret) {
+                       if (ret != -ENOSPC)
+                               mlog_errno(ret);
+                       goto out;
                }
 
                /*
-                * Get rid of 'new_bh' - we want to format the 2nd
-                * data block and return that instead.
+                * Restart the lookup. The rebalance might have
+                * changed which block our item fits into. Mark our
+                * progress, so we only execute this once.
                 */
-               brelse(new_bh);
-               new_bh = NULL;
-
-               dir_i_size = i_size_read(dir);
-               credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
-               goto do_extend;
+               brelse(dx_leaf_bh);
+               dx_leaf_bh = NULL;
+               rebalanced = 1;
+               goto restart_search;
        }
 
-       dir_i_size = i_size_read(dir);
-       mlog(0, "extending dir %llu (i_size = %lld)\n",
-            (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
+       lookup->dl_dx_leaf_bh = dx_leaf_bh;
+       dx_leaf_bh = NULL;
 
-       /* dir->i_size is always block aligned. */
-       spin_lock(&OCFS2_I(dir)->ip_lock);
-       if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) {
-               spin_unlock(&OCFS2_I(dir)->ip_lock);
-               ocfs2_init_dinode_extent_tree(&et, dir, parent_fe_bh);
-               num_free_extents = ocfs2_num_free_extents(osb, dir, &et);
-               if (num_free_extents < 0) {
-                       status = num_free_extents;
-                       mlog_errno(status);
-                       goto bail;
-               }
+out:
+       brelse(dx_leaf_bh);
+       return ret;
+}
 
-               if (!num_free_extents) {
-                       status = ocfs2_reserve_new_metadata(osb, el, &meta_ac);
-                       if (status < 0) {
-                               if (status != -ENOSPC)
-                                       mlog_errno(status);
-                               goto bail;
-                       }
+static int ocfs2_search_dx_free_list(struct inode *dir,
+                                    struct buffer_head *dx_root_bh,
+                                    int namelen,
+                                    struct ocfs2_dir_lookup_result *lookup)
+{
+       int ret = -ENOSPC;
+       struct buffer_head *leaf_bh = NULL, *prev_leaf_bh = NULL;
+       struct ocfs2_dir_block_trailer *db;
+       u64 next_block;
+       int rec_len = OCFS2_DIR_REC_LEN(namelen);
+       struct ocfs2_dx_root_block *dx_root;
+
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+       next_block = le64_to_cpu(dx_root->dr_free_blk);
+
+       while (next_block) {
+               brelse(prev_leaf_bh);
+               prev_leaf_bh = leaf_bh;
+               leaf_bh = NULL;
+
+               ret = ocfs2_read_dir_block_direct(dir, next_block, &leaf_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
                }
 
-               status = ocfs2_reserve_clusters(osb, 1, &data_ac);
-               if (status < 0) {
-                       if (status != -ENOSPC)
-                               mlog_errno(status);
-                       goto bail;
+               db = ocfs2_trailer_from_bh(leaf_bh, dir->i_sb);
+               if (rec_len <= le16_to_cpu(db->db_free_rec_len)) {
+                       lookup->dl_leaf_bh = leaf_bh;
+                       lookup->dl_prev_leaf_bh = prev_leaf_bh;
+                       leaf_bh = NULL;
+                       prev_leaf_bh = NULL;
+                       break;
                }
 
-               credits = ocfs2_calc_extend_credits(sb, el, 1);
-       } else {
-               spin_unlock(&OCFS2_I(dir)->ip_lock);
-               credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
+               next_block = le64_to_cpu(db->db_free_next);
        }
 
-do_extend:
-       down_write(&OCFS2_I(dir)->ip_alloc_sem);
-       drop_alloc_sem = 1;
+       if (!next_block)
+               ret = -ENOSPC;
 
-       handle = ocfs2_start_trans(osb, credits);
-       if (IS_ERR(handle)) {
-               status = PTR_ERR(handle);
-               handle = NULL;
-               mlog_errno(status);
-               goto bail;
+out:
+
+       brelse(leaf_bh);
+       brelse(prev_leaf_bh);
+       return ret;
+}
+
+static int ocfs2_expand_inline_dx_root(struct inode *dir,
+                                      struct buffer_head *dx_root_bh)
+{
+       int ret, num_dx_leaves, i, j, did_quota = 0;
+       struct buffer_head **dx_leaves = NULL;
+       struct ocfs2_extent_tree et;
+       u64 insert_blkno;
+       struct ocfs2_alloc_context *data_ac = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       handle_t *handle = NULL;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dx_entry_list *entry_list;
+       struct ocfs2_dx_entry *dx_entry;
+       struct ocfs2_dx_leaf *target_leaf;
+
+       ret = ocfs2_reserve_clusters(osb, 1, &data_ac);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
        }
 
-       status = ocfs2_do_extend_dir(osb->sb, handle, dir, parent_fe_bh,
-                                    data_ac, meta_ac, &new_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
+       dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, &num_dx_leaves);
+       if (!dx_leaves) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
        }
 
-       ocfs2_set_new_buffer_uptodate(dir, new_bh);
+       handle = ocfs2_start_trans(osb, ocfs2_calc_dxi_expand_credits(osb->sb));
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
 
-       status = ocfs2_journal_access_db(handle, dir, new_bh,
-                                        OCFS2_JOURNAL_ACCESS_CREATE);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
+       if (vfs_dq_alloc_space_nodirty(dir,
+                                      ocfs2_clusters_to_bytes(osb->sb, 1))) {
+               ret = -EDQUOT;
+               goto out_commit;
        }
-       memset(new_bh->b_data, 0, sb->s_blocksize);
+       did_quota = 1;
 
-       de = (struct ocfs2_dir_entry *) new_bh->b_data;
-       de->inode = 0;
-       if (ocfs2_dir_has_trailer(dir)) {
-               de->rec_len = cpu_to_le16(ocfs2_dir_trailer_blk_off(sb));
-               ocfs2_init_dir_trailer(dir, new_bh);
-       } else {
-               de->rec_len = cpu_to_le16(sb->s_blocksize);
+       /*
+        * We do this up front, before the allocation, so that a
+        * failure to add the dx_root_bh to the journal won't result
+        * us losing clusters.
+        */
+       ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
        }
-       status = ocfs2_journal_dirty(handle, new_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
+
+       ret = __ocfs2_dx_dir_new_cluster(dir, 0, handle, data_ac, dx_leaves,
+                                        num_dx_leaves, &insert_blkno);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
        }
 
-       dir_i_size += dir->i_sb->s_blocksize;
-       i_size_write(dir, dir_i_size);
-       dir->i_blocks = ocfs2_inode_sector_count(dir);
-       status = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
+       /*
+        * Transfer the entries from our dx_root into the appropriate
+        * block
+        */
+       dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data;
+       entry_list = &dx_root->dr_entries;
+
+       for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++) {
+               dx_entry = &entry_list->de_entries[i];
+
+               j = __ocfs2_dx_dir_hash_idx(osb,
+                                           le32_to_cpu(dx_entry->dx_minor_hash));
+               target_leaf = (struct ocfs2_dx_leaf *)dx_leaves[j]->b_data;
+
+               ocfs2_dx_dir_leaf_insert_tail(target_leaf, dx_entry);
+
+               /* Each leaf has been passed to the journal already
+                * via __ocfs2_dx_dir_new_cluster() */
        }
 
-bail_bh:
-       *new_de_bh = new_bh;
-       get_bh(*new_de_bh);
-bail:
-       if (drop_alloc_sem)
-               up_write(&OCFS2_I(dir)->ip_alloc_sem);
-       if (handle)
-               ocfs2_commit_trans(osb, handle);
+       dx_root->dr_flags &= ~OCFS2_DX_FLAG_INLINE;
+       memset(&dx_root->dr_list, 0, osb->sb->s_blocksize -
+              offsetof(struct ocfs2_dx_root_block, dr_list));
+       dx_root->dr_list.l_count =
+               cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb));
+
+       /* This should never fail considering we start with an empty
+        * dx_root. */
+       ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh);
+       ret = ocfs2_insert_extent(osb, handle, dir, &et, 0,
+                                 insert_blkno, 1, 0, NULL);
+       if (ret)
+               mlog_errno(ret);
+       did_quota = 0;
+
+       ocfs2_journal_dirty(handle, dx_root_bh);
+
+out_commit:
+       if (ret < 0 && did_quota)
+               vfs_dq_free_space_nodirty(dir,
+                                         ocfs2_clusters_to_bytes(dir->i_sb, 1));
+
+       ocfs2_commit_trans(osb, handle);
+
+out:
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+
+       if (dx_leaves) {
+               for (i = 0; i < num_dx_leaves; i++)
+                       brelse(dx_leaves[i]);
+               kfree(dx_leaves);
+       }
+       return ret;
+}
 
-       if (data_ac)
-               ocfs2_free_alloc_context(data_ac);
-       if (meta_ac)
-               ocfs2_free_alloc_context(meta_ac);
+static int ocfs2_inline_dx_has_space(struct buffer_head *dx_root_bh)
+{
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dx_entry_list *entry_list;
 
-       brelse(new_bh);
+       dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data;
+       entry_list = &dx_root->dr_entries;
 
-       mlog_exit(status);
-       return status;
+       if (le16_to_cpu(entry_list->de_num_used) >=
+           le16_to_cpu(entry_list->de_count))
+               return -ENOSPC;
+
+       return 0;
 }
 
-static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
-                                  const char *name, int namelen,
-                                  struct buffer_head **ret_de_bh,
-                                  unsigned int *blocks_wanted)
+static int ocfs2_prepare_dx_dir_for_insert(struct inode *dir,
+                                          struct buffer_head *di_bh,
+                                          const char *name,
+                                          int namelen,
+                                          struct ocfs2_dir_lookup_result *lookup)
 {
-       int ret;
-       struct super_block *sb = dir->i_sb;
+       int ret, free_dx_root = 1;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct buffer_head *dx_root_bh = NULL;
+       struct buffer_head *leaf_bh = NULL;
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
-       struct ocfs2_dir_entry *de, *last_de = NULL;
-       char *de_buf, *limit;
-       unsigned long offset = 0;
-       unsigned int rec_len, new_rec_len, free_space = dir->i_sb->s_blocksize;
+       struct ocfs2_dx_root_block *dx_root;
 
-       /*
-        * This calculates how many free bytes we'd have in block zero, should
-        * this function force expansion to an extent tree.
-        */
-       if (ocfs2_supports_dir_trailer(OCFS2_SB(sb)))
-               free_space = ocfs2_dir_trailer_blk_off(sb) - i_size_read(dir);
-       else
-               free_space = dir->i_sb->s_blocksize - i_size_read(dir);
+       ret = ocfs2_read_dx_root(dir, di, &dx_root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
 
-       de_buf = di->id2.i_data.id_data;
-       limit = de_buf + i_size_read(dir);
-       rec_len = OCFS2_DIR_REC_LEN(namelen);
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+       if (le32_to_cpu(dx_root->dr_num_entries) == OCFS2_DX_ENTRIES_MAX) {
+               ret = -ENOSPC;
+               mlog_errno(ret);
+               goto out;
+       }
 
-       while (de_buf < limit) {
-               de = (struct ocfs2_dir_entry *)de_buf;
+       if (ocfs2_dx_root_inline(dx_root)) {
+               ret = ocfs2_inline_dx_has_space(dx_root_bh);
+
+               if (ret == 0)
+                       goto search_el;
 
-               if (!ocfs2_check_dir_entry(dir, de, di_bh, offset)) {
-                       ret = -ENOENT;
-                       goto out;
-               }
-               if (ocfs2_match(namelen, name, de)) {
-                       ret = -EEXIST;
-                       goto out;
-               }
                /*
-                * No need to check for a trailing dirent record here as
-                * they're not used for inline dirs.
+                * We ran out of room in the root block. Expand it to
+                * an extent, then allow ocfs2_find_dir_space_dx to do
+                * the rest.
                 */
-
-               if (ocfs2_dirent_would_fit(de, rec_len)) {
-                       /* Ok, we found a spot. Return this bh and let
-                        * the caller actually fill it in. */
-                       *ret_de_bh = di_bh;
-                       get_bh(*ret_de_bh);
-                       ret = 0;
+               ret = ocfs2_expand_inline_dx_root(dir, dx_root_bh);
+               if (ret) {
+                       mlog_errno(ret);
                        goto out;
                }
-
-               last_de = de;
-               de_buf += le16_to_cpu(de->rec_len);
-               offset += le16_to_cpu(de->rec_len);
        }
 
        /*
-        * We're going to require expansion of the directory - figure
-        * out how many blocks we'll need so that a place for the
-        * dirent can be found.
+        * Insert preparation for an indexed directory is split into two
+        * steps. The call to find_dir_space_dx reserves room in the index for
+        * an additional item. If we run out of space there, it's a real error
+        * we can't continue on.
         */
-       *blocks_wanted = 1;
-       new_rec_len = le16_to_cpu(last_de->rec_len) + free_space;
-       if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len)))
-               *blocks_wanted = 2;
-
-       ret = -ENOSPC;
-out:
-       return ret;
-}
-
-static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
-                                  int namelen, struct buffer_head **ret_de_bh)
-{
-       unsigned long offset;
-       struct buffer_head *bh = NULL;
-       unsigned short rec_len;
-       struct ocfs2_dir_entry *de;
-       struct super_block *sb = dir->i_sb;
-       int status;
-       int blocksize = dir->i_sb->s_blocksize;
-
-       status = ocfs2_read_dir_block(dir, 0, &bh, 0);
-       if (status) {
-               mlog_errno(status);
-               goto bail;
+       ret = ocfs2_find_dir_space_dx(osb, dir, di_bh, dx_root_bh, name,
+                                     namelen, lookup);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
        }
 
-       rec_len = OCFS2_DIR_REC_LEN(namelen);
-       offset = 0;
-       de = (struct ocfs2_dir_entry *) bh->b_data;
-       while (1) {
-               if ((char *)de >= sb->s_blocksize + bh->b_data) {
-                       brelse(bh);
-                       bh = NULL;
+search_el:
+       /*
+        * Next, we need to find space in the unindexed tree. This call
+        * searches using the free space linked list. If the unindexed tree
+        * lacks sufficient space, we'll expand it below. The expansion code
+        * is smart enough to add any new blocks to the free space list.
+        */
+       ret = ocfs2_search_dx_free_list(dir, dx_root_bh, namelen, lookup);
+       if (ret && ret != -ENOSPC) {
+               mlog_errno(ret);
+               goto out;
+       }
 
-                       if (i_size_read(dir) <= offset) {
-                               /*
-                                * Caller will have to expand this
-                                * directory.
-                                */
-                               status = -ENOSPC;
-                               goto bail;
-                       }
-                       status = ocfs2_read_dir_block(dir,
-                                            offset >> sb->s_blocksize_bits,
-                                            &bh, 0);
-                       if (status) {
-                               mlog_errno(status);
-                               goto bail;
-                       }
-                       /* move to next block */
-                       de = (struct ocfs2_dir_entry *) bh->b_data;
-               }
-               if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
-                       status = -ENOENT;
-                       goto bail;
-               }
-               if (ocfs2_match(namelen, name, de)) {
-                       status = -EEXIST;
-                       goto bail;
-               }
+       /* Do this up here - ocfs2_extend_dir might need the dx_root */
+       lookup->dl_dx_root_bh = dx_root_bh;
+       free_dx_root = 0;
 
-               if (ocfs2_skip_dir_trailer(dir, de, offset % blocksize,
-                                          blocksize))
-                       goto next;
+       if (ret == -ENOSPC) {
+               ret = ocfs2_extend_dir(osb, dir, di_bh, 1, lookup, &leaf_bh);
 
-               if (ocfs2_dirent_would_fit(de, rec_len)) {
-                       /* Ok, we found a spot. Return this bh and let
-                        * the caller actually fill it in. */
-                       *ret_de_bh = bh;
-                       get_bh(*ret_de_bh);
-                       status = 0;
-                       goto bail;
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
                }
-next:
-               offset += le16_to_cpu(de->rec_len);
-               de = (struct ocfs2_dir_entry *)((char *) de + le16_to_cpu(de->rec_len));
-       }
 
-       status = 0;
-bail:
-       brelse(bh);
+               /*
+                * We make the assumption here that new leaf blocks are added
+                * to the front of our free list.
+                */
+               lookup->dl_prev_leaf_bh = NULL;
+               lookup->dl_leaf_bh = leaf_bh;
+       }
 
-       mlog_exit(status);
-       return status;
+out:
+       if (free_dx_root)
+               brelse(dx_root_bh);
+       return ret;
 }
 
+/*
+ * Get a directory ready for insert. Any directory allocation required
+ * happens here. Success returns zero, and enough context in the dir
+ * lookup result that ocfs2_add_entry() will be able complete the task
+ * with minimal performance impact.
+ */
 int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                                 struct inode *dir,
                                 struct buffer_head *parent_fe_bh,
                                 const char *name,
                                 int namelen,
-                                struct buffer_head **ret_de_bh)
+                                struct ocfs2_dir_lookup_result *lookup)
 {
        int ret;
        unsigned int blocks_wanted = 1;
@@ -1984,14 +4367,34 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
        mlog(0, "getting ready to insert namelen %d into dir %llu\n",
             namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
-       *ret_de_bh = NULL;
-
        if (!namelen) {
                ret = -EINVAL;
                mlog_errno(ret);
                goto out;
        }
 
+       /*
+        * Do this up front to reduce confusion.
+        *
+        * The directory might start inline, then be turned into an
+        * indexed one, in which case we'd need to hash deep inside
+        * ocfs2_find_dir_space_id(). Since
+        * ocfs2_prepare_dx_dir_for_insert() also needs this hash
+        * done, there seems no point in spreading out the calls. We
+        * can optimize away the case where the file system doesn't
+        * support indexing.
+        */
+       if (ocfs2_supports_indexed_dirs(osb))
+               ocfs2_dx_dir_name_hash(dir, name, namelen, &lookup->dl_hinfo);
+
+       if (ocfs2_dir_indexed(dir)) {
+               ret = ocfs2_prepare_dx_dir_for_insert(dir, parent_fe_bh,
+                                                     name, namelen, lookup);
+               if (ret)
+                       mlog_errno(ret);
+               goto out;
+       }
+
        if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
                ret = ocfs2_find_dir_space_id(dir, parent_fe_bh, name,
                                              namelen, &bh, &blocks_wanted);
@@ -2010,7 +4413,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                BUG_ON(bh);
 
                ret = ocfs2_extend_dir(osb, dir, parent_fe_bh, blocks_wanted,
-                                      &bh);
+                                      lookup, &bh);
                if (ret) {
                        if (ret != -ENOSPC)
                                mlog_errno(ret);
@@ -2020,9 +4423,154 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                BUG_ON(!bh);
        }
 
-       *ret_de_bh = bh;
+       lookup->dl_leaf_bh = bh;
        bh = NULL;
 out:
        brelse(bh);
        return ret;
 }
+
+static int ocfs2_dx_dir_remove_index(struct inode *dir,
+                                    struct buffer_head *di_bh,
+                                    struct buffer_head *dx_root_bh)
+{
+       int ret;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_dx_root_block *dx_root;
+       struct inode *dx_alloc_inode = NULL;
+       struct buffer_head *dx_alloc_bh = NULL;
+       handle_t *handle;
+       u64 blk;
+       u16 bit;
+       u64 bg_blkno;
+
+       dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data;
+
+       dx_alloc_inode = ocfs2_get_system_file_inode(osb,
+                                       EXTENT_ALLOC_SYSTEM_INODE,
+                                       le16_to_cpu(dx_root->dr_suballoc_slot));
+       if (!dx_alloc_inode) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+       mutex_lock(&dx_alloc_inode->i_mutex);
+
+       ret = ocfs2_inode_lock(dx_alloc_inode, &dx_alloc_bh, 1);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_mutex;
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_DX_ROOT_REMOVE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       ret = ocfs2_journal_access_di(handle, dir, di_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       OCFS2_I(dir)->ip_dyn_features &= ~OCFS2_INDEXED_DIR_FL;
+       di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features);
+       di->i_dx_root = cpu_to_le64(0ULL);
+
+       ocfs2_journal_dirty(handle, di_bh);
+
+       blk = le64_to_cpu(dx_root->dr_blkno);
+       bit = le16_to_cpu(dx_root->dr_suballoc_bit);
+       bg_blkno = ocfs2_which_suballoc_group(blk, bit);
+       ret = ocfs2_free_suballoc_bits(handle, dx_alloc_inode, dx_alloc_bh,
+                                      bit, bg_blkno, 1);
+       if (ret)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+
+out_unlock:
+       ocfs2_inode_unlock(dx_alloc_inode, 1);
+
+out_mutex:
+       mutex_unlock(&dx_alloc_inode->i_mutex);
+       brelse(dx_alloc_bh);
+out:
+       iput(dx_alloc_inode);
+       return ret;
+}
+
+int ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh)
+{
+       int ret;
+       unsigned int uninitialized_var(clen);
+       u32 major_hash = UINT_MAX, p_cpos, uninitialized_var(cpos);
+       u64 uninitialized_var(blkno);
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct buffer_head *dx_root_bh = NULL;
+       struct ocfs2_dx_root_block *dx_root;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_cached_dealloc_ctxt dealloc;
+       struct ocfs2_extent_tree et;
+
+       ocfs2_init_dealloc_ctxt(&dealloc);
+
+       if (!ocfs2_dir_indexed(dir))
+               return 0;
+
+       ret = ocfs2_read_dx_root(dir, di, &dx_root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+       dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
+
+       if (ocfs2_dx_root_inline(dx_root))
+               goto remove_index;
+
+       ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh);
+
+       /* XXX: What if dr_clusters is too large? */
+       while (le32_to_cpu(dx_root->dr_clusters)) {
+               ret = ocfs2_dx_dir_lookup_rec(dir, &dx_root->dr_list,
+                                             major_hash, &cpos, &blkno, &clen);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               p_cpos = ocfs2_blocks_to_clusters(dir->i_sb, blkno);
+
+               ret = ocfs2_remove_btree_range(dir, &et, cpos, p_cpos, clen,
+                                              &dealloc);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (cpos == 0)
+                       break;
+
+               major_hash = cpos - 1;
+       }
+
+remove_index:
+       ret = ocfs2_dx_dir_remove_index(dir, di_bh, dx_root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ocfs2_remove_from_cache(dir, dx_root_bh);
+out:
+       ocfs2_schedule_truncate_log_flush(osb, 1);
+       ocfs2_run_deallocs(osb, &dealloc);
+
+       brelse(dx_root_bh);
+       return ret;
+}
index c511e2e18e9f064ff67d7b3299bad90f4fd99a94..e683f3deb64503a3167198a88d37070cf1ee0eba 100644 (file)
 #ifndef OCFS2_DIR_H
 #define OCFS2_DIR_H
 
-struct buffer_head *ocfs2_find_entry(const char *name,
-                                    int namelen,
-                                    struct inode *dir,
-                                    struct ocfs2_dir_entry **res_dir);
+struct ocfs2_dx_hinfo {
+       u32     major_hash;
+       u32     minor_hash;
+};
+
+struct ocfs2_dir_lookup_result {
+       struct buffer_head              *dl_leaf_bh;    /* Unindexed leaf
+                                                        * block */
+       struct ocfs2_dir_entry          *dl_entry;      /* Target dirent in
+                                                        * unindexed leaf */
+
+       struct buffer_head              *dl_dx_root_bh; /* Root of indexed
+                                                        * tree */
+
+       struct buffer_head              *dl_dx_leaf_bh; /* Indexed leaf block */
+       struct ocfs2_dx_entry           *dl_dx_entry;   /* Target dx_entry in
+                                                        * indexed leaf */
+       struct ocfs2_dx_hinfo           dl_hinfo;       /* Name hash results */
+
+       struct buffer_head              *dl_prev_leaf_bh;/* Previous entry in
+                                                         * dir free space
+                                                         * list. NULL if
+                                                         * previous entry is
+                                                         * dx root block. */
+};
+
+void ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res);
+
+int ocfs2_find_entry(const char *name, int namelen,
+                    struct inode *dir,
+                    struct ocfs2_dir_lookup_result *lookup);
 int ocfs2_delete_entry(handle_t *handle,
                       struct inode *dir,
-                      struct ocfs2_dir_entry *de_del,
-                      struct buffer_head *bh);
+                      struct ocfs2_dir_lookup_result *res);
 int __ocfs2_add_entry(handle_t *handle,
                      struct inode *dir,
                      const char *name, int namelen,
                      struct inode *inode, u64 blkno,
                      struct buffer_head *parent_fe_bh,
-                     struct buffer_head *insert_bh);
+                     struct ocfs2_dir_lookup_result *lookup);
 static inline int ocfs2_add_entry(handle_t *handle,
                                  struct dentry *dentry,
                                  struct inode *inode, u64 blkno,
                                  struct buffer_head *parent_fe_bh,
-                                 struct buffer_head *insert_bh)
+                                 struct ocfs2_dir_lookup_result *lookup)
 {
        return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
                                 dentry->d_name.name, dentry->d_name.len,
-                                inode, blkno, parent_fe_bh, insert_bh);
+                                inode, blkno, parent_fe_bh, lookup);
 }
 int ocfs2_update_entry(struct inode *dir, handle_t *handle,
-                      struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
+                      struct ocfs2_dir_lookup_result *res,
                       struct inode *new_entry_inode);
 
 int ocfs2_check_dir_for_entry(struct inode *dir,
                              const char *name,
                              int namelen);
 int ocfs2_empty_dir(struct inode *inode);
+
 int ocfs2_find_files_on_disk(const char *name,
                             int namelen,
                             u64 *blkno,
                             struct inode *inode,
-                            struct buffer_head **dirent_bh,
-                            struct ocfs2_dir_entry **dirent);
+                            struct ocfs2_dir_lookup_result *res);
 int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
                               int namelen, u64 *blkno);
 int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir);
@@ -74,14 +100,17 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                                 struct buffer_head *parent_fe_bh,
                                 const char *name,
                                 int namelen,
-                                struct buffer_head **ret_de_bh);
+                                struct ocfs2_dir_lookup_result *lookup);
 struct ocfs2_alloc_context;
 int ocfs2_fill_new_dir(struct ocfs2_super *osb,
                       handle_t *handle,
                       struct inode *parent,
                       struct inode *inode,
                       struct buffer_head *fe_bh,
-                      struct ocfs2_alloc_context *data_ac);
+                      struct ocfs2_alloc_context *data_ac,
+                      struct ocfs2_alloc_context *meta_ac);
+
+int ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh);
 
 struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_size(int blocksize,
                                                            void *data);
index bb53714813abb716dca2bb2fe793ee64dd36a8e9..0102be35980c03ae0d3bcfe561282e5f9781626f 100644 (file)
 enum dlm_mle_type {
        DLM_MLE_BLOCK,
        DLM_MLE_MASTER,
-       DLM_MLE_MIGRATION
-};
-
-struct dlm_lock_name {
-       u8 len;
-       u8 name[DLM_LOCKID_NAME_MAX];
+       DLM_MLE_MIGRATION,
+       DLM_MLE_NUM_TYPES
 };
 
 struct dlm_master_list_entry {
-       struct list_head list;
+       struct hlist_node master_hash_node;
        struct list_head hb_events;
        struct dlm_ctxt *dlm;
        spinlock_t spinlock;
@@ -78,10 +74,10 @@ struct dlm_master_list_entry {
        enum dlm_mle_type type;
        struct o2hb_callback_func mle_hb_up;
        struct o2hb_callback_func mle_hb_down;
-       union {
-               struct dlm_lock_resource *res;
-               struct dlm_lock_name name;
-       } u;
+       struct dlm_lock_resource *mleres;
+       unsigned char mname[DLM_LOCKID_NAME_MAX];
+       unsigned int mnamelen;
+       unsigned int mnamehash;
 };
 
 enum dlm_ast_type {
@@ -151,13 +147,14 @@ struct dlm_ctxt
        unsigned long recovery_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
        struct dlm_recovery_ctxt reco;
        spinlock_t master_lock;
-       struct list_head master_list;
+       struct hlist_head **master_hash;
        struct list_head mle_hb_events;
 
        /* these give a really vague idea of the system load */
-       atomic_t local_resources;
-       atomic_t remote_resources;
-       atomic_t unknown_resources;
+       atomic_t mle_tot_count[DLM_MLE_NUM_TYPES];
+       atomic_t mle_cur_count[DLM_MLE_NUM_TYPES];
+       atomic_t res_tot_count;
+       atomic_t res_cur_count;
 
        struct dlm_debug_ctxt *dlm_debug_ctxt;
        struct dentry *dlm_debugfs_subroot;
@@ -195,6 +192,13 @@ static inline struct hlist_head *dlm_lockres_hash(struct dlm_ctxt *dlm, unsigned
        return dlm->lockres_hash[(i / DLM_BUCKETS_PER_PAGE) % DLM_HASH_PAGES] + (i % DLM_BUCKETS_PER_PAGE);
 }
 
+static inline struct hlist_head *dlm_master_hash(struct dlm_ctxt *dlm,
+                                                unsigned i)
+{
+       return dlm->master_hash[(i / DLM_BUCKETS_PER_PAGE) % DLM_HASH_PAGES] +
+                       (i % DLM_BUCKETS_PER_PAGE);
+}
+
 /* these keventd work queue items are for less-frequently
  * called functions that cannot be directly called from the
  * net message handlers for some reason, usually because
@@ -848,9 +852,7 @@ struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm,
                                              unsigned int len);
 
 int dlm_is_host_down(int errno);
-void dlm_change_lockres_owner(struct dlm_ctxt *dlm,
-                             struct dlm_lock_resource *res,
-                             u8 owner);
+
 struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm,
                                                 const char *lockid,
                                                 int namelen,
@@ -1008,6 +1010,9 @@ static inline void __dlm_wait_on_lockres(struct dlm_lock_resource *res)
                                          DLM_LOCK_RES_MIGRATING));
 }
 
+void __dlm_unlink_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle);
+void __dlm_insert_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle);
+
 /* create/destroy slab caches */
 int dlm_init_master_caches(void);
 void dlm_destroy_master_caches(void);
@@ -1110,6 +1115,23 @@ static inline int dlm_node_iter_next(struct dlm_node_iter *iter)
        return bit;
 }
 
+static inline void dlm_set_lockres_owner(struct dlm_ctxt *dlm,
+                                        struct dlm_lock_resource *res,
+                                        u8 owner)
+{
+       assert_spin_locked(&res->spinlock);
+
+       res->owner = owner;
+}
 
+static inline void dlm_change_lockres_owner(struct dlm_ctxt *dlm,
+                                           struct dlm_lock_resource *res,
+                                           u8 owner)
+{
+       assert_spin_locked(&res->spinlock);
+
+       if (owner != res->owner)
+               dlm_set_lockres_owner(dlm, res, owner);
+}
 
 #endif /* DLMCOMMON_H */
index b32f60a5acfb9e4353ce3ad61d009bb6858d158f..df52f706f66971026b2f09ae0f978a8ba17858f7 100644 (file)
@@ -287,18 +287,8 @@ static int stringify_nodemap(unsigned long *nodemap, int maxnodes,
 static int dump_mle(struct dlm_master_list_entry *mle, char *buf, int len)
 {
        int out = 0;
-       unsigned int namelen;
-       const char *name;
        char *mle_type;
 
-       if (mle->type != DLM_MLE_MASTER) {
-               namelen = mle->u.name.len;
-               name = mle->u.name.name;
-       } else {
-               namelen = mle->u.res->lockname.len;
-               name = mle->u.res->lockname.name;
-       }
-
        if (mle->type == DLM_MLE_BLOCK)
                mle_type = "BLK";
        else if (mle->type == DLM_MLE_MASTER)
@@ -306,7 +296,7 @@ static int dump_mle(struct dlm_master_list_entry *mle, char *buf, int len)
        else
                mle_type = "MIG";
 
-       out += stringify_lockname(name, namelen, buf + out, len - out);
+       out += stringify_lockname(mle->mname, mle->mnamelen, buf + out, len - out);
        out += snprintf(buf + out, len - out,
                        "\t%3s\tmas=%3u\tnew=%3u\tevt=%1d\tuse=%1d\tref=%3d\n",
                        mle_type, mle->master, mle->new_master,
@@ -501,23 +491,33 @@ static struct file_operations debug_purgelist_fops = {
 static int debug_mle_print(struct dlm_ctxt *dlm, struct debug_buffer *db)
 {
        struct dlm_master_list_entry *mle;
-       int out = 0;
-       unsigned long total = 0;
+       struct hlist_head *bucket;
+       struct hlist_node *list;
+       int i, out = 0;
+       unsigned long total = 0, longest = 0, bktcnt;
 
        out += snprintf(db->buf + out, db->len - out,
                        "Dumping MLEs for Domain: %s\n", dlm->name);
 
        spin_lock(&dlm->master_lock);
-       list_for_each_entry(mle, &dlm->master_list, list) {
-               ++total;
-               if (db->len - out < 200)
-                       continue;
-               out += dump_mle(mle, db->buf + out, db->len - out);
+       for (i = 0; i < DLM_HASH_BUCKETS; i++) {
+               bucket = dlm_master_hash(dlm, i);
+               hlist_for_each(list, bucket) {
+                       mle = hlist_entry(list, struct dlm_master_list_entry,
+                                         master_hash_node);
+                       ++total;
+                       ++bktcnt;
+                       if (db->len - out < 200)
+                               continue;
+                       out += dump_mle(mle, db->buf + out, db->len - out);
+               }
+               longest = max(longest, bktcnt);
+               bktcnt = 0;
        }
        spin_unlock(&dlm->master_lock);
 
        out += snprintf(db->buf + out, db->len - out,
-                       "Total on list: %ld\n", total);
+                       "Total: %ld, Longest: %ld\n", total, longest);
        return out;
 }
 
@@ -756,12 +756,8 @@ static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db)
        int out = 0;
        struct dlm_reco_node_data *node;
        char *state;
-       int lres, rres, ures, tres;
-
-       lres = atomic_read(&dlm->local_resources);
-       rres = atomic_read(&dlm->remote_resources);
-       ures = atomic_read(&dlm->unknown_resources);
-       tres = lres + rres + ures;
+       int cur_mles = 0, tot_mles = 0;
+       int i;
 
        spin_lock(&dlm->spinlock);
 
@@ -804,21 +800,48 @@ static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db)
                                 db->buf + out, db->len - out);
        out += snprintf(db->buf + out, db->len - out, "\n");
 
-       /* Mastered Resources Total: xxx  Locally: xxx  Remotely: ... */
+       /* Lock Resources: xxx (xxx) */
+       out += snprintf(db->buf + out, db->len - out,
+                       "Lock Resources: %d (%d)\n",
+                       atomic_read(&dlm->res_cur_count),
+                       atomic_read(&dlm->res_tot_count));
+
+       for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
+               tot_mles += atomic_read(&dlm->mle_tot_count[i]);
+
+       for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
+               cur_mles += atomic_read(&dlm->mle_cur_count[i]);
+
+       /* MLEs: xxx (xxx) */
+       out += snprintf(db->buf + out, db->len - out,
+                       "MLEs: %d (%d)\n", cur_mles, tot_mles);
+
+       /*  Blocking: xxx (xxx) */
+       out += snprintf(db->buf + out, db->len - out,
+                       "  Blocking: %d (%d)\n",
+                       atomic_read(&dlm->mle_cur_count[DLM_MLE_BLOCK]),
+                       atomic_read(&dlm->mle_tot_count[DLM_MLE_BLOCK]));
+
+       /*  Mastery: xxx (xxx) */
+       out += snprintf(db->buf + out, db->len - out,
+                       "  Mastery: %d (%d)\n",
+                       atomic_read(&dlm->mle_cur_count[DLM_MLE_MASTER]),
+                       atomic_read(&dlm->mle_tot_count[DLM_MLE_MASTER]));
+
+       /*  Migration: xxx (xxx) */
        out += snprintf(db->buf + out, db->len - out,
-                       "Mastered Resources Total: %d  Locally: %d  "
-                       "Remotely: %d  Unknown: %d\n",
-                       tres, lres, rres, ures);
+                       "  Migration: %d (%d)\n",
+                       atomic_read(&dlm->mle_cur_count[DLM_MLE_MIGRATION]),
+                       atomic_read(&dlm->mle_tot_count[DLM_MLE_MIGRATION]));
 
        /* Lists: Dirty=Empty  Purge=InUse  PendingASTs=Empty  ... */
        out += snprintf(db->buf + out, db->len - out,
                        "Lists: Dirty=%s  Purge=%s  PendingASTs=%s  "
-                       "PendingBASTs=%s  Master=%s\n",
+                       "PendingBASTs=%s\n",
                        (list_empty(&dlm->dirty_list) ? "Empty" : "InUse"),
                        (list_empty(&dlm->purge_list) ? "Empty" : "InUse"),
                        (list_empty(&dlm->pending_asts) ? "Empty" : "InUse"),
-                       (list_empty(&dlm->pending_basts) ? "Empty" : "InUse"),
-                       (list_empty(&dlm->master_list) ? "Empty" : "InUse"));
+                       (list_empty(&dlm->pending_basts) ? "Empty" : "InUse"));
 
        /* Purge Count: xxx  Refs: xxx */
        out += snprintf(db->buf + out, db->len - out,
index d8d578f4561389f2b5083fdd03d4a66ebfeee1a9..4d9e6b288dd871e4c4ffee4157522913988a159b 100644 (file)
@@ -304,6 +304,9 @@ static void dlm_free_ctxt_mem(struct dlm_ctxt *dlm)
        if (dlm->lockres_hash)
                dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES);
 
+       if (dlm->master_hash)
+               dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES);
+
        if (dlm->name)
                kfree(dlm->name);
 
@@ -1534,12 +1537,27 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain,
        for (i = 0; i < DLM_HASH_BUCKETS; i++)
                INIT_HLIST_HEAD(dlm_lockres_hash(dlm, i));
 
+       dlm->master_hash = (struct hlist_head **)
+                               dlm_alloc_pagevec(DLM_HASH_PAGES);
+       if (!dlm->master_hash) {
+               mlog_errno(-ENOMEM);
+               dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES);
+               kfree(dlm->name);
+               kfree(dlm);
+               dlm = NULL;
+               goto leave;
+       }
+
+       for (i = 0; i < DLM_HASH_BUCKETS; i++)
+               INIT_HLIST_HEAD(dlm_master_hash(dlm, i));
+
        strcpy(dlm->name, domain);
        dlm->key = key;
        dlm->node_num = o2nm_this_node();
 
        ret = dlm_create_debugfs_subroot(dlm);
        if (ret < 0) {
+               dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES);
                dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES);
                kfree(dlm->name);
                kfree(dlm);
@@ -1579,7 +1597,6 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain,
        init_waitqueue_head(&dlm->reco.event);
        init_waitqueue_head(&dlm->ast_wq);
        init_waitqueue_head(&dlm->migration_wq);
-       INIT_LIST_HEAD(&dlm->master_list);
        INIT_LIST_HEAD(&dlm->mle_hb_events);
 
        dlm->joining_node = DLM_LOCK_RES_OWNER_UNKNOWN;
@@ -1587,9 +1604,13 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain,
 
        dlm->reco.new_master = O2NM_INVALID_NODE_NUM;
        dlm->reco.dead_node = O2NM_INVALID_NODE_NUM;
-       atomic_set(&dlm->local_resources, 0);
-       atomic_set(&dlm->remote_resources, 0);
-       atomic_set(&dlm->unknown_resources, 0);
+
+       atomic_set(&dlm->res_tot_count, 0);
+       atomic_set(&dlm->res_cur_count, 0);
+       for (i = 0; i < DLM_MLE_NUM_TYPES; ++i) {
+               atomic_set(&dlm->mle_tot_count[i], 0);
+               atomic_set(&dlm->mle_cur_count[i], 0);
+       }
 
        spin_lock_init(&dlm->work_lock);
        INIT_LIST_HEAD(&dlm->work_list);
index 0a2813947853dfd68372506b9fb43de894c3d577..f8b653fcd4ddb872ec046217a6f1a731db36dc25 100644 (file)
@@ -73,22 +73,13 @@ static inline int dlm_mle_equal(struct dlm_ctxt *dlm,
                                const char *name,
                                unsigned int namelen)
 {
-       struct dlm_lock_resource *res;
-
        if (dlm != mle->dlm)
                return 0;
 
-       if (mle->type == DLM_MLE_BLOCK ||
-           mle->type == DLM_MLE_MIGRATION) {
-               if (namelen != mle->u.name.len ||
-                   memcmp(name, mle->u.name.name, namelen)!=0)
-                       return 0;
-       } else {
-               res = mle->u.res;
-               if (namelen != res->lockname.len ||
-                   memcmp(res->lockname.name, name, namelen) != 0)
-                       return 0;
-       }
+       if (namelen != mle->mnamelen ||
+           memcmp(name, mle->mname, namelen) != 0)
+               return 0;
+
        return 1;
 }
 
@@ -283,7 +274,7 @@ static void dlm_init_mle(struct dlm_master_list_entry *mle,
 
        mle->dlm = dlm;
        mle->type = type;
-       INIT_LIST_HEAD(&mle->list);
+       INIT_HLIST_NODE(&mle->master_hash_node);
        INIT_LIST_HEAD(&mle->hb_events);
        memset(mle->maybe_map, 0, sizeof(mle->maybe_map));
        spin_lock_init(&mle->spinlock);
@@ -295,19 +286,27 @@ static void dlm_init_mle(struct dlm_master_list_entry *mle,
        mle->new_master = O2NM_MAX_NODES;
        mle->inuse = 0;
 
+       BUG_ON(mle->type != DLM_MLE_BLOCK &&
+              mle->type != DLM_MLE_MASTER &&
+              mle->type != DLM_MLE_MIGRATION);
+
        if (mle->type == DLM_MLE_MASTER) {
                BUG_ON(!res);
-               mle->u.res = res;
-       } else if (mle->type == DLM_MLE_BLOCK) {
-               BUG_ON(!name);
-               memcpy(mle->u.name.name, name, namelen);
-               mle->u.name.len = namelen;
-       } else /* DLM_MLE_MIGRATION */ {
+               mle->mleres = res;
+               memcpy(mle->mname, res->lockname.name, res->lockname.len);
+               mle->mnamelen = res->lockname.len;
+               mle->mnamehash = res->lockname.hash;
+       } else {
                BUG_ON(!name);
-               memcpy(mle->u.name.name, name, namelen);
-               mle->u.name.len = namelen;
+               mle->mleres = NULL;
+               memcpy(mle->mname, name, namelen);
+               mle->mnamelen = namelen;
+               mle->mnamehash = dlm_lockid_hash(name, namelen);
        }
 
+       atomic_inc(&dlm->mle_tot_count[mle->type]);
+       atomic_inc(&dlm->mle_cur_count[mle->type]);
+
        /* copy off the node_map and register hb callbacks on our copy */
        memcpy(mle->node_map, dlm->domain_map, sizeof(mle->node_map));
        memcpy(mle->vote_map, dlm->domain_map, sizeof(mle->vote_map));
@@ -318,6 +317,24 @@ static void dlm_init_mle(struct dlm_master_list_entry *mle,
        __dlm_mle_attach_hb_events(dlm, mle);
 }
 
+void __dlm_unlink_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle)
+{
+       assert_spin_locked(&dlm->spinlock);
+       assert_spin_locked(&dlm->master_lock);
+
+       if (!hlist_unhashed(&mle->master_hash_node))
+               hlist_del_init(&mle->master_hash_node);
+}
+
+void __dlm_insert_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle)
+{
+       struct hlist_head *bucket;
+
+       assert_spin_locked(&dlm->master_lock);
+
+       bucket = dlm_master_hash(dlm, mle->mnamehash);
+       hlist_add_head(&mle->master_hash_node, bucket);
+}
 
 /* returns 1 if found, 0 if not */
 static int dlm_find_mle(struct dlm_ctxt *dlm,
@@ -325,10 +342,17 @@ static int dlm_find_mle(struct dlm_ctxt *dlm,
                        char *name, unsigned int namelen)
 {
        struct dlm_master_list_entry *tmpmle;
+       struct hlist_head *bucket;
+       struct hlist_node *list;
+       unsigned int hash;
 
        assert_spin_locked(&dlm->master_lock);
 
-       list_for_each_entry(tmpmle, &dlm->master_list, list) {
+       hash = dlm_lockid_hash(name, namelen);
+       bucket = dlm_master_hash(dlm, hash);
+       hlist_for_each(list, bucket) {
+               tmpmle = hlist_entry(list, struct dlm_master_list_entry,
+                                    master_hash_node);
                if (!dlm_mle_equal(dlm, tmpmle, name, namelen))
                        continue;
                dlm_get_mle(tmpmle);
@@ -408,24 +432,20 @@ static void dlm_mle_release(struct kref *kref)
        mle = container_of(kref, struct dlm_master_list_entry, mle_refs);
        dlm = mle->dlm;
 
-       if (mle->type != DLM_MLE_MASTER) {
-               mlog(0, "calling mle_release for %.*s, type %d\n",
-                    mle->u.name.len, mle->u.name.name, mle->type);
-       } else {
-               mlog(0, "calling mle_release for %.*s, type %d\n",
-                    mle->u.res->lockname.len,
-                    mle->u.res->lockname.name, mle->type);
-       }
        assert_spin_locked(&dlm->spinlock);
        assert_spin_locked(&dlm->master_lock);
 
+       mlog(0, "Releasing mle for %.*s, type %d\n", mle->mnamelen, mle->mname,
+            mle->type);
+
        /* remove from list if not already */
-       if (!list_empty(&mle->list))
-               list_del_init(&mle->list);
+       __dlm_unlink_mle(dlm, mle);
 
        /* detach the mle from the domain node up/down events */
        __dlm_mle_detach_hb_events(dlm, mle);
 
+       atomic_dec(&dlm->mle_cur_count[mle->type]);
+
        /* NOTE: kfree under spinlock here.
         * if this is bad, we can move this to a freelist. */
        kmem_cache_free(dlm_mle_cache, mle);
@@ -465,43 +485,6 @@ void dlm_destroy_master_caches(void)
                kmem_cache_destroy(dlm_lockres_cache);
 }
 
-static void dlm_set_lockres_owner(struct dlm_ctxt *dlm,
-                                 struct dlm_lock_resource *res,
-                                 u8 owner)
-{
-       assert_spin_locked(&res->spinlock);
-
-       mlog_entry("%.*s, %u\n", res->lockname.len, res->lockname.name, owner);
-
-       if (owner == dlm->node_num)
-               atomic_inc(&dlm->local_resources);
-       else if (owner == DLM_LOCK_RES_OWNER_UNKNOWN)
-               atomic_inc(&dlm->unknown_resources);
-       else
-               atomic_inc(&dlm->remote_resources);
-
-       res->owner = owner;
-}
-
-void dlm_change_lockres_owner(struct dlm_ctxt *dlm,
-                             struct dlm_lock_resource *res, u8 owner)
-{
-       assert_spin_locked(&res->spinlock);
-
-       if (owner == res->owner)
-               return;
-
-       if (res->owner == dlm->node_num)
-               atomic_dec(&dlm->local_resources);
-       else if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN)
-               atomic_dec(&dlm->unknown_resources);
-       else
-               atomic_dec(&dlm->remote_resources);
-
-       dlm_set_lockres_owner(dlm, res, owner);
-}
-
-
 static void dlm_lockres_release(struct kref *kref)
 {
        struct dlm_lock_resource *res;
@@ -527,6 +510,8 @@ static void dlm_lockres_release(struct kref *kref)
        }
        spin_unlock(&dlm->track_lock);
 
+       atomic_dec(&dlm->res_cur_count);
+
        dlm_put(dlm);
 
        if (!hlist_unhashed(&res->hash_node) ||
@@ -607,6 +592,9 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm,
 
        kref_init(&res->refs);
 
+       atomic_inc(&dlm->res_tot_count);
+       atomic_inc(&dlm->res_cur_count);
+
        /* just for consistency */
        spin_lock(&res->spinlock);
        dlm_set_lockres_owner(dlm, res, DLM_LOCK_RES_OWNER_UNKNOWN);
@@ -843,7 +831,7 @@ lookup:
                alloc_mle = NULL;
                dlm_init_mle(mle, DLM_MLE_MASTER, dlm, res, NULL, 0);
                set_bit(dlm->node_num, mle->maybe_map);
-               list_add(&mle->list, &dlm->master_list);
+               __dlm_insert_mle(dlm, mle);
 
                /* still holding the dlm spinlock, check the recovery map
                 * to see if there are any nodes that still need to be 
@@ -1270,7 +1258,7 @@ static int dlm_restart_lock_mastery(struct dlm_ctxt *dlm,
                                                     res->lockname.len,
                                                     res->lockname.name);
                                                mle->type = DLM_MLE_MASTER;
-                                               mle->u.res = res;
+                                               mle->mleres = res;
                                        }
                                }
                        }
@@ -1315,14 +1303,8 @@ static int dlm_do_master_request(struct dlm_lock_resource *res,
 
        BUG_ON(mle->type == DLM_MLE_MIGRATION);
 
-       if (mle->type != DLM_MLE_MASTER) {
-               request.namelen = mle->u.name.len;
-               memcpy(request.name, mle->u.name.name, request.namelen);
-       } else {
-               request.namelen = mle->u.res->lockname.len;
-               memcpy(request.name, mle->u.res->lockname.name,
-                       request.namelen);
-       }
+       request.namelen = (u8)mle->mnamelen;
+       memcpy(request.name, mle->mname, request.namelen);
 
 again:
        ret = o2net_send_message(DLM_MASTER_REQUEST_MSG, dlm->key, &request,
@@ -1575,7 +1557,7 @@ way_up_top:
                // "add the block.\n");
                dlm_init_mle(mle, DLM_MLE_BLOCK, dlm, NULL, name, namelen);
                set_bit(request->node_idx, mle->maybe_map);
-               list_add(&mle->list, &dlm->master_list);
+               __dlm_insert_mle(dlm, mle);
                response = DLM_MASTER_RESP_NO;
        } else {
                // mlog(0, "mle was found\n");
@@ -1967,7 +1949,7 @@ ok:
                             assert->node_idx, rr, extra_ref, mle->inuse);
                        dlm_print_one_mle(mle);
                }
-               list_del_init(&mle->list);
+               __dlm_unlink_mle(dlm, mle);
                __dlm_mle_detach_hb_events(dlm, mle);
                __dlm_put_mle(mle);
                if (extra_ref) {
@@ -3159,10 +3141,8 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm,
                        tmp->master = master;
                        atomic_set(&tmp->woken, 1);
                        wake_up(&tmp->wq);
-                       /* remove it from the list so that only one
-                        * mle will be found */
-                       list_del_init(&tmp->list);
-                       /* this was obviously WRONG.  mle is uninited here.  should be tmp. */
+                       /* remove it so that only one mle will be found */
+                       __dlm_unlink_mle(dlm, tmp);
                        __dlm_mle_detach_hb_events(dlm, tmp);
                        ret = DLM_MIGRATE_RESPONSE_MASTERY_REF;
                        mlog(0, "%s:%.*s: master=%u, newmaster=%u, "
@@ -3181,137 +3161,164 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm,
        mle->master = master;
        /* do this for consistency with other mle types */
        set_bit(new_master, mle->maybe_map);
-       list_add(&mle->list, &dlm->master_list);
+       __dlm_insert_mle(dlm, mle);
 
        return ret;
 }
 
-
-void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node)
+/*
+ * Sets the owner of the lockres, associated to the mle, to UNKNOWN
+ */
+static struct dlm_lock_resource *dlm_reset_mleres_owner(struct dlm_ctxt *dlm,
+                                       struct dlm_master_list_entry *mle)
 {
-       struct dlm_master_list_entry *mle, *next;
        struct dlm_lock_resource *res;
-       unsigned int hash;
 
-       mlog_entry("dlm=%s, dead node=%u\n", dlm->name, dead_node);
-top:
-       assert_spin_locked(&dlm->spinlock);
+       /* Find the lockres associated to the mle and set its owner to UNK */
+       res = __dlm_lookup_lockres(dlm, mle->mname, mle->mnamelen,
+                                  mle->mnamehash);
+       if (res) {
+               spin_unlock(&dlm->master_lock);
 
-       /* clean the master list */
-       spin_lock(&dlm->master_lock);
-       list_for_each_entry_safe(mle, next, &dlm->master_list, list) {
-               BUG_ON(mle->type != DLM_MLE_BLOCK &&
-                      mle->type != DLM_MLE_MASTER &&
-                      mle->type != DLM_MLE_MIGRATION);
-
-               /* MASTER mles are initiated locally.  the waiting
-                * process will notice the node map change
-                * shortly.  let that happen as normal. */
-               if (mle->type == DLM_MLE_MASTER)
-                       continue;
+               /* move lockres onto recovery list */
+               spin_lock(&res->spinlock);
+               dlm_set_lockres_owner(dlm, res, DLM_LOCK_RES_OWNER_UNKNOWN);
+               dlm_move_lockres_to_recovery_list(dlm, res);
+               spin_unlock(&res->spinlock);
+               dlm_lockres_put(res);
 
+               /* about to get rid of mle, detach from heartbeat */
+               __dlm_mle_detach_hb_events(dlm, mle);
 
-               /* BLOCK mles are initiated by other nodes.
-                * need to clean up if the dead node would have
-                * been the master. */
-               if (mle->type == DLM_MLE_BLOCK) {
-                       int bit;
+               /* dump the mle */
+               spin_lock(&dlm->master_lock);
+               __dlm_put_mle(mle);
+               spin_unlock(&dlm->master_lock);
+       }
 
-                       spin_lock(&mle->spinlock);
-                       bit = find_next_bit(mle->maybe_map, O2NM_MAX_NODES, 0);
-                       if (bit != dead_node) {
-                               mlog(0, "mle found, but dead node %u would "
-                                    "not have been master\n", dead_node);
-                               spin_unlock(&mle->spinlock);
-                       } else {
-                               /* must drop the refcount by one since the
-                                * assert_master will never arrive.  this
-                                * may result in the mle being unlinked and
-                                * freed, but there may still be a process
-                                * waiting in the dlmlock path which is fine. */
-                               mlog(0, "node %u was expected master\n",
-                                    dead_node);
-                               atomic_set(&mle->woken, 1);
-                               spin_unlock(&mle->spinlock);
-                               wake_up(&mle->wq);
-                               /* do not need events any longer, so detach 
-                                * from heartbeat */
-                               __dlm_mle_detach_hb_events(dlm, mle);
-                               __dlm_put_mle(mle);
-                       }
-                       continue;
-               }
+       return res;
+}
 
-               /* everything else is a MIGRATION mle */
-
-               /* the rule for MIGRATION mles is that the master
-                * becomes UNKNOWN if *either* the original or
-                * the new master dies.  all UNKNOWN lockreses
-                * are sent to whichever node becomes the recovery
-                * master.  the new master is responsible for
-                * determining if there is still a master for
-                * this lockres, or if he needs to take over
-                * mastery.  either way, this node should expect
-                * another message to resolve this. */
-               if (mle->master != dead_node &&
-                   mle->new_master != dead_node)
-                       continue;
+static void dlm_clean_migration_mle(struct dlm_ctxt *dlm,
+                                   struct dlm_master_list_entry *mle)
+{
+       __dlm_mle_detach_hb_events(dlm, mle);
 
-               /* if we have reached this point, this mle needs to
-                * be removed from the list and freed. */
+       spin_lock(&mle->spinlock);
+       __dlm_unlink_mle(dlm, mle);
+       atomic_set(&mle->woken, 1);
+       spin_unlock(&mle->spinlock);
 
-               /* remove from the list early.  NOTE: unlinking
-                * list_head while in list_for_each_safe */
-               __dlm_mle_detach_hb_events(dlm, mle);
-               spin_lock(&mle->spinlock);
-               list_del_init(&mle->list);
+       wake_up(&mle->wq);
+}
+
+static void dlm_clean_block_mle(struct dlm_ctxt *dlm,
+                               struct dlm_master_list_entry *mle, u8 dead_node)
+{
+       int bit;
+
+       BUG_ON(mle->type != DLM_MLE_BLOCK);
+
+       spin_lock(&mle->spinlock);
+       bit = find_next_bit(mle->maybe_map, O2NM_MAX_NODES, 0);
+       if (bit != dead_node) {
+               mlog(0, "mle found, but dead node %u would not have been "
+                    "master\n", dead_node);
+               spin_unlock(&mle->spinlock);
+       } else {
+               /* Must drop the refcount by one since the assert_master will
+                * never arrive. This may result in the mle being unlinked and
+                * freed, but there may still be a process waiting in the
+                * dlmlock path which is fine. */
+               mlog(0, "node %u was expected master\n", dead_node);
                atomic_set(&mle->woken, 1);
                spin_unlock(&mle->spinlock);
                wake_up(&mle->wq);
 
-               mlog(0, "%s: node %u died during migration from "
-                    "%u to %u!\n", dlm->name, dead_node,
-                    mle->master, mle->new_master);
-               /* if there is a lockres associated with this
-                * mle, find it and set its owner to UNKNOWN */
-               hash = dlm_lockid_hash(mle->u.name.name, mle->u.name.len);
-               res = __dlm_lookup_lockres(dlm, mle->u.name.name,
-                                          mle->u.name.len, hash);
-               if (res) {
-                       /* unfortunately if we hit this rare case, our
-                        * lock ordering is messed.  we need to drop
-                        * the master lock so that we can take the
-                        * lockres lock, meaning that we will have to
-                        * restart from the head of list. */
-                       spin_unlock(&dlm->master_lock);
+               /* Do not need events any longer, so detach from heartbeat */
+               __dlm_mle_detach_hb_events(dlm, mle);
+               __dlm_put_mle(mle);
+       }
+}
 
-                       /* move lockres onto recovery list */
-                       spin_lock(&res->spinlock);
-                       dlm_set_lockres_owner(dlm, res,
-                                       DLM_LOCK_RES_OWNER_UNKNOWN);
-                       dlm_move_lockres_to_recovery_list(dlm, res);
-                       spin_unlock(&res->spinlock);
-                       dlm_lockres_put(res);
+void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node)
+{
+       struct dlm_master_list_entry *mle;
+       struct dlm_lock_resource *res;
+       struct hlist_head *bucket;
+       struct hlist_node *list;
+       unsigned int i;
 
-                       /* about to get rid of mle, detach from heartbeat */
-                       __dlm_mle_detach_hb_events(dlm, mle);
+       mlog_entry("dlm=%s, dead node=%u\n", dlm->name, dead_node);
+top:
+       assert_spin_locked(&dlm->spinlock);
 
-                       /* dump the mle */
-                       spin_lock(&dlm->master_lock);
-                       __dlm_put_mle(mle);
-                       spin_unlock(&dlm->master_lock);
+       /* clean the master list */
+       spin_lock(&dlm->master_lock);
+       for (i = 0; i < DLM_HASH_BUCKETS; i++) {
+               bucket = dlm_master_hash(dlm, i);
+               hlist_for_each(list, bucket) {
+                       mle = hlist_entry(list, struct dlm_master_list_entry,
+                                         master_hash_node);
+
+                       BUG_ON(mle->type != DLM_MLE_BLOCK &&
+                              mle->type != DLM_MLE_MASTER &&
+                              mle->type != DLM_MLE_MIGRATION);
+
+                       /* MASTER mles are initiated locally. The waiting
+                        * process will notice the node map change shortly.
+                        * Let that happen as normal. */
+                       if (mle->type == DLM_MLE_MASTER)
+                               continue;
+
+                       /* BLOCK mles are initiated by other nodes. Need to
+                        * clean up if the dead node would have been the
+                        * master. */
+                       if (mle->type == DLM_MLE_BLOCK) {
+                               dlm_clean_block_mle(dlm, mle, dead_node);
+                               continue;
+                       }
 
-                       /* restart */
-                       goto top;
-               }
+                       /* Everything else is a MIGRATION mle */
+
+                       /* The rule for MIGRATION mles is that the master
+                        * becomes UNKNOWN if *either* the original or the new
+                        * master dies. All UNKNOWN lockres' are sent to
+                        * whichever node becomes the recovery master. The new
+                        * master is responsible for determining if there is
+                        * still a master for this lockres, or if he needs to
+                        * take over mastery. Either way, this node should
+                        * expect another message to resolve this. */
+
+                       if (mle->master != dead_node &&
+                           mle->new_master != dead_node)
+                               continue;
+
+                       /* If we have reached this point, this mle needs to be
+                        * removed from the list and freed. */
+                       dlm_clean_migration_mle(dlm, mle);
+
+                       mlog(0, "%s: node %u died during migration from "
+                            "%u to %u!\n", dlm->name, dead_node, mle->master,
+                            mle->new_master);
+
+                       /* If we find a lockres associated with the mle, we've
+                        * hit this rare case that messes up our lock ordering.
+                        * If so, we need to drop the master lock so that we can
+                        * take the lockres lock, meaning that we will have to
+                        * restart from the head of list. */
+                       res = dlm_reset_mleres_owner(dlm, mle);
+                       if (res)
+                               /* restart */
+                               goto top;
 
-               /* this may be the last reference */
-               __dlm_put_mle(mle);
+                       /* This may be the last reference */
+                       __dlm_put_mle(mle);
+               }
        }
        spin_unlock(&dlm->master_lock);
 }
 
-
 int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
                         u8 old_master)
 {
index 4060bb328bc8a08c22bbd77c59835d757ebdcda5..d490b66ad9d75e1ca24667cd6a7c8626d30200e0 100644 (file)
@@ -162,12 +162,28 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm,
 
        spin_lock(&res->spinlock);
        if (!__dlm_lockres_unused(res)) {
-               spin_unlock(&res->spinlock);
                mlog(0, "%s:%.*s: tried to purge but not unused\n",
                     dlm->name, res->lockname.len, res->lockname.name);
-               return -ENOTEMPTY;
+               __dlm_print_one_lock_resource(res);
+               spin_unlock(&res->spinlock);
+               BUG();
        }
+
+       if (res->state & DLM_LOCK_RES_MIGRATING) {
+               mlog(0, "%s:%.*s: Delay dropref as this lockres is "
+                    "being remastered\n", dlm->name, res->lockname.len,
+                    res->lockname.name);
+               /* Re-add the lockres to the end of the purge list */
+               if (!list_empty(&res->purge)) {
+                       list_del_init(&res->purge);
+                       list_add_tail(&res->purge, &dlm->purge_list);
+               }
+               spin_unlock(&res->spinlock);
+               return 0;
+       }
+
        master = (res->owner == dlm->node_num);
+
        if (!master)
                res->state |= DLM_LOCK_RES_DROPPING_REF;
        spin_unlock(&res->spinlock);
index 7219a86d34ccc3102b360e10c298ed50fda903a7..e15fc7d50827019fe974b9bb61b8f5dd7312665a 100644 (file)
@@ -244,6 +244,10 @@ static struct ocfs2_lock_res_ops ocfs2_rename_lops = {
        .flags          = 0,
 };
 
+static struct ocfs2_lock_res_ops ocfs2_nfs_sync_lops = {
+       .flags          = 0,
+};
+
 static struct ocfs2_lock_res_ops ocfs2_dentry_lops = {
        .get_osb        = ocfs2_get_dentry_osb,
        .post_unlock    = ocfs2_dentry_post_unlock,
@@ -622,6 +626,17 @@ static void ocfs2_rename_lock_res_init(struct ocfs2_lock_res *res,
                                   &ocfs2_rename_lops, osb);
 }
 
+static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res,
+                                        struct ocfs2_super *osb)
+{
+       /* nfs_sync lockres doesn't come from a slab so we call init
+        * once on it manually.  */
+       ocfs2_lock_res_init_once(res);
+       ocfs2_build_lock_name(OCFS2_LOCK_TYPE_NFS_SYNC, 0, 0, res->l_name);
+       ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_NFS_SYNC,
+                                  &ocfs2_nfs_sync_lops, osb);
+}
+
 void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
                              struct ocfs2_file_private *fp)
 {
@@ -2417,6 +2432,34 @@ void ocfs2_rename_unlock(struct ocfs2_super *osb)
                ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX);
 }
 
+int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex)
+{
+       int status;
+       struct ocfs2_lock_res *lockres = &osb->osb_nfs_sync_lockres;
+
+       if (ocfs2_is_hard_readonly(osb))
+               return -EROFS;
+
+       if (ocfs2_mount_local(osb))
+               return 0;
+
+       status = ocfs2_cluster_lock(osb, lockres, ex ? LKM_EXMODE : LKM_PRMODE,
+                                   0, 0);
+       if (status < 0)
+               mlog(ML_ERROR, "lock on nfs sync lock failed %d\n", status);
+
+       return status;
+}
+
+void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex)
+{
+       struct ocfs2_lock_res *lockres = &osb->osb_nfs_sync_lockres;
+
+       if (!ocfs2_mount_local(osb))
+               ocfs2_cluster_unlock(osb, lockres,
+                                    ex ? LKM_EXMODE : LKM_PRMODE);
+}
+
 int ocfs2_dentry_lock(struct dentry *dentry, int ex)
 {
        int ret;
@@ -2798,6 +2841,7 @@ int ocfs2_dlm_init(struct ocfs2_super *osb)
 local:
        ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb);
        ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb);
+       ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb);
 
        osb->cconn = conn;
 
@@ -2833,6 +2877,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb,
 
        ocfs2_lock_res_free(&osb->osb_super_lockres);
        ocfs2_lock_res_free(&osb->osb_rename_lockres);
+       ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres);
 
        ocfs2_cluster_disconnect(osb->cconn, hangup_pending);
        osb->cconn = NULL;
@@ -3015,6 +3060,7 @@ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb)
 {
        ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres);
        ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres);
+       ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres);
 }
 
 int ocfs2_drop_inode_locks(struct inode *inode)
index 3f8d9986b8e0e82d9f8b938ef9d648669b14fff0..e1fd5721cd7f15da6e844579e1964d691af597fe 100644 (file)
@@ -115,6 +115,8 @@ void ocfs2_super_unlock(struct ocfs2_super *osb,
                        int ex);
 int ocfs2_rename_lock(struct ocfs2_super *osb);
 void ocfs2_rename_unlock(struct ocfs2_super *osb);
+int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex);
+void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex);
 int ocfs2_dentry_lock(struct dentry *dentry, int ex);
 void ocfs2_dentry_unlock(struct dentry *dentry, int ex);
 int ocfs2_file_lock(struct file *file, int ex, int trylock);
index 2f27b332d8b316949b131eb8172c1e1bdf4d1362..de3da8eb558ced894690263794c4c1f28652f351 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "ocfs2.h"
 
+#include "alloc.h"
 #include "dir.h"
 #include "dlmglue.h"
 #include "dcache.h"
@@ -38,6 +39,7 @@
 #include "inode.h"
 
 #include "buffer_head_io.h"
+#include "suballoc.h"
 
 struct ocfs2_inode_handle
 {
@@ -49,29 +51,97 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
                struct ocfs2_inode_handle *handle)
 {
        struct inode *inode;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
+       u64 blkno = handle->ih_blkno;
+       int status, set;
        struct dentry *result;
 
        mlog_entry("(0x%p, 0x%p)\n", sb, handle);
 
-       if (handle->ih_blkno == 0) {
-               mlog_errno(-ESTALE);
-               return ERR_PTR(-ESTALE);
+       if (blkno == 0) {
+               mlog(0, "nfs wants inode with blkno: 0\n");
+               result = ERR_PTR(-ESTALE);
+               goto bail;
+       }
+
+       inode = ocfs2_ilookup(sb, blkno);
+       /*
+        * If the inode exists in memory, we only need to check it's
+        * generation number
+        */
+       if (inode)
+               goto check_gen;
+
+       /*
+        * This will synchronize us against ocfs2_delete_inode() on
+        * all nodes
+        */
+       status = ocfs2_nfs_sync_lock(osb, 1);
+       if (status < 0) {
+               mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
+               goto check_err;
+       }
+
+       status = ocfs2_test_inode_bit(osb, blkno, &set);
+       if (status < 0) {
+               if (status == -EINVAL) {
+                       /*
+                        * The blkno NFS gave us doesn't even show up
+                        * as an inode, we return -ESTALE to be
+                        * nice
+                        */
+                       mlog(0, "test inode bit failed %d\n", status);
+                       status = -ESTALE;
+               } else {
+                       mlog(ML_ERROR, "test inode bit failed %d\n", status);
+               }
+               goto unlock_nfs_sync;
+       }
+
+       /* If the inode allocator bit is clear, this inode must be stale */
+       if (!set) {
+               mlog(0, "inode %llu suballoc bit is clear\n", blkno);
+               status = -ESTALE;
+               goto unlock_nfs_sync;
        }
 
-       inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0);
+       inode = ocfs2_iget(osb, blkno, 0, 0);
 
-       if (IS_ERR(inode))
-               return (void *)inode;
+unlock_nfs_sync:
+       ocfs2_nfs_sync_unlock(osb, 1);
 
+check_err:
+       if (status < 0) {
+               if (status == -ESTALE) {
+                       mlog(0, "stale inode ino: %llu generation: %u\n",
+                            blkno, handle->ih_generation);
+               }
+               result = ERR_PTR(status);
+               goto bail;
+       }
+
+       if (IS_ERR(inode)) {
+               mlog_errno(PTR_ERR(inode));
+               result = (void *)inode;
+               goto bail;
+       }
+
+check_gen:
        if (handle->ih_generation != inode->i_generation) {
                iput(inode);
-               return ERR_PTR(-ESTALE);
+               mlog(0, "stale inode ino: %llu generation: %u\n", blkno,
+                    handle->ih_generation);
+               result = ERR_PTR(-ESTALE);
+               goto bail;
        }
 
        result = d_obtain_alias(inode);
        if (!IS_ERR(result))
                result->d_op = &ocfs2_dentry_ops;
+       else
+               mlog_errno(PTR_ERR(result));
 
+bail:
        mlog_exit_ptr(result);
        return result;
 }
index 229e707bc050629c0ad372b14c75194bf4b97f3d..10e1fa87396aedf9ea0a1cfbd501c25361a872e7 100644 (file)
@@ -38,6 +38,7 @@
 #include "ocfs2.h"
 
 #include "alloc.h"
+#include "dir.h"
 #include "blockcheck.h"
 #include "dlmglue.h"
 #include "extent_map.h"
@@ -112,6 +113,17 @@ void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi)
                oi->ip_attr |= OCFS2_DIRSYNC_FL;
 }
 
+struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno)
+{
+       struct ocfs2_find_inode_args args;
+
+       args.fi_blkno = blkno;
+       args.fi_flags = 0;
+       args.fi_ino = ino_from_blkno(sb, blkno);
+       args.fi_sysfile_type = 0;
+
+       return ilookup5(sb, blkno, ocfs2_find_actor, &args);
+}
 struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
                         int sysfile_type)
 {
@@ -275,7 +287,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
                     (unsigned long long)OCFS2_I(inode)->ip_blkno,
                     (unsigned long long)le64_to_cpu(fe->i_blkno));
 
-       inode->i_nlink = le16_to_cpu(fe->i_links_count);
+       inode->i_nlink = ocfs2_read_links_count(fe);
 
        if (fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) {
                OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SYSTEM_FILE;
@@ -351,6 +363,8 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
 
        ocfs2_set_inode_flags(inode);
 
+       OCFS2_I(inode)->ip_last_used_slot = 0;
+       OCFS2_I(inode)->ip_last_used_group = 0;
        mlog_exit_void();
 }
 
@@ -606,7 +620,7 @@ static int ocfs2_remove_inode(struct inode *inode,
        }
 
        handle = ocfs2_start_trans(osb, OCFS2_DELETE_INODE_CREDITS +
-                                       ocfs2_quota_trans_credits(inode->i_sb));
+                                  ocfs2_quota_trans_credits(inode->i_sb));
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
                mlog_errno(status);
@@ -740,6 +754,15 @@ static int ocfs2_wipe_inode(struct inode *inode,
                goto bail_unlock_dir;
        }
 
+       /* Remove any dir index tree */
+       if (S_ISDIR(inode->i_mode)) {
+               status = ocfs2_dx_dir_truncate(inode, di_bh);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail_unlock_dir;
+               }
+       }
+
        /*Free extended attribute resources associated with this inode.*/
        status = ocfs2_xattr_remove(inode, di_bh);
        if (status < 0) {
@@ -949,6 +972,17 @@ void ocfs2_delete_inode(struct inode *inode)
                goto bail;
        }
 
+       /*
+        * Synchronize us against ocfs2_get_dentry. We take this in
+        * shared mode so that all nodes can still concurrently
+        * process deletes.
+        */
+       status = ocfs2_nfs_sync_lock(OCFS2_SB(inode->i_sb), 0);
+       if (status < 0) {
+               mlog(ML_ERROR, "getting nfs sync lock(PR) failed %d\n", status);
+               ocfs2_cleanup_delete_inode(inode, 0);
+               goto bail_unblock;
+       }
        /* Lock down the inode. This gives us an up to date view of
         * it's metadata (for verification), and allows us to
         * serialize delete_inode on multiple nodes.
@@ -962,7 +996,7 @@ void ocfs2_delete_inode(struct inode *inode)
                if (status != -ENOENT)
                        mlog_errno(status);
                ocfs2_cleanup_delete_inode(inode, 0);
-               goto bail_unblock;
+               goto bail_unlock_nfs_sync;
        }
 
        /* Query the cluster. This will be the final decision made
@@ -1005,6 +1039,10 @@ void ocfs2_delete_inode(struct inode *inode)
 bail_unlock_inode:
        ocfs2_inode_unlock(inode, 1);
        brelse(di_bh);
+
+bail_unlock_nfs_sync:
+       ocfs2_nfs_sync_unlock(OCFS2_SB(inode->i_sb), 0);
+
 bail_unblock:
        status = sigprocmask(SIG_SETMASK, &oldset, NULL);
        if (status < 0)
@@ -1205,7 +1243,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
        spin_unlock(&OCFS2_I(inode)->ip_lock);
 
        fe->i_size = cpu_to_le64(i_size_read(inode));
-       fe->i_links_count = cpu_to_le16(inode->i_nlink);
+       ocfs2_set_links_count(fe, inode->i_nlink);
        fe->i_uid = cpu_to_le32(inode->i_uid);
        fe->i_gid = cpu_to_le32(inode->i_gid);
        fe->i_mode = cpu_to_le16(inode->i_mode);
@@ -1242,7 +1280,7 @@ void ocfs2_refresh_inode(struct inode *inode,
        OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
        ocfs2_set_inode_flags(inode);
        i_size_write(inode, le64_to_cpu(fe->i_size));
-       inode->i_nlink = le16_to_cpu(fe->i_links_count);
+       inode->i_nlink = ocfs2_read_links_count(fe);
        inode->i_uid = le32_to_cpu(fe->i_uid);
        inode->i_gid = le32_to_cpu(fe->i_gid);
        inode->i_mode = le16_to_cpu(fe->i_mode);
index eb3c302b38d34c15d96057ff4484e22ba9574999..ea71525aad41fdc4070cd52890d6385359dec7f5 100644 (file)
@@ -72,6 +72,10 @@ struct ocfs2_inode_info
 
        struct inode                    vfs_inode;
        struct jbd2_inode               ip_jinode;
+
+       /* Only valid if the inode is the dir. */
+       u32                             ip_last_used_slot;
+       u64                             ip_last_used_group;
 };
 
 /*
@@ -124,6 +128,7 @@ void ocfs2_drop_inode(struct inode *inode);
 /* Flags for ocfs2_iget() */
 #define OCFS2_FI_FLAG_SYSFILE          0x1
 #define OCFS2_FI_FLAG_ORPHAN_RECOVERY  0x2
+struct inode *ocfs2_ilookup(struct super_block *sb, u64 feoff);
 struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
                         int sysfile_type);
 int ocfs2_inode_init_private(struct inode *inode);
index 57d7d25a2b9a3b9e0a68c7bf8f1348832e69cb25..a20a0f1e37fd18e898ade8803d19ff7489df7e85 100644 (file)
@@ -65,6 +65,11 @@ static int ocfs2_trylock_journal(struct ocfs2_super *osb,
 static int ocfs2_recover_orphans(struct ocfs2_super *osb,
                                 int slot);
 static int ocfs2_commit_thread(void *arg);
+static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
+                                           int slot_num,
+                                           struct ocfs2_dinode *la_dinode,
+                                           struct ocfs2_dinode *tl_dinode,
+                                           struct ocfs2_quota_recovery *qrec);
 
 static inline int ocfs2_wait_on_mount(struct ocfs2_super *osb)
 {
@@ -76,18 +81,97 @@ static inline int ocfs2_wait_on_quotas(struct ocfs2_super *osb)
        return __ocfs2_wait_on_mount(osb, 1);
 }
 
-
-
 /*
- * The recovery_list is a simple linked list of node numbers to recover.
- * It is protected by the recovery_lock.
+ * This replay_map is to track online/offline slots, so we could recover
+ * offline slots during recovery and mount
  */
 
-struct ocfs2_recovery_map {
-       unsigned int rm_used;
-       unsigned int *rm_entries;
+enum ocfs2_replay_state {
+       REPLAY_UNNEEDED = 0,    /* Replay is not needed, so ignore this map */
+       REPLAY_NEEDED,          /* Replay slots marked in rm_replay_slots */
+       REPLAY_DONE             /* Replay was already queued */
 };
 
+struct ocfs2_replay_map {
+       unsigned int rm_slots;
+       enum ocfs2_replay_state rm_state;
+       unsigned char rm_replay_slots[0];
+};
+
+void ocfs2_replay_map_set_state(struct ocfs2_super *osb, int state)
+{
+       if (!osb->replay_map)
+               return;
+
+       /* If we've already queued the replay, we don't have any more to do */
+       if (osb->replay_map->rm_state == REPLAY_DONE)
+               return;
+
+       osb->replay_map->rm_state = state;
+}
+
+int ocfs2_compute_replay_slots(struct ocfs2_super *osb)
+{
+       struct ocfs2_replay_map *replay_map;
+       int i, node_num;
+
+       /* If replay map is already set, we don't do it again */
+       if (osb->replay_map)
+               return 0;
+
+       replay_map = kzalloc(sizeof(struct ocfs2_replay_map) +
+                            (osb->max_slots * sizeof(char)), GFP_KERNEL);
+
+       if (!replay_map) {
+               mlog_errno(-ENOMEM);
+               return -ENOMEM;
+       }
+
+       spin_lock(&osb->osb_lock);
+
+       replay_map->rm_slots = osb->max_slots;
+       replay_map->rm_state = REPLAY_UNNEEDED;
+
+       /* set rm_replay_slots for offline slot(s) */
+       for (i = 0; i < replay_map->rm_slots; i++) {
+               if (ocfs2_slot_to_node_num_locked(osb, i, &node_num) == -ENOENT)
+                       replay_map->rm_replay_slots[i] = 1;
+       }
+
+       osb->replay_map = replay_map;
+       spin_unlock(&osb->osb_lock);
+       return 0;
+}
+
+void ocfs2_queue_replay_slots(struct ocfs2_super *osb)
+{
+       struct ocfs2_replay_map *replay_map = osb->replay_map;
+       int i;
+
+       if (!replay_map)
+               return;
+
+       if (replay_map->rm_state != REPLAY_NEEDED)
+               return;
+
+       for (i = 0; i < replay_map->rm_slots; i++)
+               if (replay_map->rm_replay_slots[i])
+                       ocfs2_queue_recovery_completion(osb->journal, i, NULL,
+                                                       NULL, NULL);
+       replay_map->rm_state = REPLAY_DONE;
+}
+
+void ocfs2_free_replay_slots(struct ocfs2_super *osb)
+{
+       struct ocfs2_replay_map *replay_map = osb->replay_map;
+
+       if (!osb->replay_map)
+               return;
+
+       kfree(replay_map);
+       osb->replay_map = NULL;
+}
+
 int ocfs2_recovery_init(struct ocfs2_super *osb)
 {
        struct ocfs2_recovery_map *rm;
@@ -496,6 +580,22 @@ static struct ocfs2_triggers dq_triggers = {
        },
 };
 
+static struct ocfs2_triggers dr_triggers = {
+       .ot_triggers = {
+               .t_commit = ocfs2_commit_trigger,
+               .t_abort = ocfs2_abort_trigger,
+       },
+       .ot_offset      = offsetof(struct ocfs2_dx_root_block, dr_check),
+};
+
+static struct ocfs2_triggers dl_triggers = {
+       .ot_triggers = {
+               .t_commit = ocfs2_commit_trigger,
+               .t_abort = ocfs2_abort_trigger,
+       },
+       .ot_offset      = offsetof(struct ocfs2_dx_leaf, dl_check),
+};
+
 static int __ocfs2_journal_access(handle_t *handle,
                                  struct inode *inode,
                                  struct buffer_head *bh,
@@ -600,6 +700,20 @@ int ocfs2_journal_access_dq(handle_t *handle, struct inode *inode,
                                      type);
 }
 
+int ocfs2_journal_access_dr(handle_t *handle, struct inode *inode,
+                           struct buffer_head *bh, int type)
+{
+       return __ocfs2_journal_access(handle, inode, bh, &dr_triggers,
+                                     type);
+}
+
+int ocfs2_journal_access_dl(handle_t *handle, struct inode *inode,
+                           struct buffer_head *bh, int type)
+{
+       return __ocfs2_journal_access(handle, inode, bh, &dl_triggers,
+                                     type);
+}
+
 int ocfs2_journal_access(handle_t *handle, struct inode *inode,
                         struct buffer_head *bh, int type)
 {
@@ -1176,24 +1290,24 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
 }
 
 /* Called by the mount code to queue recovery the last part of
- * recovery for it's own slot. */
+ * recovery for it's own and offline slot(s). */
 void ocfs2_complete_mount_recovery(struct ocfs2_super *osb)
 {
        struct ocfs2_journal *journal = osb->journal;
 
-       if (osb->dirty) {
-               /* No need to queue up our truncate_log as regular
-                * cleanup will catch that. */
-               ocfs2_queue_recovery_completion(journal,
-                                               osb->slot_num,
-                                               osb->local_alloc_copy,
-                                               NULL,
-                                               NULL);
-               ocfs2_schedule_truncate_log_flush(osb, 0);
+       /* No need to queue up our truncate_log as regular cleanup will catch
+        * that */
+       ocfs2_queue_recovery_completion(journal, osb->slot_num,
+                                       osb->local_alloc_copy, NULL, NULL);
+       ocfs2_schedule_truncate_log_flush(osb, 0);
 
-               osb->local_alloc_copy = NULL;
-               osb->dirty = 0;
-       }
+       osb->local_alloc_copy = NULL;
+       osb->dirty = 0;
+
+       /* queue to recover orphan slots for all offline slots */
+       ocfs2_replay_map_set_state(osb, REPLAY_NEEDED);
+       ocfs2_queue_replay_slots(osb);
+       ocfs2_free_replay_slots(osb);
 }
 
 void ocfs2_complete_quota_recovery(struct ocfs2_super *osb)
@@ -1236,6 +1350,14 @@ restart:
                goto bail;
        }
 
+       status = ocfs2_compute_replay_slots(osb);
+       if (status < 0)
+               mlog_errno(status);
+
+       /* queue recovery for our own slot */
+       ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL,
+                                       NULL, NULL);
+
        spin_lock(&osb->osb_lock);
        while (rm->rm_used) {
                /* It's always safe to remove entry zero, as we won't
@@ -1301,11 +1423,8 @@ skip_recovery:
 
        ocfs2_super_unlock(osb, 1);
 
-       /* We always run recovery on our own orphan dir - the dead
-        * node(s) may have disallowd a previos inode delete. Re-processing
-        * is therefore required. */
-       ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL,
-                                       NULL, NULL);
+       /* queue recovery for offline slots */
+       ocfs2_queue_replay_slots(osb);
 
 bail:
        mutex_lock(&osb->recovery_lock);
@@ -1314,6 +1433,7 @@ bail:
                goto restart;
        }
 
+       ocfs2_free_replay_slots(osb);
        osb->recovery_thread_task = NULL;
        mb(); /* sync with ocfs2_recovery_thread_running */
        wake_up(&osb->recovery_event);
@@ -1465,6 +1585,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
                goto done;
        }
 
+       /* we need to run complete recovery for offline orphan slots */
+       ocfs2_replay_map_set_state(osb, REPLAY_NEEDED);
+
        mlog(ML_NOTICE, "Recovering node %d from slot %d on device (%u,%u)\n",
             node_num, slot_num,
             MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev));
index 172850a9a12a7d78cc115e80500979673f4ae7f5..619dd7f6c053c1562863707bebc7c3c6e1753b52 100644 (file)
@@ -38,6 +38,17 @@ enum ocfs2_journal_state {
 struct ocfs2_super;
 struct ocfs2_dinode;
 
+/*
+ * The recovery_list is a simple linked list of node numbers to recover.
+ * It is protected by the recovery_lock.
+ */
+
+struct ocfs2_recovery_map {
+       unsigned int rm_used;
+       unsigned int *rm_entries;
+};
+
+
 struct ocfs2_journal {
        enum ocfs2_journal_state   j_state;    /* Journals current state   */
 
@@ -139,6 +150,7 @@ void ocfs2_wait_for_recovery(struct ocfs2_super *osb);
 int ocfs2_recovery_init(struct ocfs2_super *osb);
 void ocfs2_recovery_exit(struct ocfs2_super *osb);
 
+int ocfs2_compute_replay_slots(struct ocfs2_super *osb);
 /*
  *  Journal Control:
  *  Initialize, Load, Shutdown, Wipe a journal.
@@ -266,6 +278,12 @@ int ocfs2_journal_access_dq(handle_t *handle, struct inode *inode,
 /* dirblock */
 int ocfs2_journal_access_db(handle_t *handle, struct inode *inode,
                            struct buffer_head *bh, int type);
+/* ocfs2_dx_root_block */
+int ocfs2_journal_access_dr(handle_t *handle, struct inode *inode,
+                           struct buffer_head *bh, int type);
+/* ocfs2_dx_leaf */
+int ocfs2_journal_access_dl(handle_t *handle, struct inode *inode,
+                           struct buffer_head *bh, int type);
 /* Anything that has no ecc */
 int ocfs2_journal_access(handle_t *handle, struct inode *inode,
                         struct buffer_head *bh, int type);
@@ -368,14 +386,29 @@ static inline int ocfs2_remove_extent_credits(struct super_block *sb)
 }
 
 /* data block for new dir/symlink, 2 for bitmap updates (bitmap fe +
- * bitmap block for the new bit) */
-#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2)
+ * bitmap block for the new bit) dx_root update for free list */
+#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2 + 1)
+
+static inline int ocfs2_add_dir_index_credits(struct super_block *sb)
+{
+       /* 1 block for index, 2 allocs (data, metadata), 1 clusters
+        * worth of blocks for initial extent. */
+       return 1 + 2 * OCFS2_SUBALLOC_ALLOC +
+               ocfs2_clusters_to_blocks(sb, 1);
+}
 
-/* parent fe, parent block, new file entry, inode alloc fe, inode alloc
- * group descriptor + mkdir/symlink blocks + quota update */
-static inline int ocfs2_mknod_credits(struct super_block *sb)
+/* parent fe, parent block, new file entry, index leaf, inode alloc fe, inode
+ * alloc group descriptor + mkdir/symlink blocks + dir blocks + xattr
+ * blocks + quota update */
+static inline int ocfs2_mknod_credits(struct super_block *sb, int is_dir,
+                                     int xattr_credits)
 {
-       return 3 + OCFS2_SUBALLOC_ALLOC + OCFS2_DIR_LINK_ADDITIONAL_CREDITS +
+       int dir_credits = OCFS2_DIR_LINK_ADDITIONAL_CREDITS;
+
+       if (is_dir)
+               dir_credits += ocfs2_add_dir_index_credits(sb);
+
+       return 4 + OCFS2_SUBALLOC_ALLOC + dir_credits + xattr_credits +
               ocfs2_quota_trans_credits(sb);
 }
 
@@ -388,31 +421,31 @@ static inline int ocfs2_mknod_credits(struct super_block *sb)
 #define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2)
 
 /* file update (nlink, etc) + directory mtime/ctime + dir entry block + quota
- * update on dir */
+ * update on dir + index leaf + dx root update for free list */
 static inline int ocfs2_link_credits(struct super_block *sb)
 {
-       return 2*OCFS2_INODE_UPDATE_CREDITS + 1 +
+       return 2*OCFS2_INODE_UPDATE_CREDITS + 3 +
               ocfs2_quota_trans_credits(sb);
 }
 
 /* inode + dir inode (if we unlink a dir), + dir entry block + orphan
- * dir inode link */
+ * dir inode link + dir inode index leaf + dir index root */
 static inline int ocfs2_unlink_credits(struct super_block *sb)
 {
        /* The quota update from ocfs2_link_credits is unused here... */
-       return 2 * OCFS2_INODE_UPDATE_CREDITS + 1 + ocfs2_link_credits(sb);
+       return 2 * OCFS2_INODE_UPDATE_CREDITS + 3 + ocfs2_link_credits(sb);
 }
 
 /* dinode + orphan dir dinode + inode alloc dinode + orphan dir entry +
- * inode alloc group descriptor */
-#define OCFS2_DELETE_INODE_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 1 + 1)
+ * inode alloc group descriptor + orphan dir index leaf */
+#define OCFS2_DELETE_INODE_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3)
 
 /* dinode update, old dir dinode update, new dir dinode update, old
  * dir dir entry, new dir dir entry, dir entry update for renaming
- * directory + target unlink */
+ * directory + target unlink + 3 x dir index leaves */
 static inline int ocfs2_rename_credits(struct super_block *sb)
 {
-       return 3 * OCFS2_INODE_UPDATE_CREDITS + 3 + ocfs2_unlink_credits(sb);
+       return 3 * OCFS2_INODE_UPDATE_CREDITS + 6 + ocfs2_unlink_credits(sb);
 }
 
 /* global bitmap dinode, group desc., relinked group,
@@ -422,6 +455,20 @@ static inline int ocfs2_rename_credits(struct super_block *sb)
                                          + OCFS2_INODE_UPDATE_CREDITS \
                                          + OCFS2_XATTR_BLOCK_UPDATE_CREDITS)
 
+/* inode update, removal of dx root block from allocator */
+#define OCFS2_DX_ROOT_REMOVE_CREDITS (OCFS2_INODE_UPDATE_CREDITS +     \
+                                     OCFS2_SUBALLOC_FREE)
+
+static inline int ocfs2_calc_dxi_expand_credits(struct super_block *sb)
+{
+       int credits = 1 + OCFS2_SUBALLOC_ALLOC;
+
+       credits += ocfs2_clusters_to_blocks(sb, 1);
+       credits += ocfs2_quota_trans_credits(sb);
+
+       return credits;
+}
+
 /*
  * Please note that the caller must make sure that root_el is the root
  * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
@@ -457,7 +504,7 @@ static inline int ocfs2_calc_extend_credits(struct super_block *sb,
 
 static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
 {
-       int blocks = ocfs2_mknod_credits(sb);
+       int blocks = ocfs2_mknod_credits(sb, 0, 0);
 
        /* links can be longer than one block so we may update many
         * within our single allocated extent. */
index ec70cdbe77fcb6a360efa338ce7f832f5937965b..bac7e6abaf4763f75f873592beec3c0d4cb63472 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/bitops.h>
-#include <linux/debugfs.h>
 
 #define MLOG_MASK_PREFIX ML_DISK_ALLOC
 #include <cluster/masklog.h>
@@ -75,84 +74,6 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
 static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
                                          struct inode *local_alloc_inode);
 
-#ifdef CONFIG_OCFS2_FS_STATS
-
-static int ocfs2_la_debug_open(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-#define LA_DEBUG_BUF_SZ        PAGE_CACHE_SIZE
-#define LA_DEBUG_VER   1
-static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf,
-                                  size_t count, loff_t *ppos)
-{
-       static DEFINE_MUTEX(la_debug_mutex);
-       struct ocfs2_super *osb = file->private_data;
-       int written, ret;
-       char *buf = osb->local_alloc_debug_buf;
-
-       mutex_lock(&la_debug_mutex);
-       memset(buf, 0, LA_DEBUG_BUF_SZ);
-
-       written = snprintf(buf, LA_DEBUG_BUF_SZ,
-                          "0x%x\t0x%llx\t%u\t%u\t0x%x\n",
-                          LA_DEBUG_VER,
-                          (unsigned long long)osb->la_last_gd,
-                          osb->local_alloc_default_bits,
-                          osb->local_alloc_bits, osb->local_alloc_state);
-
-       ret = simple_read_from_buffer(userbuf, count, ppos, buf, written);
-
-       mutex_unlock(&la_debug_mutex);
-       return ret;
-}
-
-static const struct file_operations ocfs2_la_debug_fops = {
-       .open =         ocfs2_la_debug_open,
-       .read =         ocfs2_la_debug_read,
-};
-
-static void ocfs2_init_la_debug(struct ocfs2_super *osb)
-{
-       osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS);
-       if (!osb->local_alloc_debug_buf)
-               return;
-
-       osb->local_alloc_debug = debugfs_create_file("local_alloc_stats",
-                                                    S_IFREG|S_IRUSR,
-                                                    osb->osb_debug_root,
-                                                    osb,
-                                                    &ocfs2_la_debug_fops);
-       if (!osb->local_alloc_debug) {
-               kfree(osb->local_alloc_debug_buf);
-               osb->local_alloc_debug_buf = NULL;
-       }
-}
-
-static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
-{
-       if (osb->local_alloc_debug)
-               debugfs_remove(osb->local_alloc_debug);
-
-       if (osb->local_alloc_debug_buf)
-               kfree(osb->local_alloc_debug_buf);
-
-       osb->local_alloc_debug_buf = NULL;
-       osb->local_alloc_debug = NULL;
-}
-#else  /* CONFIG_OCFS2_FS_STATS */
-static void ocfs2_init_la_debug(struct ocfs2_super *osb)
-{
-       return;
-}
-static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
-{
-       return;
-}
-#endif
-
 static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb)
 {
        return (osb->local_alloc_state == OCFS2_LA_THROTTLED ||
@@ -226,8 +147,6 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
 
        mlog_entry_void();
 
-       ocfs2_init_la_debug(osb);
-
        if (osb->local_alloc_bits == 0)
                goto bail;
 
@@ -299,9 +218,6 @@ bail:
        if (inode)
                iput(inode);
 
-       if (status < 0)
-               ocfs2_shutdown_la_debug(osb);
-
        mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits);
 
        mlog_exit(status);
@@ -331,8 +247,6 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
        cancel_delayed_work(&osb->la_enable_wq);
        flush_workqueue(ocfs2_wq);
 
-       ocfs2_shutdown_la_debug(osb);
-
        if (osb->local_alloc_state == OCFS2_LA_UNUSED)
                goto out;
 
index eea1d24713ea13d6f4500eb059613a75d98ae933..b606496b72ec55c65554c6e72a9353e7739a4e9f 100644 (file)
@@ -154,8 +154,9 @@ out:
        return ret;
 }
 
-static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        struct buffer_head *di_bh = NULL;
        sigset_t blocked, oldset;
@@ -196,7 +197,8 @@ out:
        ret2 = ocfs2_vm_op_unblock_sigs(&oldset);
        if (ret2 < 0)
                mlog_errno(ret2);
-
+       if (ret)
+               ret = VM_FAULT_SIGBUS;
        return ret;
 }
 
index 4b11762f249e91aba2d4ece846bbc86ac8058005..2220f93f668bc9d0b0cc5446efdb612ccfd1d4bb 100644 (file)
@@ -80,14 +80,14 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
                                    struct inode **ret_orphan_dir,
                                    struct inode *inode,
                                    char *name,
-                                   struct buffer_head **de_bh);
+                                   struct ocfs2_dir_lookup_result *lookup);
 
 static int ocfs2_orphan_add(struct ocfs2_super *osb,
                            handle_t *handle,
                            struct inode *inode,
                            struct ocfs2_dinode *fe,
                            char *name,
-                           struct buffer_head *de_bh,
+                           struct ocfs2_dir_lookup_result *lookup,
                            struct inode *orphan_dir_inode);
 
 static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
@@ -228,17 +228,18 @@ static int ocfs2_mknod(struct inode *dir,
        struct ocfs2_super *osb;
        struct ocfs2_dinode *dirfe;
        struct buffer_head *new_fe_bh = NULL;
-       struct buffer_head *de_bh = NULL;
        struct inode *inode = NULL;
        struct ocfs2_alloc_context *inode_ac = NULL;
        struct ocfs2_alloc_context *data_ac = NULL;
-       struct ocfs2_alloc_context *xattr_ac = NULL;
+       struct ocfs2_alloc_context *meta_ac = NULL;
        int want_clusters = 0;
+       int want_meta = 0;
        int xattr_credits = 0;
        struct ocfs2_security_xattr_info si = {
                .enable = 1,
        };
        int did_quota_inode = 0;
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
 
        mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode,
                   (unsigned long)dev, dentry->d_name.len,
@@ -254,13 +255,13 @@ static int ocfs2_mknod(struct inode *dir,
                return status;
        }
 
-       if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) {
+       if (S_ISDIR(mode) && (dir->i_nlink >= ocfs2_link_max(osb))) {
                status = -EMLINK;
                goto leave;
        }
 
        dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
-       if (!dirfe->i_links_count) {
+       if (!ocfs2_read_links_count(dirfe)) {
                /* can't make a file in a deleted directory. */
                status = -ENOENT;
                goto leave;
@@ -274,7 +275,7 @@ static int ocfs2_mknod(struct inode *dir,
        /* get a spot inside the dir. */
        status = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh,
                                              dentry->d_name.name,
-                                             dentry->d_name.len, &de_bh);
+                                             dentry->d_name.len, &lookup);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -308,17 +309,29 @@ static int ocfs2_mknod(struct inode *dir,
 
        /* calculate meta data/clusters for setting security and acl xattr */
        status = ocfs2_calc_xattr_init(dir, parent_fe_bh, mode,
-                                       &si, &want_clusters,
-                                       &xattr_credits, &xattr_ac);
+                                      &si, &want_clusters,
+                                      &xattr_credits, &want_meta);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
        }
 
        /* Reserve a cluster if creating an extent based directory. */
-       if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb))
+       if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
                want_clusters += 1;
 
+               /* Dir indexing requires extra space as well */
+               if (ocfs2_supports_indexed_dirs(osb))
+                       want_meta++;
+       }
+
+       status = ocfs2_reserve_new_metadata_blocks(osb, want_meta, &meta_ac);
+       if (status < 0) {
+               if (status != -ENOSPC)
+                       mlog_errno(status);
+               goto leave;
+       }
+
        status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac);
        if (status < 0) {
                if (status != -ENOSPC)
@@ -326,8 +339,9 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
-       handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb) +
-                                  xattr_credits);
+       handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb,
+                                                           S_ISDIR(mode),
+                                                           xattr_credits));
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
                handle = NULL;
@@ -355,7 +369,7 @@ static int ocfs2_mknod(struct inode *dir,
 
        if (S_ISDIR(mode)) {
                status = ocfs2_fill_new_dir(osb, handle, dir, inode,
-                                           new_fe_bh, data_ac);
+                                           new_fe_bh, data_ac, meta_ac);
                if (status < 0) {
                        mlog_errno(status);
                        goto leave;
@@ -367,7 +381,7 @@ static int ocfs2_mknod(struct inode *dir,
                        mlog_errno(status);
                        goto leave;
                }
-               le16_add_cpu(&dirfe->i_links_count, 1);
+               ocfs2_add_links_count(dirfe, 1);
                status = ocfs2_journal_dirty(handle, parent_fe_bh);
                if (status < 0) {
                        mlog_errno(status);
@@ -377,7 +391,7 @@ static int ocfs2_mknod(struct inode *dir,
        }
 
        status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
-                               xattr_ac, data_ac);
+                               meta_ac, data_ac);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -385,7 +399,7 @@ static int ocfs2_mknod(struct inode *dir,
 
        if (si.enable) {
                status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si,
-                                                xattr_ac, data_ac);
+                                                meta_ac, data_ac);
                if (status < 0) {
                        mlog_errno(status);
                        goto leave;
@@ -394,7 +408,7 @@ static int ocfs2_mknod(struct inode *dir,
 
        status = ocfs2_add_entry(handle, dentry, inode,
                                 OCFS2_I(inode)->ip_blkno, parent_fe_bh,
-                                de_bh);
+                                &lookup);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -423,11 +437,12 @@ leave:
                mlog(0, "Disk is full\n");
 
        brelse(new_fe_bh);
-       brelse(de_bh);
        brelse(parent_fe_bh);
        kfree(si.name);
        kfree(si.value);
 
+       ocfs2_free_dir_lookup_result(&lookup);
+
        if ((status < 0) && inode) {
                clear_nlink(inode);
                iput(inode);
@@ -439,8 +454,8 @@ leave:
        if (data_ac)
                ocfs2_free_alloc_context(data_ac);
 
-       if (xattr_ac)
-               ocfs2_free_alloc_context(xattr_ac);
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
 
        mlog_exit(status);
 
@@ -462,6 +477,7 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
        struct ocfs2_extent_list *fel;
        u64 fe_blkno = 0;
        u16 suballoc_bit;
+       u16 feat;
 
        mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry,
                   inode->i_mode, (unsigned long)dev, dentry->d_name.len,
@@ -469,8 +485,8 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
 
        *new_fe_bh = NULL;
 
-       status = ocfs2_claim_new_inode(osb, handle, inode_ac, &suballoc_bit,
-                                      &fe_blkno);
+       status = ocfs2_claim_new_inode(osb, handle, dir, parent_fe_bh,
+                                      inode_ac, &suballoc_bit, &fe_blkno);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -513,7 +529,8 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
        fe->i_mode = cpu_to_le16(inode->i_mode);
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
                fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev));
-       fe->i_links_count = cpu_to_le16(inode->i_nlink);
+
+       ocfs2_set_links_count(fe, inode->i_nlink);
 
        fe->i_last_eb_blk = 0;
        strcpy(fe->i_signature, OCFS2_INODE_SIGNATURE);
@@ -525,11 +542,11 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
        fe->i_dtime = 0;
 
        /*
-        * If supported, directories start with inline data.
+        * If supported, directories start with inline data. If inline
+        * isn't supported, but indexing is, we start them as indexed.
         */
+       feat = le16_to_cpu(fe->i_dyn_features);
        if (S_ISDIR(inode->i_mode) && ocfs2_supports_inline_data(osb)) {
-               u16 feat = le16_to_cpu(fe->i_dyn_features);
-
                fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);
 
                fe->id2.i_data.id_count = cpu_to_le16(
@@ -608,9 +625,9 @@ static int ocfs2_link(struct dentry *old_dentry,
        int err;
        struct buffer_head *fe_bh = NULL;
        struct buffer_head *parent_fe_bh = NULL;
-       struct buffer_head *de_bh = NULL;
        struct ocfs2_dinode *fe = NULL;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
 
        mlog_entry("(inode=%lu, old='%.*s' new='%.*s')\n", inode->i_ino,
                   old_dentry->d_name.len, old_dentry->d_name.name,
@@ -638,7 +655,7 @@ static int ocfs2_link(struct dentry *old_dentry,
 
        err = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh,
                                           dentry->d_name.name,
-                                          dentry->d_name.len, &de_bh);
+                                          dentry->d_name.len, &lookup);
        if (err < 0) {
                mlog_errno(err);
                goto out;
@@ -652,7 +669,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        }
 
        fe = (struct ocfs2_dinode *) fe_bh->b_data;
-       if (le16_to_cpu(fe->i_links_count) >= OCFS2_LINK_MAX) {
+       if (ocfs2_read_links_count(fe) >= ocfs2_link_max(osb)) {
                err = -EMLINK;
                goto out_unlock_inode;
        }
@@ -674,13 +691,13 @@ static int ocfs2_link(struct dentry *old_dentry,
 
        inc_nlink(inode);
        inode->i_ctime = CURRENT_TIME;
-       fe->i_links_count = cpu_to_le16(inode->i_nlink);
+       ocfs2_set_links_count(fe, inode->i_nlink);
        fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
        fe->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
 
        err = ocfs2_journal_dirty(handle, fe_bh);
        if (err < 0) {
-               le16_add_cpu(&fe->i_links_count, -1);
+               ocfs2_add_links_count(fe, -1);
                drop_nlink(inode);
                mlog_errno(err);
                goto out_commit;
@@ -688,9 +705,9 @@ static int ocfs2_link(struct dentry *old_dentry,
 
        err = ocfs2_add_entry(handle, dentry, inode,
                              OCFS2_I(inode)->ip_blkno,
-                             parent_fe_bh, de_bh);
+                             parent_fe_bh, &lookup);
        if (err) {
-               le16_add_cpu(&fe->i_links_count, -1);
+               ocfs2_add_links_count(fe, -1);
                drop_nlink(inode);
                mlog_errno(err);
                goto out_commit;
@@ -714,10 +731,11 @@ out_unlock_inode:
 out:
        ocfs2_inode_unlock(dir, 1);
 
-       brelse(de_bh);
        brelse(fe_bh);
        brelse(parent_fe_bh);
 
+       ocfs2_free_dir_lookup_result(&lookup);
+
        mlog_exit(err);
 
        return err;
@@ -766,10 +784,9 @@ static int ocfs2_unlink(struct inode *dir,
        struct buffer_head *fe_bh = NULL;
        struct buffer_head *parent_node_bh = NULL;
        handle_t *handle = NULL;
-       struct ocfs2_dir_entry *dirent = NULL;
-       struct buffer_head *dirent_bh = NULL;
        char orphan_name[OCFS2_ORPHAN_NAMELEN + 1];
-       struct buffer_head *orphan_entry_bh = NULL;
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
+       struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
 
        mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
                   dentry->d_name.len, dentry->d_name.name);
@@ -791,8 +808,8 @@ static int ocfs2_unlink(struct inode *dir,
        }
 
        status = ocfs2_find_files_on_disk(dentry->d_name.name,
-                                         dentry->d_name.len, &blkno,
-                                         dir, &dirent_bh, &dirent);
+                                         dentry->d_name.len, &blkno, dir,
+                                         &lookup);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -817,10 +834,7 @@ static int ocfs2_unlink(struct inode *dir,
        child_locked = 1;
 
        if (S_ISDIR(inode->i_mode)) {
-               if (!ocfs2_empty_dir(inode)) {
-                       status = -ENOTEMPTY;
-                       goto leave;
-               } else if (inode->i_nlink != 2) {
+               if (inode->i_nlink != 2 || !ocfs2_empty_dir(inode)) {
                        status = -ENOTEMPTY;
                        goto leave;
                }
@@ -836,8 +850,7 @@ static int ocfs2_unlink(struct inode *dir,
 
        if (inode_is_unlinkable(inode)) {
                status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, inode,
-                                                 orphan_name,
-                                                 &orphan_entry_bh);
+                                                 orphan_name, &orphan_insert);
                if (status < 0) {
                        mlog_errno(status);
                        goto leave;
@@ -863,7 +876,7 @@ static int ocfs2_unlink(struct inode *dir,
 
        if (inode_is_unlinkable(inode)) {
                status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name,
-                                         orphan_entry_bh, orphan_dir);
+                                         &orphan_insert, orphan_dir);
                if (status < 0) {
                        mlog_errno(status);
                        goto leave;
@@ -871,7 +884,7 @@ static int ocfs2_unlink(struct inode *dir,
        }
 
        /* delete the name from the parent dir */
-       status = ocfs2_delete_entry(handle, dir, dirent, dirent_bh);
+       status = ocfs2_delete_entry(handle, dir, &lookup);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -880,7 +893,7 @@ static int ocfs2_unlink(struct inode *dir,
        if (S_ISDIR(inode->i_mode))
                drop_nlink(inode);
        drop_nlink(inode);
-       fe->i_links_count = cpu_to_le16(inode->i_nlink);
+       ocfs2_set_links_count(fe, inode->i_nlink);
 
        status = ocfs2_journal_dirty(handle, fe_bh);
        if (status < 0) {
@@ -916,9 +929,10 @@ leave:
        }
 
        brelse(fe_bh);
-       brelse(dirent_bh);
        brelse(parent_node_bh);
-       brelse(orphan_entry_bh);
+
+       ocfs2_free_dir_lookup_result(&orphan_insert);
+       ocfs2_free_dir_lookup_result(&lookup);
 
        mlog_exit(status);
 
@@ -1004,8 +1018,8 @@ static int ocfs2_rename(struct inode *old_dir,
                        struct inode *new_dir,
                        struct dentry *new_dentry)
 {
-       int status = 0, rename_lock = 0, parents_locked = 0;
-       int old_child_locked = 0, new_child_locked = 0;
+       int status = 0, rename_lock = 0, parents_locked = 0, target_exists = 0;
+       int old_child_locked = 0, new_child_locked = 0, update_dot_dot = 0;
        struct inode *old_inode = old_dentry->d_inode;
        struct inode *new_inode = new_dentry->d_inode;
        struct inode *orphan_dir = NULL;
@@ -1020,13 +1034,13 @@ static int ocfs2_rename(struct inode *old_dir,
        handle_t *handle = NULL;
        struct buffer_head *old_dir_bh = NULL;
        struct buffer_head *new_dir_bh = NULL;
-       struct ocfs2_dir_entry *old_inode_dot_dot_de = NULL, *old_de = NULL,
-               *new_de = NULL;
-       struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above
-       struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
-                                                   // this is the 1st dirent bh
        nlink_t old_dir_nlink = old_dir->i_nlink;
        struct ocfs2_dinode *old_di;
+       struct ocfs2_dir_lookup_result old_inode_dot_dot_res = { NULL, };
+       struct ocfs2_dir_lookup_result target_lookup_res = { NULL, };
+       struct ocfs2_dir_lookup_result old_entry_lookup = { NULL, };
+       struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
+       struct ocfs2_dir_lookup_result target_insert = { NULL, };
 
        /* At some point it might be nice to break this function up a
         * bit. */
@@ -1108,9 +1122,10 @@ static int ocfs2_rename(struct inode *old_dir,
        if (S_ISDIR(old_inode->i_mode)) {
                u64 old_inode_parent;
 
+               update_dot_dot = 1;
                status = ocfs2_find_files_on_disk("..", 2, &old_inode_parent,
-                                                 old_inode, &old_inode_de_bh,
-                                                 &old_inode_dot_dot_de);
+                                                 old_inode,
+                                                 &old_inode_dot_dot_res);
                if (status) {
                        status = -EIO;
                        goto bail;
@@ -1122,7 +1137,7 @@ static int ocfs2_rename(struct inode *old_dir,
                }
 
                if (!new_inode && new_dir != old_dir &&
-                   new_dir->i_nlink >= OCFS2_LINK_MAX) {
+                   new_dir->i_nlink >= ocfs2_link_max(osb)) {
                        status = -EMLINK;
                        goto bail;
                }
@@ -1151,8 +1166,8 @@ static int ocfs2_rename(struct inode *old_dir,
         * to delete it */
        status = ocfs2_find_files_on_disk(new_dentry->d_name.name,
                                          new_dentry->d_name.len,
-                                         &newfe_blkno, new_dir, &new_de_bh,
-                                         &new_de);
+                                         &newfe_blkno, new_dir,
+                                         &target_lookup_res);
        /* The only error we allow here is -ENOENT because the new
         * file not existing is perfectly valid. */
        if ((status < 0) && (status != -ENOENT)) {
@@ -1161,8 +1176,10 @@ static int ocfs2_rename(struct inode *old_dir,
                mlog_errno(status);
                goto bail;
        }
+       if (status == 0)
+               target_exists = 1;
 
-       if (!new_de && new_inode) {
+       if (!target_exists && new_inode) {
                /*
                 * Target was unlinked by another node while we were
                 * waiting to get to ocfs2_rename(). There isn't
@@ -1175,7 +1192,7 @@ static int ocfs2_rename(struct inode *old_dir,
 
        /* In case we need to overwrite an existing file, we blow it
         * away first */
-       if (new_de) {
+       if (target_exists) {
                /* VFS didn't think there existed an inode here, but
                 * someone else in the cluster must have raced our
                 * rename to create one. Today we error cleanly, in
@@ -1216,8 +1233,8 @@ static int ocfs2_rename(struct inode *old_dir,
 
                newfe = (struct ocfs2_dinode *) newfe_bh->b_data;
 
-               mlog(0, "aha rename over existing... new_de=%p new_blkno=%llu "
-                    "newfebh=%p bhblocknr=%llu\n", new_de,
+               mlog(0, "aha rename over existing... new_blkno=%llu "
+                    "newfebh=%p bhblocknr=%llu\n",
                     (unsigned long long)newfe_blkno, newfe_bh, newfe_bh ?
                     (unsigned long long)newfe_bh->b_blocknr : 0ULL);
 
@@ -1225,7 +1242,7 @@ static int ocfs2_rename(struct inode *old_dir,
                        status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
                                                          new_inode,
                                                          orphan_name,
-                                                         &orphan_entry_bh);
+                                                         &orphan_insert);
                        if (status < 0) {
                                mlog_errno(status);
                                goto bail;
@@ -1243,7 +1260,7 @@ static int ocfs2_rename(struct inode *old_dir,
                status = ocfs2_prepare_dir_for_insert(osb, new_dir, new_dir_bh,
                                                      new_dentry->d_name.name,
                                                      new_dentry->d_name.len,
-                                                     &insert_entry_bh);
+                                                     &target_insert);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -1258,10 +1275,10 @@ static int ocfs2_rename(struct inode *old_dir,
                goto bail;
        }
 
-       if (new_de) {
+       if (target_exists) {
                if (S_ISDIR(new_inode->i_mode)) {
-                       if (!ocfs2_empty_dir(new_inode) ||
-                           new_inode->i_nlink != 2) {
+                       if (new_inode->i_nlink != 2 ||
+                           !ocfs2_empty_dir(new_inode)) {
                                status = -ENOTEMPTY;
                                goto bail;
                        }
@@ -1274,10 +1291,10 @@ static int ocfs2_rename(struct inode *old_dir,
                }
 
                if (S_ISDIR(new_inode->i_mode) ||
-                   (newfe->i_links_count == cpu_to_le16(1))){
+                   (ocfs2_read_links_count(newfe) == 1)) {
                        status = ocfs2_orphan_add(osb, handle, new_inode,
                                                  newfe, orphan_name,
-                                                 orphan_entry_bh, orphan_dir);
+                                                 &orphan_insert, orphan_dir);
                        if (status < 0) {
                                mlog_errno(status);
                                goto bail;
@@ -1285,8 +1302,8 @@ static int ocfs2_rename(struct inode *old_dir,
                }
 
                /* change the dirent to point to the correct inode */
-               status = ocfs2_update_entry(new_dir, handle, new_de_bh,
-                                           new_de, old_inode);
+               status = ocfs2_update_entry(new_dir, handle, &target_lookup_res,
+                                           old_inode);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -1294,9 +1311,9 @@ static int ocfs2_rename(struct inode *old_dir,
                new_dir->i_version++;
 
                if (S_ISDIR(new_inode->i_mode))
-                       newfe->i_links_count = 0;
+                       ocfs2_set_links_count(newfe, 0);
                else
-                       le16_add_cpu(&newfe->i_links_count, -1);
+                       ocfs2_add_links_count(newfe, -1);
 
                status = ocfs2_journal_dirty(handle, newfe_bh);
                if (status < 0) {
@@ -1307,7 +1324,7 @@ static int ocfs2_rename(struct inode *old_dir,
                /* if the name was not found in new_dir, add it now */
                status = ocfs2_add_entry(handle, new_dentry, old_inode,
                                         OCFS2_I(old_inode)->ip_blkno,
-                                        new_dir_bh, insert_entry_bh);
+                                        new_dir_bh, &target_insert);
        }
 
        old_inode->i_ctime = CURRENT_TIME;
@@ -1334,15 +1351,13 @@ static int ocfs2_rename(struct inode *old_dir,
         * because the insert might have changed the type of directory
         * we're dealing with.
         */
-       old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
-                                    old_dentry->d_name.len,
-                                    old_dir, &old_de);
-       if (!old_de_bh) {
-               status = -EIO;
+       status = ocfs2_find_entry(old_dentry->d_name.name,
+                                 old_dentry->d_name.len, old_dir,
+                                 &old_entry_lookup);
+       if (status)
                goto bail;
-       }
 
-       status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh);
+       status = ocfs2_delete_entry(handle, old_dir, &old_entry_lookup);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -1353,9 +1368,10 @@ static int ocfs2_rename(struct inode *old_dir,
                new_inode->i_ctime = CURRENT_TIME;
        }
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-       if (old_inode_de_bh) {
-               status = ocfs2_update_entry(old_inode, handle, old_inode_de_bh,
-                                           old_inode_dot_dot_de, new_dir);
+
+       if (update_dot_dot) {
+               status = ocfs2_update_entry(old_inode, handle,
+                                           &old_inode_dot_dot_res, new_dir);
                old_dir->i_nlink--;
                if (new_inode) {
                        new_inode->i_nlink--;
@@ -1391,14 +1407,13 @@ static int ocfs2_rename(struct inode *old_dir,
                } else {
                        struct ocfs2_dinode *fe;
                        status = ocfs2_journal_access_di(handle, old_dir,
-                                                        old_dir_bh,
-                                                        OCFS2_JOURNAL_ACCESS_WRITE);
+                                                     old_dir_bh,
+                                                     OCFS2_JOURNAL_ACCESS_WRITE);
                        fe = (struct ocfs2_dinode *) old_dir_bh->b_data;
-                       fe->i_links_count = cpu_to_le16(old_dir->i_nlink);
+                       ocfs2_set_links_count(fe, old_dir->i_nlink);
                        status = ocfs2_journal_dirty(handle, old_dir_bh);
                }
        }
-
        ocfs2_dentry_move(old_dentry, new_dentry, old_dir, new_dir);
        status = 0;
 bail:
@@ -1429,13 +1444,17 @@ bail:
 
        if (new_inode)
                iput(new_inode);
+
+       ocfs2_free_dir_lookup_result(&target_lookup_res);
+       ocfs2_free_dir_lookup_result(&old_entry_lookup);
+       ocfs2_free_dir_lookup_result(&old_inode_dot_dot_res);
+       ocfs2_free_dir_lookup_result(&orphan_insert);
+       ocfs2_free_dir_lookup_result(&target_insert);
+
        brelse(newfe_bh);
        brelse(old_inode_bh);
        brelse(old_dir_bh);
        brelse(new_dir_bh);
-       brelse(new_de_bh);
-       brelse(old_de_bh);
-       brelse(old_inode_de_bh);
        brelse(orphan_entry_bh);
        brelse(insert_entry_bh);
 
@@ -1558,7 +1577,6 @@ static int ocfs2_symlink(struct inode *dir,
        struct inode *inode = NULL;
        struct super_block *sb;
        struct buffer_head *new_fe_bh = NULL;
-       struct buffer_head *de_bh = NULL;
        struct buffer_head *parent_fe_bh = NULL;
        struct ocfs2_dinode *fe = NULL;
        struct ocfs2_dinode *dirfe;
@@ -1572,6 +1590,7 @@ static int ocfs2_symlink(struct inode *dir,
                .enable = 1,
        };
        int did_quota = 0, did_quota_inode = 0;
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
 
        mlog_entry("(0x%p, 0x%p, symname='%s' actual='%.*s')\n", dir,
                   dentry, symname, dentry->d_name.len, dentry->d_name.name);
@@ -1592,7 +1611,7 @@ static int ocfs2_symlink(struct inode *dir,
        }
 
        dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
-       if (!dirfe->i_links_count) {
+       if (!ocfs2_read_links_count(dirfe)) {
                /* can't make a file in a deleted directory. */
                status = -ENOENT;
                goto bail;
@@ -1605,7 +1624,7 @@ static int ocfs2_symlink(struct inode *dir,
 
        status = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh,
                                              dentry->d_name.name,
-                                             dentry->d_name.len, &de_bh);
+                                             dentry->d_name.len, &lookup);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -1744,7 +1763,7 @@ static int ocfs2_symlink(struct inode *dir,
 
        status = ocfs2_add_entry(handle, dentry, inode,
                                 le64_to_cpu(fe->i_blkno), parent_fe_bh,
-                                de_bh);
+                                &lookup);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -1772,9 +1791,9 @@ bail:
 
        brelse(new_fe_bh);
        brelse(parent_fe_bh);
-       brelse(de_bh);
        kfree(si.name);
        kfree(si.value);
+       ocfs2_free_dir_lookup_result(&lookup);
        if (inode_ac)
                ocfs2_free_alloc_context(inode_ac);
        if (data_ac)
@@ -1826,7 +1845,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
                                    struct inode **ret_orphan_dir,
                                    struct inode *inode,
                                    char *name,
-                                   struct buffer_head **de_bh)
+                                   struct ocfs2_dir_lookup_result *lookup)
 {
        struct inode *orphan_dir_inode;
        struct buffer_head *orphan_dir_bh = NULL;
@@ -1857,7 +1876,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
 
        status = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode,
                                              orphan_dir_bh, name,
-                                             OCFS2_ORPHAN_NAMELEN, de_bh);
+                                             OCFS2_ORPHAN_NAMELEN, lookup);
        if (status < 0) {
                ocfs2_inode_unlock(orphan_dir_inode, 1);
 
@@ -1884,7 +1903,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
                            struct inode *inode,
                            struct ocfs2_dinode *fe,
                            char *name,
-                           struct buffer_head *de_bh,
+                           struct ocfs2_dir_lookup_result *lookup,
                            struct inode *orphan_dir_inode)
 {
        struct buffer_head *orphan_dir_bh = NULL;
@@ -1910,8 +1929,8 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
         * underneath us... */
        orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;
        if (S_ISDIR(inode->i_mode))
-               le16_add_cpu(&orphan_fe->i_links_count, 1);
-       orphan_dir_inode->i_nlink = le16_to_cpu(orphan_fe->i_links_count);
+               ocfs2_add_links_count(orphan_fe, 1);
+       orphan_dir_inode->i_nlink = ocfs2_read_links_count(orphan_fe);
 
        status = ocfs2_journal_dirty(handle, orphan_dir_bh);
        if (status < 0) {
@@ -1922,7 +1941,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
        status = __ocfs2_add_entry(handle, orphan_dir_inode, name,
                                   OCFS2_ORPHAN_NAMELEN, inode,
                                   OCFS2_I(inode)->ip_blkno,
-                                  orphan_dir_bh, de_bh);
+                                  orphan_dir_bh, lookup);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -1955,8 +1974,7 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
        char name[OCFS2_ORPHAN_NAMELEN + 1];
        struct ocfs2_dinode *orphan_fe;
        int status = 0;
-       struct buffer_head *target_de_bh = NULL;
-       struct ocfs2_dir_entry *target_de = NULL;
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
 
        mlog_entry_void();
 
@@ -1971,17 +1989,15 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
             OCFS2_ORPHAN_NAMELEN);
 
        /* find it's spot in the orphan directory */
-       target_de_bh = ocfs2_find_entry(name, OCFS2_ORPHAN_NAMELEN,
-                                       orphan_dir_inode, &target_de);
-       if (!target_de_bh) {
-               status = -ENOENT;
+       status = ocfs2_find_entry(name, OCFS2_ORPHAN_NAMELEN, orphan_dir_inode,
+                                 &lookup);
+       if (status) {
                mlog_errno(status);
                goto leave;
        }
 
        /* remove it from the orphan directory */
-       status = ocfs2_delete_entry(handle, orphan_dir_inode, target_de,
-                                   target_de_bh);
+       status = ocfs2_delete_entry(handle, orphan_dir_inode, &lookup);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -1997,8 +2013,8 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
        /* do the i_nlink dance! :) */
        orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;
        if (S_ISDIR(inode->i_mode))
-               le16_add_cpu(&orphan_fe->i_links_count, -1);
-       orphan_dir_inode->i_nlink = le16_to_cpu(orphan_fe->i_links_count);
+               ocfs2_add_links_count(orphan_fe, -1);
+       orphan_dir_inode->i_nlink = ocfs2_read_links_count(orphan_fe);
 
        status = ocfs2_journal_dirty(handle, orphan_dir_bh);
        if (status < 0) {
@@ -2007,7 +2023,7 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
        }
 
 leave:
-       brelse(target_de_bh);
+       ocfs2_free_dir_lookup_result(&lookup);
 
        mlog_exit(status);
        return status;
index 946d3c34b90ba29e0e1cc0d44df7ca9bfe1878f5..1386281950dbead47e4b5528cde7caae706cb3f2 100644 (file)
@@ -209,6 +209,7 @@ enum ocfs2_mount_options
 struct ocfs2_journal;
 struct ocfs2_slot_info;
 struct ocfs2_recovery_map;
+struct ocfs2_replay_map;
 struct ocfs2_quota_recovery;
 struct ocfs2_dentry_lock;
 struct ocfs2_super
@@ -264,6 +265,7 @@ struct ocfs2_super
        atomic_t vol_state;
        struct mutex recovery_lock;
        struct ocfs2_recovery_map *recovery_map;
+       struct ocfs2_replay_map *replay_map;
        struct task_struct *recovery_thread_task;
        int disable_recovery;
        wait_queue_head_t checkpoint_event;
@@ -287,11 +289,6 @@ struct ocfs2_super
 
        u64 la_last_gd;
 
-#ifdef CONFIG_OCFS2_FS_STATS
-       struct dentry *local_alloc_debug;
-       char *local_alloc_debug_buf;
-#endif
-
        /* Next three fields are for local node slot recovery during
         * mount. */
        int dirty;
@@ -305,9 +302,11 @@ struct ocfs2_super
        struct ocfs2_cluster_connection *cconn;
        struct ocfs2_lock_res osb_super_lockres;
        struct ocfs2_lock_res osb_rename_lockres;
+       struct ocfs2_lock_res osb_nfs_sync_lockres;
        struct ocfs2_dlm_debug *osb_dlm_debug;
 
        struct dentry *osb_debug_root;
+       struct dentry *osb_ctxt;
 
        wait_queue_head_t recovery_event;
 
@@ -344,6 +343,12 @@ struct ocfs2_super
 
        /* used to protect metaecc calculation check of xattr. */
        spinlock_t osb_xattr_lock;
+
+       unsigned int                    osb_dx_mask;
+       u32                             osb_dx_seed[4];
+
+       /* the group we used to allocate inodes. */
+       u64                             osb_inode_alloc_group;
 };
 
 #define OCFS2_SB(sb)       ((struct ocfs2_super *)(sb)->s_fs_info)
@@ -402,6 +407,51 @@ static inline int ocfs2_meta_ecc(struct ocfs2_super *osb)
        return 0;
 }
 
+static inline int ocfs2_supports_indexed_dirs(struct ocfs2_super *osb)
+{
+       if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS)
+               return 1;
+       return 0;
+}
+
+static inline unsigned int ocfs2_link_max(struct ocfs2_super *osb)
+{
+       if (ocfs2_supports_indexed_dirs(osb))
+               return OCFS2_DX_LINK_MAX;
+       return OCFS2_LINK_MAX;
+}
+
+static inline unsigned int ocfs2_read_links_count(struct ocfs2_dinode *di)
+{
+       u32 nlink = le16_to_cpu(di->i_links_count);
+       u32 hi = le16_to_cpu(di->i_links_count_hi);
+
+       if (di->i_dyn_features & cpu_to_le16(OCFS2_INDEXED_DIR_FL))
+               nlink |= (hi << OCFS2_LINKS_HI_SHIFT);
+
+       return nlink;
+}
+
+static inline void ocfs2_set_links_count(struct ocfs2_dinode *di, u32 nlink)
+{
+       u16 lo, hi;
+
+       lo = nlink;
+       hi = nlink >> OCFS2_LINKS_HI_SHIFT;
+
+       di->i_links_count = cpu_to_le16(lo);
+       di->i_links_count_hi = cpu_to_le16(hi);
+}
+
+static inline void ocfs2_add_links_count(struct ocfs2_dinode *di, int n)
+{
+       u32 links = ocfs2_read_links_count(di);
+
+       links += n;
+
+       ocfs2_set_links_count(di, links);
+}
+
 /* set / clear functions because cluster events can make these happen
  * in parallel so we want the transitions to be atomic. this also
  * means that any future flags osb_flags must be protected by spinlock
@@ -482,6 +532,12 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb)
 #define OCFS2_IS_VALID_DIR_TRAILER(ptr)                                        \
        (!strcmp((ptr)->db_signature, OCFS2_DIR_TRAILER_SIGNATURE))
 
+#define OCFS2_IS_VALID_DX_ROOT(ptr)                                    \
+       (!strcmp((ptr)->dr_signature, OCFS2_DX_ROOT_SIGNATURE))
+
+#define OCFS2_IS_VALID_DX_LEAF(ptr)                                    \
+       (!strcmp((ptr)->dl_signature, OCFS2_DX_LEAF_SIGNATURE))
+
 static inline unsigned long ino_from_blkno(struct super_block *sb,
                                           u64 blkno)
 {
@@ -532,6 +588,16 @@ static inline u64 ocfs2_clusters_to_bytes(struct super_block *sb,
        return (u64)clusters << OCFS2_SB(sb)->s_clustersize_bits;
 }
 
+static inline u64 ocfs2_block_to_cluster_start(struct super_block *sb,
+                                              u64 blocks)
+{
+       int bits = OCFS2_SB(sb)->s_clustersize_bits - sb->s_blocksize_bits;
+       unsigned int clusters;
+
+       clusters = ocfs2_blocks_to_clusters(sb, blocks);
+       return (u64)clusters << bits;
+}
+
 static inline u64 ocfs2_align_bytes_to_clusters(struct super_block *sb,
                                                u64 bytes)
 {
index 2332ef740f4f9bc852ad064832d9fa5a161bb2fe..7ab6e9e5e77c0beda01c3d4bcfb6d95551127b61 100644 (file)
@@ -66,6 +66,8 @@
 #define OCFS2_GROUP_DESC_SIGNATURE      "GROUP01"
 #define OCFS2_XATTR_BLOCK_SIGNATURE    "XATTR01"
 #define OCFS2_DIR_TRAILER_SIGNATURE    "DIRTRL1"
+#define OCFS2_DX_ROOT_SIGNATURE                "DXDIR01"
+#define OCFS2_DX_LEAF_SIGNATURE                "DXLEAF1"
 
 /* Compatibility flags */
 #define OCFS2_HAS_COMPAT_FEATURE(sb,mask)                      \
@@ -95,7 +97,8 @@
                                         | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \
                                         | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \
                                         | OCFS2_FEATURE_INCOMPAT_XATTR \
-                                        | OCFS2_FEATURE_INCOMPAT_META_ECC)
+                                        | OCFS2_FEATURE_INCOMPAT_META_ECC \
+                                        | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP   (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
                                         | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
                                         | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
 /* Support for extended attributes */
 #define OCFS2_FEATURE_INCOMPAT_XATTR           0x0200
 
+/* Support for indexed directores */
+#define OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS    0x0400
+
 /* Metadata checksum and error correction */
 #define OCFS2_FEATURE_INCOMPAT_META_ECC                0x0800
 
@@ -411,8 +417,12 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
 #define OCFS2_DIR_REC_LEN(name_len)    (((name_len) + OCFS2_DIR_MEMBER_LEN + \
                                           OCFS2_DIR_ROUND) & \
                                         ~OCFS2_DIR_ROUND)
+#define OCFS2_DIR_MIN_REC_LEN  OCFS2_DIR_REC_LEN(1)
 
 #define OCFS2_LINK_MAX         32000
+#define        OCFS2_DX_LINK_MAX       ((1U << 31) - 1U)
+#define        OCFS2_LINKS_HI_SHIFT    16
+#define        OCFS2_DX_ENTRIES_MAX    (0xffffffffU)
 
 #define S_SHIFT                        12
 static unsigned char ocfs2_type_by_mode[S_IFMT >> S_SHIFT] = {
@@ -628,8 +638,9 @@ struct ocfs2_super_block {
 /*B8*/ __le16 s_xattr_inline_size;     /* extended attribute inline size
                                           for this fs*/
        __le16 s_reserved0;
-       __le32 s_reserved1;
-/*C0*/  __le64 s_reserved2[16];                /* Fill out superblock */
+       __le32 s_dx_seed[3];            /* seed[0-2] for dx dir hash.
+                                        * s_uuid_hash serves as seed[3]. */
+/*C0*/  __le64 s_reserved2[15];                /* Fill out superblock */
 /*140*/
 
        /*
@@ -679,7 +690,7 @@ struct ocfs2_dinode {
                                           belongs to */
        __le16 i_suballoc_bit;          /* Bit offset in suballocator
                                           block group */
-/*10*/ __le16 i_reserved0;
+/*10*/ __le16 i_links_count_hi;        /* High 16 bits of links count */
        __le16 i_xattr_inline_size;
        __le32 i_clusters;              /* Cluster count */
        __le32 i_uid;                   /* Owner UID */
@@ -705,7 +716,8 @@ struct ocfs2_dinode {
        __le16 i_dyn_features;
        __le64 i_xattr_loc;
 /*80*/ struct ocfs2_block_check i_check;       /* Error checking */
-/*88*/ __le64 i_reserved2[6];
+/*88*/ __le64 i_dx_root;               /* Pointer to dir index root block */
+       __le64 i_reserved2[5];
 /*B8*/ union {
                __le64 i_pad1;          /* Generic way to refer to this
                                           64bit union */
@@ -781,6 +793,90 @@ struct ocfs2_dir_block_trailer {
 /*40*/
 };
 
+ /*
+ * A directory entry in the indexed tree. We don't store the full name here,
+ * but instead provide a pointer to the full dirent in the unindexed tree.
+ *
+ * We also store name_len here so as to reduce the number of leaf blocks we
+ * need to search in case of collisions.
+ */
+struct ocfs2_dx_entry {
+       __le32          dx_major_hash;  /* Used to find logical
+                                        * cluster in index */
+       __le32          dx_minor_hash;  /* Lower bits used to find
+                                        * block in cluster */
+       __le64          dx_dirent_blk;  /* Physical block in unindexed
+                                        * tree holding this dirent. */
+};
+
+struct ocfs2_dx_entry_list {
+       __le32          de_reserved;
+       __le16          de_count;       /* Maximum number of entries
+                                        * possible in de_entries */
+       __le16          de_num_used;    /* Current number of
+                                        * de_entries entries */
+       struct  ocfs2_dx_entry          de_entries[0];  /* Indexed dir entries
+                                                        * in a packed array of
+                                                        * length de_num_used */
+};
+
+#define OCFS2_DX_FLAG_INLINE   0x01
+
+/*
+ * A directory indexing block. Each indexed directory has one of these,
+ * pointed to by ocfs2_dinode.
+ *
+ * This block stores an indexed btree root, and a set of free space
+ * start-of-list pointers.
+ */
+struct ocfs2_dx_root_block {
+       __u8            dr_signature[8];        /* Signature for verification */
+       struct ocfs2_block_check dr_check;      /* Error checking */
+       __le16          dr_suballoc_slot;       /* Slot suballocator this
+                                                * block belongs to. */
+       __le16          dr_suballoc_bit;        /* Bit offset in suballocator
+                                                * block group */
+       __le32          dr_fs_generation;       /* Must match super block */
+       __le64          dr_blkno;               /* Offset on disk, in blocks */
+       __le64          dr_last_eb_blk;         /* Pointer to last
+                                                * extent block */
+       __le32          dr_clusters;            /* Clusters allocated
+                                                * to the indexed tree. */
+       __u8            dr_flags;               /* OCFS2_DX_FLAG_* flags */
+       __u8            dr_reserved0;
+       __le16          dr_reserved1;
+       __le64          dr_dir_blkno;           /* Pointer to parent inode */
+       __le32          dr_num_entries;         /* Total number of
+                                                * names stored in
+                                                * this directory.*/
+       __le32          dr_reserved2;
+       __le64          dr_free_blk;            /* Pointer to head of free
+                                                * unindexed block list. */
+       __le64          dr_reserved3[15];
+       union {
+               struct ocfs2_extent_list dr_list; /* Keep this aligned to 128
+                                                  * bits for maximum space
+                                                  * efficiency. */
+               struct ocfs2_dx_entry_list dr_entries; /* In-root-block list of
+                                                       * entries. We grow out
+                                                       * to extents if this
+                                                       * gets too big. */
+       };
+};
+
+/*
+ * The header of a leaf block in the indexed tree.
+ */
+struct ocfs2_dx_leaf {
+       __u8            dl_signature[8];/* Signature for verification */
+       struct ocfs2_block_check dl_check;      /* Error checking */
+       __le64          dl_blkno;       /* Offset on disk, in blocks */
+       __le32          dl_fs_generation;/* Must match super block */
+       __le32          dl_reserved0;
+       __le64          dl_reserved1;
+       struct ocfs2_dx_entry_list      dl_list;
+};
+
 /*
  * On disk allocator group structure for OCFS2
  */
@@ -1112,6 +1208,16 @@ static inline int ocfs2_extent_recs_per_inode_with_xattr(
        return size / sizeof(struct ocfs2_extent_rec);
 }
 
+static inline int ocfs2_extent_recs_per_dx_root(struct super_block *sb)
+{
+       int size;
+
+       size = sb->s_blocksize -
+               offsetof(struct ocfs2_dx_root_block, dr_list.l_recs);
+
+       return size / sizeof(struct ocfs2_extent_rec);
+}
+
 static inline int ocfs2_chain_recs_per_inode(struct super_block *sb)
 {
        int size;
@@ -1132,6 +1238,26 @@ static inline u16 ocfs2_extent_recs_per_eb(struct super_block *sb)
        return size / sizeof(struct ocfs2_extent_rec);
 }
 
+static inline int ocfs2_dx_entries_per_leaf(struct super_block *sb)
+{
+       int size;
+
+       size = sb->s_blocksize -
+               offsetof(struct ocfs2_dx_leaf, dl_list.de_entries);
+
+       return size / sizeof(struct ocfs2_dx_entry);
+}
+
+static inline int ocfs2_dx_entries_per_root(struct super_block *sb)
+{
+       int size;
+
+       size = sb->s_blocksize -
+               offsetof(struct ocfs2_dx_root_block, dr_entries.de_entries);
+
+       return size / sizeof(struct ocfs2_dx_entry);
+}
+
 static inline u16 ocfs2_local_alloc_size(struct super_block *sb)
 {
        u16 size;
index eb6f50c9cecae194cab61bb88ee5a185a90a1e93..a53ce87481bf20b1c724d2c699fab3c52674b991 100644 (file)
@@ -47,6 +47,7 @@ enum ocfs2_lock_type {
        OCFS2_LOCK_TYPE_OPEN,
        OCFS2_LOCK_TYPE_FLOCK,
        OCFS2_LOCK_TYPE_QINFO,
+       OCFS2_LOCK_TYPE_NFS_SYNC,
        OCFS2_NUM_LOCK_TYPES
 };
 
@@ -81,6 +82,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
                case OCFS2_LOCK_TYPE_QINFO:
                        c = 'Q';
                        break;
+               case OCFS2_LOCK_TYPE_NFS_SYNC:
+                       c = 'Y';
+                       break;
                default:
                        c = '\0';
        }
index a69628603e18273cdbc3d2b5d7e5a440623c17c8..b4ca5911caafc3824f6cc8c1a61e69f5a316c4eb 100644 (file)
@@ -48,7 +48,8 @@
 #include "buffer_head_io.h"
 
 #define NOT_ALLOC_NEW_GROUP            0
-#define ALLOC_NEW_GROUP                        1
+#define ALLOC_NEW_GROUP                        0x1
+#define ALLOC_GROUPS_FROM_GLOBAL       0x2
 
 #define OCFS2_MAX_INODES_TO_STEAL      1024
 
@@ -64,7 +65,9 @@ static int ocfs2_block_group_fill(handle_t *handle,
 static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
                                   struct inode *alloc_inode,
                                   struct buffer_head *bh,
-                                  u64 max_block);
+                                  u64 max_block,
+                                  u64 *last_alloc_group,
+                                  int flags);
 
 static int ocfs2_cluster_group_search(struct inode *inode,
                                      struct buffer_head *group_bh,
@@ -116,6 +119,7 @@ static inline void ocfs2_block_to_cluster_group(struct inode *inode,
                                                u16 *bg_bit_off);
 static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
                                             u32 bits_wanted, u64 max_block,
+                                            int flags,
                                             struct ocfs2_alloc_context **ac);
 
 void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
@@ -403,7 +407,9 @@ static inline u16 ocfs2_find_smallest_chain(struct ocfs2_chain_list *cl)
 static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
                                   struct inode *alloc_inode,
                                   struct buffer_head *bh,
-                                  u64 max_block)
+                                  u64 max_block,
+                                  u64 *last_alloc_group,
+                                  int flags)
 {
        int status, credits;
        struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data;
@@ -423,7 +429,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
        cl = &fe->id2.i_chain;
        status = ocfs2_reserve_clusters_with_limit(osb,
                                                   le16_to_cpu(cl->cl_cpg),
-                                                  max_block, &ac);
+                                                  max_block, flags, &ac);
        if (status < 0) {
                if (status != -ENOSPC)
                        mlog_errno(status);
@@ -440,6 +446,11 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
                goto bail;
        }
 
+       if (last_alloc_group && *last_alloc_group != 0) {
+               mlog(0, "use old allocation group %llu for block group alloc\n",
+                    (unsigned long long)*last_alloc_group);
+               ac->ac_last_group = *last_alloc_group;
+       }
        status = ocfs2_claim_clusters(osb,
                                      handle,
                                      ac,
@@ -514,6 +525,11 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
        alloc_inode->i_blocks = ocfs2_inode_sector_count(alloc_inode);
 
        status = 0;
+
+       /* save the new last alloc group so that the caller can cache it. */
+       if (last_alloc_group)
+               *last_alloc_group = ac->ac_last_group;
+
 bail:
        if (handle)
                ocfs2_commit_trans(osb, handle);
@@ -531,7 +547,8 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
                                       struct ocfs2_alloc_context *ac,
                                       int type,
                                       u32 slot,
-                                      int alloc_new_group)
+                                      u64 *last_alloc_group,
+                                      int flags)
 {
        int status;
        u32 bits_wanted = ac->ac_bits_wanted;
@@ -587,7 +604,7 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
                        goto bail;
                }
 
-               if (alloc_new_group != ALLOC_NEW_GROUP) {
+               if (!(flags & ALLOC_NEW_GROUP)) {
                        mlog(0, "Alloc File %u Full: wanted=%u, free_bits=%u, "
                             "and we don't alloc a new group for it.\n",
                             slot, bits_wanted, free_bits);
@@ -596,7 +613,8 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
                }
 
                status = ocfs2_block_group_alloc(osb, alloc_inode, bh,
-                                                ac->ac_max_block);
+                                                ac->ac_max_block,
+                                                last_alloc_group, flags);
                if (status < 0) {
                        if (status != -ENOSPC)
                                mlog_errno(status);
@@ -640,7 +658,7 @@ int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
 
        status = ocfs2_reserve_suballoc_bits(osb, (*ac),
                                             EXTENT_ALLOC_SYSTEM_INODE,
-                                            slot, ALLOC_NEW_GROUP);
+                                            slot, NULL, ALLOC_NEW_GROUP);
        if (status < 0) {
                if (status != -ENOSPC)
                        mlog_errno(status);
@@ -686,7 +704,8 @@ static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
 
                status = ocfs2_reserve_suballoc_bits(osb, ac,
                                                     INODE_ALLOC_SYSTEM_INODE,
-                                                    slot, NOT_ALLOC_NEW_GROUP);
+                                                    slot, NULL,
+                                                    NOT_ALLOC_NEW_GROUP);
                if (status >= 0) {
                        ocfs2_set_inode_steal_slot(osb, slot);
                        break;
@@ -703,6 +722,7 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
 {
        int status;
        s16 slot = ocfs2_get_inode_steal_slot(osb);
+       u64 alloc_group;
 
        *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
        if (!(*ac)) {
@@ -738,12 +758,22 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
                goto inode_steal;
 
        atomic_set(&osb->s_num_inodes_stolen, 0);
+       alloc_group = osb->osb_inode_alloc_group;
        status = ocfs2_reserve_suballoc_bits(osb, *ac,
                                             INODE_ALLOC_SYSTEM_INODE,
-                                            osb->slot_num, ALLOC_NEW_GROUP);
+                                            osb->slot_num,
+                                            &alloc_group,
+                                            ALLOC_NEW_GROUP |
+                                            ALLOC_GROUPS_FROM_GLOBAL);
        if (status >= 0) {
                status = 0;
 
+               spin_lock(&osb->osb_lock);
+               osb->osb_inode_alloc_group = alloc_group;
+               spin_unlock(&osb->osb_lock);
+               mlog(0, "after reservation, new allocation group is "
+                    "%llu\n", (unsigned long long)alloc_group);
+
                /*
                 * Some inodes must be freed by us, so try to allocate
                 * from our own next time.
@@ -790,7 +820,7 @@ int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
 
        status = ocfs2_reserve_suballoc_bits(osb, ac,
                                             GLOBAL_BITMAP_SYSTEM_INODE,
-                                            OCFS2_INVALID_SLOT,
+                                            OCFS2_INVALID_SLOT, NULL,
                                             ALLOC_NEW_GROUP);
        if (status < 0 && status != -ENOSPC) {
                mlog_errno(status);
@@ -806,6 +836,7 @@ bail:
  * things a bit. */
 static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
                                             u32 bits_wanted, u64 max_block,
+                                            int flags,
                                             struct ocfs2_alloc_context **ac)
 {
        int status;
@@ -823,7 +854,8 @@ static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
        (*ac)->ac_max_block = max_block;
 
        status = -ENOSPC;
-       if (ocfs2_alloc_should_use_local(osb, bits_wanted)) {
+       if (!(flags & ALLOC_GROUPS_FROM_GLOBAL) &&
+           ocfs2_alloc_should_use_local(osb, bits_wanted)) {
                status = ocfs2_reserve_local_alloc_bits(osb,
                                                        bits_wanted,
                                                        *ac);
@@ -861,7 +893,8 @@ int ocfs2_reserve_clusters(struct ocfs2_super *osb,
                           u32 bits_wanted,
                           struct ocfs2_alloc_context **ac)
 {
-       return ocfs2_reserve_clusters_with_limit(osb, bits_wanted, 0, ac);
+       return ocfs2_reserve_clusters_with_limit(osb, bits_wanted, 0,
+                                                ALLOC_NEW_GROUP, ac);
 }
 
 /*
@@ -1618,8 +1651,41 @@ bail:
        return status;
 }
 
+static void ocfs2_init_inode_ac_group(struct inode *dir,
+                                     struct buffer_head *parent_fe_bh,
+                                     struct ocfs2_alloc_context *ac)
+{
+       struct ocfs2_dinode *fe = (struct ocfs2_dinode *)parent_fe_bh->b_data;
+       /*
+        * Try to allocate inodes from some specific group.
+        *
+        * If the parent dir has recorded the last group used in allocation,
+        * cool, use it. Otherwise if we try to allocate new inode from the
+        * same slot the parent dir belongs to, use the same chunk.
+        *
+        * We are very careful here to avoid the mistake of setting
+        * ac_last_group to a group descriptor from a different (unlocked) slot.
+        */
+       if (OCFS2_I(dir)->ip_last_used_group &&
+           OCFS2_I(dir)->ip_last_used_slot == ac->ac_alloc_slot)
+               ac->ac_last_group = OCFS2_I(dir)->ip_last_used_group;
+       else if (le16_to_cpu(fe->i_suballoc_slot) == ac->ac_alloc_slot)
+               ac->ac_last_group = ocfs2_which_suballoc_group(
+                                       le64_to_cpu(fe->i_blkno),
+                                       le16_to_cpu(fe->i_suballoc_bit));
+}
+
+static inline void ocfs2_save_inode_ac_group(struct inode *dir,
+                                            struct ocfs2_alloc_context *ac)
+{
+       OCFS2_I(dir)->ip_last_used_group = ac->ac_last_group;
+       OCFS2_I(dir)->ip_last_used_slot = ac->ac_alloc_slot;
+}
+
 int ocfs2_claim_new_inode(struct ocfs2_super *osb,
                          handle_t *handle,
+                         struct inode *dir,
+                         struct buffer_head *parent_fe_bh,
                          struct ocfs2_alloc_context *ac,
                          u16 *suballoc_bit,
                          u64 *fe_blkno)
@@ -1635,6 +1701,8 @@ int ocfs2_claim_new_inode(struct ocfs2_super *osb,
        BUG_ON(ac->ac_bits_wanted != 1);
        BUG_ON(ac->ac_which != OCFS2_AC_USE_INODE);
 
+       ocfs2_init_inode_ac_group(dir, parent_fe_bh, ac);
+
        status = ocfs2_claim_suballoc_bits(osb,
                                           ac,
                                           handle,
@@ -1653,6 +1721,7 @@ int ocfs2_claim_new_inode(struct ocfs2_super *osb,
 
        *fe_blkno = bg_blkno + (u64) (*suballoc_bit);
        ac->ac_bits_given++;
+       ocfs2_save_inode_ac_group(dir, ac);
        status = 0;
 bail:
        mlog_exit(status);
@@ -2116,3 +2185,162 @@ out:
 
        return ret;
 }
+
+/*
+ * Read the inode specified by blkno to get suballoc_slot and
+ * suballoc_bit.
+ */
+static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno,
+                                      u16 *suballoc_slot, u16 *suballoc_bit)
+{
+       int status;
+       struct buffer_head *inode_bh = NULL;
+       struct ocfs2_dinode *inode_fe;
+
+       mlog_entry("blkno: %llu\n", blkno);
+
+       /* dirty read disk */
+       status = ocfs2_read_blocks_sync(osb, blkno, 1, &inode_bh);
+       if (status < 0) {
+               mlog(ML_ERROR, "read block %llu failed %d\n", blkno, status);
+               goto bail;
+       }
+
+       inode_fe = (struct ocfs2_dinode *) inode_bh->b_data;
+       if (!OCFS2_IS_VALID_DINODE(inode_fe)) {
+               mlog(ML_ERROR, "invalid inode %llu requested\n", blkno);
+               status = -EINVAL;
+               goto bail;
+       }
+
+       if (le16_to_cpu(inode_fe->i_suballoc_slot) != OCFS2_INVALID_SLOT &&
+           (u32)le16_to_cpu(inode_fe->i_suballoc_slot) > osb->max_slots - 1) {
+               mlog(ML_ERROR, "inode %llu has invalid suballoc slot %u\n",
+                    blkno, (u32)le16_to_cpu(inode_fe->i_suballoc_slot));
+               status = -EINVAL;
+               goto bail;
+       }
+
+       if (suballoc_slot)
+               *suballoc_slot = le16_to_cpu(inode_fe->i_suballoc_slot);
+       if (suballoc_bit)
+               *suballoc_bit = le16_to_cpu(inode_fe->i_suballoc_bit);
+
+bail:
+       brelse(inode_bh);
+
+       mlog_exit(status);
+       return status;
+}
+
+/*
+ * test whether bit is SET in allocator bitmap or not.  on success, 0
+ * is returned and *res is 1 for SET; 0 otherwise.  when fails, errno
+ * is returned and *res is meaningless.  Call this after you have
+ * cluster locked against suballoc, or you may get a result based on
+ * non-up2date contents
+ */
+static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb,
+                                  struct inode *suballoc,
+                                  struct buffer_head *alloc_bh, u64 blkno,
+                                  u16 bit, int *res)
+{
+       struct ocfs2_dinode *alloc_fe;
+       struct ocfs2_group_desc *group;
+       struct buffer_head *group_bh = NULL;
+       u64 bg_blkno;
+       int status;
+
+       mlog_entry("blkno: %llu bit: %u\n", blkno, (unsigned int)bit);
+
+       alloc_fe = (struct ocfs2_dinode *)alloc_bh->b_data;
+       if ((bit + 1) > ocfs2_bits_per_group(&alloc_fe->id2.i_chain)) {
+               mlog(ML_ERROR, "suballoc bit %u out of range of %u\n",
+                    (unsigned int)bit,
+                    ocfs2_bits_per_group(&alloc_fe->id2.i_chain));
+               status = -EINVAL;
+               goto bail;
+       }
+
+       bg_blkno = ocfs2_which_suballoc_group(blkno, bit);
+       status = ocfs2_read_group_descriptor(suballoc, alloc_fe, bg_blkno,
+                                            &group_bh);
+       if (status < 0) {
+               mlog(ML_ERROR, "read group %llu failed %d\n", bg_blkno, status);
+               goto bail;
+       }
+
+       group = (struct ocfs2_group_desc *) group_bh->b_data;
+       *res = ocfs2_test_bit(bit, (unsigned long *)group->bg_bitmap);
+
+bail:
+       brelse(group_bh);
+
+       mlog_exit(status);
+       return status;
+}
+
+/*
+ * Test if the bit representing this inode (blkno) is set in the
+ * suballocator.
+ *
+ * On success, 0 is returned and *res is 1 for SET; 0 otherwise.
+ *
+ * In the event of failure, a negative value is returned and *res is
+ * meaningless.
+ *
+ * Callers must make sure to hold nfs_sync_lock to prevent
+ * ocfs2_delete_inode() on another node from accessing the same
+ * suballocator concurrently.
+ */
+int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res)
+{
+       int status;
+       u16 suballoc_bit = 0, suballoc_slot = 0;
+       struct inode *inode_alloc_inode;
+       struct buffer_head *alloc_bh = NULL;
+
+       mlog_entry("blkno: %llu", blkno);
+
+       status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot,
+                                            &suballoc_bit);
+       if (status < 0) {
+               mlog(ML_ERROR, "get alloc slot and bit failed %d\n", status);
+               goto bail;
+       }
+
+       inode_alloc_inode =
+               ocfs2_get_system_file_inode(osb, INODE_ALLOC_SYSTEM_INODE,
+                                           suballoc_slot);
+       if (!inode_alloc_inode) {
+               /* the error code could be inaccurate, but we are not able to
+                * get the correct one. */
+               status = -EINVAL;
+               mlog(ML_ERROR, "unable to get alloc inode in slot %u\n",
+                    (u32)suballoc_slot);
+               goto bail;
+       }
+
+       mutex_lock(&inode_alloc_inode->i_mutex);
+       status = ocfs2_inode_lock(inode_alloc_inode, &alloc_bh, 0);
+       if (status < 0) {
+               mutex_unlock(&inode_alloc_inode->i_mutex);
+               mlog(ML_ERROR, "lock on alloc inode on slot %u failed %d\n",
+                    (u32)suballoc_slot, status);
+               goto bail;
+       }
+
+       status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh,
+                                        blkno, suballoc_bit, res);
+       if (status < 0)
+               mlog(ML_ERROR, "test suballoc bit failed %d\n", status);
+
+       ocfs2_inode_unlock(inode_alloc_inode, 0);
+       mutex_unlock(&inode_alloc_inode->i_mutex);
+
+       iput(inode_alloc_inode);
+       brelse(alloc_bh);
+bail:
+       mlog_exit(status);
+       return status;
+}
index e3c13c77f9e8272baa4c0aa7651caee03ea6260f..8c9a78a43164c1f900e4961d64a3dd68de174372 100644 (file)
@@ -88,6 +88,8 @@ int ocfs2_claim_metadata(struct ocfs2_super *osb,
                         u64 *blkno_start);
 int ocfs2_claim_new_inode(struct ocfs2_super *osb,
                          handle_t *handle,
+                         struct inode *dir,
+                         struct buffer_head *parent_fe_bh,
                          struct ocfs2_alloc_context *ac,
                          u16 *suballoc_bit,
                          u64 *fe_blkno);
@@ -186,4 +188,6 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et,
                          u32 clusters_to_add, u32 extents_to_split,
                          struct ocfs2_alloc_context **data_ac,
                          struct ocfs2_alloc_context **meta_ac);
+
+int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res);
 #endif /* _CHAINALLOC_H_ */
index 7ac83a81ee55d86466329d7f9b568432666b5144..79ff8d9d37e0844252130272309cd5853b04445e 100644 (file)
@@ -201,6 +201,170 @@ static const match_table_t tokens = {
        {Opt_err, NULL}
 };
 
+#ifdef CONFIG_DEBUG_FS
+static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
+{
+       int out = 0;
+       int i;
+       struct ocfs2_cluster_connection *cconn = osb->cconn;
+       struct ocfs2_recovery_map *rm = osb->recovery_map;
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Id: %-s  Uuid: %-s  Gen: 0x%X  Label: %-s\n",
+                       "Device", osb->dev_str, osb->uuid_str,
+                       osb->fs_generation, osb->vol_label);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => State: %d  Flags: 0x%lX\n", "Volume",
+                       atomic_read(&osb->vol_state), osb->osb_flags);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Block: %lu  Cluster: %d\n", "Sizes",
+                       osb->sb->s_blocksize, osb->s_clustersize);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Compat: 0x%X  Incompat: 0x%X  "
+                       "ROcompat: 0x%X\n",
+                       "Features", osb->s_feature_compat,
+                       osb->s_feature_incompat, osb->s_feature_ro_compat);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Opts: 0x%lX  AtimeQuanta: %u\n", "Mount",
+                       osb->s_mount_opt, osb->s_atime_quantum);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Stack: %s  Name: %*s  Version: %d.%d\n",
+                       "Cluster",
+                       (*osb->osb_cluster_stack == '\0' ?
+                        "o2cb" : osb->osb_cluster_stack),
+                       cconn->cc_namelen, cconn->cc_name,
+                       cconn->cc_version.pv_major, cconn->cc_version.pv_minor);
+
+       spin_lock(&osb->dc_task_lock);
+       out += snprintf(buf + out, len - out,
+                       "%10s => Pid: %d  Count: %lu  WakeSeq: %lu  "
+                       "WorkSeq: %lu\n", "DownCnvt",
+                       task_pid_nr(osb->dc_task), osb->blocked_lock_count,
+                       osb->dc_wake_sequence, osb->dc_work_sequence);
+       spin_unlock(&osb->dc_task_lock);
+
+       spin_lock(&osb->osb_lock);
+       out += snprintf(buf + out, len - out, "%10s => Pid: %d  Nodes:",
+                       "Recovery",
+                       (osb->recovery_thread_task ?
+                        task_pid_nr(osb->recovery_thread_task) : -1));
+       if (rm->rm_used == 0)
+               out += snprintf(buf + out, len - out, " None\n");
+       else {
+               for (i = 0; i < rm->rm_used; i++)
+                       out += snprintf(buf + out, len - out, " %d",
+                                       rm->rm_entries[i]);
+               out += snprintf(buf + out, len - out, "\n");
+       }
+       spin_unlock(&osb->osb_lock);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Pid: %d  Interval: %lu  Needs: %d\n", "Commit",
+                       task_pid_nr(osb->commit_task), osb->osb_commit_interval,
+                       atomic_read(&osb->needs_checkpoint));
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => State: %d  NumTxns: %d  TxnId: %lu\n",
+                       "Journal", osb->journal->j_state,
+                       atomic_read(&osb->journal->j_num_trans),
+                       osb->journal->j_trans_id);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => GlobalAllocs: %d  LocalAllocs: %d  "
+                       "SubAllocs: %d  LAWinMoves: %d  SAExtends: %d\n",
+                       "Stats",
+                       atomic_read(&osb->alloc_stats.bitmap_data),
+                       atomic_read(&osb->alloc_stats.local_data),
+                       atomic_read(&osb->alloc_stats.bg_allocs),
+                       atomic_read(&osb->alloc_stats.moves),
+                       atomic_read(&osb->alloc_stats.bg_extends));
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => State: %u  Descriptor: %llu  Size: %u bits  "
+                       "Default: %u bits\n",
+                       "LocalAlloc", osb->local_alloc_state,
+                       (unsigned long long)osb->la_last_gd,
+                       osb->local_alloc_bits, osb->local_alloc_default_bits);
+
+       spin_lock(&osb->osb_lock);
+       out += snprintf(buf + out, len - out,
+                       "%10s => Slot: %d  NumStolen: %d\n", "Steal",
+                       osb->s_inode_steal_slot,
+                       atomic_read(&osb->s_num_inodes_stolen));
+       spin_unlock(&osb->osb_lock);
+
+       out += snprintf(buf + out, len - out, "%10s => %3s  %10s\n",
+                       "Slots", "Num", "RecoGen");
+
+       for (i = 0; i < osb->max_slots; ++i) {
+               out += snprintf(buf + out, len - out,
+                               "%10s  %c %3d  %10d\n",
+                               " ",
+                               (i == osb->slot_num ? '*' : ' '),
+                               i, osb->slot_recovery_generations[i]);
+       }
+
+       return out;
+}
+
+static int ocfs2_osb_debug_open(struct inode *inode, struct file *file)
+{
+       struct ocfs2_super *osb = inode->i_private;
+       char *buf = NULL;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               goto bail;
+
+       i_size_write(inode, ocfs2_osb_dump(osb, buf, PAGE_SIZE));
+
+       file->private_data = buf;
+
+       return 0;
+bail:
+       return -ENOMEM;
+}
+
+static int ocfs2_debug_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
+static ssize_t ocfs2_debug_read(struct file *file, char __user *buf,
+                               size_t nbytes, loff_t *ppos)
+{
+       return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
+                                      i_size_read(file->f_mapping->host));
+}
+#else
+static int ocfs2_osb_debug_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+static int ocfs2_debug_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+static ssize_t ocfs2_debug_read(struct file *file, char __user *buf,
+                               size_t nbytes, loff_t *ppos)
+{
+       return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct file_operations ocfs2_osb_debug_fops = {
+       .open =         ocfs2_osb_debug_open,
+       .release =      ocfs2_debug_release,
+       .read =         ocfs2_debug_read,
+       .llseek =       generic_file_llseek,
+};
+
 /*
  * write_super and sync_fs ripped right out of ext3.
  */
@@ -926,6 +1090,16 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
                goto read_super_error;
        }
 
+       osb->osb_ctxt = debugfs_create_file("fs_state", S_IFREG|S_IRUSR,
+                                           osb->osb_debug_root,
+                                           osb,
+                                           &ocfs2_osb_debug_fops);
+       if (!osb->osb_ctxt) {
+               status = -EINVAL;
+               mlog_errno(status);
+               goto read_super_error;
+       }
+
        status = ocfs2_mount_volume(sb);
        if (osb->root_inode)
                inode = igrab(osb->root_inode);
@@ -1620,6 +1794,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
        osb = OCFS2_SB(sb);
        BUG_ON(!osb);
 
+       debugfs_remove(osb->osb_ctxt);
+
        ocfs2_disable_quotas(osb);
 
        ocfs2_shutdown_local_alloc(osb);
@@ -1742,6 +1918,12 @@ static int ocfs2_initialize_super(struct super_block *sb,
        bbits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
        sb->s_maxbytes = ocfs2_max_file_offset(bbits, cbits);
 
+       osb->osb_dx_mask = (1 << (cbits - bbits)) - 1;
+
+       for (i = 0; i < 3; i++)
+               osb->osb_dx_seed[i] = le32_to_cpu(di->id2.i_super.s_dx_seed[i]);
+       osb->osb_dx_seed[3] = le32_to_cpu(di->id2.i_super.s_uuid_hash);
+
        osb->sb = sb;
        /* Save off for ocfs2_rw_direct */
        osb->s_sectsize_bits = blksize_bits(sector_size);
@@ -2130,6 +2312,12 @@ static int ocfs2_check_volume(struct ocfs2_super *osb)
         * lock, and it's marked as dirty, set the bit in the recover
         * map and launch a recovery thread for it. */
        status = ocfs2_mark_dead_nodes(osb);
+       if (status < 0) {
+               mlog_errno(status);
+               goto finally;
+       }
+
+       status = ocfs2_compute_replay_slots(osb);
        if (status < 0)
                mlog_errno(status);
 
index 2563df89fc2a0e60f28a2e8958ddfda525099fb4..15631019dc634561838919310b2566e263f1d8dc 100644 (file)
@@ -512,7 +512,7 @@ int ocfs2_calc_xattr_init(struct inode *dir,
                          struct ocfs2_security_xattr_info *si,
                          int *want_clusters,
                          int *xattr_credits,
-                         struct ocfs2_alloc_context **xattr_ac)
+                         int *want_meta)
 {
        int ret = 0;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
@@ -554,11 +554,7 @@ int ocfs2_calc_xattr_init(struct inode *dir,
        if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE ||
            (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) ||
            (s_size + a_size) > OCFS2_XATTR_FREE_IN_IBODY) {
-               ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac);
-               if (ret) {
-                       mlog_errno(ret);
-                       return ret;
-               }
+               *want_meta = *want_meta + 1;
                *xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS;
        }
 
index 5a1ebc789f7eff51d8e364217171c3b0188983a8..1ca7e9a1b7bccbf4b34c270c7cc2009b53e3d370 100644 (file)
@@ -68,7 +68,7 @@ int ocfs2_calc_security_init(struct inode *,
                             int *, int *, struct ocfs2_alloc_context **);
 int ocfs2_calc_xattr_init(struct inode *, struct buffer_head *,
                          int, struct ocfs2_security_xattr_info *,
-                         int *, int *, struct ocfs2_alloc_context **);
+                         int *, int *, int *);
 
 /*
  * xattrs can live inside an inode, as part of an external xattr block,
index 633e9dc972bbc63edb052e89cd924aad8e25e8c3..379ae5fb441154a0f2e27fb0f9b34846c7ca089a 100644 (file)
@@ -262,14 +262,19 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *s = dentry->d_sb;
        struct omfs_sb_info *sbi = OMFS_SB(s);
+       u64 id = huge_encode_dev(s->s_bdev->bd_dev);
+
        buf->f_type = OMFS_MAGIC;
        buf->f_bsize = sbi->s_blocksize;
        buf->f_blocks = sbi->s_num_blocks;
        buf->f_files = sbi->s_num_blocks;
        buf->f_namelen = OMFS_NAMELEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        buf->f_bfree = buf->f_bavail = buf->f_ffree =
                omfs_count_free(s);
+
        return 0;
 }
 
@@ -421,7 +426,7 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
 
        sbi->s_uid = current_uid();
        sbi->s_gid = current_gid();
-       sbi->s_dmask = sbi->s_fmask = current->fs->umask;
+       sbi->s_dmask = sbi->s_fmask = current_umask();
 
        if (!parse_options((char *) data, sbi))
                goto end;
index 75b61677daafa9fdf0317ae58afd5d017ef03c2e..377eb25b6abfd84a11dadb716cb03cffe6b32f99 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -29,6 +29,7 @@
 #include <linux/rcupdate.h>
 #include <linux/audit.h>
 #include <linux/falloc.h>
+#include <linux/fs_struct.h>
 
 int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
index e0afd326b6881b7ff2506e1d9041ed12c7ce1e0d..f71559784bfb9bbc70b4d021cd2120c4bfa2121c 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/oom.h>
 #include <linux/elf.h>
 #include <linux/pid_namespace.h>
+#include <linux/fs_struct.h>
 #include "internal.h"
 
 /* NOTE:
index 5d2989e9dcc125d17aac475df1007b86f43490fd..fa678abc9db1524c35cd543c9b32a1b49e713faf 100644 (file)
@@ -37,7 +37,7 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de)
 #define PROC_BLOCK_SIZE        (PAGE_SIZE - 1024)
 
 static ssize_t
-proc_file_read(struct file *file, char __user *buf, size_t nbytes,
+__proc_file_read(struct file *file, char __user *buf, size_t nbytes,
               loff_t *ppos)
 {
        struct inode * inode = file->f_path.dentry->d_inode;
@@ -182,20 +182,48 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes,
        return retval;
 }
 
+static ssize_t
+proc_file_read(struct file *file, char __user *buf, size_t nbytes,
+              loff_t *ppos)
+{
+       struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+       ssize_t rv = -EIO;
+
+       spin_lock(&pde->pde_unload_lock);
+       if (!pde->proc_fops) {
+               spin_unlock(&pde->pde_unload_lock);
+               return rv;
+       }
+       pde->pde_users++;
+       spin_unlock(&pde->pde_unload_lock);
+
+       rv = __proc_file_read(file, buf, nbytes, ppos);
+
+       pde_users_dec(pde);
+       return rv;
+}
+
 static ssize_t
 proc_file_write(struct file *file, const char __user *buffer,
                size_t count, loff_t *ppos)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct proc_dir_entry * dp;
-       
-       dp = PDE(inode);
-
-       if (!dp->write_proc)
-               return -EIO;
+       struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+       ssize_t rv = -EIO;
+
+       if (pde->write_proc) {
+               spin_lock(&pde->pde_unload_lock);
+               if (!pde->proc_fops) {
+                       spin_unlock(&pde->pde_unload_lock);
+                       return rv;
+               }
+               pde->pde_users++;
+               spin_unlock(&pde->pde_unload_lock);
 
-       /* FIXME: does this routine need ppos?  probably... */
-       return dp->write_proc(file, buffer, count, dp->data);
+               /* FIXME: does this routine need ppos?  probably... */
+               rv = pde->write_proc(file, buffer, count, pde->data);
+               pde_users_dec(pde);
+       }
+       return rv;
 }
 
 
@@ -307,6 +335,21 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
 /*
  * Return an inode number between PROC_DYNAMIC_FIRST and
  * 0xffffffff, or zero on failure.
+ *
+ * Current inode allocations in the proc-fs (hex-numbers):
+ *
+ * 00000000            reserved
+ * 00000001-00000fff   static entries  (goners)
+ *      001            root-ino
+ *
+ * 00001000-00001fff   unused
+ * 0001xxxx-7fffxxxx   pid-dir entries for pid 1-7fff
+ * 80000000-efffffff   unused
+ * f0000000-ffffffff   dynamic entries
+ *
+ * Goal:
+ *     Once we split the thing into several virtual filesystems,
+ *     we will get rid of magical ranges (and this comment, BTW).
  */
 static unsigned int get_inode_number(void)
 {
diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt
deleted file mode 100644 (file)
index 77212f9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Current inode allocations in the proc-fs (hex-numbers):
-
-  00000000             reserved
-  00000001-00000fff    static entries  (goners)
-       001             root-ino
-
-  00001000-00001fff    unused
-  0001xxxx-7fffxxxx    pid-dir entries for pid 1-7fff
-  80000000-efffffff    unused
-  f0000000-ffffffff    dynamic entries
-
-Goal:
-       a) once we'll split the thing into several virtual filesystems we
-       will get rid of magical ranges (and this file, BTW).
index d8bb5c671f420a83c17c740425e6f71f9d85799e..d78ade305541d84a0a7b7682f203cd649c1e5a6a 100644 (file)
@@ -58,11 +58,8 @@ static void proc_delete_inode(struct inode *inode)
 
        /* Let go of any associated proc directory entry */
        de = PROC_I(inode)->pde;
-       if (de) {
-               if (de->owner)
-                       module_put(de->owner);
+       if (de)
                de_put(de);
-       }
        if (PROC_I(inode)->sysctl)
                sysctl_head_put(PROC_I(inode)->sysctl);
        clear_inode(inode);
@@ -127,7 +124,7 @@ static void __pde_users_dec(struct proc_dir_entry *pde)
                complete(pde->pde_unload_completion);
 }
 
-static void pde_users_dec(struct proc_dir_entry *pde)
+void pde_users_dec(struct proc_dir_entry *pde)
 {
        spin_lock(&pde->pde_unload_lock);
        __pde_users_dec(pde);
@@ -449,12 +446,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
 {
        struct inode * inode;
 
-       if (!try_module_get(de->owner))
-               goto out_mod;
-
        inode = iget_locked(sb, ino);
        if (!inode)
-               goto out_ino;
+               return NULL;
        if (inode->i_state & I_NEW) {
                inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
                PROC_I(inode)->fd = 0;
@@ -485,16 +479,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
                        }
                }
                unlock_new_inode(inode);
-       } else {
-              module_put(de->owner);
+       } else
               de_put(de);
-       }
        return inode;
-
-out_ino:
-       module_put(de->owner);
-out_mod:
-       return NULL;
 }                      
 
 int proc_fill_super(struct super_block *s)
index cd53ff838498de03973494d6a70ddae9f193a1ce..f6db9618a88896f741bff9d1403d20189b445e6e 100644 (file)
@@ -91,3 +91,4 @@ struct pde_opener {
        int (*release)(struct inode *, struct file *);
        struct list_head lh;
 };
+void pde_users_dec(struct proc_dir_entry *pde);
index 43d23948384addca6930aa65acbf49804226827f..74ea974f5ca6d86bd249ee920527be9c95157522 100644 (file)
@@ -120,7 +120,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                K(i.freeram-i.freehigh),
 #endif
 #ifndef CONFIG_MMU
-               K((unsigned long) atomic_read(&mmap_pages_allocated)),
+               K((unsigned long) atomic_long_read(&mmap_pages_allocated)),
 #endif
                K(i.totalswap),
                K(i.freeswap),
index b446d7ad0b0da469f02521c451b98ec8cc1bed32..7e14d1a0400122700df380aeb0746cac9c5ff8a3 100644 (file)
@@ -76,7 +76,7 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 
 /*
  * display a list of all the REGIONs the kernel knows about
- * - nommu kernals have a single flat list
+ * - nommu kernels have a single flat list
  */
 static int nommu_region_list_show(struct seq_file *m, void *_p)
 {
index d153946d6d15553223c563f901d12bd976c65832..83adcc86943742ef58bf22b4fb16a986a560450e 100644 (file)
@@ -144,17 +144,12 @@ void proc_tty_register_driver(struct tty_driver *driver)
 {
        struct proc_dir_entry *ent;
                
-       if (!driver->ops->read_proc || !driver->driver_name ||
-           driver->proc_entry)
+       if (!driver->driver_name || driver->proc_entry ||
+           !driver->ops->proc_fops)
                return;
 
-       ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver);
-       if (!ent)
-               return;
-       ent->read_proc = driver->ops->read_proc;
-       ent->owner = driver->owner;
-       ent->data = driver;
-
+       ent = proc_create_data(driver->driver_name, 0, proc_tty_driver,
+                              driver->ops->proc_fops, driver);
        driver->proc_entry = ent;
 }
 
index 94063840832ad99709d4ca878d9aff8704ac6424..b0ae0be4801f821f81c872299c135f55e6fb377c 100644 (file)
@@ -693,8 +693,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
                goto out_pages;
        }
 
-       pm.out = (u64 *)buf;
-       pm.end = (u64 *)(buf + count);
+       pm.out = (u64 __user *)buf;
+       pm.end = (u64 __user *)(buf + count);
 
        pagemap_walk.pmd_entry = pagemap_pte_range;
        pagemap_walk.pte_hole = pagemap_pte_hole;
@@ -720,9 +720,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        if (ret == PM_END_OF_BUFFER)
                ret = 0;
        /* don't need mmap_sem for these, but this looks cleaner */
-       *ppos += (char *)pm.out - buf;
+       *ppos += (char __user *)pm.out - buf;
        if (!ret)
-               ret = (char *)pm.out - buf;
+               ret = (char __user *)pm.out - buf;
 
 out_pages:
        for (; pagecount; pagecount--) {
index 343ea1216bc8e05ddc84e75af47cfbab73fee529..863464d5519c935df03a510f9ab03f7e731f14e9 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/fs_struct.h>
 #include <linux/mount.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
@@ -49,7 +50,7 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
        else
                bytes += kobjsize(mm);
        
-       if (current->fs && atomic_read(&current->fs->count) > 1)
+       if (current->fs && current->fs->users > 1)
                sbytes += kobjsize(current->fs);
        else
                bytes += kobjsize(current->fs);
@@ -136,14 +137,14 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
        }
 
        seq_printf(m,
-                  "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
+                  "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
                   vma->vm_start,
                   vma->vm_end,
                   flags & VM_READ ? 'r' : '-',
                   flags & VM_WRITE ? 'w' : '-',
                   flags & VM_EXEC ? 'x' : '-',
                   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
-                  vma->vm_pgoff << PAGE_SHIFT,
+                  (unsigned long long) vma->vm_pgoff << PAGE_SHIFT,
                   MAJOR(dev), MINOR(dev), ino, &len);
 
        if (file) {
index df26aa88fa47cd46731f506d270d2faafc2e1fbd..0c10a0b3f1460c5ff8d533de1c6304a657c097fd 100644 (file)
@@ -1,45 +1,43 @@
+#include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 #include <linux/time.h>
 #include <asm/cputime.h>
 
-static int proc_calc_metrics(char *page, char **start, off_t off,
-                                int count, int *eof, int len)
-{
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       len -= off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
-       return len;
-}
-
-static int uptime_read_proc(char *page, char **start, off_t off, int count,
-                           int *eof, void *data)
+static int uptime_proc_show(struct seq_file *m, void *v)
 {
        struct timespec uptime;
        struct timespec idle;
-       int len;
        cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
 
        do_posix_clock_monotonic_gettime(&uptime);
        monotonic_to_bootbased(&uptime);
        cputime_to_timespec(idletime, &idle);
-       len = sprintf(page, "%lu.%02lu %lu.%02lu\n",
+       seq_printf(m, "%lu.%02lu %lu.%02lu\n",
                        (unsigned long) uptime.tv_sec,
                        (uptime.tv_nsec / (NSEC_PER_SEC / 100)),
                        (unsigned long) idle.tv_sec,
                        (idle.tv_nsec / (NSEC_PER_SEC / 100)));
-       return proc_calc_metrics(page, start, off, count, eof, len);
+       return 0;
 }
 
+static int uptime_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, uptime_proc_show, NULL);
+}
+
+static const struct file_operations uptime_proc_fops = {
+       .open           = uptime_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int __init proc_uptime_init(void)
 {
-       create_proc_read_entry("uptime", 0, NULL, uptime_read_proc, NULL);
+       proc_create("uptime", 0, NULL, &uptime_proc_fops);
        return 0;
 }
 module_init(proc_uptime_init);
index 2aad1044b84ccf1342578cd66407ef88e406cf1d..fe1f0f31d11caac6854e9ced2fb471075f3bf894 100644 (file)
@@ -282,6 +282,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
 static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        lock_kernel();
 
@@ -291,6 +292,8 @@ static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bfree   = qnx4_count_free_blocks(sb);
        buf->f_bavail  = buf->f_bfree;
        buf->f_namelen = QNX4_NAME_MAX;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        unlock_kernel();
 
index 2ca967a5ef77de2011d9896695bf80ad4f0e155b..607c579e5eca0cc0427c53a844d68ff159186e47 100644 (file)
@@ -823,7 +823,7 @@ static void add_dquot_ref(struct super_block *sb, int type)
 
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+               if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
                        continue;
                if (!atomic_read(&inode->i_writecount))
                        continue;
index 995ef1d6686cf38348af80da2083eb0c90bcf2ca..ebb2c417912c0c7306d73c007b771702e7faee2e 100644 (file)
@@ -59,7 +59,6 @@ const struct inode_operations ramfs_file_inode_operations = {
  */
 int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 {
-       struct pagevec lru_pvec;
        unsigned long npages, xpages, loop, limit;
        struct page *pages;
        unsigned order;
@@ -102,24 +101,20 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
        memset(data, 0, newsize);
 
        /* attach all the pages to the inode's address space */
-       pagevec_init(&lru_pvec, 0);
        for (loop = 0; loop < npages; loop++) {
                struct page *page = pages + loop;
 
-               ret = add_to_page_cache(page, inode->i_mapping, loop, GFP_KERNEL);
+               ret = add_to_page_cache_lru(page, inode->i_mapping, loop,
+                                       GFP_KERNEL);
                if (ret < 0)
                        goto add_error;
 
-               if (!pagevec_add(&lru_pvec, page))
-                       __pagevec_lru_add_file(&lru_pvec);
-
                /* prevent the page from being discarded on memory pressure */
                SetPageDirty(page);
 
                unlock_page(page);
        }
 
-       pagevec_lru_add_file(&lru_pvec);
        return 0;
 
  fsize_exceeded:
@@ -128,10 +123,8 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
        return -EFBIG;
 
  add_error:
-       pagevec_lru_add_file(&lru_pvec);
-       page_cache_release(pages + loop);
-       for (loop++; loop < npages; loop++)
-               __free_page(pages + loop);
+       while (loop < npages)
+               __free_page(pages + loop++);
        return ret;
 }
 
index b7e6ac706b87b30ba96701b3bb7820e47f319218..a404fb88e4569ff63ef9cc001216519d702c577c 100644 (file)
 #include <linux/backing-dev.h>
 #include <linux/ramfs.h>
 #include <linux/sched.h>
+#include <linux/parser.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
 /* some random number */
 #define RAMFS_MAGIC    0x858458f6
 
+#define RAMFS_DEFAULT_MODE     0755
+
 static const struct super_operations ramfs_ops;
 static const struct inode_operations ramfs_dir_inode_operations;
 
@@ -158,12 +161,75 @@ static const struct inode_operations ramfs_dir_inode_operations = {
 static const struct super_operations ramfs_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
+       .show_options   = generic_show_options,
+};
+
+struct ramfs_mount_opts {
+       umode_t mode;
+};
+
+enum {
+       Opt_mode,
+       Opt_err
+};
+
+static const match_table_t tokens = {
+       {Opt_mode, "mode=%o"},
+       {Opt_err, NULL}
+};
+
+struct ramfs_fs_info {
+       struct ramfs_mount_opts mount_opts;
 };
 
+static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)
+{
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+       int token;
+       char *p;
+
+       opts->mode = RAMFS_DEFAULT_MODE;
+
+       while ((p = strsep(&data, ",")) != NULL) {
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               return -EINVAL;
+                       opts->mode = option & S_IALLUGO;
+                       break;
+               default:
+                       printk(KERN_ERR "ramfs: bad mount option: %s\n", p);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
 {
-       struct inode * inode;
-       struct dentry * root;
+       struct ramfs_fs_info *fsi;
+       struct inode *inode = NULL;
+       struct dentry *root;
+       int err;
+
+       save_mount_options(sb, data);
+
+       fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
+       if (!fsi) {
+               err = -ENOMEM;
+               goto fail;
+       }
+       sb->s_fs_info = fsi;
+
+       err = ramfs_parse_options(data, &fsi->mount_opts);
+       if (err)
+               goto fail;
 
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_blocksize = PAGE_CACHE_SIZE;
@@ -171,17 +237,23 @@ static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
        sb->s_magic = RAMFS_MAGIC;
        sb->s_op = &ramfs_ops;
        sb->s_time_gran = 1;
-       inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
-       if (!inode)
-               return -ENOMEM;
+       inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);
+       if (!inode) {
+               err = -ENOMEM;
+               goto fail;
+       }
 
        root = d_alloc_root(inode);
        if (!root) {
-               iput(inode);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto fail;
        }
        sb->s_root = root;
        return 0;
+fail:
+       kfree(fsi);
+       iput(inode);
+       return err;
 }
 
 int ramfs_get_sb(struct file_system_type *fs_type,
@@ -197,10 +269,16 @@ static int rootfs_get_sb(struct file_system_type *fs_type,
                            mnt);
 }
 
+static void ramfs_kill_sb(struct super_block *sb)
+{
+       kfree(sb->s_fs_info);
+       kill_litter_super(sb);
+}
+
 static struct file_system_type ramfs_fs_type = {
        .name           = "ramfs",
        .get_sb         = ramfs_get_sb,
-       .kill_sb        = kill_litter_super,
+       .kill_sb        = ramfs_kill_sb,
 };
 static struct file_system_type rootfs_fs_type = {
        .name           = "rootfs",
index 400fe81c973e90cccdb94c814325bc3ce4e39d19..6d5d8ff238aa50cdce17c4126f775d9af9b00b8f 100644 (file)
@@ -731,6 +731,56 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
        return ret;
 }
 
+SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec,
+               unsigned long, vlen, u32, pos_high, u32, pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       ssize_t ret = -EBADF;
+       int fput_needed;
+
+       if (pos < 0)
+               return -EINVAL;
+
+       file = fget_light(fd, &fput_needed);
+       if (file) {
+               ret = -ESPIPE;
+               if (file->f_mode & FMODE_PREAD)
+                       ret = vfs_readv(file, vec, vlen, &pos);
+               fput_light(file, fput_needed);
+       }
+
+       if (ret > 0)
+               add_rchar(current, ret);
+       inc_syscr(current);
+       return ret;
+}
+
+SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec,
+               unsigned long, vlen, u32, pos_high, u32, pos_low)
+{
+       loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+       struct file *file;
+       ssize_t ret = -EBADF;
+       int fput_needed;
+
+       if (pos < 0)
+               return -EINVAL;
+
+       file = fget_light(fd, &fput_needed);
+       if (file) {
+               ret = -ESPIPE;
+               if (file->f_mode & FMODE_PWRITE)
+                       ret = vfs_writev(file, vec, vlen, &pos);
+               fput_light(file, fput_needed);
+       }
+
+       if (ret > 0)
+               add_wchar(current, ret);
+       inc_syscw(current);
+       return ret;
+}
+
 static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                           size_t count, loff_t max)
 {
index 949b8c6addc84c40bf57a58d32932529957f4f09..513f431038f9a749960b6c9b328ece5799684330 100644 (file)
@@ -1,5 +1,6 @@
 config REISERFS_FS
        tristate "Reiserfs support"
+       select CRC32
        help
          Stores not just filenames but the files themselves in a balanced
          tree.  Uses journalling.
index d5066400638a5f5c292ae1eb83daae0871b7b256..9229e5514a4e13eef0fbaaef47f547bc90989a10 100644 (file)
@@ -492,7 +492,6 @@ int reiserfs_proc_info_init(struct super_block *sb)
        spin_lock_init(&__PINFO(sb).lock);
        REISERFS_SB(sb)->procdir = proc_mkdir(b, proc_info_root);
        if (REISERFS_SB(sb)->procdir) {
-               REISERFS_SB(sb)->procdir->owner = THIS_MODULE;
                REISERFS_SB(sb)->procdir->data = sb;
                add_file(sb, "version", show_version);
                add_file(sb, "super", show_super);
@@ -556,9 +555,7 @@ int reiserfs_proc_info_global_init(void)
 {
        if (proc_info_root == NULL) {
                proc_info_root = proc_mkdir(proc_info_root_name, NULL);
-               if (proc_info_root) {
-                       proc_info_root->owner = THIS_MODULE;
-               } else {
+               if (!proc_info_root) {
                        reiserfs_warning(NULL, "cannot create /proc/%s",
                                         proc_info_root_name);
                        return 1;
index 972250c62896708c0b252a424378484b3f5cc04b..0ae6486d90462ae4b644611fbd7baa221af8db57 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mnt_namespace.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/crc32.h>
 
 struct file_system_type reiserfs_fs_type;
 
@@ -1904,6 +1905,10 @@ static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bsize = dentry->d_sb->s_blocksize;
        /* changed to accommodate gcc folks. */
        buf->f_type = REISERFS_SUPER_MAGIC;
+       buf->f_fsid.val[0] = (u32)crc32_le(0, rs->s_uuid, sizeof(rs->s_uuid)/2);
+       buf->f_fsid.val[1] = (u32)crc32_le(0, rs->s_uuid + sizeof(rs->s_uuid)/2,
+                               sizeof(rs->s_uuid)/2);
+
        return 0;
 }
 
index e52743e7700060dfb25416ff52e74385d4448ab5..f83f52bae390f6484702f8e470de497b41b59921 100644 (file)
 /* Helpers for inode ops. We do this so that we don't have all the VFS
  * overhead and also for proper i_mutex annotation.
  * dir->i_mutex must be held for all of them. */
+#ifdef CONFIG_REISERFS_FS_XATTR
 static int xattr_create(struct inode *dir, struct dentry *dentry, int mode)
 {
        BUG_ON(!mutex_is_locked(&dir->i_mutex));
        vfs_dq_init(dir);
        return dir->i_op->create(dir, dentry, mode, NULL);
 }
+#endif
 
 static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
index d423416d93d14a90e894331b574f238b45055d78..c303c426fe2ba6ffec8d708323026f36fbd40f90 100644 (file)
@@ -428,7 +428,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
        } else {
              apply_umask:
                /* no ACL, apply umask */
-               inode->i_mode &= ~current->fs->umask;
+               inode->i_mode &= ~current_umask();
        }
 
        return err;
index a1a4cfe1921040d6044657e6c235e2f5d55f8292..7f40f30c55c5bdf31ecab91b9075b5d320e8ae0d 100644 (file)
@@ -513,7 +513,7 @@ int seq_bitmap(struct seq_file *m, const unsigned long *bits,
 }
 EXPORT_SYMBOL(seq_bitmap);
 
-int seq_bitmap_list(struct seq_file *m, unsigned long *bits,
+int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
                unsigned int nr_bits)
 {
        if (m->count < m->size) {
index 4ed0ba44a966ce053cdf11475333f4bdb0bb73b4..dd727d43e5b788cead6f13e85944f594791c5e14 100644 (file)
@@ -59,7 +59,8 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
                 */
                wait_on_page_writeback(page);
 
-               if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL))
+               if (page_has_private(page) &&
+                   !try_to_release_page(page, GFP_KERNEL))
                        goto out_unlock;
 
                /*
index 681ec0d83799cc22595f44aadad42ca5d63e0538..ffa6edcd2d0cd30822490df1b2d9ebcde4b44867 100644 (file)
@@ -301,6 +301,7 @@ failure:
 static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
+       u64 id = huge_encode_dev(dentry->d_sb->s_bdev->bd_dev);
 
        TRACE("Entered squashfs_statfs\n");
 
@@ -311,6 +312,8 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = msblk->inodes;
        buf->f_ffree = 0;
        buf->f_namelen = SQUASHFS_NAME_LEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        return 0;
 }
index 2ba481518ba784ec82cbe7c83fbb3801f1f17186..77cb4ec919b9a7bf941a3effe524c180343d8dee 100644 (file)
@@ -287,6 +287,7 @@ int fsync_super(struct super_block *sb)
        __fsync_super(sb);
        return sync_blockdev(sb->s_bdev);
 }
+EXPORT_SYMBOL_GPL(fsync_super);
 
 /**
  *     generic_shutdown_super  -       common helper for ->kill_sb()
index 07703d3ff4a1ebdb8729bfcbfd7d759a7afbc06a..93e0c0281d4511cc1319bcb0fdb2ed05eb1453a4 100644 (file)
@@ -234,7 +234,7 @@ static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        return ret;
 }
 
-static int bin_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct file *file = vma->vm_file;
        struct bin_buffer *bb = file->private_data;
@@ -242,15 +242,15 @@ static int bin_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        int ret;
 
        if (!bb->vm_ops)
-               return -EINVAL;
+               return VM_FAULT_SIGBUS;
 
        if (!bb->vm_ops->page_mkwrite)
                return 0;
 
        if (!sysfs_get_active_two(attr_sd))
-               return -EINVAL;
+               return VM_FAULT_SIGBUS;
 
-       ret = bb->vm_ops->page_mkwrite(vma, page);
+       ret = bb->vm_ops->page_mkwrite(vma, vmf);
 
        sysfs_put_active_two(attr_sd);
        return ret;
index 3d81bf58dae2d5ebef8f430914d3cc06d5bb9302..da20b48d350fdd674d3a7e6ec2fd64984473a20b 100644 (file)
@@ -90,6 +90,7 @@ static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        struct sysv_sb_info *sbi = SYSV_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = sb->s_magic;
        buf->f_bsize = sb->s_blocksize;
@@ -98,6 +99,8 @@ static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = sbi->s_ninodes;
        buf->f_ffree = sysv_count_free_inodes(sb);
        buf->f_namelen = SYSV_NAMELEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        return 0;
 }
 
index e35b54d5059d16226f8931fc4ed942218e5cffab..830e3f76f44265e9629e5aa59dcd445fbb91c530 100644 (file)
@@ -22,7 +22,7 @@ config UBIFS_FS_ADVANCED_COMPR
        depends on UBIFS_FS
        help
          This option allows to explicitly choose which compressions, if any,
-         are enabled in UBIFS. Removing compressors means inbility to read
+         are enabled in UBIFS. Removing compressors means inability to read
          existing file systems.
 
          If unsure, say 'N'.
@@ -32,7 +32,7 @@ config UBIFS_FS_LZO
        depends on UBIFS_FS
        default y
        help
-          LZO compressor is generally faster then zlib but compresses worse.
+          LZO compressor is generally faster than zlib but compresses worse.
           Say 'Y' if unsure.
 
 config UBIFS_FS_ZLIB
index 93b6de51f261727f2c5f4e62814a0e79d3b109b5..0ff89fe71e5103c3effe3dfd27dc2bac58b8bfc5 100644 (file)
@@ -1434,8 +1434,9 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
  * mmap()d file has taken write protection fault and is being made
  * writable. UBIFS must ensure page is budgeted for.
  */
-static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
+       struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        struct timespec now = ubifs_current_time(inode);
@@ -1447,7 +1448,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY));
 
        if (unlikely(c->ro_media))
-               return -EROFS;
+               return VM_FAULT_SIGBUS; /* -EROFS */
 
        /*
         * We have not locked @page so far so we may budget for changing the
@@ -1480,7 +1481,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
                if (err == -ENOSPC)
                        ubifs_warn("out of space for mmapped file "
                                   "(inode number %lu)", inode->i_ino);
-               return err;
+               return VM_FAULT_SIGBUS;
        }
 
        lock_page(page);
@@ -1520,6 +1521,8 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
 out_unlock:
        unlock_page(page);
        ubifs_release_budget(c, &req);
+       if (err)
+               err = VM_FAULT_SIGBUS;
        return err;
 }
 
index 2bb788a2acb16bf24ab25a708390e58842f06116..e48e9a3af76312d683723658ed42c51db7d8a740 100644 (file)
@@ -87,12 +87,12 @@ static int read_block_bitmap(struct super_block *sb,
 {
        struct buffer_head *bh = NULL;
        int retval = 0;
-       kernel_lb_addr loc;
+       struct kernel_lb_addr loc;
 
        loc.logicalBlockNum = bitmap->s_extPosition;
        loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
 
-       bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block));
+       bh = udf_tread(sb, udf_get_lb_pblock(sb, &loc, block));
        if (!bh)
                retval = -EIO;
 
@@ -140,27 +140,29 @@ static inline int load_block_bitmap(struct super_block *sb,
        return slot;
 }
 
-static bool udf_add_free_space(struct udf_sb_info *sbi,
-                               u16 partition, u32 cnt)
+static void udf_add_free_space(struct super_block *sb, u16 partition, u32 cnt)
 {
+       struct udf_sb_info *sbi = UDF_SB(sb);
        struct logicalVolIntegrityDesc *lvid;
 
-       if (sbi->s_lvid_bh == NULL)
-               return false;
+       if (!sbi->s_lvid_bh)
+               return;
 
        lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
        le32_add_cpu(&lvid->freeSpaceTable[partition], cnt);
-       return true;
+       udf_updated_lvid(sb);
 }
 
 static void udf_bitmap_free_blocks(struct super_block *sb,
                                   struct inode *inode,
                                   struct udf_bitmap *bitmap,
-                                  kernel_lb_addr bloc, uint32_t offset,
+                                  struct kernel_lb_addr *bloc,
+                                  uint32_t offset,
                                   uint32_t count)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct buffer_head *bh = NULL;
+       struct udf_part_map *partmap;
        unsigned long block;
        unsigned long block_group;
        unsigned long bit;
@@ -169,17 +171,17 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
        unsigned long overflow;
 
        mutex_lock(&sbi->s_alloc_mutex);
-       if (bloc.logicalBlockNum < 0 ||
-           (bloc.logicalBlockNum + count) >
-               sbi->s_partmaps[bloc.partitionReferenceNum].s_partition_len) {
+       partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
+       if (bloc->logicalBlockNum < 0 ||
+           (bloc->logicalBlockNum + count) >
+               partmap->s_partition_len) {
                udf_debug("%d < %d || %d + %d > %d\n",
-                         bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
-                         sbi->s_partmaps[bloc.partitionReferenceNum].
-                                                       s_partition_len);
+                         bloc->logicalBlockNum, 0, bloc->logicalBlockNum,
+                         count, partmap->s_partition_len);
                goto error_return;
        }
 
-       block = bloc.logicalBlockNum + offset +
+       block = bloc->logicalBlockNum + offset +
                (sizeof(struct spaceBitmapDesc) << 3);
 
        do {
@@ -207,7 +209,7 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
                        } else {
                                if (inode)
                                        vfs_dq_free_block(inode, 1);
-                               udf_add_free_space(sbi, sbi->s_partition, 1);
+                               udf_add_free_space(sb, sbi->s_partition, 1);
                        }
                }
                mark_buffer_dirty(bh);
@@ -218,9 +220,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
        } while (overflow);
 
 error_return:
-       sb->s_dirt = 1;
-       if (sbi->s_lvid_bh)
-               mark_buffer_dirty(sbi->s_lvid_bh);
        mutex_unlock(&sbi->s_alloc_mutex);
 }
 
@@ -277,9 +276,7 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb,
        } while (block_count > 0);
 
 out:
-       if (udf_add_free_space(sbi, partition, -alloc_count))
-               mark_buffer_dirty(sbi->s_lvid_bh);
-       sb->s_dirt = 1;
+       udf_add_free_space(sb, partition, -alloc_count);
        mutex_unlock(&sbi->s_alloc_mutex);
        return alloc_count;
 }
@@ -409,9 +406,7 @@ got_block:
 
        mark_buffer_dirty(bh);
 
-       if (udf_add_free_space(sbi, partition, -1))
-               mark_buffer_dirty(sbi->s_lvid_bh);
-       sb->s_dirt = 1;
+       udf_add_free_space(sb, partition, -1);
        mutex_unlock(&sbi->s_alloc_mutex);
        *err = 0;
        return newblock;
@@ -425,26 +420,28 @@ error_return:
 static void udf_table_free_blocks(struct super_block *sb,
                                  struct inode *inode,
                                  struct inode *table,
-                                 kernel_lb_addr bloc, uint32_t offset,
+                                 struct kernel_lb_addr *bloc,
+                                 uint32_t offset,
                                  uint32_t count)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *partmap;
        uint32_t start, end;
        uint32_t elen;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        struct extent_position oepos, epos;
        int8_t etype;
        int i;
        struct udf_inode_info *iinfo;
 
        mutex_lock(&sbi->s_alloc_mutex);
-       if (bloc.logicalBlockNum < 0 ||
-           (bloc.logicalBlockNum + count) >
-               sbi->s_partmaps[bloc.partitionReferenceNum].s_partition_len) {
+       partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
+       if (bloc->logicalBlockNum < 0 ||
+           (bloc->logicalBlockNum + count) >
+               partmap->s_partition_len) {
                udf_debug("%d < %d || %d + %d > %d\n",
                          bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
-                         sbi->s_partmaps[bloc.partitionReferenceNum].
-                                                       s_partition_len);
+                         partmap->s_partition_len);
                goto error_return;
        }
 
@@ -453,11 +450,10 @@ static void udf_table_free_blocks(struct super_block *sb,
           could occure, but.. oh well */
        if (inode)
                vfs_dq_free_block(inode, count);
-       if (udf_add_free_space(sbi, sbi->s_partition, count))
-               mark_buffer_dirty(sbi->s_lvid_bh);
+       udf_add_free_space(sb, sbi->s_partition, count);
 
-       start = bloc.logicalBlockNum + offset;
-       end = bloc.logicalBlockNum + offset + count - 1;
+       start = bloc->logicalBlockNum + offset;
+       end = bloc->logicalBlockNum + offset + count - 1;
 
        epos.offset = oepos.offset = sizeof(struct unallocSpaceEntry);
        elen = 0;
@@ -483,7 +479,7 @@ static void udf_table_free_blocks(struct super_block *sb,
                                start += count;
                                count = 0;
                        }
-                       udf_write_aext(table, &oepos, eloc, elen, 1);
+                       udf_write_aext(table, &oepos, &eloc, elen, 1);
                } else if (eloc.logicalBlockNum == (end + 1)) {
                        if ((0x3FFFFFFF - elen) <
                                        (count << sb->s_blocksize_bits)) {
@@ -502,7 +498,7 @@ static void udf_table_free_blocks(struct super_block *sb,
                                end -= count;
                                count = 0;
                        }
-                       udf_write_aext(table, &oepos, eloc, elen, 1);
+                       udf_write_aext(table, &oepos, &eloc, elen, 1);
                }
 
                if (epos.bh != oepos.bh) {
@@ -532,8 +528,8 @@ static void udf_table_free_blocks(struct super_block *sb,
                 */
 
                int adsize;
-               short_ad *sad = NULL;
-               long_ad *lad = NULL;
+               struct short_ad *sad = NULL;
+               struct long_ad *lad = NULL;
                struct allocExtDesc *aed;
 
                eloc.logicalBlockNum = start;
@@ -541,9 +537,9 @@ static void udf_table_free_blocks(struct super_block *sb,
                        (count << sb->s_blocksize_bits);
 
                if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-                       adsize = sizeof(short_ad);
+                       adsize = sizeof(struct short_ad);
                else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-                       adsize = sizeof(long_ad);
+                       adsize = sizeof(struct long_ad);
                else {
                        brelse(oepos.bh);
                        brelse(epos.bh);
@@ -563,7 +559,7 @@ static void udf_table_free_blocks(struct super_block *sb,
                        elen -= sb->s_blocksize;
 
                        epos.bh = udf_tread(sb,
-                                       udf_get_lb_pblock(sb, epos.block, 0));
+                                       udf_get_lb_pblock(sb, &epos.block, 0));
                        if (!epos.bh) {
                                brelse(oepos.bh);
                                goto error_return;
@@ -601,15 +597,15 @@ static void udf_table_free_blocks(struct super_block *sb,
                        if (sbi->s_udfrev >= 0x0200)
                                udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
                                            3, 1, epos.block.logicalBlockNum,
-                                           sizeof(tag));
+                                           sizeof(struct tag));
                        else
                                udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
                                            2, 1, epos.block.logicalBlockNum,
-                                           sizeof(tag));
+                                           sizeof(struct tag));
 
                        switch (iinfo->i_alloc_type) {
                        case ICBTAG_FLAG_AD_SHORT:
-                               sad = (short_ad *)sptr;
+                               sad = (struct short_ad *)sptr;
                                sad->extLength = cpu_to_le32(
                                        EXT_NEXT_EXTENT_ALLOCDECS |
                                        sb->s_blocksize);
@@ -617,7 +613,7 @@ static void udf_table_free_blocks(struct super_block *sb,
                                        cpu_to_le32(epos.block.logicalBlockNum);
                                break;
                        case ICBTAG_FLAG_AD_LONG:
-                               lad = (long_ad *)sptr;
+                               lad = (struct long_ad *)sptr;
                                lad->extLength = cpu_to_le32(
                                        EXT_NEXT_EXTENT_ALLOCDECS |
                                        sb->s_blocksize);
@@ -635,7 +631,7 @@ static void udf_table_free_blocks(struct super_block *sb,
 
                /* It's possible that stealing the block emptied the extent */
                if (elen) {
-                       udf_write_aext(table, &epos, eloc, elen, 1);
+                       udf_write_aext(table, &epos, &eloc, elen, 1);
 
                        if (!epos.bh) {
                                iinfo->i_lenAlloc += adsize;
@@ -653,7 +649,6 @@ static void udf_table_free_blocks(struct super_block *sb,
        brelse(oepos.bh);
 
 error_return:
-       sb->s_dirt = 1;
        mutex_unlock(&sbi->s_alloc_mutex);
        return;
 }
@@ -666,7 +661,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
        struct udf_sb_info *sbi = UDF_SB(sb);
        int alloc_count = 0;
        uint32_t elen, adsize;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        struct extent_position epos;
        int8_t etype = -1;
        struct udf_inode_info *iinfo;
@@ -677,9 +672,9 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
 
        iinfo = UDF_I(table);
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               adsize = sizeof(short_ad);
+               adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
        else
                return 0;
 
@@ -707,7 +702,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
                        alloc_count = block_count;
                        eloc.logicalBlockNum += alloc_count;
                        elen -= (alloc_count << sb->s_blocksize_bits);
-                       udf_write_aext(table, &epos, eloc,
+                       udf_write_aext(table, &epos, &eloc,
                                        (etype << 30) | elen, 1);
                } else
                        udf_delete_aext(table, epos, eloc,
@@ -718,10 +713,8 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
 
        brelse(epos.bh);
 
-       if (alloc_count && udf_add_free_space(sbi, partition, -alloc_count)) {
-               mark_buffer_dirty(sbi->s_lvid_bh);
-               sb->s_dirt = 1;
-       }
+       if (alloc_count)
+               udf_add_free_space(sb, partition, -alloc_count);
        mutex_unlock(&sbi->s_alloc_mutex);
        return alloc_count;
 }
@@ -735,7 +728,7 @@ static int udf_table_new_block(struct super_block *sb,
        uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
        uint32_t newblock = 0, adsize;
        uint32_t elen, goal_elen = 0;
-       kernel_lb_addr eloc, uninitialized_var(goal_eloc);
+       struct kernel_lb_addr eloc, uninitialized_var(goal_eloc);
        struct extent_position epos, goal_epos;
        int8_t etype;
        struct udf_inode_info *iinfo = UDF_I(table);
@@ -743,9 +736,9 @@ static int udf_table_new_block(struct super_block *sb,
        *err = -ENOSPC;
 
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               adsize = sizeof(short_ad);
+               adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
        else
                return newblock;
 
@@ -814,46 +807,37 @@ static int udf_table_new_block(struct super_block *sb,
        }
 
        if (goal_elen)
-               udf_write_aext(table, &goal_epos, goal_eloc, goal_elen, 1);
+               udf_write_aext(table, &goal_epos, &goal_eloc, goal_elen, 1);
        else
                udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
        brelse(goal_epos.bh);
 
-       if (udf_add_free_space(sbi, partition, -1))
-               mark_buffer_dirty(sbi->s_lvid_bh);
+       udf_add_free_space(sb, partition, -1);
 
-       sb->s_dirt = 1;
        mutex_unlock(&sbi->s_alloc_mutex);
        *err = 0;
        return newblock;
 }
 
-inline void udf_free_blocks(struct super_block *sb,
-                           struct inode *inode,
-                           kernel_lb_addr bloc, uint32_t offset,
-                           uint32_t count)
+void udf_free_blocks(struct super_block *sb, struct inode *inode,
+                    struct kernel_lb_addr *bloc, uint32_t offset,
+                    uint32_t count)
 {
-       uint16_t partition = bloc.partitionReferenceNum;
+       uint16_t partition = bloc->partitionReferenceNum;
        struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
 
        if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
-               return udf_bitmap_free_blocks(sb, inode,
-                                             map->s_uspace.s_bitmap,
-                                             bloc, offset, count);
+               udf_bitmap_free_blocks(sb, inode, map->s_uspace.s_bitmap,
+                                      bloc, offset, count);
        } else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) {
-               return udf_table_free_blocks(sb, inode,
-                                            map->s_uspace.s_table,
-                                            bloc, offset, count);
+               udf_table_free_blocks(sb, inode, map->s_uspace.s_table,
+                                     bloc, offset, count);
        } else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) {
-               return udf_bitmap_free_blocks(sb, inode,
-                                             map->s_fspace.s_bitmap,
-                                             bloc, offset, count);
+               udf_bitmap_free_blocks(sb, inode, map->s_fspace.s_bitmap,
+                                      bloc, offset, count);
        } else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) {
-               return udf_table_free_blocks(sb, inode,
-                                            map->s_fspace.s_table,
-                                            bloc, offset, count);
-       } else {
-               return;
+               udf_table_free_blocks(sb, inode, map->s_fspace.s_table,
+                                     bloc, offset, count);
        }
 }
 
index 62dc270c69d1addaffb0919e1d5308421a2d1200..2efd4d5291b69cd8fb6c3be7ee020cd54d15f962 100644 (file)
@@ -51,7 +51,7 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
        uint8_t lfi;
        loff_t size = udf_ext0_offset(dir) + dir->i_size;
        struct buffer_head *tmp, *bha[16];
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
        int i, num, ret = 0;
@@ -80,13 +80,13 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
                        ret = -ENOENT;
                        goto out;
                }
-               block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-                               epos.offset -= sizeof(short_ad);
+                               epos.offset -= sizeof(struct short_ad);
                        else if (iinfo->i_alloc_type ==
                                        ICBTAG_FLAG_AD_LONG)
-                               epos.offset -= sizeof(long_ad);
+                               epos.offset -= sizeof(struct long_ad);
                } else {
                        offset = 0;
                }
@@ -101,7 +101,7 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
                        if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
                                i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
                        for (num = 0; i > 0; i--) {
-                               block = udf_get_lb_pblock(dir->i_sb, eloc, offset + i);
+                               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset + i);
                                tmp = udf_tgetblk(dir->i_sb, block);
                                if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
                                        bha[num++] = tmp;
@@ -161,9 +161,9 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
                        memcpy(fname, "..", flen);
                        dt_type = DT_DIR;
                } else {
-                       kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
+                       struct kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
 
-                       iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0);
+                       iblock = udf_get_lb_pblock(dir->i_sb, &tloc, 0);
                        flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
                        dt_type = DT_UNKNOWN;
                }
index 2820f8fcf4cc2e932b72f70cf25a7c69586546d9..1d2c570704c8f217ecf756a9b08c63457e139484 100644 (file)
@@ -20,7 +20,7 @@
 
 #if 0
 static uint8_t *udf_filead_read(struct inode *dir, uint8_t *tmpad,
-                               uint8_t ad_size, kernel_lb_addr fe_loc,
+                               uint8_t ad_size, struct kernel_lb_addr fe_loc,
                                int *pos, int *offset, struct buffer_head **bh,
                                int *error)
 {
@@ -75,7 +75,7 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
                                         struct udf_fileident_bh *fibh,
                                         struct fileIdentDesc *cfi,
                                         struct extent_position *epos,
-                                        kernel_lb_addr *eloc, uint32_t *elen,
+                                        struct kernel_lb_addr *eloc, uint32_t *elen,
                                         sector_t *offset)
 {
        struct fileIdentDesc *fi;
@@ -111,7 +111,7 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
                    (EXT_RECORDED_ALLOCATED >> 30))
                        return NULL;
 
-               block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
+               block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
 
                (*offset)++;
 
@@ -131,7 +131,7 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
                        if (i + *offset > (*elen >> blocksize_bits))
                                i = (*elen >> blocksize_bits)-*offset;
                        for (num = 0; i > 0; i--) {
-                               block = udf_get_lb_pblock(dir->i_sb, *eloc,
+                               block = udf_get_lb_pblock(dir->i_sb, eloc,
                                                          *offset + i);
                                tmp = udf_tgetblk(dir->i_sb, block);
                                if (tmp && !buffer_uptodate(tmp) &&
@@ -169,7 +169,7 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
                    (EXT_RECORDED_ALLOCATED >> 30))
                        return NULL;
 
-               block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
+               block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
 
                (*offset)++;
 
@@ -249,9 +249,9 @@ struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
 }
 
 #if 0
-static extent_ad *udf_get_fileextent(void *buffer, int bufsize, int *offset)
+static struct extent_ad *udf_get_fileextent(void *buffer, int bufsize, int *offset)
 {
-       extent_ad *ext;
+       struct extent_ad *ext;
        struct fileEntry *fe;
        uint8_t *ptr;
 
@@ -274,54 +274,54 @@ static extent_ad *udf_get_fileextent(void *buffer, int bufsize, int *offset)
        if ((*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)))
                ptr += *offset;
 
-       ext = (extent_ad *)ptr;
+       ext = (struct extent_ad *)ptr;
 
-       *offset = *offset + sizeof(extent_ad);
+       *offset = *offset + sizeof(struct extent_ad);
        return ext;
 }
 #endif
 
-short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
+struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
                              int inc)
 {
-       short_ad *sa;
+       struct short_ad *sa;
 
        if ((!ptr) || (!offset)) {
                printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
                return NULL;
        }
 
-       if ((*offset + sizeof(short_ad)) > maxoffset)
+       if ((*offset + sizeof(struct short_ad)) > maxoffset)
                return NULL;
        else {
-               sa = (short_ad *)ptr;
+               sa = (struct short_ad *)ptr;
                if (sa->extLength == 0)
                        return NULL;
        }
 
        if (inc)
-               *offset += sizeof(short_ad);
+               *offset += sizeof(struct short_ad);
        return sa;
 }
 
-long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
+struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
 {
-       long_ad *la;
+       struct long_ad *la;
 
        if ((!ptr) || (!offset)) {
                printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
                return NULL;
        }
 
-       if ((*offset + sizeof(long_ad)) > maxoffset)
+       if ((*offset + sizeof(struct long_ad)) > maxoffset)
                return NULL;
        else {
-               la = (long_ad *)ptr;
+               la = (struct long_ad *)ptr;
                if (la->extLength == 0)
                        return NULL;
        }
 
        if (inc)
-               *offset += sizeof(long_ad);
+               *offset += sizeof(struct long_ad);
        return la;
 }
index a0974df82b318b27d2be5e772eb5cf276f6658e1..4792b771aa8073231ee46116af2bfffe009b92a3 100644 (file)
 #define _ECMA_167_H 1
 
 /* Character set specification (ECMA 167r3 1/7.2.1) */
-typedef struct {
+struct charspec {
        uint8_t         charSetType;
        uint8_t         charSetInfo[63];
-} __attribute__ ((packed)) charspec;
+} __attribute__ ((packed));
 
 /* Character Set Type (ECMA 167r3 1/7.2.1.1) */
 #define CHARSPEC_TYPE_CS0              0x00    /* (1/7.2.2) */
@@ -57,7 +57,7 @@ typedef struct {
 typedef uint8_t                dstring;
 
 /* Timestamp (ECMA 167r3 1/7.3) */
-typedef struct {
+struct timestamp {
        __le16          typeAndTimezone;
        __le16          year;
        uint8_t         month;
@@ -68,7 +68,7 @@ typedef struct {
        uint8_t         centiseconds;
        uint8_t         hundredsOfMicroseconds;
        uint8_t         microseconds;
-} __attribute__ ((packed)) timestamp;
+} __attribute__ ((packed));
 
 /* Type and Time Zone (ECMA 167r3 1/7.3.1) */
 #define TIMESTAMP_TYPE_MASK            0xF000
@@ -78,11 +78,11 @@ typedef struct {
 #define TIMESTAMP_TIMEZONE_MASK                0x0FFF
 
 /* Entity identifier (ECMA 167r3 1/7.4) */
-typedef struct {
+struct regid {
        uint8_t         flags;
        uint8_t         ident[23];
        uint8_t         identSuffix[8];
-} __attribute__ ((packed)) regid;
+} __attribute__ ((packed));
 
 /* Flags (ECMA 167r3 1/7.4.1) */
 #define ENTITYID_FLAGS_DIRTY           0x00
@@ -126,38 +126,38 @@ struct terminatingExtendedAreaDesc {
 
 /* Boot Descriptor (ECMA 167r3 2/9.4) */
 struct bootDesc {
-       uint8_t         structType;
-       uint8_t         stdIdent[VSD_STD_ID_LEN];
-       uint8_t         structVersion;
-       uint8_t         reserved1;
-       regid           archType;
-       regid           bootIdent;
-       __le32          bootExtLocation;
-       __le32          bootExtLength;
-       __le64          loadAddress;
-       __le64          startAddress;
-       timestamp       descCreationDateAndTime;
-       __le16          flags;
-       uint8_t         reserved2[32];
-       uint8_t         bootUse[1906];
+       uint8_t                 structType;
+       uint8_t                 stdIdent[VSD_STD_ID_LEN];
+       uint8_t                 structVersion;
+       uint8_t                 reserved1;
+       struct regid            archType;
+       struct regid            bootIdent;
+       __le32                  bootExtLocation;
+       __le32                  bootExtLength;
+       __le64                  loadAddress;
+       __le64                  startAddress;
+       struct timestamp        descCreationDateAndTime;
+       __le16                  flags;
+       uint8_t                 reserved2[32];
+       uint8_t                 bootUse[1906];
 } __attribute__ ((packed));
 
 /* Flags (ECMA 167r3 2/9.4.12) */
 #define BOOT_FLAGS_ERASE               0x01
 
 /* Extent Descriptor (ECMA 167r3 3/7.1) */
-typedef struct {
+struct extent_ad {
        __le32          extLength;
        __le32          extLocation;
-} __attribute__ ((packed)) extent_ad;
+} __attribute__ ((packed));
 
-typedef struct {
+struct kernel_extent_ad {
        uint32_t        extLength;
        uint32_t        extLocation;
-} kernel_extent_ad;
+};
 
 /* Descriptor Tag (ECMA 167r3 3/7.2) */
-typedef struct {
+struct tag {
        __le16          tagIdent;
        __le16          descVersion;
        uint8_t         tagChecksum;
@@ -166,7 +166,7 @@ typedef struct {
        __le16          descCRC;
        __le16          descCRCLength;
        __le32          tagLocation;
-} __attribute__ ((packed)) tag;
+} __attribute__ ((packed));
 
 /* Tag Identifier (ECMA 167r3 3/7.2.1) */
 #define TAG_IDENT_PVD                  0x0001
@@ -190,28 +190,28 @@ struct NSRDesc {
 
 /* Primary Volume Descriptor (ECMA 167r3 3/10.1) */
 struct primaryVolDesc {
-       tag             descTag;
-       __le32          volDescSeqNum;
-       __le32          primaryVolDescNum;
-       dstring         volIdent[32];
-       __le16          volSeqNum;
-       __le16          maxVolSeqNum;
-       __le16          interchangeLvl;
-       __le16          maxInterchangeLvl;
-       __le32          charSetList;
-       __le32          maxCharSetList;
-       dstring         volSetIdent[128];
-       charspec        descCharSet;
-       charspec        explanatoryCharSet;
-       extent_ad       volAbstract;
-       extent_ad       volCopyright;
-       regid           appIdent;
-       timestamp       recordingDateAndTime;
-       regid           impIdent;
-       uint8_t         impUse[64];
-       __le32          predecessorVolDescSeqLocation;
-       __le16          flags;
-       uint8_t         reserved[22];
+       struct tag              descTag;
+       __le32                  volDescSeqNum;
+       __le32                  primaryVolDescNum;
+       dstring                 volIdent[32];
+       __le16                  volSeqNum;
+       __le16                  maxVolSeqNum;
+       __le16                  interchangeLvl;
+       __le16                  maxInterchangeLvl;
+       __le32                  charSetList;
+       __le32                  maxCharSetList;
+       dstring                 volSetIdent[128];
+       struct charspec         descCharSet;
+       struct charspec         explanatoryCharSet;
+       struct extent_ad        volAbstract;
+       struct extent_ad        volCopyright;
+       struct regid            appIdent;
+       struct timestamp        recordingDateAndTime;
+       struct regid            impIdent;
+       uint8_t                 impUse[64];
+       __le32                  predecessorVolDescSeqLocation;
+       __le16                  flags;
+       uint8_t                 reserved[22];
 } __attribute__ ((packed));
 
 /* Flags (ECMA 167r3 3/10.1.21) */
@@ -219,40 +219,40 @@ struct primaryVolDesc {
 
 /* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) */
 struct anchorVolDescPtr {
-       tag             descTag;
-       extent_ad       mainVolDescSeqExt;
-       extent_ad       reserveVolDescSeqExt;
-       uint8_t         reserved[480];
+       struct tag              descTag;
+       struct extent_ad        mainVolDescSeqExt;
+       struct extent_ad        reserveVolDescSeqExt;
+       uint8_t                 reserved[480];
 } __attribute__ ((packed));
 
 /* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
 struct volDescPtr {
-       tag             descTag;
-       __le32          volDescSeqNum;
-       extent_ad       nextVolDescSeqExt;
-       uint8_t         reserved[484];
+       struct tag              descTag;
+       __le32                  volDescSeqNum;
+       struct extent_ad        nextVolDescSeqExt;
+       uint8_t                 reserved[484];
 } __attribute__ ((packed));
 
 /* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
 struct impUseVolDesc {
-       tag             descTag;
+       struct tag      descTag;
        __le32          volDescSeqNum;
-       regid           impIdent;
+       struct regid    impIdent;
        uint8_t         impUse[460];
 } __attribute__ ((packed));
 
 /* Partition Descriptor (ECMA 167r3 3/10.5) */
 struct partitionDesc {
-       tag descTag;
+       struct tag descTag;
        __le32 volDescSeqNum;
        __le16 partitionFlags;
        __le16 partitionNumber;
-       regid partitionContents;
+       struct regid partitionContents;
        uint8_t partitionContentsUse[128];
        __le32 accessType;
        __le32 partitionStartingLocation;
        __le32 partitionLength;
-       regid impIdent;
+       struct regid impIdent;
        uint8_t impUse[128];
        uint8_t reserved[156];
 } __attribute__ ((packed));
@@ -278,19 +278,19 @@ struct partitionDesc {
 
 /* Logical Volume Descriptor (ECMA 167r3 3/10.6) */
 struct logicalVolDesc {
-       tag             descTag;
-       __le32          volDescSeqNum;
-       charspec        descCharSet;
-       dstring         logicalVolIdent[128];
-       __le32          logicalBlockSize;
-       regid           domainIdent;
-       uint8_t         logicalVolContentsUse[16];
-       __le32          mapTableLength;
-       __le32          numPartitionMaps;
-       regid           impIdent;
-       uint8_t         impUse[128];
-       extent_ad       integritySeqExt;
-       uint8_t         partitionMaps[0];
+       struct tag              descTag;
+       __le32                  volDescSeqNum;
+       struct charspec         descCharSet;
+       dstring                 logicalVolIdent[128];
+       __le32                  logicalBlockSize;
+       struct regid            domainIdent;
+       uint8_t                 logicalVolContentsUse[16];
+       __le32                  mapTableLength;
+       __le32                  numPartitionMaps;
+       struct regid            impIdent;
+       uint8_t                 impUse[128];
+       struct extent_ad        integritySeqExt;
+       uint8_t                 partitionMaps[0];
 } __attribute__ ((packed));
 
 /* Generic Partition Map (ECMA 167r3 3/10.7.1) */
@@ -322,30 +322,30 @@ struct genericPartitionMap2 {
 
 /* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */
 struct unallocSpaceDesc {
-       tag             descTag;
-       __le32          volDescSeqNum;
-       __le32          numAllocDescs;
-       extent_ad       allocDescs[0];
+       struct tag              descTag;
+       __le32                  volDescSeqNum;
+       __le32                  numAllocDescs;
+       struct extent_ad        allocDescs[0];
 } __attribute__ ((packed));
 
 /* Terminating Descriptor (ECMA 167r3 3/10.9) */
 struct terminatingDesc {
-       tag             descTag;
+       struct tag      descTag;
        uint8_t         reserved[496];
 } __attribute__ ((packed));
 
 /* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
 struct logicalVolIntegrityDesc {
-       tag             descTag;
-       timestamp       recordingDateAndTime;
-       __le32          integrityType;
-       extent_ad       nextIntegrityExt;
-       uint8_t         logicalVolContentsUse[32];
-       __le32          numOfPartitions;
-       __le32          lengthOfImpUse;
-       __le32          freeSpaceTable[0];
-       __le32          sizeTable[0];
-       uint8_t         impUse[0];
+       struct tag              descTag;
+       struct timestamp        recordingDateAndTime;
+       __le32                  integrityType;
+       struct extent_ad        nextIntegrityExt;
+       uint8_t                 logicalVolContentsUse[32];
+       __le32                  numOfPartitions;
+       __le32                  lengthOfImpUse;
+       __le32                  freeSpaceTable[0];
+       __le32                  sizeTable[0];
+       uint8_t                 impUse[0];
 } __attribute__ ((packed));
 
 /* Integrity Type (ECMA 167r3 3/10.10.3) */
@@ -353,50 +353,50 @@ struct logicalVolIntegrityDesc {
 #define LVID_INTEGRITY_TYPE_CLOSE      0x00000001
 
 /* Recorded Address (ECMA 167r3 4/7.1) */
-typedef struct {
+struct lb_addr {
        __le32          logicalBlockNum;
        __le16          partitionReferenceNum;
-} __attribute__ ((packed)) lb_addr;
+} __attribute__ ((packed));
 
 /* ... and its in-core analog */
-typedef struct {
+struct kernel_lb_addr {
        uint32_t                logicalBlockNum;
        uint16_t                partitionReferenceNum;
-} kernel_lb_addr;
+};
 
 /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
-typedef struct {
+struct short_ad {
         __le32         extLength;
         __le32         extPosition;
-} __attribute__ ((packed)) short_ad;
+} __attribute__ ((packed));
 
 /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
-typedef struct {
+struct long_ad {
        __le32          extLength;
-       lb_addr         extLocation;
+       struct lb_addr  extLocation;
        uint8_t         impUse[6];
-} __attribute__ ((packed)) long_ad;
+} __attribute__ ((packed));
 
-typedef struct {
-       uint32_t        extLength;
-       kernel_lb_addr  extLocation;
-       uint8_t         impUse[6];
-} kernel_long_ad;
+struct kernel_long_ad {
+       uint32_t                extLength;
+       struct kernel_lb_addr   extLocation;
+       uint8_t                 impUse[6];
+};
 
 /* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
-typedef struct {
+struct ext_ad {
        __le32          extLength;
        __le32          recordedLength;
        __le32          informationLength;
-       lb_addr         extLocation;
-} __attribute__ ((packed)) ext_ad;
+       struct lb_addr  extLocation;
+} __attribute__ ((packed));
 
-typedef struct {
-       uint32_t        extLength;
-       uint32_t        recordedLength;
-       uint32_t        informationLength;
-       kernel_lb_addr  extLocation;
-} kernel_ext_ad;
+struct kernel_ext_ad {
+       uint32_t                extLength;
+       uint32_t                recordedLength;
+       uint32_t                informationLength;
+       struct kernel_lb_addr   extLocation;
+};
 
 /* Descriptor Tag (ECMA 167r3 4/7.2 - See 3/7.2) */
 
@@ -415,44 +415,44 @@ typedef struct {
 
 /* File Set Descriptor (ECMA 167r3 4/14.1) */
 struct fileSetDesc {
-       tag             descTag;
-       timestamp       recordingDateAndTime;
-       __le16          interchangeLvl;
-       __le16          maxInterchangeLvl;
-       __le32          charSetList;
-       __le32          maxCharSetList;
-       __le32          fileSetNum;
-       __le32          fileSetDescNum;
-       charspec        logicalVolIdentCharSet;
-       dstring         logicalVolIdent[128];
-       charspec        fileSetCharSet;
-       dstring         fileSetIdent[32];
-       dstring         copyrightFileIdent[32];
-       dstring         abstractFileIdent[32];
-       long_ad         rootDirectoryICB;
-       regid           domainIdent;
-       long_ad         nextExt;
-       long_ad         streamDirectoryICB;
-       uint8_t         reserved[32];
+       struct tag              descTag;
+       struct timestamp        recordingDateAndTime;
+       __le16                  interchangeLvl;
+       __le16                  maxInterchangeLvl;
+       __le32                  charSetList;
+       __le32                  maxCharSetList;
+       __le32                  fileSetNum;
+       __le32                  fileSetDescNum;
+       struct charspec         logicalVolIdentCharSet;
+       dstring                 logicalVolIdent[128];
+       struct charspec         fileSetCharSet;
+       dstring                 fileSetIdent[32];
+       dstring                 copyrightFileIdent[32];
+       dstring                 abstractFileIdent[32];
+       struct long_ad          rootDirectoryICB;
+       struct regid            domainIdent;
+       struct long_ad          nextExt;
+       struct long_ad          streamDirectoryICB;
+       uint8_t                 reserved[32];
 } __attribute__ ((packed));
 
 /* Partition Header Descriptor (ECMA 167r3 4/14.3) */
 struct partitionHeaderDesc {
-       short_ad        unallocSpaceTable;
-       short_ad        unallocSpaceBitmap;
-       short_ad        partitionIntegrityTable;
-       short_ad        freedSpaceTable;
-       short_ad        freedSpaceBitmap;
+       struct short_ad unallocSpaceTable;
+       struct short_ad unallocSpaceBitmap;
+       struct short_ad partitionIntegrityTable;
+       struct short_ad freedSpaceTable;
+       struct short_ad freedSpaceBitmap;
        uint8_t         reserved[88];
 } __attribute__ ((packed));
 
 /* File Identifier Descriptor (ECMA 167r3 4/14.4) */
 struct fileIdentDesc {
-       tag             descTag;
+       struct tag      descTag;
        __le16          fileVersionNum;
        uint8_t         fileCharacteristics;
        uint8_t         lengthFileIdent;
-       long_ad         icb;
+       struct long_ad  icb;
        __le16          lengthOfImpUse;
        uint8_t         impUse[0];
        uint8_t         fileIdent[0];
@@ -468,22 +468,22 @@ struct fileIdentDesc {
 
 /* Allocation Ext Descriptor (ECMA 167r3 4/14.5) */
 struct allocExtDesc {
-       tag             descTag;
+       struct tag      descTag;
        __le32          previousAllocExtLocation;
        __le32          lengthAllocDescs;
 } __attribute__ ((packed));
 
 /* ICB Tag (ECMA 167r3 4/14.6) */
-typedef struct {
+struct icbtag {
        __le32          priorRecordedNumDirectEntries;
        __le16          strategyType;
        __le16          strategyParameter;
        __le16          numEntries;
        uint8_t         reserved;
        uint8_t         fileType;
-       lb_addr         parentICBLocation;
+       struct lb_addr  parentICBLocation;
        __le16          flags;
-} __attribute__ ((packed)) icbtag;
+} __attribute__ ((packed));
 
 /* Strategy Type (ECMA 167r3 4/14.6.2) */
 #define ICBTAG_STRATEGY_TYPE_UNDEF     0x0000
@@ -528,41 +528,41 @@ typedef struct {
 
 /* Indirect Entry (ECMA 167r3 4/14.7) */
 struct indirectEntry {
-       tag             descTag;
-       icbtag          icbTag;
-       long_ad         indirectICB;
+       struct tag      descTag;
+       struct icbtag   icbTag;
+       struct long_ad  indirectICB;
 } __attribute__ ((packed));
 
 /* Terminal Entry (ECMA 167r3 4/14.8) */
 struct terminalEntry {
-       tag             descTag;
-       icbtag          icbTag;
+       struct tag      descTag;
+       struct icbtag   icbTag;
 } __attribute__ ((packed));
 
 /* File Entry (ECMA 167r3 4/14.9) */
 struct fileEntry {
-       tag             descTag;
-       icbtag          icbTag;
-       __le32          uid;
-       __le32          gid;
-       __le32          permissions;
-       __le16          fileLinkCount;
-       uint8_t         recordFormat;
-       uint8_t         recordDisplayAttr;
-       __le32          recordLength;
-       __le64          informationLength;
-       __le64          logicalBlocksRecorded;
-       timestamp       accessTime;
-       timestamp       modificationTime;
-       timestamp       attrTime;
-       __le32          checkpoint;
-       long_ad         extendedAttrICB;
-       regid           impIdent;
-       __le64          uniqueID;
-       __le32          lengthExtendedAttr;
-       __le32          lengthAllocDescs;
-       uint8_t         extendedAttr[0];
-       uint8_t         allocDescs[0];
+       struct tag              descTag;
+       struct icbtag           icbTag;
+       __le32                  uid;
+       __le32                  gid;
+       __le32                  permissions;
+       __le16                  fileLinkCount;
+       uint8_t                 recordFormat;
+       uint8_t                 recordDisplayAttr;
+       __le32                  recordLength;
+       __le64                  informationLength;
+       __le64                  logicalBlocksRecorded;
+       struct timestamp        accessTime;
+       struct timestamp        modificationTime;
+       struct timestamp        attrTime;
+       __le32                  checkpoint;
+       struct long_ad          extendedAttrICB;
+       struct regid            impIdent;
+       __le64                  uniqueID;
+       __le32                  lengthExtendedAttr;
+       __le32                  lengthAllocDescs;
+       uint8_t                 extendedAttr[0];
+       uint8_t                 allocDescs[0];
 } __attribute__ ((packed));
 
 /* Permissions (ECMA 167r3 4/14.9.5) */
@@ -604,7 +604,7 @@ struct fileEntry {
 
 /* Extended Attribute Header Descriptor (ECMA 167r3 4/14.10.1) */
 struct extendedAttrHeaderDesc {
-       tag             descTag;
+       struct tag      descTag;
        __le32          impAttrLocation;
        __le32          appAttrLocation;
 } __attribute__ ((packed));
@@ -687,7 +687,7 @@ struct impUseExtAttr {
        uint8_t         reserved[3];
        __le32          attrLength;
        __le32          impUseLength;
-       regid           impIdent;
+       struct regid    impIdent;
        uint8_t         impUse[0];
 } __attribute__ ((packed));
 
@@ -698,7 +698,7 @@ struct appUseExtAttr {
        uint8_t         reserved[3];
        __le32          attrLength;
        __le32          appUseLength;
-       regid           appIdent;
+       struct regid    appIdent;
        uint8_t         appUse[0];
 } __attribute__ ((packed));
 
@@ -712,15 +712,15 @@ struct appUseExtAttr {
 
 /* Unallocated Space Entry (ECMA 167r3 4/14.11) */
 struct unallocSpaceEntry {
-       tag             descTag;
-       icbtag          icbTag;
+       struct tag      descTag;
+       struct icbtag   icbTag;
        __le32          lengthAllocDescs;
        uint8_t         allocDescs[0];
 } __attribute__ ((packed));
 
 /* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
 struct spaceBitmapDesc {
-       tag             descTag;
+       struct tag      descTag;
        __le32          numOfBits;
        __le32          numOfBytes;
        uint8_t         bitmap[0];
@@ -728,13 +728,13 @@ struct spaceBitmapDesc {
 
 /* Partition Integrity Entry (ECMA 167r3 4/14.13) */
 struct partitionIntegrityEntry {
-       tag             descTag;
-       icbtag          icbTag;
-       timestamp       recordingDateAndTime;
-       uint8_t         integrityType;
-       uint8_t         reserved[175];
-       regid           impIdent;
-       uint8_t         impUse[256];
+       struct tag              descTag;
+       struct icbtag           icbTag;
+       struct timestamp        recordingDateAndTime;
+       uint8_t                 integrityType;
+       uint8_t                 reserved[175];
+       struct regid            impIdent;
+       uint8_t                 impUse[256];
 } __attribute__ ((packed));
 
 /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
@@ -765,32 +765,32 @@ struct pathComponent {
 
 /* File Entry (ECMA 167r3 4/14.17) */
 struct extendedFileEntry {
-       tag             descTag;
-       icbtag          icbTag;
-       __le32          uid;
-       __le32          gid;
-       __le32          permissions;
-       __le16          fileLinkCount;
-       uint8_t         recordFormat;
-       uint8_t         recordDisplayAttr;
-       __le32          recordLength;
-       __le64          informationLength;
-       __le64          objectSize;
-       __le64          logicalBlocksRecorded;
-       timestamp       accessTime;
-       timestamp       modificationTime;
-       timestamp       createTime;
-       timestamp       attrTime;
-       __le32          checkpoint;
-       __le32          reserved;
-       long_ad         extendedAttrICB;
-       long_ad         streamDirectoryICB;
-       regid           impIdent;
-       __le64          uniqueID;
-       __le32          lengthExtendedAttr;
-       __le32          lengthAllocDescs;
-       uint8_t         extendedAttr[0];
-       uint8_t         allocDescs[0];
+       struct tag              descTag;
+       struct icbtag           icbTag;
+       __le32                  uid;
+       __le32                  gid;
+       __le32                  permissions;
+       __le16                  fileLinkCount;
+       uint8_t                 recordFormat;
+       uint8_t                 recordDisplayAttr;
+       __le32                  recordLength;
+       __le64                  informationLength;
+       __le64                  objectSize;
+       __le64                  logicalBlocksRecorded;
+       struct timestamp        accessTime;
+       struct timestamp        modificationTime;
+       struct timestamp        createTime;
+       struct timestamp        attrTime;
+       __le32                  checkpoint;
+       __le32                  reserved;
+       struct long_ad          extendedAttrICB;
+       struct long_ad          streamDirectoryICB;
+       struct regid            impIdent;
+       __le64                  uniqueID;
+       __le32                  lengthExtendedAttr;
+       __le32                  lengthAllocDescs;
+       uint8_t                 extendedAttr[0];
+       uint8_t                 allocDescs[0];
 } __attribute__ ((packed));
 
 #endif /* _ECMA_167_H */
index 47dbe5613f90ff456b2a52f4a8a4c8aee8f6fb12..c10fa39f97e2e7dacd56ff39c13365140dc8f577 100644 (file)
@@ -49,12 +49,11 @@ void udf_free_inode(struct inode *inode)
                        le32_add_cpu(&lvidiu->numDirs, -1);
                else
                        le32_add_cpu(&lvidiu->numFiles, -1);
-
-               mark_buffer_dirty(sbi->s_lvid_bh);
+               udf_updated_lvid(sb);
        }
        mutex_unlock(&sbi->s_alloc_mutex);
 
-       udf_free_blocks(sb, NULL, UDF_I(inode)->i_location, 0, 1);
+       udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 0, 1);
 }
 
 struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
@@ -122,7 +121,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
                if (!(++uniqueID & 0x00000000FFFFFFFFUL))
                        uniqueID += 16;
                lvhd->uniqueID = cpu_to_le64(uniqueID);
-               mark_buffer_dirty(sbi->s_lvid_bh);
+               udf_updated_lvid(sb);
        }
        mutex_unlock(&sbi->s_alloc_mutex);
        inode->i_mode = mode;
@@ -138,7 +137,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
        iinfo->i_location.logicalBlockNum = block;
        iinfo->i_location.partitionReferenceNum =
                                dinfo->i_location.partitionReferenceNum;
-       inode->i_ino = udf_get_lb_pblock(sb, iinfo->i_location, 0);
+       inode->i_ino = udf_get_lb_pblock(sb, &iinfo->i_location, 0);
        inode->i_blocks = 0;
        iinfo->i_lenEAttr = 0;
        iinfo->i_lenAlloc = 0;
index 30ebde490f7f5ebc3a4b79331191706c180b5a8f..e7533f7856368d17a15728c5113e816546cff4e7 100644 (file)
@@ -55,15 +55,15 @@ static int udf_alloc_i_data(struct inode *inode, size_t size);
 static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,
                                        sector_t *, int *);
 static int8_t udf_insert_aext(struct inode *, struct extent_position,
-                             kernel_lb_addr, uint32_t);
+                             struct kernel_lb_addr, uint32_t);
 static void udf_split_extents(struct inode *, int *, int, int,
-                             kernel_long_ad[EXTENT_MERGE_SIZE], int *);
+                             struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
 static void udf_prealloc_extents(struct inode *, int, int,
-                                kernel_long_ad[EXTENT_MERGE_SIZE], int *);
+                                struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
 static void udf_merge_extents(struct inode *,
-                             kernel_long_ad[EXTENT_MERGE_SIZE], int *);
+                             struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
 static void udf_update_extents(struct inode *,
-                              kernel_long_ad[EXTENT_MERGE_SIZE], int, int,
+                              struct kernel_long_ad[EXTENT_MERGE_SIZE], int, int,
                               struct extent_position *);
 static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
@@ -200,7 +200,7 @@ struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block,
 {
        int newblock;
        struct buffer_head *dbh = NULL;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen;
        uint8_t alloctype;
        struct extent_position epos;
@@ -281,7 +281,7 @@ struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block,
        epos.bh = NULL;
        epos.block = iinfo->i_location;
        epos.offset = udf_file_entry_alloc_offset(inode);
-       udf_add_aext(inode, &epos, eloc, elen, 0);
+       udf_add_aext(inode, &epos, &eloc, elen, 0);
        /* UniqueID stuff */
 
        brelse(epos.bh);
@@ -359,12 +359,12 @@ static struct buffer_head *udf_getblk(struct inode *inode, long block,
 
 /* Extend the file by 'blocks' blocks, return the number of extents added */
 int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
-                   kernel_long_ad *last_ext, sector_t blocks)
+                   struct kernel_long_ad *last_ext, sector_t blocks)
 {
        sector_t add;
        int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
        struct super_block *sb = inode->i_sb;
-       kernel_lb_addr prealloc_loc = {};
+       struct kernel_lb_addr prealloc_loc = {};
        int prealloc_len = 0;
        struct udf_inode_info *iinfo;
 
@@ -411,11 +411,11 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
        }
 
        if (fake) {
-               udf_add_aext(inode, last_pos, last_ext->extLocation,
+               udf_add_aext(inode, last_pos, &last_ext->extLocation,
                             last_ext->extLength, 1);
                count++;
        } else
-               udf_write_aext(inode, last_pos, last_ext->extLocation,
+               udf_write_aext(inode, last_pos, &last_ext->extLocation,
                                last_ext->extLength, 1);
 
        /* Managed to do everything necessary? */
@@ -432,7 +432,7 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
        /* Create enough extents to cover the whole hole */
        while (blocks > add) {
                blocks -= add;
-               if (udf_add_aext(inode, last_pos, last_ext->extLocation,
+               if (udf_add_aext(inode, last_pos, &last_ext->extLocation,
                                 last_ext->extLength, 1) == -1)
                        return -1;
                count++;
@@ -440,7 +440,7 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
        if (blocks) {
                last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
                        (blocks << sb->s_blocksize_bits);
-               if (udf_add_aext(inode, last_pos, last_ext->extLocation,
+               if (udf_add_aext(inode, last_pos, &last_ext->extLocation,
                                 last_ext->extLength, 1) == -1)
                        return -1;
                count++;
@@ -449,7 +449,7 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
 out:
        /* Do we have some preallocated blocks saved? */
        if (prealloc_len) {
-               if (udf_add_aext(inode, last_pos, prealloc_loc,
+               if (udf_add_aext(inode, last_pos, &prealloc_loc,
                                 prealloc_len, 1) == -1)
                        return -1;
                last_ext->extLocation = prealloc_loc;
@@ -459,9 +459,9 @@ out:
 
        /* last_pos should point to the last written extent... */
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               last_pos->offset -= sizeof(short_ad);
+               last_pos->offset -= sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               last_pos->offset -= sizeof(long_ad);
+               last_pos->offset -= sizeof(struct long_ad);
        else
                return -1;
 
@@ -473,11 +473,11 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
 {
        static sector_t last_block;
        struct buffer_head *result = NULL;
-       kernel_long_ad laarr[EXTENT_MERGE_SIZE];
+       struct kernel_long_ad laarr[EXTENT_MERGE_SIZE];
        struct extent_position prev_epos, cur_epos, next_epos;
        int count = 0, startnum = 0, endnum = 0;
        uint32_t elen = 0, tmpelen;
-       kernel_lb_addr eloc, tmpeloc;
+       struct kernel_lb_addr eloc, tmpeloc;
        int c = 1;
        loff_t lbcount = 0, b_off = 0;
        uint32_t newblocknum, newblock;
@@ -550,12 +550,12 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
                        elen = EXT_RECORDED_ALLOCATED |
                                ((elen + inode->i_sb->s_blocksize - 1) &
                                 ~(inode->i_sb->s_blocksize - 1));
-                       etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1);
+                       etype = udf_write_aext(inode, &cur_epos, &eloc, elen, 1);
                }
                brelse(prev_epos.bh);
                brelse(cur_epos.bh);
                brelse(next_epos.bh);
-               newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);
+               newblock = udf_get_lb_pblock(inode->i_sb, &eloc, offset);
                *phys = newblock;
                return NULL;
        }
@@ -572,7 +572,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
                } else {
                        /* Create a fake extent when there's not one */
                        memset(&laarr[0].extLocation, 0x00,
-                               sizeof(kernel_lb_addr));
+                               sizeof(struct kernel_lb_addr));
                        laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
                        /* Will udf_extend_file() create real extent from
                           a fake one? */
@@ -602,7 +602,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
                        laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
                                inode->i_sb->s_blocksize;
                        memset(&laarr[c].extLocation, 0x00,
-                               sizeof(kernel_lb_addr));
+                               sizeof(struct kernel_lb_addr));
                        count++;
                        endnum++;
                }
@@ -699,7 +699,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
 
 static void udf_split_extents(struct inode *inode, int *c, int offset,
                              int newblocknum,
-                             kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                             struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
                              int *endnum)
 {
        unsigned long blocksize = inode->i_sb->s_blocksize;
@@ -726,7 +726,7 @@ static void udf_split_extents(struct inode *inode, int *c, int offset,
                if (offset) {
                        if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
                                udf_free_blocks(inode->i_sb, inode,
-                                               laarr[curr].extLocation,
+                                               &laarr[curr].extLocation,
                                                0, offset);
                                laarr[curr].extLength =
                                        EXT_NOT_RECORDED_NOT_ALLOCATED |
@@ -763,7 +763,7 @@ static void udf_split_extents(struct inode *inode, int *c, int offset,
 }
 
 static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
-                                kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                                struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
                                 int *endnum)
 {
        int start, length = 0, currlength = 0, i;
@@ -817,7 +817,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
                                         inode->i_sb->s_blocksize_bits);
                        else {
                                memmove(&laarr[c + 2], &laarr[c + 1],
-                                       sizeof(long_ad) * (*endnum - (c + 1)));
+                                       sizeof(struct long_ad) * (*endnum - (c + 1)));
                                (*endnum)++;
                                laarr[c + 1].extLocation.logicalBlockNum = next;
                                laarr[c + 1].extLocation.partitionReferenceNum =
@@ -846,7 +846,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
                                        if (*endnum > (i + 1))
                                                memmove(&laarr[i],
                                                        &laarr[i + 1],
-                                                       sizeof(long_ad) *
+                                                       sizeof(struct long_ad) *
                                                        (*endnum - (i + 1)));
                                        i--;
                                        (*endnum)--;
@@ -859,7 +859,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
 }
 
 static void udf_merge_extents(struct inode *inode,
-                             kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                             struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
                              int *endnum)
 {
        int i;
@@ -867,8 +867,8 @@ static void udf_merge_extents(struct inode *inode,
        unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
 
        for (i = 0; i < (*endnum - 1); i++) {
-               kernel_long_ad *li /*l[i]*/ = &laarr[i];
-               kernel_long_ad *lip1 /*l[i plus 1]*/ = &laarr[i + 1];
+               struct kernel_long_ad *li /*l[i]*/ = &laarr[i];
+               struct kernel_long_ad *lip1 /*l[i plus 1]*/ = &laarr[i + 1];
 
                if (((li->extLength >> 30) == (lip1->extLength >> 30)) &&
                        (((li->extLength >> 30) ==
@@ -902,7 +902,7 @@ static void udf_merge_extents(struct inode *inode,
                                         blocksize - 1) & ~(blocksize - 1));
                                if (*endnum > (i + 2))
                                        memmove(&laarr[i + 1], &laarr[i + 2],
-                                               sizeof(long_ad) *
+                                               sizeof(struct long_ad) *
                                                (*endnum - (i + 2)));
                                i--;
                                (*endnum)--;
@@ -911,7 +911,7 @@ static void udf_merge_extents(struct inode *inode,
                                (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
                           ((lip1->extLength >> 30) ==
                                (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) {
-                       udf_free_blocks(inode->i_sb, inode, li->extLocation, 0,
+                       udf_free_blocks(inode->i_sb, inode, &li->extLocation, 0,
                                        ((li->extLength &
                                          UDF_EXTENT_LENGTH_MASK) +
                                         blocksize - 1) >> blocksize_bits);
@@ -937,7 +937,7 @@ static void udf_merge_extents(struct inode *inode,
                                          blocksize - 1) & ~(blocksize - 1));
                                if (*endnum > (i + 2))
                                        memmove(&laarr[i + 1], &laarr[i + 2],
-                                               sizeof(long_ad) *
+                                               sizeof(struct long_ad) *
                                                (*endnum - (i + 2)));
                                i--;
                                (*endnum)--;
@@ -945,7 +945,7 @@ static void udf_merge_extents(struct inode *inode,
                } else if ((li->extLength >> 30) ==
                                        (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
                        udf_free_blocks(inode->i_sb, inode,
-                                       li->extLocation, 0,
+                                       &li->extLocation, 0,
                                        ((li->extLength &
                                                UDF_EXTENT_LENGTH_MASK) +
                                         blocksize - 1) >> blocksize_bits);
@@ -959,12 +959,12 @@ static void udf_merge_extents(struct inode *inode,
 }
 
 static void udf_update_extents(struct inode *inode,
-                              kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                              struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
                               int startnum, int endnum,
                               struct extent_position *epos)
 {
        int start = 0, i;
-       kernel_lb_addr tmploc;
+       struct kernel_lb_addr tmploc;
        uint32_t tmplen;
 
        if (startnum > endnum) {
@@ -983,7 +983,7 @@ static void udf_update_extents(struct inode *inode,
 
        for (i = start; i < endnum; i++) {
                udf_next_aext(inode, epos, &tmploc, &tmplen, 0);
-               udf_write_aext(inode, epos, laarr[i].extLocation,
+               udf_write_aext(inode, epos, &laarr[i].extLocation,
                               laarr[i].extLength, 1);
        }
 }
@@ -1076,7 +1076,7 @@ static void __udf_read_inode(struct inode *inode)
         *      i_nlink = 1
         *      i_op = NULL;
         */
-       bh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 0, &ident);
+       bh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 0, &ident);
        if (!bh) {
                printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n",
                       inode->i_ino);
@@ -1098,24 +1098,24 @@ static void __udf_read_inode(struct inode *inode)
        if (fe->icbTag.strategyType == cpu_to_le16(4096)) {
                struct buffer_head *ibh;
 
-               ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1,
+               ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1,
                                        &ident);
                if (ident == TAG_IDENT_IE && ibh) {
                        struct buffer_head *nbh = NULL;
-                       kernel_lb_addr loc;
+                       struct kernel_lb_addr loc;
                        struct indirectEntry *ie;
 
                        ie = (struct indirectEntry *)ibh->b_data;
                        loc = lelb_to_cpu(ie->indirectICB.extLocation);
 
                        if (ie->indirectICB.extLength &&
-                               (nbh = udf_read_ptagged(inode->i_sb, loc, 0,
+                               (nbh = udf_read_ptagged(inode->i_sb, &loc, 0,
                                                        &ident))) {
                                if (ident == TAG_IDENT_FE ||
                                        ident == TAG_IDENT_EFE) {
                                        memcpy(&iinfo->i_location,
                                                &loc,
-                                               sizeof(kernel_lb_addr));
+                                               sizeof(struct kernel_lb_addr));
                                        brelse(bh);
                                        brelse(ibh);
                                        brelse(nbh);
@@ -1222,8 +1222,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        inode->i_size = le64_to_cpu(fe->informationLength);
        iinfo->i_lenExtents = inode->i_size;
 
-       inode->i_mode = udf_convert_permissions(fe);
-       inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
+       if (fe->icbTag.fileType != ICBTAG_FILE_TYPE_DIRECTORY &&
+                       sbi->s_fmode != UDF_INVALID_MODE)
+               inode->i_mode = sbi->s_fmode;
+       else if (fe->icbTag.fileType == ICBTAG_FILE_TYPE_DIRECTORY &&
+                       sbi->s_dmode != UDF_INVALID_MODE)
+               inode->i_mode = sbi->s_dmode;
+       else
+               inode->i_mode = udf_convert_permissions(fe);
+       inode->i_mode &= ~sbi->s_umask;
 
        if (iinfo->i_efe == 0) {
                inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
@@ -1396,7 +1403,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
 
        bh = udf_tread(inode->i_sb,
                        udf_get_lb_pblock(inode->i_sb,
-                                         iinfo->i_location, 0));
+                                         &iinfo->i_location, 0));
        if (!bh) {
                udf_debug("bread failure\n");
                return -EIO;
@@ -1416,13 +1423,13 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                       iinfo->i_ext.i_data, inode->i_sb->s_blocksize -
                                        sizeof(struct unallocSpaceEntry));
                crclen = sizeof(struct unallocSpaceEntry) +
-                               iinfo->i_lenAlloc - sizeof(tag);
+                               iinfo->i_lenAlloc - sizeof(struct tag);
                use->descTag.tagLocation = cpu_to_le32(
                                                iinfo->i_location.
                                                        logicalBlockNum);
                use->descTag.descCRCLength = cpu_to_le16(crclen);
                use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use +
-                                                          sizeof(tag),
+                                                          sizeof(struct tag),
                                                           crclen));
                use->descTag.tagChecksum = udf_tag_checksum(&use->descTag);
 
@@ -1459,23 +1466,23 @@ static int udf_update_inode(struct inode *inode, int do_sync)
        fe->informationLength = cpu_to_le64(inode->i_size);
 
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-               regid *eid;
+               struct regid *eid;
                struct deviceSpec *dsea =
                        (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
                if (!dsea) {
                        dsea = (struct deviceSpec *)
                                udf_add_extendedattr(inode,
                                                     sizeof(struct deviceSpec) +
-                                                    sizeof(regid), 12, 0x3);
+                                                    sizeof(struct regid), 12, 0x3);
                        dsea->attrType = cpu_to_le32(12);
                        dsea->attrSubtype = 1;
                        dsea->attrLength = cpu_to_le32(
                                                sizeof(struct deviceSpec) +
-                                               sizeof(regid));
-                       dsea->impUseLength = cpu_to_le32(sizeof(regid));
+                                               sizeof(struct regid));
+                       dsea->impUseLength = cpu_to_le32(sizeof(struct regid));
                }
-               eid = (regid *)dsea->impUse;
-               memset(eid, 0, sizeof(regid));
+               eid = (struct regid *)dsea->impUse;
+               memset(eid, 0, sizeof(struct regid));
                strcpy(eid->ident, UDF_ID_DEVELOPER);
                eid->identSuffix[0] = UDF_OS_CLASS_UNIX;
                eid->identSuffix[1] = UDF_OS_ID_LINUX;
@@ -1494,7 +1501,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime);
                udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime);
                udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime);
-               memset(&(fe->impIdent), 0, sizeof(regid));
+               memset(&(fe->impIdent), 0, sizeof(struct regid));
                strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
                fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
                fe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
@@ -1533,7 +1540,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime);
                udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime);
 
-               memset(&(efe->impIdent), 0, sizeof(regid));
+               memset(&(efe->impIdent), 0, sizeof(struct regid));
                strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
                efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
                efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
@@ -1584,9 +1591,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
        fe->descTag.tagLocation = cpu_to_le32(
                                        iinfo->i_location.logicalBlockNum);
        crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc -
-                                                               sizeof(tag);
+                                                               sizeof(struct tag);
        fe->descTag.descCRCLength = cpu_to_le16(crclen);
-       fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(tag),
+       fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(struct tag),
                                                  crclen));
        fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag);
 
@@ -1606,7 +1613,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
        return err;
 }
 
-struct inode *udf_iget(struct super_block *sb, kernel_lb_addr ino)
+struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
 {
        unsigned long block = udf_get_lb_pblock(sb, ino, 0);
        struct inode *inode = iget_locked(sb, block);
@@ -1615,7 +1622,7 @@ struct inode *udf_iget(struct super_block *sb, kernel_lb_addr ino)
                return NULL;
 
        if (inode->i_state & I_NEW) {
-               memcpy(&UDF_I(inode)->i_location, &ino, sizeof(kernel_lb_addr));
+               memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr));
                __udf_read_inode(inode);
                unlock_new_inode(inode);
        }
@@ -1623,10 +1630,10 @@ struct inode *udf_iget(struct super_block *sb, kernel_lb_addr ino)
        if (is_bad_inode(inode))
                goto out_iput;
 
-       if (ino.logicalBlockNum >= UDF_SB(sb)->
-                       s_partmaps[ino.partitionReferenceNum].s_partition_len) {
+       if (ino->logicalBlockNum >= UDF_SB(sb)->
+                       s_partmaps[ino->partitionReferenceNum].s_partition_len) {
                udf_debug("block=%d, partition=%d out of range\n",
-                         ino.logicalBlockNum, ino.partitionReferenceNum);
+                         ino->logicalBlockNum, ino->partitionReferenceNum);
                make_bad_inode(inode);
                goto out_iput;
        }
@@ -1639,11 +1646,11 @@ struct inode *udf_iget(struct super_block *sb, kernel_lb_addr ino)
 }
 
 int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
-                   kernel_lb_addr eloc, uint32_t elen, int inc)
+                   struct kernel_lb_addr *eloc, uint32_t elen, int inc)
 {
        int adsize;
-       short_ad *sad = NULL;
-       long_ad *lad = NULL;
+       struct short_ad *sad = NULL;
+       struct long_ad *lad = NULL;
        struct allocExtDesc *aed;
        int8_t etype;
        uint8_t *ptr;
@@ -1657,9 +1664,9 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
                ptr = epos->bh->b_data + epos->offset;
 
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               adsize = sizeof(short_ad);
+               adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
        else
                return -1;
 
@@ -1667,7 +1674,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
                char *sptr, *dptr;
                struct buffer_head *nbh;
                int err, loffset;
-               kernel_lb_addr obloc = epos->block;
+               struct kernel_lb_addr obloc = epos->block;
 
                epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
                                                obloc.partitionReferenceNum,
@@ -1675,7 +1682,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
                if (!epos->block.logicalBlockNum)
                        return -1;
                nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
-                                                                epos->block,
+                                                                &epos->block,
                                                                 0));
                if (!nbh)
                        return -1;
@@ -1712,20 +1719,20 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
                }
                if (UDF_SB(inode->i_sb)->s_udfrev >= 0x0200)
                        udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
-                                   epos->block.logicalBlockNum, sizeof(tag));
+                                   epos->block.logicalBlockNum, sizeof(struct tag));
                else
                        udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
-                                   epos->block.logicalBlockNum, sizeof(tag));
+                                   epos->block.logicalBlockNum, sizeof(struct tag));
                switch (iinfo->i_alloc_type) {
                case ICBTAG_FLAG_AD_SHORT:
-                       sad = (short_ad *)sptr;
+                       sad = (struct short_ad *)sptr;
                        sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
                                                     inode->i_sb->s_blocksize);
                        sad->extPosition =
                                cpu_to_le32(epos->block.logicalBlockNum);
                        break;
                case ICBTAG_FLAG_AD_LONG:
-                       lad = (long_ad *)sptr;
+                       lad = (struct long_ad *)sptr;
                        lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
                                                     inode->i_sb->s_blocksize);
                        lad->extLocation = cpu_to_lelb(epos->block);
@@ -1769,12 +1776,12 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
 }
 
 int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
-                     kernel_lb_addr eloc, uint32_t elen, int inc)
+                     struct kernel_lb_addr *eloc, uint32_t elen, int inc)
 {
        int adsize;
        uint8_t *ptr;
-       short_ad *sad;
-       long_ad *lad;
+       struct short_ad *sad;
+       struct long_ad *lad;
        struct udf_inode_info *iinfo = UDF_I(inode);
 
        if (!epos->bh)
@@ -1786,17 +1793,17 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
 
        switch (iinfo->i_alloc_type) {
        case ICBTAG_FLAG_AD_SHORT:
-               sad = (short_ad *)ptr;
+               sad = (struct short_ad *)ptr;
                sad->extLength = cpu_to_le32(elen);
-               sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
-               adsize = sizeof(short_ad);
+               sad->extPosition = cpu_to_le32(eloc->logicalBlockNum);
+               adsize = sizeof(struct short_ad);
                break;
        case ICBTAG_FLAG_AD_LONG:
-               lad = (long_ad *)ptr;
+               lad = (struct long_ad *)ptr;
                lad->extLength = cpu_to_le32(elen);
-               lad->extLocation = cpu_to_lelb(eloc);
+               lad->extLocation = cpu_to_lelb(*eloc);
                memset(lad->impUse, 0x00, sizeof(lad->impUse));
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
                break;
        default:
                return -1;
@@ -1823,7 +1830,7 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
 }
 
 int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
-                    kernel_lb_addr *eloc, uint32_t *elen, int inc)
+                    struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
 {
        int8_t etype;
 
@@ -1833,7 +1840,7 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
                epos->block = *eloc;
                epos->offset = sizeof(struct allocExtDesc);
                brelse(epos->bh);
-               block = udf_get_lb_pblock(inode->i_sb, epos->block, 0);
+               block = udf_get_lb_pblock(inode->i_sb, &epos->block, 0);
                epos->bh = udf_tread(inode->i_sb, block);
                if (!epos->bh) {
                        udf_debug("reading block %d failed!\n", block);
@@ -1845,13 +1852,13 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
 }
 
 int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
-                       kernel_lb_addr *eloc, uint32_t *elen, int inc)
+                       struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
 {
        int alen;
        int8_t etype;
        uint8_t *ptr;
-       short_ad *sad;
-       long_ad *lad;
+       struct short_ad *sad;
+       struct long_ad *lad;
        struct udf_inode_info *iinfo = UDF_I(inode);
 
        if (!epos->bh) {
@@ -1900,9 +1907,9 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
 }
 
 static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos,
-                             kernel_lb_addr neloc, uint32_t nelen)
+                             struct kernel_lb_addr neloc, uint32_t nelen)
 {
-       kernel_lb_addr oeloc;
+       struct kernel_lb_addr oeloc;
        uint32_t oelen;
        int8_t etype;
 
@@ -1910,18 +1917,18 @@ static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos,
                get_bh(epos.bh);
 
        while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) {
-               udf_write_aext(inode, &epos, neloc, nelen, 1);
+               udf_write_aext(inode, &epos, &neloc, nelen, 1);
                neloc = oeloc;
                nelen = (etype << 30) | oelen;
        }
-       udf_add_aext(inode, &epos, neloc, nelen, 1);
+       udf_add_aext(inode, &epos, &neloc, nelen, 1);
        brelse(epos.bh);
 
        return (nelen >> 30);
 }
 
 int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
-                      kernel_lb_addr eloc, uint32_t elen)
+                      struct kernel_lb_addr eloc, uint32_t elen)
 {
        struct extent_position oepos;
        int adsize;
@@ -1936,9 +1943,9 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
 
        iinfo = UDF_I(inode);
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               adsize = sizeof(short_ad);
+               adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
        else
                adsize = 0;
 
@@ -1947,7 +1954,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
                return -1;
 
        while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
-               udf_write_aext(inode, &oepos, eloc, (etype << 30) | elen, 1);
+               udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1);
                if (oepos.bh != epos.bh) {
                        oepos.block = epos.block;
                        brelse(oepos.bh);
@@ -1956,13 +1963,13 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
                        oepos.offset = epos.offset - adsize;
                }
        }
-       memset(&eloc, 0x00, sizeof(kernel_lb_addr));
+       memset(&eloc, 0x00, sizeof(struct kernel_lb_addr));
        elen = 0;
 
        if (epos.bh != oepos.bh) {
-               udf_free_blocks(inode->i_sb, inode, epos.block, 0, 1);
-               udf_write_aext(inode, &oepos, eloc, elen, 1);
-               udf_write_aext(inode, &oepos, eloc, elen, 1);
+               udf_free_blocks(inode->i_sb, inode, &epos.block, 0, 1);
+               udf_write_aext(inode, &oepos, &eloc, elen, 1);
+               udf_write_aext(inode, &oepos, &eloc, elen, 1);
                if (!oepos.bh) {
                        iinfo->i_lenAlloc -= (adsize * 2);
                        mark_inode_dirty(inode);
@@ -1979,7 +1986,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
                        mark_buffer_dirty_inode(oepos.bh, inode);
                }
        } else {
-               udf_write_aext(inode, &oepos, eloc, elen, 1);
+               udf_write_aext(inode, &oepos, &eloc, elen, 1);
                if (!oepos.bh) {
                        iinfo->i_lenAlloc -= adsize;
                        mark_inode_dirty(inode);
@@ -2004,7 +2011,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
 }
 
 int8_t inode_bmap(struct inode *inode, sector_t block,
-                 struct extent_position *pos, kernel_lb_addr *eloc,
+                 struct extent_position *pos, struct kernel_lb_addr *eloc,
                  uint32_t *elen, sector_t *offset)
 {
        unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
@@ -2036,7 +2043,7 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
 
 long udf_block_map(struct inode *inode, sector_t block)
 {
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
        struct extent_position epos = {};
@@ -2046,7 +2053,7 @@ long udf_block_map(struct inode *inode, sector_t block)
 
        if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) ==
                                                (EXT_RECORDED_ALLOCATED >> 30))
-               ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);
+               ret = udf_get_lb_pblock(inode->i_sb, &eloc, offset);
        else
                ret = 0;
 
index 84bf0fd4a4f1e24a3ff70f0e8de32fb514feb6e1..9215700c00a4448eedd1e5306cb2c3410f3f4b45 100644 (file)
@@ -134,10 +134,10 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
                        }
                }
                /* rewrite CRC + checksum of eahd */
-               crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
+               crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(struct tag);
                eahd->descTag.descCRCLength = cpu_to_le16(crclen);
                eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
-                                               sizeof(tag), crclen));
+                                               sizeof(struct tag), crclen));
                eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
                iinfo->i_lenEAttr += size;
                return (struct genericFormat *)&ea[offset];
@@ -202,7 +202,7 @@ struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
 struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
                                    uint32_t location, uint16_t *ident)
 {
-       tag *tag_p;
+       struct tag *tag_p;
        struct buffer_head *bh = NULL;
 
        /* Read the block */
@@ -216,7 +216,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
                return NULL;
        }
 
-       tag_p = (tag *)(bh->b_data);
+       tag_p = (struct tag *)(bh->b_data);
 
        *ident = le16_to_cpu(tag_p->tagIdent);
 
@@ -241,9 +241,9 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
        }
 
        /* Verify the descriptor CRC */
-       if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
+       if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize ||
            le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
-                                       bh->b_data + sizeof(tag),
+                                       bh->b_data + sizeof(struct tag),
                                        le16_to_cpu(tag_p->descCRCLength)))
                return bh;
 
@@ -255,27 +255,28 @@ error_out:
        return NULL;
 }
 
-struct buffer_head *udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc,
+struct buffer_head *udf_read_ptagged(struct super_block *sb,
+                                    struct kernel_lb_addr *loc,
                                     uint32_t offset, uint16_t *ident)
 {
        return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
-                              loc.logicalBlockNum + offset, ident);
+                              loc->logicalBlockNum + offset, ident);
 }
 
 void udf_update_tag(char *data, int length)
 {
-       tag *tptr = (tag *)data;
-       length -= sizeof(tag);
+       struct tag *tptr = (struct tag *)data;
+       length -= sizeof(struct tag);
 
        tptr->descCRCLength = cpu_to_le16(length);
-       tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(tag), length));
+       tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(struct tag), length));
        tptr->tagChecksum = udf_tag_checksum(tptr);
 }
 
 void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
                 uint32_t loc, int length)
 {
-       tag *tptr = (tag *)data;
+       struct tag *tptr = (struct tag *)data;
        tptr->tagIdent = cpu_to_le16(ident);
        tptr->descVersion = cpu_to_le16(version);
        tptr->tagSerialNum = cpu_to_le16(snum);
@@ -283,12 +284,12 @@ void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
        udf_update_tag(data, length);
 }
 
-u8 udf_tag_checksum(const tag *t)
+u8 udf_tag_checksum(const struct tag *t)
 {
        u8 *data = (u8 *)t;
        u8 checksum = 0;
        int i;
-       for (i = 0; i < sizeof(tag); ++i)
+       for (i = 0; i < sizeof(struct tag); ++i)
                if (i != 4) /* position of checksum */
                        checksum += data[i];
        return checksum;
index f84bfaa8d941bf2ba6b60793ea34d081c9c2fb2d..6a29fa34c478490cc45732af39072e78fee180e0 100644 (file)
@@ -47,7 +47,7 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
                 struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
                 uint8_t *impuse, uint8_t *fileident)
 {
-       uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
+       uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(struct tag);
        uint16_t crc;
        int offset;
        uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);
@@ -99,18 +99,18 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
                memset(fibh->ebh->b_data, 0x00, padlen + offset);
        }
 
-       crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag),
-                     sizeof(struct fileIdentDesc) - sizeof(tag));
+       crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(struct tag),
+                     sizeof(struct fileIdentDesc) - sizeof(struct tag));
 
        if (fibh->sbh == fibh->ebh) {
                crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
-                             crclen + sizeof(tag) -
+                             crclen + sizeof(struct tag) -
                              sizeof(struct fileIdentDesc));
        } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
                crc = crc_itu_t(crc, fibh->ebh->b_data +
                                        sizeof(struct fileIdentDesc) +
                                        fibh->soffset,
-                             crclen + sizeof(tag) -
+                             crclen + sizeof(struct tag) -
                                        sizeof(struct fileIdentDesc));
        } else {
                crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
@@ -154,7 +154,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
        uint8_t lfi;
        uint16_t liu;
        loff_t size;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
        struct extent_position epos = {};
@@ -171,12 +171,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
                if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
                    &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
                        goto out_err;
-               block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-                               epos.offset -= sizeof(short_ad);
+                               epos.offset -= sizeof(struct short_ad);
                        else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-                               epos.offset -= sizeof(long_ad);
+                               epos.offset -= sizeof(struct long_ad);
                } else
                        offset = 0;
 
@@ -268,7 +268,7 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
 #ifdef UDF_RECOVERY
        /* temporary shorthand for specifying files by inode number */
        if (!strncmp(dentry->d_name.name, ".B=", 3)) {
-               kernel_lb_addr lb = {
+               struct kernel_lb_addr lb = {
                        .logicalBlockNum = 0,
                        .partitionReferenceNum =
                                simple_strtoul(dentry->d_name.name + 3,
@@ -283,11 +283,14 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
 #endif /* UDF_RECOVERY */
 
        if (udf_find_entry(dir, &dentry->d_name, &fibh, &cfi)) {
+               struct kernel_lb_addr loc;
+
                if (fibh.sbh != fibh.ebh)
                        brelse(fibh.ebh);
                brelse(fibh.sbh);
 
-               inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
+               loc = lelb_to_cpu(cfi.icb.extLocation);
+               inode = udf_iget(dir->i_sb, &loc);
                if (!inode) {
                        unlock_kernel();
                        return ERR_PTR(-EACCES);
@@ -313,7 +316,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
        uint8_t lfi;
        uint16_t liu;
        int block;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen = 0;
        sector_t offset;
        struct extent_position epos = {};
@@ -351,16 +354,16 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
                if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
                    &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
                        block = udf_get_lb_pblock(dir->i_sb,
-                                       dinfo->i_location, 0);
+                                       &dinfo->i_location, 0);
                        fibh->soffset = fibh->eoffset = sb->s_blocksize;
                        goto add;
                }
-               block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-                               epos.offset -= sizeof(short_ad);
+                               epos.offset -= sizeof(struct short_ad);
                        else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-                               epos.offset -= sizeof(long_ad);
+                               epos.offset -= sizeof(struct long_ad);
                } else
                        offset = 0;
 
@@ -409,10 +412,10 @@ add:
        if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && elen) {
                elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
                if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-                       epos.offset -= sizeof(short_ad);
+                       epos.offset -= sizeof(struct short_ad);
                else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-                       epos.offset -= sizeof(long_ad);
-               udf_write_aext(dir, &epos, eloc, elen, 1);
+                       epos.offset -= sizeof(struct long_ad);
+               udf_write_aext(dir, &epos, &eloc, elen, 1);
        }
        f_pos += nfidlen;
 
@@ -494,10 +497,10 @@ add:
        memset(cfi, 0, sizeof(struct fileIdentDesc));
        if (UDF_SB(sb)->s_udfrev >= 0x0200)
                udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block,
-                           sizeof(tag));
+                           sizeof(struct tag));
        else
                udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block,
-                           sizeof(tag));
+                           sizeof(struct tag));
        cfi->fileVersionNum = cpu_to_le16(1);
        cfi->lengthFileIdent = namelen;
        cfi->lengthOfImpUse = cpu_to_le16(0);
@@ -530,7 +533,7 @@ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
        cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
-               memset(&(cfi->icb), 0x00, sizeof(long_ad));
+               memset(&(cfi->icb), 0x00, sizeof(struct long_ad));
 
        return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
 }
@@ -710,7 +713,7 @@ static int empty_dir(struct inode *dir)
        loff_t f_pos;
        loff_t size = udf_ext0_offset(dir) + dir->i_size;
        int block;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
        struct extent_position epos = {};
@@ -724,12 +727,12 @@ static int empty_dir(struct inode *dir)
        else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
                              &epos, &eloc, &elen, &offset) ==
                                        (EXT_RECORDED_ALLOCATED >> 30)) {
-               block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-                               epos.offset -= sizeof(short_ad);
+                               epos.offset -= sizeof(struct short_ad);
                        else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-                               epos.offset -= sizeof(long_ad);
+                               epos.offset -= sizeof(struct long_ad);
                } else
                        offset = 0;
 
@@ -778,7 +781,7 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
        struct inode *inode = dentry->d_inode;
        struct udf_fileident_bh fibh;
        struct fileIdentDesc *fi, cfi;
-       kernel_lb_addr tloc;
+       struct kernel_lb_addr tloc;
 
        retval = -ENOENT;
        lock_kernel();
@@ -788,7 +791,7 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
 
        retval = -EIO;
        tloc = lelb_to_cpu(cfi.icb.extLocation);
-       if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
+       if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
                goto end_rmdir;
        retval = -ENOTEMPTY;
        if (!empty_dir(inode))
@@ -824,7 +827,7 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
        struct udf_fileident_bh fibh;
        struct fileIdentDesc *fi;
        struct fileIdentDesc cfi;
-       kernel_lb_addr tloc;
+       struct kernel_lb_addr tloc;
 
        retval = -ENOENT;
        lock_kernel();
@@ -834,7 +837,7 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
 
        retval = -EIO;
        tloc = lelb_to_cpu(cfi.icb.extLocation);
-       if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
+       if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
                goto end_unlink;
 
        if (!inode->i_nlink) {
@@ -897,7 +900,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        inode->i_op = &page_symlink_inode_operations;
 
        if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
-               kernel_lb_addr eloc;
+               struct kernel_lb_addr eloc;
                uint32_t bsize;
 
                block = udf_new_block(inode->i_sb, inode,
@@ -913,7 +916,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
                                iinfo->i_location.partitionReferenceNum;
                bsize = inode->i_sb->s_blocksize;
                iinfo->i_lenExtents = bsize;
-               udf_add_aext(inode, &epos, eloc, bsize, 0);
+               udf_add_aext(inode, &epos, &eloc, bsize, 0);
                brelse(epos.bh);
 
                block = udf_get_pblock(inode->i_sb, block,
@@ -1108,7 +1111,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct fileIdentDesc ocfi, ncfi;
        struct buffer_head *dir_bh = NULL;
        int retval = -ENOENT;
-       kernel_lb_addr tloc;
+       struct kernel_lb_addr tloc;
        struct udf_inode_info *old_iinfo = UDF_I(old_inode);
 
        lock_kernel();
@@ -1119,7 +1122,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                brelse(ofibh.sbh);
        }
        tloc = lelb_to_cpu(ocfi.icb.extLocation);
-       if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
+       if (!ofi || udf_get_lb_pblock(old_dir->i_sb, &tloc, 0)
            != old_inode->i_ino)
                goto end_rename;
 
@@ -1158,7 +1161,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (!dir_fi)
                        goto end_rename;
                tloc = lelb_to_cpu(dir_fi->icb.extLocation);
-               if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) !=
+               if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) !=
                                old_dir->i_ino)
                        goto end_rename;
 
@@ -1187,7 +1190,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
         */
        ncfi.fileVersionNum = ocfi.fileVersionNum;
        ncfi.fileCharacteristics = ocfi.fileCharacteristics;
-       memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
+       memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(struct long_ad));
        udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
 
        /* The old fid may have moved - find it again */
@@ -1242,6 +1245,7 @@ end_rename:
 
 static struct dentry *udf_get_parent(struct dentry *child)
 {
+       struct kernel_lb_addr tloc;
        struct inode *inode = NULL;
        struct qstr dotdot = {.name = "..", .len = 2};
        struct fileIdentDesc cfi;
@@ -1255,8 +1259,8 @@ static struct dentry *udf_get_parent(struct dentry *child)
                brelse(fibh.ebh);
        brelse(fibh.sbh);
 
-       inode = udf_iget(child->d_inode->i_sb,
-                        lelb_to_cpu(cfi.icb.extLocation));
+       tloc = lelb_to_cpu(cfi.icb.extLocation);
+       inode = udf_iget(child->d_inode->i_sb, &tloc);
        if (!inode)
                goto out_unlock;
        unlock_kernel();
@@ -1272,14 +1276,14 @@ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
                                        u16 partref, __u32 generation)
 {
        struct inode *inode;
-       kernel_lb_addr loc;
+       struct kernel_lb_addr loc;
 
        if (block == 0)
                return ERR_PTR(-ESTALE);
 
        loc.logicalBlockNum = block;
        loc.partitionReferenceNum = partref;
-       inode = udf_iget(sb, loc);
+       inode = udf_iget(sb, &loc);
 
        if (inode == NULL)
                return ERR_PTR(-ENOMEM);
@@ -1318,7 +1322,7 @@ static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
 {
        int len = *lenp;
        struct inode *inode =  de->d_inode;
-       kernel_lb_addr location = UDF_I(inode)->i_location;
+       struct kernel_lb_addr location = UDF_I(inode)->i_location;
        struct fid *fid = (struct fid *)fh;
        int type = FILEID_UDF_WITHOUT_PARENT;
 
index 65ff47902bd25784940b9ac3bc7744fc9da0e04f..fbff74654df2242f0df086237512226923c76429 100644 (file)
@@ -85,7 +85,7 @@ struct appIdentSuffix {
 /* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
 /* Implementation Use (UDF 2.50 2.2.6.4) */
 struct logicalVolIntegrityDescImpUse {
-       regid           impIdent;
+       struct regid    impIdent;
        __le32          numFiles;
        __le32          numDirs;
        __le16          minUDFReadRev;
@@ -97,12 +97,12 @@ struct logicalVolIntegrityDescImpUse {
 /* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
 /* Implementation Use (UDF 2.50 2.2.7.2) */
 struct impUseVolDescImpUse {
-       charspec        LVICharset;
+       struct charspec LVICharset;
        dstring         logicalVolIdent[128];
        dstring         LVInfo1[36];
        dstring         LVInfo2[36];
        dstring         LVInfo3[36];
-       regid           impIdent;
+       struct regid    impIdent;
        uint8_t         impUse[128];
 } __attribute__ ((packed));
 
@@ -110,7 +110,7 @@ struct udfPartitionMap2 {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         reserved1[2];
-       regid           partIdent;
+       struct regid    partIdent;
        __le16          volSeqNum;
        __le16          partitionNum;
 } __attribute__ ((packed));
@@ -120,7 +120,7 @@ struct virtualPartitionMap {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         reserved1[2];
-       regid           partIdent;
+       struct regid    partIdent;
        __le16          volSeqNum;
        __le16          partitionNum;
        uint8_t         reserved2[24];
@@ -131,7 +131,7 @@ struct sparablePartitionMap {
        uint8_t partitionMapType;
        uint8_t partitionMapLength;
        uint8_t reserved1[2];
-       regid partIdent;
+       struct regid partIdent;
        __le16 volSeqNum;
        __le16 partitionNum;
        __le16 packetLength;
@@ -146,7 +146,7 @@ struct metadataPartitionMap {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         reserved1[2];
-       regid           partIdent;
+       struct regid    partIdent;
        __le16          volSeqNum;
        __le16          partitionNum;
        __le32          metadataFileLoc;
@@ -161,7 +161,7 @@ struct metadataPartitionMap {
 /* Virtual Allocation Table (UDF 1.5 2.2.10) */
 struct virtualAllocationTable15 {
        __le32          VirtualSector[0];
-       regid           vatIdent;
+       struct regid    vatIdent;
        __le32          previousVATICBLoc;
 } __attribute__ ((packed));
 
@@ -192,8 +192,8 @@ struct sparingEntry {
 } __attribute__ ((packed));
 
 struct sparingTable {
-       tag             descTag;
-       regid           sparingIdent;
+       struct tag      descTag;
+       struct regid    sparingIdent;
        __le16          reallocationTableLen;
        __le16          reserved;
        __le32          sequenceNum;
@@ -206,7 +206,7 @@ struct sparingTable {
 #define ICBTAG_FILE_TYPE_MIRROR                0xFB
 #define ICBTAG_FILE_TYPE_BITMAP                0xFC
 
-/* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
+/* struct struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
 struct allocDescImpUse {
        __le16          flags;
        uint8_t         impUse[4];
index 96dfd207c3d6339f5a07377a217e5f15c01140e2..4b540ee632d5ba919ee93a5ef2689794c4935bb5 100644 (file)
@@ -273,7 +273,7 @@ static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
 {
        struct super_block *sb = inode->i_sb;
        struct udf_part_map *map;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen;
        sector_t ext_offset;
        struct extent_position epos = {};
index e25e7010627b887bee05a004d55642888a00a291..72348cc855a45dd25126aaba8557772e0d4b491d 100644 (file)
@@ -81,16 +81,13 @@ static char error_buf[1024];
 /* These are the "meat" - everything else is stuffing */
 static int udf_fill_super(struct super_block *, void *, int);
 static void udf_put_super(struct super_block *);
-static void udf_write_super(struct super_block *);
+static int udf_sync_fs(struct super_block *, int);
 static int udf_remount_fs(struct super_block *, int *, char *);
-static int udf_check_valid(struct super_block *, int, int);
-static int udf_vrs(struct super_block *sb, int silent);
-static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad);
-static void udf_find_anchor(struct super_block *);
-static int udf_find_fileset(struct super_block *, kernel_lb_addr *,
-                           kernel_lb_addr *);
+static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad);
+static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *,
+                           struct kernel_lb_addr *);
 static void udf_load_fileset(struct super_block *, struct buffer_head *,
-                            kernel_lb_addr *);
+                            struct kernel_lb_addr *);
 static void udf_open_lvid(struct super_block *);
 static void udf_close_lvid(struct super_block *);
 static unsigned int udf_count_free(struct super_block *);
@@ -181,7 +178,7 @@ static const struct super_operations udf_sb_ops = {
        .delete_inode   = udf_delete_inode,
        .clear_inode    = udf_clear_inode,
        .put_super      = udf_put_super,
-       .write_super    = udf_write_super,
+       .sync_fs        = udf_sync_fs,
        .statfs         = udf_statfs,
        .remount_fs     = udf_remount_fs,
        .show_options   = udf_show_options,
@@ -201,6 +198,8 @@ struct udf_options {
        mode_t umask;
        gid_t gid;
        uid_t uid;
+       mode_t fmode;
+       mode_t dmode;
        struct nls_table *nls_map;
 };
 
@@ -258,7 +257,7 @@ static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt)
 
        if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT))
                seq_puts(seq, ",nostrict");
-       if (sb->s_blocksize != UDF_DEFAULT_BLOCKSIZE)
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_BLOCKSIZE_SET))
                seq_printf(seq, ",bs=%lu", sb->s_blocksize);
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
                seq_puts(seq, ",unhide");
@@ -282,18 +281,16 @@ static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt)
                seq_printf(seq, ",gid=%u", sbi->s_gid);
        if (sbi->s_umask != 0)
                seq_printf(seq, ",umask=%o", sbi->s_umask);
+       if (sbi->s_fmode != UDF_INVALID_MODE)
+               seq_printf(seq, ",mode=%o", sbi->s_fmode);
+       if (sbi->s_dmode != UDF_INVALID_MODE)
+               seq_printf(seq, ",dmode=%o", sbi->s_dmode);
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET))
                seq_printf(seq, ",session=%u", sbi->s_session);
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET))
                seq_printf(seq, ",lastblock=%u", sbi->s_last_block);
-       /*
-        * s_anchor[2] could be zeroed out in case there is no anchor
-        * in the specified block, but then the "anchor=N" option
-        * originally given by the user wasn't effective, so it's OK
-        * if we don't show it.
-        */
-       if (sbi->s_anchor[2] != 0)
-               seq_printf(seq, ",anchor=%u", sbi->s_anchor[2]);
+       if (sbi->s_anchor != 0)
+               seq_printf(seq, ",anchor=%u", sbi->s_anchor);
        /*
         * volume, partition, fileset and rootdir seem to be ignored
         * currently
@@ -317,6 +314,8 @@ static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt)
  *
  *     gid=            Set the default group.
  *     umask=          Set the default umask.
+ *     mode=           Set the default file permissions.
+ *     dmode=          Set the default directory permissions.
  *     uid=            Set the default user.
  *     bs=             Set the block size.
  *     unhide          Show otherwise hidden files.
@@ -366,7 +365,8 @@ enum {
        Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock,
        Opt_anchor, Opt_volume, Opt_partition, Opt_fileset,
        Opt_rootdir, Opt_utf8, Opt_iocharset,
-       Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore
+       Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore,
+       Opt_fmode, Opt_dmode
 };
 
 static const match_table_t tokens = {
@@ -395,6 +395,8 @@ static const match_table_t tokens = {
        {Opt_rootdir,   "rootdir=%u"},
        {Opt_utf8,      "utf8"},
        {Opt_iocharset, "iocharset=%s"},
+       {Opt_fmode,     "mode=%o"},
+       {Opt_dmode,     "dmode=%o"},
        {Opt_err,       NULL}
 };
 
@@ -405,7 +407,6 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
        int option;
 
        uopt->novrs = 0;
-       uopt->blocksize = UDF_DEFAULT_BLOCKSIZE;
        uopt->partition = 0xFFFF;
        uopt->session = 0xFFFFFFFF;
        uopt->lastblock = 0;
@@ -428,10 +429,12 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
                switch (token) {
                case Opt_novrs:
                        uopt->novrs = 1;
+                       break;
                case Opt_bs:
                        if (match_int(&args[0], &option))
                                return 0;
                        uopt->blocksize = option;
+                       uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET);
                        break;
                case Opt_unhide:
                        uopt->flags |= (1 << UDF_FLAG_UNHIDE);
@@ -531,6 +534,16 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
                case Opt_gforget:
                        uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
                        break;
+               case Opt_fmode:
+                       if (match_octal(args, &option))
+                               return 0;
+                       uopt->fmode = option & 0777;
+                       break;
+               case Opt_dmode:
+                       if (match_octal(args, &option))
+                               return 0;
+                       uopt->dmode = option & 0777;
+                       break;
                default:
                        printk(KERN_ERR "udf: bad mount option \"%s\" "
                               "or missing value\n", p);
@@ -540,17 +553,6 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
        return 1;
 }
 
-static void udf_write_super(struct super_block *sb)
-{
-       lock_kernel();
-
-       if (!(sb->s_flags & MS_RDONLY))
-               udf_open_lvid(sb);
-       sb->s_dirt = 0;
-
-       unlock_kernel();
-}
-
 static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
 {
        struct udf_options uopt;
@@ -560,6 +562,8 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        uopt.uid   = sbi->s_uid;
        uopt.gid   = sbi->s_gid;
        uopt.umask = sbi->s_umask;
+       uopt.fmode = sbi->s_fmode;
+       uopt.dmode = sbi->s_dmode;
 
        if (!udf_parse_options(options, &uopt, true))
                return -EINVAL;
@@ -568,6 +572,8 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        sbi->s_uid   = uopt.uid;
        sbi->s_gid   = uopt.gid;
        sbi->s_umask = uopt.umask;
+       sbi->s_fmode = uopt.fmode;
+       sbi->s_dmode = uopt.dmode;
 
        if (sbi->s_lvid_bh) {
                int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev);
@@ -585,22 +591,19 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        return 0;
 }
 
-static int udf_vrs(struct super_block *sb, int silent)
+/* Check Volume Structure Descriptors (ECMA 167 2/9.1) */
+/* We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
+static loff_t udf_check_vsd(struct super_block *sb)
 {
        struct volStructDesc *vsd = NULL;
        loff_t sector = 32768;
        int sectorsize;
        struct buffer_head *bh = NULL;
-       int iso9660 = 0;
        int nsr02 = 0;
        int nsr03 = 0;
        struct udf_sb_info *sbi;
 
-       /* Block size must be a multiple of 512 */
-       if (sb->s_blocksize & 511)
-               return 0;
        sbi = UDF_SB(sb);
-
        if (sb->s_blocksize < sizeof(struct volStructDesc))
                sectorsize = sizeof(struct volStructDesc);
        else
@@ -627,7 +630,6 @@ static int udf_vrs(struct super_block *sb, int silent)
                        break;
                } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,
                                    VSD_STD_ID_LEN)) {
-                       iso9660 = sector;
                        switch (vsd->structType) {
                        case 0:
                                udf_debug("ISO9660 Boot Record found\n");
@@ -679,139 +681,9 @@ static int udf_vrs(struct super_block *sb, int silent)
                return 0;
 }
 
-/*
- * Check whether there is an anchor block in the given block
- */
-static int udf_check_anchor_block(struct super_block *sb, sector_t block)
-{
-       struct buffer_head *bh;
-       uint16_t ident;
-
-       if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
-           udf_fixed_to_variable(block) >=
-           sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
-               return 0;
-
-       bh = udf_read_tagged(sb, block, block, &ident);
-       if (!bh)
-               return 0;
-       brelse(bh);
-
-       return ident == TAG_IDENT_AVDP;
-}
-
-/* Search for an anchor volume descriptor pointer */
-static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock)
-{
-       sector_t last[6];
-       int i;
-       struct udf_sb_info *sbi = UDF_SB(sb);
-
-       last[0] = lastblock;
-       last[1] = last[0] - 1;
-       last[2] = last[0] + 1;
-       last[3] = last[0] - 2;
-       last[4] = last[0] - 150;
-       last[5] = last[0] - 152;
-
-       /*  according to spec, anchor is in either:
-        *     block 256
-        *     lastblock-256
-        *     lastblock
-        *  however, if the disc isn't closed, it could be 512 */
-
-       for (i = 0; i < ARRAY_SIZE(last); i++) {
-               if (last[i] < 0)
-                       continue;
-               if (last[i] >= sb->s_bdev->bd_inode->i_size >>
-                               sb->s_blocksize_bits)
-                       continue;
-
-               if (udf_check_anchor_block(sb, last[i])) {
-                       sbi->s_anchor[0] = last[i];
-                       sbi->s_anchor[1] = last[i] - 256;
-                       return last[i];
-               }
-
-               if (last[i] < 256)
-                       continue;
-
-               if (udf_check_anchor_block(sb, last[i] - 256)) {
-                       sbi->s_anchor[1] = last[i] - 256;
-                       return last[i];
-               }
-       }
-
-       if (udf_check_anchor_block(sb, sbi->s_session + 256)) {
-               sbi->s_anchor[0] = sbi->s_session + 256;
-               return last[0];
-       }
-       if (udf_check_anchor_block(sb, sbi->s_session + 512)) {
-               sbi->s_anchor[0] = sbi->s_session + 512;
-               return last[0];
-       }
-       return 0;
-}
-
-/*
- * Find an anchor volume descriptor. The function expects sbi->s_lastblock to
- * be the last block on the media.
- *
- * Return 1 if not found, 0 if ok
- *
- */
-static void udf_find_anchor(struct super_block *sb)
-{
-       sector_t lastblock;
-       struct buffer_head *bh = NULL;
-       uint16_t ident;
-       int i;
-       struct udf_sb_info *sbi = UDF_SB(sb);
-
-       lastblock = udf_scan_anchors(sb, sbi->s_last_block);
-       if (lastblock)
-               goto check_anchor;
-
-       /* No anchor found? Try VARCONV conversion of block numbers */
-       UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
-       /* Firstly, we try to not convert number of the last block */
-       lastblock = udf_scan_anchors(sb,
-                               udf_variable_to_fixed(sbi->s_last_block));
-       if (lastblock)
-               goto check_anchor;
-
-       /* Secondly, we try with converted number of the last block */
-       lastblock = udf_scan_anchors(sb, sbi->s_last_block);
-       if (!lastblock) {
-               /* VARCONV didn't help. Clear it. */
-               UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
-       }
-
-check_anchor:
-       /*
-        * Check located anchors and the anchor block supplied via
-        * mount options
-        */
-       for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
-               if (!sbi->s_anchor[i])
-                       continue;
-               bh = udf_read_tagged(sb, sbi->s_anchor[i],
-                                       sbi->s_anchor[i], &ident);
-               if (!bh)
-                       sbi->s_anchor[i] = 0;
-               else {
-                       brelse(bh);
-                       if (ident != TAG_IDENT_AVDP)
-                               sbi->s_anchor[i] = 0;
-               }
-       }
-
-       sbi->s_last_block = lastblock;
-}
-
 static int udf_find_fileset(struct super_block *sb,
-                           kernel_lb_addr *fileset,
-                           kernel_lb_addr *root)
+                           struct kernel_lb_addr *fileset,
+                           struct kernel_lb_addr *root)
 {
        struct buffer_head *bh = NULL;
        long lastblock;
@@ -820,7 +692,7 @@ static int udf_find_fileset(struct super_block *sb,
 
        if (fileset->logicalBlockNum != 0xFFFFFFFF ||
            fileset->partitionReferenceNum != 0xFFFF) {
-               bh = udf_read_ptagged(sb, *fileset, 0, &ident);
+               bh = udf_read_ptagged(sb, fileset, 0, &ident);
 
                if (!bh) {
                        return 1;
@@ -834,7 +706,7 @@ static int udf_find_fileset(struct super_block *sb,
        sbi = UDF_SB(sb);
        if (!bh) {
                /* Search backwards through the partitions */
-               kernel_lb_addr newfileset;
+               struct kernel_lb_addr newfileset;
 
 /* --> cvg: FIXME - is it reasonable? */
                return 1;
@@ -850,7 +722,7 @@ static int udf_find_fileset(struct super_block *sb,
                        newfileset.logicalBlockNum = 0;
 
                        do {
-                               bh = udf_read_ptagged(sb, newfileset, 0,
+                               bh = udf_read_ptagged(sb, &newfileset, 0,
                                                      &ident);
                                if (!bh) {
                                        newfileset.logicalBlockNum++;
@@ -902,14 +774,23 @@ static int udf_find_fileset(struct super_block *sb,
 static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
 {
        struct primaryVolDesc *pvoldesc;
-       struct ustr instr;
-       struct ustr outstr;
+       struct ustr *instr, *outstr;
        struct buffer_head *bh;
        uint16_t ident;
+       int ret = 1;
+
+       instr = kmalloc(sizeof(struct ustr), GFP_NOFS);
+       if (!instr)
+               return 1;
+
+       outstr = kmalloc(sizeof(struct ustr), GFP_NOFS);
+       if (!outstr)
+               goto out1;
 
        bh = udf_read_tagged(sb, block, block, &ident);
        if (!bh)
-               return 1;
+               goto out2;
+
        BUG_ON(ident != TAG_IDENT_PVD);
 
        pvoldesc = (struct primaryVolDesc *)bh->b_data;
@@ -917,7 +798,7 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
        if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
                              pvoldesc->recordingDateAndTime)) {
 #ifdef UDFFS_DEBUG
-               timestamp *ts = &pvoldesc->recordingDateAndTime;
+               struct timestamp *ts = &pvoldesc->recordingDateAndTime;
                udf_debug("recording time %04u/%02u/%02u"
                          " %02u:%02u (%x)\n",
                          le16_to_cpu(ts->year), ts->month, ts->day, ts->hour,
@@ -925,20 +806,25 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
 #endif
        }
 
-       if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32))
-               if (udf_CS0toUTF8(&outstr, &instr)) {
-                       strncpy(UDF_SB(sb)->s_volume_ident, outstr.u_name,
-                               outstr.u_len > 31 ? 31 : outstr.u_len);
+       if (!udf_build_ustr(instr, pvoldesc->volIdent, 32))
+               if (udf_CS0toUTF8(outstr, instr)) {
+                       strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name,
+                               outstr->u_len > 31 ? 31 : outstr->u_len);
                        udf_debug("volIdent[] = '%s'\n",
                                        UDF_SB(sb)->s_volume_ident);
                }
 
-       if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128))
-               if (udf_CS0toUTF8(&outstr, &instr))
-                       udf_debug("volSetIdent[] = '%s'\n", outstr.u_name);
+       if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128))
+               if (udf_CS0toUTF8(outstr, instr))
+                       udf_debug("volSetIdent[] = '%s'\n", outstr->u_name);
 
        brelse(bh);
-       return 0;
+       ret = 0;
+out2:
+       kfree(outstr);
+out1:
+       kfree(instr);
+       return ret;
 }
 
 static int udf_load_metadata_files(struct super_block *sb, int partition)
@@ -946,7 +832,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct udf_part_map *map;
        struct udf_meta_data *mdata;
-       kernel_lb_addr addr;
+       struct kernel_lb_addr addr;
        int fe_error = 0;
 
        map = &sbi->s_partmaps[partition];
@@ -959,7 +845,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
        udf_debug("Metadata file location: block = %d part = %d\n",
                          addr.logicalBlockNum, addr.partitionReferenceNum);
 
-       mdata->s_metadata_fe = udf_iget(sb, addr);
+       mdata->s_metadata_fe = udf_iget(sb, &addr);
 
        if (mdata->s_metadata_fe == NULL) {
                udf_warning(sb, __func__, "metadata inode efe not found, "
@@ -981,7 +867,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
        udf_debug("Mirror metadata file location: block = %d part = %d\n",
                          addr.logicalBlockNum, addr.partitionReferenceNum);
 
-       mdata->s_mirror_fe = udf_iget(sb, addr);
+       mdata->s_mirror_fe = udf_iget(sb, &addr);
 
        if (mdata->s_mirror_fe == NULL) {
                if (fe_error) {
@@ -1013,7 +899,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
                udf_debug("Bitmap file location: block = %d part = %d\n",
                        addr.logicalBlockNum, addr.partitionReferenceNum);
 
-               mdata->s_bitmap_fe = udf_iget(sb, addr);
+               mdata->s_bitmap_fe = udf_iget(sb, &addr);
 
                if (mdata->s_bitmap_fe == NULL) {
                        if (sb->s_flags & MS_RDONLY)
@@ -1037,7 +923,7 @@ error_exit:
 }
 
 static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
-                            kernel_lb_addr *root)
+                            struct kernel_lb_addr *root)
 {
        struct fileSetDesc *fset;
 
@@ -1119,13 +1005,13 @@ static int udf_fill_partdesc_info(struct super_block *sb,
 
        phd = (struct partitionHeaderDesc *)p->partitionContentsUse;
        if (phd->unallocSpaceTable.extLength) {
-               kernel_lb_addr loc = {
+               struct kernel_lb_addr loc = {
                        .logicalBlockNum = le32_to_cpu(
                                phd->unallocSpaceTable.extPosition),
                        .partitionReferenceNum = p_index,
                };
 
-               map->s_uspace.s_table = udf_iget(sb, loc);
+               map->s_uspace.s_table = udf_iget(sb, &loc);
                if (!map->s_uspace.s_table) {
                        udf_debug("cannot load unallocSpaceTable (part %d)\n",
                                        p_index);
@@ -1154,13 +1040,13 @@ static int udf_fill_partdesc_info(struct super_block *sb,
                udf_debug("partitionIntegrityTable (part %d)\n", p_index);
 
        if (phd->freedSpaceTable.extLength) {
-               kernel_lb_addr loc = {
+               struct kernel_lb_addr loc = {
                        .logicalBlockNum = le32_to_cpu(
                                phd->freedSpaceTable.extPosition),
                        .partitionReferenceNum = p_index,
                };
 
-               map->s_fspace.s_table = udf_iget(sb, loc);
+               map->s_fspace.s_table = udf_iget(sb, &loc);
                if (!map->s_fspace.s_table) {
                        udf_debug("cannot load freedSpaceTable (part %d)\n",
                                p_index);
@@ -1192,7 +1078,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct udf_part_map *map = &sbi->s_partmaps[p_index];
-       kernel_lb_addr ino;
+       struct kernel_lb_addr ino;
        struct buffer_head *bh = NULL;
        struct udf_inode_info *vati;
        uint32_t pos;
@@ -1201,7 +1087,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
        /* VAT file entry is in the last recorded block */
        ino.partitionReferenceNum = type1_index;
        ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root;
-       sbi->s_vat_inode = udf_iget(sb, ino);
+       sbi->s_vat_inode = udf_iget(sb, &ino);
        if (!sbi->s_vat_inode)
                return 1;
 
@@ -1322,7 +1208,7 @@ out_bh:
 }
 
 static int udf_load_logicalvol(struct super_block *sb, sector_t block,
-                              kernel_lb_addr *fileset)
+                              struct kernel_lb_addr *fileset)
 {
        struct logicalVolDesc *lvd;
        int i, j, offset;
@@ -1471,7 +1357,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
        }
 
        if (fileset) {
-               long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]);
+               struct long_ad *la = (struct long_ad *)&(lvd->logicalVolContentsUse[0]);
 
                *fileset = lelb_to_cpu(la->extLocation);
                udf_debug("FileSet found in LogicalVolDesc at block=%d, "
@@ -1490,7 +1376,7 @@ out_bh:
  * udf_load_logicalvolint
  *
  */
-static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
+static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ad loc)
 {
        struct buffer_head *bh = NULL;
        uint16_t ident;
@@ -1533,7 +1419,7 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
  *     Written, tested, and released.
  */
 static noinline int udf_process_sequence(struct super_block *sb, long block,
-                               long lastblock, kernel_lb_addr *fileset)
+                               long lastblock, struct kernel_lb_addr *fileset)
 {
        struct buffer_head *bh = NULL;
        struct udf_vds_record vds[VDS_POS_LENGTH];
@@ -1655,85 +1541,199 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
        return 0;
 }
 
+static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
+                            struct kernel_lb_addr *fileset)
+{
+       struct anchorVolDescPtr *anchor;
+       long main_s, main_e, reserve_s, reserve_e;
+       struct udf_sb_info *sbi;
+
+       sbi = UDF_SB(sb);
+       anchor = (struct anchorVolDescPtr *)bh->b_data;
+
+       /* Locate the main sequence */
+       main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
+       main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
+       main_e = main_e >> sb->s_blocksize_bits;
+       main_e += main_s;
+
+       /* Locate the reserve sequence */
+       reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
+       reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
+       reserve_e = reserve_e >> sb->s_blocksize_bits;
+       reserve_e += reserve_s;
+
+       /* Process the main & reserve sequences */
+       /* responsible for finding the PartitionDesc(s) */
+       if (!udf_process_sequence(sb, main_s, main_e, fileset))
+               return 1;
+       return !udf_process_sequence(sb, reserve_s, reserve_e, fileset);
+}
+
 /*
- * udf_check_valid()
+ * Check whether there is an anchor block in the given block and
+ * load Volume Descriptor Sequence if so.
  */
-static int udf_check_valid(struct super_block *sb, int novrs, int silent)
+static int udf_check_anchor_block(struct super_block *sb, sector_t block,
+                                 struct kernel_lb_addr *fileset)
 {
-       long block;
-       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct buffer_head *bh;
+       uint16_t ident;
+       int ret;
 
-       if (novrs) {
-               udf_debug("Validity check skipped because of novrs option\n");
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
+           udf_fixed_to_variable(block) >=
+           sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
+               return 0;
+
+       bh = udf_read_tagged(sb, block, block, &ident);
+       if (!bh)
+               return 0;
+       if (ident != TAG_IDENT_AVDP) {
+               brelse(bh);
                return 0;
        }
-       /* Check that it is NSR02 compliant */
-       /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
-       block = udf_vrs(sb, silent);
-       if (block == -1)
-               udf_debug("Failed to read byte 32768. Assuming open "
-                         "disc. Skipping validity check\n");
-       if (block && !sbi->s_last_block)
-               sbi->s_last_block = udf_get_last_block(sb);
-       return !block;
+       ret = udf_load_sequence(sb, bh, fileset);
+       brelse(bh);
+       return ret;
 }
 
-static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset)
+/* Search for an anchor volume descriptor pointer */
+static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock,
+                                struct kernel_lb_addr *fileset)
 {
-       struct anchorVolDescPtr *anchor;
-       uint16_t ident;
-       struct buffer_head *bh;
-       long main_s, main_e, reserve_s, reserve_e;
+       sector_t last[6];
        int i;
-       struct udf_sb_info *sbi;
-
-       if (!sb)
-               return 1;
-       sbi = UDF_SB(sb);
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       int last_count = 0;
 
-       for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
-               if (!sbi->s_anchor[i])
+       /* First try user provided anchor */
+       if (sbi->s_anchor) {
+               if (udf_check_anchor_block(sb, sbi->s_anchor, fileset))
+                       return lastblock;
+       }
+       /*
+        * according to spec, anchor is in either:
+        *     block 256
+        *     lastblock-256
+        *     lastblock
+        *  however, if the disc isn't closed, it could be 512.
+        */
+       if (udf_check_anchor_block(sb, sbi->s_session + 256, fileset))
+               return lastblock;
+       /*
+        * The trouble is which block is the last one. Drives often misreport
+        * this so we try various possibilities.
+        */
+       last[last_count++] = lastblock;
+       if (lastblock >= 1)
+               last[last_count++] = lastblock - 1;
+       last[last_count++] = lastblock + 1;
+       if (lastblock >= 2)
+               last[last_count++] = lastblock - 2;
+       if (lastblock >= 150)
+               last[last_count++] = lastblock - 150;
+       if (lastblock >= 152)
+               last[last_count++] = lastblock - 152;
+
+       for (i = 0; i < last_count; i++) {
+               if (last[i] >= sb->s_bdev->bd_inode->i_size >>
+                               sb->s_blocksize_bits)
                        continue;
-
-               bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i],
-                                    &ident);
-               if (!bh)
+               if (udf_check_anchor_block(sb, last[i], fileset))
+                       return last[i];
+               if (last[i] < 256)
                        continue;
+               if (udf_check_anchor_block(sb, last[i] - 256, fileset))
+                       return last[i];
+       }
 
-               anchor = (struct anchorVolDescPtr *)bh->b_data;
+       /* Finally try block 512 in case media is open */
+       if (udf_check_anchor_block(sb, sbi->s_session + 512, fileset))
+               return last[0];
+       return 0;
+}
 
-               /* Locate the main sequence */
-               main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
-               main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
-               main_e = main_e >> sb->s_blocksize_bits;
-               main_e += main_s;
+/*
+ * Find an anchor volume descriptor and load Volume Descriptor Sequence from
+ * area specified by it. The function expects sbi->s_lastblock to be the last
+ * block on the media.
+ *
+ * Return 1 if ok, 0 if not found.
+ *
+ */
+static int udf_find_anchor(struct super_block *sb,
+                          struct kernel_lb_addr *fileset)
+{
+       sector_t lastblock;
+       struct udf_sb_info *sbi = UDF_SB(sb);
 
-               /* Locate the reserve sequence */
-               reserve_s = le32_to_cpu(
-                               anchor->reserveVolDescSeqExt.extLocation);
-               reserve_e = le32_to_cpu(
-                               anchor->reserveVolDescSeqExt.extLength);
-               reserve_e = reserve_e >> sb->s_blocksize_bits;
-               reserve_e += reserve_s;
+       lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset);
+       if (lastblock)
+               goto out;
 
-               brelse(bh);
+       /* No anchor found? Try VARCONV conversion of block numbers */
+       UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+       /* Firstly, we try to not convert number of the last block */
+       lastblock = udf_scan_anchors(sb,
+                               udf_variable_to_fixed(sbi->s_last_block),
+                               fileset);
+       if (lastblock)
+               goto out;
 
-               /* Process the main & reserve sequences */
-               /* responsible for finding the PartitionDesc(s) */
-               if (!(udf_process_sequence(sb, main_s, main_e,
-                                          fileset) &&
-                     udf_process_sequence(sb, reserve_s, reserve_e,
-                                          fileset)))
-                       break;
+       /* Secondly, we try with converted number of the last block */
+       lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset);
+       if (!lastblock) {
+               /* VARCONV didn't help. Clear it. */
+               UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
+               return 0;
        }
+out:
+       sbi->s_last_block = lastblock;
+       return 1;
+}
 
-       if (i == ARRAY_SIZE(sbi->s_anchor)) {
-               udf_debug("No Anchor block found\n");
-               return 1;
+/*
+ * Check Volume Structure Descriptor, find Anchor block and load Volume
+ * Descriptor Sequence
+ */
+static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
+                       int silent, struct kernel_lb_addr *fileset)
+{
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       loff_t nsr_off;
+
+       if (!sb_set_blocksize(sb, uopt->blocksize)) {
+               if (!silent)
+                       printk(KERN_WARNING "UDF-fs: Bad block size\n");
+               return 0;
+       }
+       sbi->s_last_block = uopt->lastblock;
+       if (!uopt->novrs) {
+               /* Check that it is NSR02 compliant */
+               nsr_off = udf_check_vsd(sb);
+               if (!nsr_off) {
+                       if (!silent)
+                               printk(KERN_WARNING "UDF-fs: No VRS found\n");
+                       return 0;
+               }
+               if (nsr_off == -1)
+                       udf_debug("Failed to read byte 32768. Assuming open "
+                                 "disc. Skipping validity check\n");
+               if (!sbi->s_last_block)
+                       sbi->s_last_block = udf_get_last_block(sb);
+       } else {
+               udf_debug("Validity check skipped because of novrs option\n");
        }
-       udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]);
 
-       return 0;
+       /* Look for anchor block and load Volume Descriptor Sequence */
+       sbi->s_anchor = uopt->anchor;
+       if (!udf_find_anchor(sb, fileset)) {
+               if (!silent)
+                       printk(KERN_WARNING "UDF-fs: No anchor found\n");
+               return 0;
+       }
+       return 1;
 }
 
 static void udf_open_lvid(struct super_block *sb)
@@ -1742,9 +1742,9 @@ static void udf_open_lvid(struct super_block *sb)
        struct buffer_head *bh = sbi->s_lvid_bh;
        struct logicalVolIntegrityDesc *lvid;
        struct logicalVolIntegrityDescImpUse *lvidiu;
+
        if (!bh)
                return;
-
        lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
        lvidiu = udf_sb_lvidiu(sbi);
 
@@ -1752,14 +1752,15 @@ static void udf_open_lvid(struct super_block *sb)
        lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
        udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
                                CURRENT_TIME);
-       lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN;
+       lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
 
        lvid->descTag.descCRC = cpu_to_le16(
-               crc_itu_t(0, (char *)lvid + sizeof(tag),
+               crc_itu_t(0, (char *)lvid + sizeof(struct tag),
                        le16_to_cpu(lvid->descTag.descCRCLength)));
 
        lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
        mark_buffer_dirty(bh);
+       sbi->s_lvid_dirty = 0;
 }
 
 static void udf_close_lvid(struct super_block *sb)
@@ -1773,10 +1774,6 @@ static void udf_close_lvid(struct super_block *sb)
                return;
 
        lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
-
-       if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN)
-               return;
-
        lvidiu = udf_sb_lvidiu(sbi);
        lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
        lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
@@ -1790,11 +1787,12 @@ static void udf_close_lvid(struct super_block *sb)
        lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
 
        lvid->descTag.descCRC = cpu_to_le16(
-                       crc_itu_t(0, (char *)lvid + sizeof(tag),
+                       crc_itu_t(0, (char *)lvid + sizeof(struct tag),
                                le16_to_cpu(lvid->descTag.descCRCLength)));
 
        lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
        mark_buffer_dirty(bh);
+       sbi->s_lvid_dirty = 0;
 }
 
 static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
@@ -1846,15 +1844,18 @@ static void udf_free_partition(struct udf_part_map *map)
 static int udf_fill_super(struct super_block *sb, void *options, int silent)
 {
        int i;
+       int ret;
        struct inode *inode = NULL;
        struct udf_options uopt;
-       kernel_lb_addr rootdir, fileset;
+       struct kernel_lb_addr rootdir, fileset;
        struct udf_sb_info *sbi;
 
        uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
        uopt.uid = -1;
        uopt.gid = -1;
        uopt.umask = 0;
+       uopt.fmode = UDF_INVALID_MODE;
+       uopt.dmode = UDF_INVALID_MODE;
 
        sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
        if (!sbi)
@@ -1892,15 +1893,10 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sbi->s_uid = uopt.uid;
        sbi->s_gid = uopt.gid;
        sbi->s_umask = uopt.umask;
+       sbi->s_fmode = uopt.fmode;
+       sbi->s_dmode = uopt.dmode;
        sbi->s_nls_map = uopt.nls_map;
 
-       /* Set the block size for all transfers */
-       if (!sb_min_blocksize(sb, uopt.blocksize)) {
-               udf_debug("Bad block size (%d)\n", uopt.blocksize);
-               printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize);
-               goto error_out;
-       }
-
        if (uopt.session == 0xFFFFFFFF)
                sbi->s_session = udf_get_last_session(sb);
        else
@@ -1908,18 +1904,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 
        udf_debug("Multi-session=%d\n", sbi->s_session);
 
-       sbi->s_last_block = uopt.lastblock;
-       sbi->s_anchor[0] = sbi->s_anchor[1] = 0;
-       sbi->s_anchor[2] = uopt.anchor;
-
-       if (udf_check_valid(sb, uopt.novrs, silent)) {
-               /* read volume recognition sequences */
-               printk(KERN_WARNING "UDF-fs: No VRS found\n");
-               goto error_out;
-       }
-
-       udf_find_anchor(sb);
-
        /* Fill in the rest of the superblock */
        sb->s_op = &udf_sb_ops;
        sb->s_export_op = &udf_export_ops;
@@ -1928,7 +1912,21 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sb->s_magic = UDF_SUPER_MAGIC;
        sb->s_time_gran = 1000;
 
-       if (udf_load_sequence(sb, &fileset)) {
+       if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) {
+               ret = udf_load_vrs(sb, &uopt, silent, &fileset);
+       } else {
+               uopt.blocksize = bdev_hardsect_size(sb->s_bdev);
+               ret = udf_load_vrs(sb, &uopt, silent, &fileset);
+               if (!ret && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
+                       if (!silent)
+                               printk(KERN_NOTICE
+                                      "UDF-fs: Rescanning with blocksize "
+                                      "%d\n", UDF_DEFAULT_BLOCKSIZE);
+                       uopt.blocksize = UDF_DEFAULT_BLOCKSIZE;
+                       ret = udf_load_vrs(sb, &uopt, silent, &fileset);
+               }
+       }
+       if (!ret) {
                printk(KERN_WARNING "UDF-fs: No partition found (1)\n");
                goto error_out;
        }
@@ -1978,7 +1976,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        }
 
        if (!silent) {
-               timestamp ts;
+               struct timestamp ts;
                udf_time_to_disk_stamp(&ts, sbi->s_record_time);
                udf_info("UDF: Mounting volume '%s', "
                         "timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
@@ -1991,7 +1989,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        /* Assign the root inode */
        /* assign inodes by physical block number */
        /* perhaps it's not extensible enough, but for now ... */
-       inode = udf_iget(sb, rootdir);
+       inode = udf_iget(sb, &rootdir);
        if (!inode) {
                printk(KERN_ERR "UDF-fs: Error in udf_iget, block=%d, "
                                "partition=%d\n",
@@ -2081,11 +2079,31 @@ static void udf_put_super(struct super_block *sb)
        sb->s_fs_info = NULL;
 }
 
+static int udf_sync_fs(struct super_block *sb, int wait)
+{
+       struct udf_sb_info *sbi = UDF_SB(sb);
+
+       mutex_lock(&sbi->s_alloc_mutex);
+       if (sbi->s_lvid_dirty) {
+               /*
+                * Blockdevice will be synced later so we don't have to submit
+                * the buffer for IO
+                */
+               mark_buffer_dirty(sbi->s_lvid_bh);
+               sb->s_dirt = 0;
+               sbi->s_lvid_dirty = 0;
+       }
+       mutex_unlock(&sbi->s_alloc_mutex);
+
+       return 0;
+}
+
 static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct logicalVolIntegrityDescImpUse *lvidiu;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        if (sbi->s_lvid_bh != NULL)
                lvidiu = udf_sb_lvidiu(sbi);
@@ -2101,8 +2119,9 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
                                          le32_to_cpu(lvidiu->numDirs)) : 0)
                        + buf->f_bfree;
        buf->f_ffree = buf->f_bfree;
-       /* __kernel_fsid_t f_fsid */
        buf->f_namelen = UDF_NAME_LEN - 2;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        return 0;
 }
@@ -2114,7 +2133,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
        unsigned int accum = 0;
        int index;
        int block = 0, newblock;
-       kernel_lb_addr loc;
+       struct kernel_lb_addr loc;
        uint32_t bytes;
        uint8_t *ptr;
        uint16_t ident;
@@ -2124,7 +2143,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
 
        loc.logicalBlockNum = bitmap->s_extPosition;
        loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
-       bh = udf_read_ptagged(sb, loc, 0, &ident);
+       bh = udf_read_ptagged(sb, &loc, 0, &ident);
 
        if (!bh) {
                printk(KERN_ERR "udf: udf_count_free failed\n");
@@ -2147,7 +2166,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
                bytes -= cur_bytes;
                if (bytes) {
                        brelse(bh);
-                       newblock = udf_get_lb_pblock(sb, loc, ++block);
+                       newblock = udf_get_lb_pblock(sb, &loc, ++block);
                        bh = udf_tread(sb, newblock);
                        if (!bh) {
                                udf_debug("read failed\n");
@@ -2170,7 +2189,7 @@ static unsigned int udf_count_free_table(struct super_block *sb,
 {
        unsigned int accum = 0;
        uint32_t elen;
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        int8_t etype;
        struct extent_position epos;
 
index 65e19b4f9424c20f8f616b7ee5de3db55f33ed0e..225527cdc885591614e92ff6ff325c7fdd459229 100644 (file)
 #include "udf_sb.h"
 
 static void extent_trunc(struct inode *inode, struct extent_position *epos,
-                        kernel_lb_addr eloc, int8_t etype, uint32_t elen,
+                        struct kernel_lb_addr *eloc, int8_t etype, uint32_t elen,
                         uint32_t nelen)
 {
-       kernel_lb_addr neloc = {};
+       struct kernel_lb_addr neloc = {};
        int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
                inode->i_sb->s_blocksize_bits;
        int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
@@ -43,12 +43,12 @@ static void extent_trunc(struct inode *inode, struct extent_position *epos,
                                        last_block);
                        etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
                } else
-                       neloc = eloc;
+                       neloc = *eloc;
                nelen = (etype << 30) | nelen;
        }
 
        if (elen != nelen) {
-               udf_write_aext(inode, epos, neloc, nelen, 0);
+               udf_write_aext(inode, epos, &neloc, nelen, 0);
                if (last_block - first_block > 0) {
                        if (etype == (EXT_RECORDED_ALLOCATED >> 30))
                                mark_inode_dirty(inode);
@@ -68,7 +68,7 @@ static void extent_trunc(struct inode *inode, struct extent_position *epos,
 void udf_truncate_tail_extent(struct inode *inode)
 {
        struct extent_position epos = {};
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen, nelen;
        uint64_t lbcount = 0;
        int8_t etype = -1, netype;
@@ -83,9 +83,9 @@ void udf_truncate_tail_extent(struct inode *inode)
                return;
 
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               adsize = sizeof(short_ad);
+               adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
        else
                BUG();
 
@@ -106,7 +106,7 @@ void udf_truncate_tail_extent(struct inode *inode)
                                       (unsigned)elen);
                        nelen = elen - (lbcount - inode->i_size);
                        epos.offset -= adsize;
-                       extent_trunc(inode, &epos, eloc, etype, elen, nelen);
+                       extent_trunc(inode, &epos, &eloc, etype, elen, nelen);
                        epos.offset += adsize;
                        if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1)
                                printk(KERN_ERR "udf_truncate_tail_extent(): "
@@ -124,7 +124,7 @@ void udf_truncate_tail_extent(struct inode *inode)
 void udf_discard_prealloc(struct inode *inode)
 {
        struct extent_position epos = { NULL, 0, {0, 0} };
-       kernel_lb_addr eloc;
+       struct kernel_lb_addr eloc;
        uint32_t elen;
        uint64_t lbcount = 0;
        int8_t etype = -1, netype;
@@ -136,9 +136,9 @@ void udf_discard_prealloc(struct inode *inode)
                return;
 
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               adsize = sizeof(short_ad);
+               adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
        else
                adsize = 0;
 
@@ -152,7 +152,7 @@ void udf_discard_prealloc(struct inode *inode)
        if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
                epos.offset -= adsize;
                lbcount -= elen;
-               extent_trunc(inode, &epos, eloc, etype, elen, 0);
+               extent_trunc(inode, &epos, &eloc, etype, elen, 0);
                if (!epos.bh) {
                        iinfo->i_lenAlloc =
                                epos.offset -
@@ -200,7 +200,7 @@ static void udf_update_alloc_ext_desc(struct inode *inode,
 void udf_truncate_extents(struct inode *inode)
 {
        struct extent_position epos;
-       kernel_lb_addr eloc, neloc = {};
+       struct kernel_lb_addr eloc, neloc = {};
        uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
        int8_t etype;
        struct super_block *sb = inode->i_sb;
@@ -210,9 +210,9 @@ void udf_truncate_extents(struct inode *inode)
        struct udf_inode_info *iinfo = UDF_I(inode);
 
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-               adsize = sizeof(short_ad);
+               adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-               adsize = sizeof(long_ad);
+               adsize = sizeof(struct long_ad);
        else
                BUG();
 
@@ -221,7 +221,7 @@ void udf_truncate_extents(struct inode *inode)
                (inode->i_size & (sb->s_blocksize - 1));
        if (etype != -1) {
                epos.offset -= adsize;
-               extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
+               extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
                epos.offset += adsize;
                if (byte_offset)
                        lenalloc = epos.offset;
@@ -236,12 +236,12 @@ void udf_truncate_extents(struct inode *inode)
                while ((etype = udf_current_aext(inode, &epos, &eloc,
                                                 &elen, 0)) != -1) {
                        if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
-                               udf_write_aext(inode, &epos, neloc, nelen, 0);
+                               udf_write_aext(inode, &epos, &neloc, nelen, 0);
                                if (indirect_ext_len) {
                                        /* We managed to free all extents in the
                                         * indirect extent - free it too */
                                        BUG_ON(!epos.bh);
-                                       udf_free_blocks(sb, inode, epos.block,
+                                       udf_free_blocks(sb, inode, &epos.block,
                                                        0, indirect_ext_len);
                                } else if (!epos.bh) {
                                        iinfo->i_lenAlloc = lenalloc;
@@ -253,7 +253,7 @@ void udf_truncate_extents(struct inode *inode)
                                epos.offset = sizeof(struct allocExtDesc);
                                epos.block = eloc;
                                epos.bh = udf_tread(sb,
-                                               udf_get_lb_pblock(sb, eloc, 0));
+                                               udf_get_lb_pblock(sb, &eloc, 0));
                                if (elen)
                                        indirect_ext_len =
                                                (elen + sb->s_blocksize - 1) >>
@@ -261,7 +261,7 @@ void udf_truncate_extents(struct inode *inode)
                                else
                                        indirect_ext_len = 1;
                        } else {
-                               extent_trunc(inode, &epos, eloc, etype,
+                               extent_trunc(inode, &epos, &eloc, etype,
                                             elen, 0);
                                epos.offset += adsize;
                        }
@@ -269,7 +269,7 @@ void udf_truncate_extents(struct inode *inode)
 
                if (indirect_ext_len) {
                        BUG_ON(!epos.bh);
-                       udf_free_blocks(sb, inode, epos.block, 0,
+                       udf_free_blocks(sb, inode, &epos.block, 0,
                                        indirect_ext_len);
                } else if (!epos.bh) {
                        iinfo->i_lenAlloc = lenalloc;
@@ -278,7 +278,7 @@ void udf_truncate_extents(struct inode *inode)
                        udf_update_alloc_ext_desc(inode, &epos, lenalloc);
        } else if (inode->i_size) {
                if (byte_offset) {
-                       kernel_long_ad extent;
+                       struct kernel_long_ad extent;
 
                        /*
                         *  OK, there is not extent covering inode->i_size and
index 4f86b1d98a5d44ffbf1ae64bee4618c2dfcf3b4a..e58d1de41073ccd8768d3cda0ba8c058b17dfa12 100644 (file)
@@ -4,7 +4,7 @@
 struct udf_inode_info {
        struct timespec         i_crtime;
        /* Physical address of inode */
-       kernel_lb_addr          i_location;
+       struct kernel_lb_addr           i_location;
        __u64                   i_unique;
        __u32                   i_lenEAttr;
        __u32                   i_lenAlloc;
@@ -17,8 +17,8 @@ struct udf_inode_info {
        unsigned                i_strat4096 : 1;
        unsigned                reserved : 26;
        union {
-               short_ad        *i_sad;
-               long_ad         *i_lad;
+               struct short_ad *i_sad;
+               struct long_ad          *i_lad;
                __u8            *i_data;
        } i_ext;
        struct inode vfs_inode;
index 1c1c514a9725116f19cf559e3af969251d99c74e..d113b72c2768318cc9401175479515d8557bf387 100644 (file)
@@ -30,6 +30,7 @@
 #define UDF_FLAG_GID_SET       16
 #define UDF_FLAG_SESSION_SET   17
 #define UDF_FLAG_LASTBLOCK_SET 18
+#define UDF_FLAG_BLOCKSIZE_SET 19
 
 #define UDF_PART_FLAG_UNALLOC_BITMAP   0x0001
 #define UDF_PART_FLAG_UNALLOC_TABLE    0x0002
@@ -48,6 +49,8 @@
 #define UDF_SPARABLE_MAP15             0x1522U
 #define UDF_METADATA_MAP25             0x2511U
 
+#define UDF_INVALID_MODE               ((mode_t)-1)
+
 #pragma pack(1) /* XXX(hch): Why?  This file just defines in-core structures */
 
 struct udf_meta_data {
@@ -114,7 +117,7 @@ struct udf_sb_info {
 
        /* Sector headers */
        __s32                   s_session;
-       __u32                   s_anchor[3];
+       __u32                   s_anchor;
        __u32                   s_last_block;
 
        struct buffer_head      *s_lvid_bh;
@@ -123,6 +126,8 @@ struct udf_sb_info {
        mode_t                  s_umask;
        gid_t                   s_gid;
        uid_t                   s_uid;
+       mode_t                  s_fmode;
+       mode_t                  s_dmode;
 
        /* Root Info */
        struct timespec         s_record_time;
@@ -143,6 +148,8 @@ struct udf_sb_info {
        struct inode            *s_vat_inode;
 
        struct mutex            s_alloc_mutex;
+       /* Protected by s_alloc_mutex */
+       unsigned int            s_lvid_dirty;
 };
 
 static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
index 8ec865de5f133052771c1a428bb94e3834b9f374..cac51b77a5d165beaffb57032e3498363321f64e 100644 (file)
@@ -62,10 +62,8 @@ static inline size_t udf_ext0_offset(struct inode *inode)
                return 0;
 }
 
-#define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset))
-
 /* computes tag checksum */
-u8 udf_tag_checksum(const tag *t);
+u8 udf_tag_checksum(const struct tag *t);
 
 struct dentry;
 struct inode;
@@ -95,7 +93,7 @@ struct udf_vds_record {
 };
 
 struct generic_desc {
-       tag             descTag;
+       struct tag      descTag;
        __le32          volDescSeqNum;
 };
 
@@ -108,11 +106,22 @@ struct ustr {
 struct extent_position {
        struct buffer_head *bh;
        uint32_t offset;
-       kernel_lb_addr block;
+       struct kernel_lb_addr block;
 };
 
 /* super.c */
 extern void udf_warning(struct super_block *, const char *, const char *, ...);
+static inline void udf_updated_lvid(struct super_block *sb)
+{
+       struct buffer_head *bh = UDF_SB(sb)->s_lvid_bh;
+
+       BUG_ON(!bh);
+       WARN_ON_ONCE(((struct logicalVolIntegrityDesc *)
+                    bh->b_data)->integrityType !=
+                    cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN));
+       sb->s_dirt = 1;
+       UDF_SB(sb)->s_lvid_dirty = 1;
+}
 
 /* namei.c */
 extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
@@ -124,7 +133,7 @@ extern int udf_ioctl(struct inode *, struct file *, unsigned int,
                     unsigned long);
 
 /* inode.c */
-extern struct inode *udf_iget(struct super_block *, kernel_lb_addr);
+extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *);
 extern int udf_sync_inode(struct inode *);
 extern void udf_expand_file_adinicb(struct inode *, int, int *);
 extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);
@@ -136,19 +145,19 @@ extern void udf_clear_inode(struct inode *);
 extern int udf_write_inode(struct inode *, int);
 extern long udf_block_map(struct inode *, sector_t);
 extern int udf_extend_file(struct inode *, struct extent_position *,
-                          kernel_long_ad *, sector_t);
+                          struct kernel_long_ad *, sector_t);
 extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
-                        kernel_lb_addr *, uint32_t *, sector_t *);
+                        struct kernel_lb_addr *, uint32_t *, sector_t *);
 extern int8_t udf_add_aext(struct inode *, struct extent_position *,
-                          kernel_lb_addr, uint32_t, int);
+                          struct kernel_lb_addr *, uint32_t, int);
 extern int8_t udf_write_aext(struct inode *, struct extent_position *,
-                            kernel_lb_addr, uint32_t, int);
+                            struct kernel_lb_addr *, uint32_t, int);
 extern int8_t udf_delete_aext(struct inode *, struct extent_position,
-                             kernel_lb_addr, uint32_t);
+                             struct kernel_lb_addr, uint32_t);
 extern int8_t udf_next_aext(struct inode *, struct extent_position *,
-                           kernel_lb_addr *, uint32_t *, int);
+                           struct kernel_lb_addr *, uint32_t *, int);
 extern int8_t udf_current_aext(struct inode *, struct extent_position *,
-                              kernel_lb_addr *, uint32_t *, int);
+                              struct kernel_lb_addr *, uint32_t *, int);
 
 /* misc.c */
 extern struct buffer_head *udf_tgetblk(struct super_block *, int);
@@ -160,7 +169,7 @@ extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t,
 extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t,
                                           uint32_t, uint16_t *);
 extern struct buffer_head *udf_read_ptagged(struct super_block *,
-                                           kernel_lb_addr, uint32_t,
+                                           struct kernel_lb_addr *, uint32_t,
                                            uint16_t *);
 extern void udf_update_tag(char *, int);
 extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
@@ -182,6 +191,14 @@ extern uint32_t udf_get_pblock_meta25(struct super_block *, uint32_t, uint16_t,
                                          uint32_t);
 extern int udf_relocate_blocks(struct super_block *, long, long *);
 
+static inline uint32_t
+udf_get_lb_pblock(struct super_block *sb, struct kernel_lb_addr *loc,
+                 uint32_t offset)
+{
+       return udf_get_pblock(sb, loc->logicalBlockNum,
+                       loc->partitionReferenceNum, offset);
+}
+
 /* unicode.c */
 extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int);
 extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
@@ -200,7 +217,7 @@ extern void udf_truncate_extents(struct inode *);
 
 /* balloc.c */
 extern void udf_free_blocks(struct super_block *, struct inode *,
-                           kernel_lb_addr, uint32_t, uint32_t);
+                           struct kernel_lb_addr *, uint32_t, uint32_t);
 extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t,
                               uint32_t, uint32_t);
 extern int udf_new_block(struct super_block *, struct inode *, uint16_t,
@@ -214,16 +231,16 @@ extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
                                                struct udf_fileident_bh *,
                                                struct fileIdentDesc *,
                                                struct extent_position *,
-                                               kernel_lb_addr *, uint32_t *,
+                                               struct kernel_lb_addr *, uint32_t *,
                                                sector_t *);
 extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
                                               int *offset);
-extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
-extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
+extern struct long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
+extern struct short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
 
 /* udftime.c */
 extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest,
-                                               timestamp src);
-extern timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec src);
+                                               struct timestamp src);
+extern struct timestamp *udf_time_to_disk_stamp(struct timestamp *dest, struct timespec src);
 
 #endif                         /* __UDF_DECL_H */
index 489f52fb428cd309fb73002be58ce8b38bb09f0d..6a9f3a9cc4281adf8f7ff6498ee6a38c3b04e565 100644 (file)
@@ -4,9 +4,9 @@
 #include <asm/byteorder.h>
 #include <linux/string.h>
 
-static inline kernel_lb_addr lelb_to_cpu(lb_addr in)
+static inline struct kernel_lb_addr lelb_to_cpu(struct lb_addr in)
 {
-       kernel_lb_addr out;
+       struct kernel_lb_addr out;
 
        out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
        out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
@@ -14,9 +14,9 @@ static inline kernel_lb_addr lelb_to_cpu(lb_addr in)
        return out;
 }
 
-static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
+static inline struct lb_addr cpu_to_lelb(struct kernel_lb_addr in)
 {
-       lb_addr out;
+       struct lb_addr out;
 
        out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
        out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
@@ -24,9 +24,9 @@ static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
        return out;
 }
 
-static inline short_ad lesa_to_cpu(short_ad in)
+static inline struct short_ad lesa_to_cpu(struct short_ad in)
 {
-       short_ad out;
+       struct short_ad out;
 
        out.extLength = le32_to_cpu(in.extLength);
        out.extPosition = le32_to_cpu(in.extPosition);
@@ -34,9 +34,9 @@ static inline short_ad lesa_to_cpu(short_ad in)
        return out;
 }
 
-static inline short_ad cpu_to_lesa(short_ad in)
+static inline struct short_ad cpu_to_lesa(struct short_ad in)
 {
-       short_ad out;
+       struct short_ad out;
 
        out.extLength = cpu_to_le32(in.extLength);
        out.extPosition = cpu_to_le32(in.extPosition);
@@ -44,9 +44,9 @@ static inline short_ad cpu_to_lesa(short_ad in)
        return out;
 }
 
-static inline kernel_long_ad lela_to_cpu(long_ad in)
+static inline struct kernel_long_ad lela_to_cpu(struct long_ad in)
 {
-       kernel_long_ad out;
+       struct kernel_long_ad out;
 
        out.extLength = le32_to_cpu(in.extLength);
        out.extLocation = lelb_to_cpu(in.extLocation);
@@ -54,9 +54,9 @@ static inline kernel_long_ad lela_to_cpu(long_ad in)
        return out;
 }
 
-static inline long_ad cpu_to_lela(kernel_long_ad in)
+static inline struct long_ad cpu_to_lela(struct kernel_long_ad in)
 {
-       long_ad out;
+       struct long_ad out;
 
        out.extLength = cpu_to_le32(in.extLength);
        out.extLocation = cpu_to_lelb(in.extLocation);
@@ -64,9 +64,9 @@ static inline long_ad cpu_to_lela(kernel_long_ad in)
        return out;
 }
 
-static inline kernel_extent_ad leea_to_cpu(extent_ad in)
+static inline struct kernel_extent_ad leea_to_cpu(struct extent_ad in)
 {
-       kernel_extent_ad out;
+       struct kernel_extent_ad out;
 
        out.extLength = le32_to_cpu(in.extLength);
        out.extLocation = le32_to_cpu(in.extLocation);
index 5f811655c9b51abbdbd33f39113a9e963df66aa5..b8c828c4d20034fcf046d21b2946e94044b5a74e 100644 (file)
@@ -85,7 +85,8 @@ extern struct timezone sys_tz;
 #define SECS_PER_HOUR  (60 * 60)
 #define SECS_PER_DAY   (SECS_PER_HOUR * 24)
 
-struct timespec *udf_disk_stamp_to_time(struct timespec *dest, timestamp src)
+struct timespec *
+udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 {
        int yday;
        u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
@@ -116,7 +117,8 @@ struct timespec *udf_disk_stamp_to_time(struct timespec *dest, timestamp src)
        return dest;
 }
 
-timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts)
+struct timestamp *
+udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
 {
        long int days, rem, y;
        const unsigned short int *ip;
index 9fdf8c93c58e7893616bea99730cc594a3731361..cefa8c8913e68a77100d2bdb5cf377b323483ec0 100644 (file)
@@ -254,7 +254,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
 {
        const uint8_t *ocu;
        uint8_t cmp_id, ocu_len;
-       int i;
+       int i, len;
 
 
        ocu_len = ocu_i->u_len;
@@ -279,8 +279,13 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
                if (cmp_id == 16)
                        c = (c << 8) | ocu[i++];
 
-               utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
-                                             UDF_NAME_LEN - utf_o->u_len);
+               len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
+                                   UDF_NAME_LEN - utf_o->u_len);
+               /* Valid character? */
+               if (len >= 0)
+                       utf_o->u_len += len;
+               else
+                       utf_o->u_name[utf_o->u_len++] = '?';
        }
        utf_o->u_cmpID = 8;
 
@@ -290,7 +295,8 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
 static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
                        int length)
 {
-       unsigned len, i, max_val;
+       int len;
+       unsigned i, max_val;
        uint16_t uni_char;
        int u_len;
 
@@ -302,8 +308,13 @@ try_again:
        u_len = 0U;
        for (i = 0U; i < uni->u_len; i++) {
                len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
-               if (len <= 0)
+               if (!len)
                        continue;
+               /* Invalid character, deal with it */
+               if (len < 0) {
+                       len = 1;
+                       uni_char = '?';
+               }
 
                if (uni_char > max_val) {
                        max_val = 0xffffU;
@@ -324,34 +335,43 @@ try_again:
 int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
                     int flen)
 {
-       struct ustr filename, unifilename;
-       int len;
+       struct ustr *filename, *unifilename;
+       int len = 0;
 
-       if (udf_build_ustr_exact(&unifilename, sname, flen))
+       filename = kmalloc(sizeof(struct ustr), GFP_NOFS);
+       if (!filename)
                return 0;
 
+       unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS);
+       if (!unifilename)
+               goto out1;
+
+       if (udf_build_ustr_exact(unifilename, sname, flen))
+               goto out2;
+
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
-               if (!udf_CS0toUTF8(&filename, &unifilename)) {
+               if (!udf_CS0toUTF8(filename, unifilename)) {
                        udf_debug("Failed in udf_get_filename: sname = %s\n",
                                  sname);
-                       return 0;
+                       goto out2;
                }
        } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
-               if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename,
-                                 &unifilename)) {
+               if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename,
+                                 unifilename)) {
                        udf_debug("Failed in udf_get_filename: sname = %s\n",
                                  sname);
-                       return 0;
+                       goto out2;
                }
        } else
-               return 0;
-
-       len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
-                                    unifilename.u_name, unifilename.u_len);
-       if (len)
-               return len;
-
-       return 0;
+               goto out2;
+
+       len = udf_translate_to_linux(dname, filename->u_name, filename->u_len,
+                                    unifilename->u_name, unifilename->u_len);
+out2:
+       kfree(unifilename);
+out1:
+       kfree(filename);
+       return len;
 }
 
 int udf_put_filename(struct super_block *sb, const uint8_t *sname,
index e1c1fc5ee2395cca67ad36e10f0577fdef0f0651..60359291761f2eb2a8229f053b1d5763c19115c6 100644 (file)
@@ -1268,6 +1268,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct ufs_super_block_first *usb1;
        struct ufs_super_block_second *usb2;
        struct ufs_super_block_third *usb3;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        lock_kernel();
 
@@ -1290,6 +1291,8 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
                ? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0;
        buf->f_files = uspi->s_ncg * uspi->s_ipg;
        buf->f_namelen = UFS_MAXNAMLEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
 
        unlock_kernel();
 
index c3dc491fff89c468806fca873a34eedc5843cd91..60f107e47fe94253f1b1b55a443959bd15a036cc 100644 (file)
@@ -33,6 +33,7 @@ xfs-$(CONFIG_XFS_QUOTA)               += $(addprefix quota/, \
                                   xfs_qm_syscalls.o \
                                   xfs_qm_bhv.o \
                                   xfs_qm.o)
+xfs-$(CONFIG_XFS_QUOTA)                += linux-2.6/xfs_quotaops.o
 
 ifeq ($(CONFIG_XFS_QUOTA),y)
 xfs-$(CONFIG_PROC_FS)          += quota/xfs_qm_stats.o
diff --git a/fs/xfs/linux-2.6/mutex.h b/fs/xfs/linux-2.6/mutex.h
deleted file mode 100644 (file)
index 2a88d56..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
- * 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.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef __XFS_SUPPORT_MUTEX_H__
-#define __XFS_SUPPORT_MUTEX_H__
-
-#include <linux/mutex.h>
-
-typedef struct mutex mutex_t;
-
-#endif /* __XFS_SUPPORT_MUTEX_H__ */
index de3a198f771e20627769b837d6f2460ec18077fc..c13f67300fe76aa0a40ee64b0690dd2c8161a8ea 100644 (file)
@@ -1623,4 +1623,5 @@ const struct address_space_operations xfs_address_space_operations = {
        .bmap                   = xfs_vm_bmap,
        .direct_IO              = xfs_vm_direct_IO,
        .migratepage            = buffer_migrate_page,
+       .is_partially_uptodate  = block_is_partially_uptodate,
 };
index e14c4e3aea0c331f67ba529946e201c6d814e8ce..f4e25544157422812b4a1e576d3539e86b75b9bd 100644 (file)
@@ -234,9 +234,9 @@ xfs_file_mmap(
 STATIC int
 xfs_vm_page_mkwrite(
        struct vm_area_struct   *vma,
-       struct page             *page)
+       struct vm_fault         *vmf)
 {
-       return block_page_mkwrite(vma, page, xfs_get_blocks);
+       return block_page_mkwrite(vma, vmf, xfs_get_blocks);
 }
 
 const struct file_operations xfs_file_operations = {
index 4bd112313f3351eef0304cabf898eb96fb91f9b0..d0b499418a7d43e16313c053571267433d6c03a6 100644 (file)
@@ -34,6 +34,7 @@
 #include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
+#include "xfs_ioctl.h"
 #include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_rtalloc.h"
@@ -78,92 +79,74 @@ xfs_find_handle(
        int                     hsize;
        xfs_handle_t            handle;
        struct inode            *inode;
+       struct file             *file = NULL;
+       struct path             path;
+       int                     error;
+       struct xfs_inode        *ip;
 
-       memset((char *)&handle, 0, sizeof(handle));
-
-       switch (cmd) {
-       case XFS_IOC_PATH_TO_FSHANDLE:
-       case XFS_IOC_PATH_TO_HANDLE: {
-               struct path path;
-               int error = user_lpath((const char __user *)hreq->path, &path);
+       if (cmd == XFS_IOC_FD_TO_HANDLE) {
+               file = fget(hreq->fd);
+               if (!file)
+                       return -EBADF;
+               inode = file->f_path.dentry->d_inode;
+       } else {
+               error = user_lpath((const char __user *)hreq->path, &path);
                if (error)
                        return error;
-
-               ASSERT(path.dentry);
-               ASSERT(path.dentry->d_inode);
-               inode = igrab(path.dentry->d_inode);
-               path_put(&path);
-               break;
+               inode = path.dentry->d_inode;
        }
+       ip = XFS_I(inode);
 
-       case XFS_IOC_FD_TO_HANDLE: {
-               struct file     *file;
-
-               file = fget(hreq->fd);
-               if (!file)
-                   return -EBADF;
+       /*
+        * We can only generate handles for inodes residing on a XFS filesystem,
+        * and only for regular files, directories or symbolic links.
+        */
+       error = -EINVAL;
+       if (inode->i_sb->s_magic != XFS_SB_MAGIC)
+               goto out_put;
 
-               ASSERT(file->f_path.dentry);
-               ASSERT(file->f_path.dentry->d_inode);
-               inode = igrab(file->f_path.dentry->d_inode);
-               fput(file);
-               break;
-       }
+       error = -EBADF;
+       if (!S_ISREG(inode->i_mode) &&
+           !S_ISDIR(inode->i_mode) &&
+           !S_ISLNK(inode->i_mode))
+               goto out_put;
 
-       default:
-               ASSERT(0);
-               return -XFS_ERROR(EINVAL);
-       }
 
-       if (inode->i_sb->s_magic != XFS_SB_MAGIC) {
-               /* we're not in XFS anymore, Toto */
-               iput(inode);
-               return -XFS_ERROR(EINVAL);
-       }
+       memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t));
 
-       switch (inode->i_mode & S_IFMT) {
-       case S_IFREG:
-       case S_IFDIR:
-       case S_IFLNK:
-               break;
-       default:
-               iput(inode);
-               return -XFS_ERROR(EBADF);
-       }
-
-       /* now we can grab the fsid */
-       memcpy(&handle.ha_fsid, XFS_I(inode)->i_mount->m_fixedfsid,
-                       sizeof(xfs_fsid_t));
-       hsize = sizeof(xfs_fsid_t);
-
-       if (cmd != XFS_IOC_PATH_TO_FSHANDLE) {
-               xfs_inode_t     *ip = XFS_I(inode);
+       if (cmd == XFS_IOC_PATH_TO_FSHANDLE) {
+               /*
+                * This handle only contains an fsid, zero the rest.
+                */
+               memset(&handle.ha_fid, 0, sizeof(handle.ha_fid));
+               hsize = sizeof(xfs_fsid_t);
+       } else {
                int             lock_mode;
 
-               /* need to get access to the xfs_inode to read the generation */
                lock_mode = xfs_ilock_map_shared(ip);
-
-               /* fill in fid section of handle from inode */
                handle.ha_fid.fid_len = sizeof(xfs_fid_t) -
                                        sizeof(handle.ha_fid.fid_len);
                handle.ha_fid.fid_pad = 0;
                handle.ha_fid.fid_gen = ip->i_d.di_gen;
                handle.ha_fid.fid_ino = ip->i_ino;
-
                xfs_iunlock_map_shared(ip, lock_mode);
 
                hsize = XFS_HSIZE(handle);
        }
 
-       /* now copy our handle into the user buffer & write out the size */
+       error = -EFAULT;
        if (copy_to_user(hreq->ohandle, &handle, hsize) ||
-           copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) {
-               iput(inode);
-               return -XFS_ERROR(EFAULT);
-       }
+           copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32)))
+               goto out_put;
 
-       iput(inode);
-       return 0;
+       error = 0;
+
+ out_put:
+       if (cmd == XFS_IOC_FD_TO_HANDLE)
+               fput(file);
+       else
+               path_put(&path);
+       return error;
 }
 
 /*
index 7aa53fefc67fafe14bb54db40398f79945f1baae..6075382336d70b0feca5d7e84b1a53b9926987fd 100644 (file)
@@ -211,8 +211,13 @@ xfs_vn_mknod(
         * Irix uses Missed'em'V split, but doesn't want to see
         * the upper 5 bits of (14bit) major.
         */
-       if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff))
-               return -EINVAL;
+       if (S_ISCHR(mode) || S_ISBLK(mode)) {
+               if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff))
+                       return -EINVAL;
+               rdev = sysv_encode_dev(rdev);
+       } else {
+               rdev = 0;
+       }
 
        if (test_default_acl && test_default_acl(dir)) {
                if (!_ACL_ALLOC(default_acl)) {
@@ -224,28 +229,11 @@ xfs_vn_mknod(
                }
        }
 
-       xfs_dentry_to_name(&name, dentry);
-
        if (IS_POSIXACL(dir) && !default_acl)
-               mode &= ~current->fs->umask;
-
-       switch (mode & S_IFMT) {
-       case S_IFCHR:
-       case S_IFBLK:
-       case S_IFIFO:
-       case S_IFSOCK:
-               rdev = sysv_encode_dev(rdev);
-       case S_IFREG:
-               error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip, NULL);
-               break;
-       case S_IFDIR:
-               error = xfs_mkdir(XFS_I(dir), &name, mode, &ip, NULL);
-               break;
-       default:
-               error = EINVAL;
-               break;
-       }
+               mode &= ~current_umask();
 
+       xfs_dentry_to_name(&name, dentry);
+       error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip, NULL);
        if (unlikely(error))
                goto out_free_acl;
 
@@ -416,7 +404,7 @@ xfs_vn_symlink(
        mode_t          mode;
 
        mode = S_IFLNK |
-               (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
+               (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO);
        xfs_dentry_to_name(&name, dentry);
 
        error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip, NULL);
@@ -553,9 +541,6 @@ xfs_vn_getattr(
        stat->uid = ip->i_d.di_uid;
        stat->gid = ip->i_d.di_gid;
        stat->ino = ip->i_ino;
-#if XFS_BIG_INUMS
-       stat->ino += mp->m_inoadd;
-#endif
        stat->atime = inode->i_atime;
        stat->mtime.tv_sec = ip->i_d.di_mtime.t_sec;
        stat->mtime.tv_nsec = ip->i_d.di_mtime.t_nsec;
index 507492d6dccd0d9de4e8591ba2ca9dfdb831b44d..f65a53f8752f239410a66f6bc564c8c1a3e4dc81 100644 (file)
@@ -38,7 +38,6 @@
 #include <kmem.h>
 #include <mrlock.h>
 #include <sv.h>
-#include <mutex.h>
 #include <time.h>
 
 #include <support/ktrace.h>
@@ -51,6 +50,7 @@
 #include <linux/blkdev.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/file.h>
 #include <linux/swap.h>
 #include <linux/errno.h>
 #define SYNCHRONIZE()  barrier()
 #define __return_address __builtin_return_address(0)
 
-/*
- * IRIX (BSD) quotactl makes use of separate commands for user/group,
- * whereas on Linux the syscall encodes this information into the cmd
- * field (see the QCMD macro in quota.h).  These macros help keep the
- * code portable - they are not visible from the syscall interface.
- */
-#define Q_XSETGQLIM    XQM_CMD(8)      /* set groups disk limits */
-#define Q_XGETGQUOTA   XQM_CMD(9)      /* get groups disk limits */
-#define Q_XSETPQLIM    XQM_CMD(10)     /* set projects disk limits */
-#define Q_XGETPQUOTA   XQM_CMD(11)     /* get projects disk limits */
-
 #define dfltprid       0
 #define MAXPATHLEN     1024
 
diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/linux-2.6/xfs_quotaops.c
new file mode 100644 (file)
index 0000000..94d9a63
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2008, Christoph Hellwig
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include "xfs.h"
+#include "xfs_dmapi.h"
+#include "xfs_sb.h"
+#include "xfs_inum.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_quota.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "quota/xfs_qm.h"
+#include <linux/quota.h>
+
+
+STATIC int
+xfs_quota_type(int type)
+{
+       switch (type) {
+       case USRQUOTA:
+               return XFS_DQ_USER;
+       case GRPQUOTA:
+               return XFS_DQ_GROUP;
+       default:
+               return XFS_DQ_PROJ;
+       }
+}
+
+STATIC int
+xfs_fs_quota_sync(
+       struct super_block      *sb,
+       int                     type)
+{
+       struct xfs_mount        *mp = XFS_M(sb);
+
+       if (!XFS_IS_QUOTA_RUNNING(mp))
+               return -ENOSYS;
+       return -xfs_sync_inodes(mp, SYNC_DELWRI);
+}
+
+STATIC int
+xfs_fs_get_xstate(
+       struct super_block      *sb,
+       struct fs_quota_stat    *fqs)
+{
+       struct xfs_mount        *mp = XFS_M(sb);
+
+       if (!XFS_IS_QUOTA_RUNNING(mp))
+               return -ENOSYS;
+       return -xfs_qm_scall_getqstat(mp, fqs);
+}
+
+STATIC int
+xfs_fs_set_xstate(
+       struct super_block      *sb,
+       unsigned int            uflags,
+       int                     op)
+{
+       struct xfs_mount        *mp = XFS_M(sb);
+       unsigned int            flags = 0;
+
+       if (sb->s_flags & MS_RDONLY)
+               return -EROFS;
+       if (!XFS_IS_QUOTA_RUNNING(mp))
+               return -ENOSYS;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (uflags & XFS_QUOTA_UDQ_ACCT)
+               flags |= XFS_UQUOTA_ACCT;
+       if (uflags & XFS_QUOTA_PDQ_ACCT)
+               flags |= XFS_PQUOTA_ACCT;
+       if (uflags & XFS_QUOTA_GDQ_ACCT)
+               flags |= XFS_GQUOTA_ACCT;
+       if (uflags & XFS_QUOTA_UDQ_ENFD)
+               flags |= XFS_UQUOTA_ENFD;
+       if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD))
+               flags |= XFS_OQUOTA_ENFD;
+
+       switch (op) {
+       case Q_XQUOTAON:
+               return -xfs_qm_scall_quotaon(mp, flags);
+       case Q_XQUOTAOFF:
+               if (!XFS_IS_QUOTA_ON(mp))
+                       return -EINVAL;
+               return -xfs_qm_scall_quotaoff(mp, flags);
+       case Q_XQUOTARM:
+               if (XFS_IS_QUOTA_ON(mp))
+                       return -EINVAL;
+               return -xfs_qm_scall_trunc_qfiles(mp, flags);
+       }
+
+       return -EINVAL;
+}
+
+STATIC int
+xfs_fs_get_xquota(
+       struct super_block      *sb,
+       int                     type,
+       qid_t                   id,
+       struct fs_disk_quota    *fdq)
+{
+       struct xfs_mount        *mp = XFS_M(sb);
+
+       if (!XFS_IS_QUOTA_RUNNING(mp))
+               return -ENOSYS;
+       if (!XFS_IS_QUOTA_ON(mp))
+               return -ESRCH;
+
+       return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
+}
+
+STATIC int
+xfs_fs_set_xquota(
+       struct super_block      *sb,
+       int                     type,
+       qid_t                   id,
+       struct fs_disk_quota    *fdq)
+{
+       struct xfs_mount        *mp = XFS_M(sb);
+
+       if (sb->s_flags & MS_RDONLY)
+               return -EROFS;
+       if (!XFS_IS_QUOTA_RUNNING(mp))
+               return -ENOSYS;
+       if (!XFS_IS_QUOTA_ON(mp))
+               return -ESRCH;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
+}
+
+struct quotactl_ops xfs_quotactl_operations = {
+       .quota_sync             = xfs_fs_quota_sync,
+       .get_xstate             = xfs_fs_get_xstate,
+       .set_xstate             = xfs_fs_set_xstate,
+       .get_xquota             = xfs_fs_get_xquota,
+       .set_xquota             = xfs_fs_set_xquota,
+};
index 32ae5028e96b5cb8c8bafaf5ae93089ee798855a..bb685269f832ede5fa0f97eed990c3a988b26426 100644 (file)
@@ -68,7 +68,6 @@
 #include <linux/freezer.h>
 #include <linux/parser.h>
 
-static struct quotactl_ops xfs_quotactl_operations;
 static struct super_operations xfs_super_operations;
 static kmem_zone_t *xfs_ioend_zone;
 mempool_t *xfs_ioend_pool;
@@ -79,7 +78,6 @@ mempool_t *xfs_ioend_pool;
 #define MNTOPT_RTDEV   "rtdev"         /* realtime I/O device */
 #define MNTOPT_BIOSIZE "biosize"       /* log2 of preferred buffered io size */
 #define MNTOPT_WSYNC   "wsync"         /* safe-mode nfs compatible mount */
-#define MNTOPT_INO64   "ino64"         /* force inodes into 64-bit range */
 #define MNTOPT_NOALIGN "noalign"       /* turn off stripe alignment */
 #define MNTOPT_SWALLOC "swalloc"       /* turn on stripe width allocation */
 #define MNTOPT_SUNIT   "sunit"         /* data volume stripe unit */
@@ -180,7 +178,7 @@ xfs_parseargs(
        int                     dswidth = 0;
        int                     iosize = 0;
        int                     dmapi_implies_ikeep = 1;
-       uchar_t                 iosizelog = 0;
+       __uint8_t               iosizelog = 0;
 
        /*
         * Copy binary VFS mount flags we are interested in.
@@ -291,16 +289,6 @@ xfs_parseargs(
                        mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC;
                } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
                        mp->m_flags |= XFS_MOUNT_NORECOVERY;
-               } else if (!strcmp(this_char, MNTOPT_INO64)) {
-#if XFS_BIG_INUMS
-                       mp->m_flags |= XFS_MOUNT_INO64;
-                       mp->m_inoadd = XFS_INO64_OFFSET;
-#else
-                       cmn_err(CE_WARN,
-                               "XFS: %s option not allowed on this system",
-                               this_char);
-                       return EINVAL;
-#endif
                } else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
                        mp->m_flags |= XFS_MOUNT_NOALIGN;
                } else if (!strcmp(this_char, MNTOPT_SWALLOC)) {
@@ -529,7 +517,6 @@ xfs_showargs(
                /* the few simple ones we can get from the mount struct */
                { XFS_MOUNT_IKEEP,              "," MNTOPT_IKEEP },
                { XFS_MOUNT_WSYNC,              "," MNTOPT_WSYNC },
-               { XFS_MOUNT_INO64,              "," MNTOPT_INO64 },
                { XFS_MOUNT_NOALIGN,            "," MNTOPT_NOALIGN },
                { XFS_MOUNT_SWALLOC,            "," MNTOPT_SWALLOC },
                { XFS_MOUNT_NOUUID,             "," MNTOPT_NOUUID },
@@ -634,7 +621,7 @@ xfs_max_file_offset(
        return (((__uint64_t)pagefactor) << bitshift) - 1;
 }
 
-int
+STATIC int
 xfs_blkdev_get(
        xfs_mount_t             *mp,
        const char              *name,
@@ -651,7 +638,7 @@ xfs_blkdev_get(
        return -error;
 }
 
-void
+STATIC void
 xfs_blkdev_put(
        struct block_device     *bdev)
 {
@@ -872,7 +859,7 @@ xfsaild_wakeup(
        wake_up_process(ailp->xa_task);
 }
 
-int
+STATIC int
 xfsaild(
        void    *data)
 {
@@ -990,26 +977,57 @@ xfs_fs_write_inode(
        int                     sync)
 {
        struct xfs_inode        *ip = XFS_I(inode);
+       struct xfs_mount        *mp = ip->i_mount;
        int                     error = 0;
-       int                     flags = 0;
 
        xfs_itrace_entry(ip);
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
        if (sync) {
                error = xfs_wait_on_pages(ip, 0, -1);
                if (error)
-                       goto out_error;
-               flags |= FLUSH_SYNC;
+                       goto out;
        }
-       error = xfs_inode_flush(ip, flags);
 
-out_error:
+       /*
+        * Bypass inodes which have already been cleaned by
+        * the inode flush clustering code inside xfs_iflush
+        */
+       if (xfs_inode_clean(ip))
+               goto out;
+
+       /*
+        * We make this non-blocking if the inode is contended, return
+        * EAGAIN to indicate to the caller that they did not succeed.
+        * This prevents the flush path from blocking on inodes inside
+        * another operation right now, they get caught later by xfs_sync.
+        */
+       if (sync) {
+               xfs_ilock(ip, XFS_ILOCK_SHARED);
+               xfs_iflock(ip);
+
+               error = xfs_iflush(ip, XFS_IFLUSH_SYNC);
+       } else {
+               error = EAGAIN;
+               if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
+                       goto out;
+               if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
+                       goto out_unlock;
+
+               error = xfs_iflush(ip, XFS_IFLUSH_ASYNC_NOBLOCK);
+       }
+
+ out_unlock:
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ out:
        /*
         * if we failed to write out the inode then mark
         * it dirty again so we'll try again later.
         */
        if (error)
                xfs_mark_inode_dirty_sync(ip);
-
        return -error;
 }
 
@@ -1169,18 +1187,12 @@ xfs_fs_statfs(
        statp->f_bfree = statp->f_bavail =
                                sbp->sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
        fakeinos = statp->f_bfree << sbp->sb_inopblog;
-#if XFS_BIG_INUMS
-       fakeinos += mp->m_inoadd;
-#endif
        statp->f_files =
            MIN(sbp->sb_icount + fakeinos, (__uint64_t)XFS_MAXINUMBER);
        if (mp->m_maxicount)
-#if XFS_BIG_INUMS
-               if (!mp->m_inoadd)
-#endif
-                       statp->f_files = min_t(typeof(statp->f_files),
-                                               statp->f_files,
-                                               mp->m_maxicount);
+               statp->f_files = min_t(typeof(statp->f_files),
+                                       statp->f_files,
+                                       mp->m_maxicount);
        statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree);
        spin_unlock(&mp->m_sb_lock);
 
@@ -1302,57 +1314,6 @@ xfs_fs_show_options(
        return -xfs_showargs(XFS_M(mnt->mnt_sb), m);
 }
 
-STATIC int
-xfs_fs_quotasync(
-       struct super_block      *sb,
-       int                     type)
-{
-       return -XFS_QM_QUOTACTL(XFS_M(sb), Q_XQUOTASYNC, 0, NULL);
-}
-
-STATIC int
-xfs_fs_getxstate(
-       struct super_block      *sb,
-       struct fs_quota_stat    *fqs)
-{
-       return -XFS_QM_QUOTACTL(XFS_M(sb), Q_XGETQSTAT, 0, (caddr_t)fqs);
-}
-
-STATIC int
-xfs_fs_setxstate(
-       struct super_block      *sb,
-       unsigned int            flags,
-       int                     op)
-{
-       return -XFS_QM_QUOTACTL(XFS_M(sb), op, 0, (caddr_t)&flags);
-}
-
-STATIC int
-xfs_fs_getxquota(
-       struct super_block      *sb,
-       int                     type,
-       qid_t                   id,
-       struct fs_disk_quota    *fdq)
-{
-       return -XFS_QM_QUOTACTL(XFS_M(sb),
-                                (type == USRQUOTA) ? Q_XGETQUOTA :
-                                 ((type == GRPQUOTA) ? Q_XGETGQUOTA :
-                                  Q_XGETPQUOTA), id, (caddr_t)fdq);
-}
-
-STATIC int
-xfs_fs_setxquota(
-       struct super_block      *sb,
-       int                     type,
-       qid_t                   id,
-       struct fs_disk_quota    *fdq)
-{
-       return -XFS_QM_QUOTACTL(XFS_M(sb),
-                                (type == USRQUOTA) ? Q_XSETQLIM :
-                                 ((type == GRPQUOTA) ? Q_XSETGQLIM :
-                                  Q_XSETPQLIM), id, (caddr_t)fdq);
-}
-
 /*
  * This function fills in xfs_mount_t fields based on mount args.
  * Note: the superblock _has_ now been read in.
@@ -1435,7 +1396,9 @@ xfs_fs_fill_super(
        sb_min_blocksize(sb, BBSIZE);
        sb->s_xattr = xfs_xattr_handlers;
        sb->s_export_op = &xfs_export_operations;
+#ifdef CONFIG_XFS_QUOTA
        sb->s_qcop = &xfs_quotactl_operations;
+#endif
        sb->s_op = &xfs_super_operations;
 
        error = xfs_dmops_get(mp);
@@ -1578,14 +1541,6 @@ static struct super_operations xfs_super_operations = {
        .show_options           = xfs_fs_show_options,
 };
 
-static struct quotactl_ops xfs_quotactl_operations = {
-       .quota_sync             = xfs_fs_quotasync,
-       .get_xstate             = xfs_fs_getxstate,
-       .set_xstate             = xfs_fs_setxstate,
-       .get_xquota             = xfs_fs_getxquota,
-       .set_xquota             = xfs_fs_setxquota,
-};
-
 static struct file_system_type xfs_fs_type = {
        .owner                  = THIS_MODULE,
        .name                   = "xfs",
index d5d776d4cd6780fe92c389a763cc5295c076ee43..5a2ea3a217810be4efc6ebde932ece2d58d90360 100644 (file)
@@ -93,6 +93,7 @@ extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
 extern const struct export_operations xfs_export_operations;
 extern struct xattr_handler *xfs_xattr_handlers[];
+extern struct quotactl_ops xfs_quotactl_operations;
 
 #define XFS_M(sb)              ((struct xfs_mount *)((sb)->s_fs_info))
 
index 5f6de1efe1f696c51ea5e433120762e0c7e20bf4..04f058c848ae18c320ac7c47c4b1c0e87ca0865b 100644 (file)
@@ -19,6 +19,7 @@
 #define XFS_SYNC_H 1
 
 struct xfs_mount;
+struct xfs_perag;
 
 typedef struct bhv_vfs_sync_work {
        struct list_head        w_list;
index f65983a230d3610b94c192d880dac5a302200c9e..ad7fbead4c97664331fb406d8d2f5a29640b9208 100644 (file)
@@ -40,11 +40,6 @@ struct attrlist_cursor_kern;
 #define IO_ISDIRECT    0x00004         /* bypass page cache */
 #define IO_INVIS       0x00020         /* don't update inode timestamps */
 
-/*
- * Flags for xfs_inode_flush
- */
-#define FLUSH_SYNC             1       /* wait for flush to complete   */
-
 /*
  * Flush/Invalidate options for vop_toss/flush/flushinval_pages.
  */
@@ -54,33 +49,6 @@ struct attrlist_cursor_kern;
                                           Prevent VM access to the pages until
                                           the operation completes. */
 
-/*
- * Dealing with bad inodes
- */
-static inline int VN_BAD(struct inode *vp)
-{
-       return is_bad_inode(vp);
-}
-
-/*
- * Extracting atime values in various formats
- */
-static inline void vn_atime_to_bstime(struct inode *vp, xfs_bstime_t *bs_atime)
-{
-       bs_atime->tv_sec = vp->i_atime.tv_sec;
-       bs_atime->tv_nsec = vp->i_atime.tv_nsec;
-}
-
-static inline void vn_atime_to_timespec(struct inode *vp, struct timespec *ts)
-{
-       *ts = vp->i_atime;
-}
-
-static inline void vn_atime_to_time_t(struct inode *vp, time_t *tt)
-{
-       *tt = vp->i_atime.tv_sec;
-}
-
 /*
  * Some useful predicates.
  */
index 6543c0b297534a33f1af97d95cda43662a9d700b..e4babcc63423fef26351c5e9255757ec5d4dbba7 100644 (file)
@@ -804,7 +804,7 @@ xfs_qm_dqlookup(
        uint                    flist_locked;
        xfs_dquot_t             *d;
 
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+       ASSERT(mutex_is_locked(&qh->qh_lock));
 
        flist_locked = B_FALSE;
 
@@ -877,7 +877,7 @@ xfs_qm_dqlookup(
                        /*
                         * move the dquot to the front of the hashchain
                         */
-                       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+                       ASSERT(mutex_is_locked(&qh->qh_lock));
                        if (dqp->HL_PREVP != &qh->qh_next) {
                                xfs_dqtrace_entry(dqp,
                                                  "DQLOOKUP: HASH MOVETOFRONT");
@@ -892,13 +892,13 @@ xfs_qm_dqlookup(
                        }
                        xfs_dqtrace_entry(dqp, "LOOKUP END");
                        *O_dqpp = dqp;
-                       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+                       ASSERT(mutex_is_locked(&qh->qh_lock));
                        return (0);
                }
        }
 
        *O_dqpp = NULL;
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+       ASSERT(mutex_is_locked(&qh->qh_lock));
        return (1);
 }
 
@@ -956,7 +956,7 @@ xfs_qm_dqget(
                        ASSERT(ip->i_gdquot == NULL);
        }
 #endif
-       XFS_DQ_HASH_LOCK(h);
+       mutex_lock(&h->qh_lock);
 
        /*
         * Look in the cache (hashtable).
@@ -971,7 +971,7 @@ xfs_qm_dqget(
                 */
                ASSERT(*O_dqpp);
                ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
-               XFS_DQ_HASH_UNLOCK(h);
+               mutex_unlock(&h->qh_lock);
                xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)");
                return (0);     /* success */
        }
@@ -991,7 +991,7 @@ xfs_qm_dqget(
         * we don't keep the lock across a disk read
         */
        version = h->qh_version;
-       XFS_DQ_HASH_UNLOCK(h);
+       mutex_unlock(&h->qh_lock);
 
        /*
         * Allocate the dquot on the kernel heap, and read the ondisk
@@ -1056,7 +1056,7 @@ xfs_qm_dqget(
        /*
         * Hashlock comes after ilock in lock order
         */
-       XFS_DQ_HASH_LOCK(h);
+       mutex_lock(&h->qh_lock);
        if (version != h->qh_version) {
                xfs_dquot_t *tmpdqp;
                /*
@@ -1072,7 +1072,7 @@ xfs_qm_dqget(
                         * and start over.
                         */
                        xfs_qm_dqput(tmpdqp);
-                       XFS_DQ_HASH_UNLOCK(h);
+                       mutex_unlock(&h->qh_lock);
                        xfs_qm_dqdestroy(dqp);
                        XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
                        goto again;
@@ -1083,7 +1083,7 @@ xfs_qm_dqget(
         * Put the dquot at the beginning of the hash-chain and mp's list
         * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
         */
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(h));
+       ASSERT(mutex_is_locked(&h->qh_lock));
        dqp->q_hash = h;
        XQM_HASHLIST_INSERT(h, dqp);
 
@@ -1102,7 +1102,7 @@ xfs_qm_dqget(
        XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp);
 
        xfs_qm_mplist_unlock(mp);
-       XFS_DQ_HASH_UNLOCK(h);
+       mutex_unlock(&h->qh_lock);
  dqret:
        ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
        xfs_dqtrace_entry(dqp, "DQGET DONE");
@@ -1440,7 +1440,7 @@ xfs_qm_dqpurge(
        xfs_mount_t     *mp = dqp->q_mount;
 
        ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash));
+       ASSERT(mutex_is_locked(&dqp->q_hash->qh_lock));
 
        xfs_dqlock(dqp);
        /*
@@ -1453,7 +1453,7 @@ xfs_qm_dqpurge(
         */
        if (dqp->q_nrefs != 0) {
                xfs_dqunlock(dqp);
-               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+               mutex_unlock(&dqp->q_hash->qh_lock);
                return (1);
        }
 
@@ -1517,7 +1517,7 @@ xfs_qm_dqpurge(
        memset(&dqp->q_core, 0, sizeof(dqp->q_core));
        xfs_dqfunlock(dqp);
        xfs_dqunlock(dqp);
-       XFS_DQ_HASH_UNLOCK(thishash);
+       mutex_unlock(&thishash->qh_lock);
        return (0);
 }
 
index d443e93b43313c4c4f72fef3e14f8e1c2aa6e8a9..de0f402ddb4c2df0f97d040ccfc1df80a9bee190 100644 (file)
@@ -34,7 +34,7 @@
  */
 typedef struct xfs_dqhash {
        struct xfs_dquot *qh_next;
-       mutex_t           qh_lock;
+       struct mutex      qh_lock;
        uint              qh_version;   /* ever increasing version */
        uint              qh_nelems;    /* number of dquots on the list */
 } xfs_dqhash_t;
@@ -81,7 +81,7 @@ typedef struct xfs_dquot {
        xfs_qcnt_t       q_res_bcount;  /* total regular nblks used+reserved */
        xfs_qcnt_t       q_res_icount;  /* total inos allocd+reserved */
        xfs_qcnt_t       q_res_rtbcount;/* total realtime blks used+reserved */
-       mutex_t          q_qlock;       /* quota lock */
+       struct mutex     q_qlock;       /* quota lock */
        struct completion q_flush;      /* flush completion queue */
        atomic_t          q_pincount;   /* dquot pin count */
        wait_queue_head_t q_pinwait;    /* dquot pinning wait queue */
@@ -109,19 +109,6 @@ enum {
 
 #define XFS_DQHOLD(dqp)                ((dqp)->q_nrefs++)
 
-#ifdef DEBUG
-static inline int
-XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
-{
-       if (mutex_trylock(&dqp->q_qlock)) {
-               mutex_unlock(&dqp->q_qlock);
-               return 0;
-       }
-       return 1;
-}
-#endif
-
-
 /*
  * Manage the q_flush completion queue embedded in the dquot.  This completion
  * queue synchronizes processes attempting to flush the in-core dquot back to
@@ -142,6 +129,7 @@ static inline void xfs_dqfunlock(xfs_dquot_t *dqp)
        complete(&dqp->q_flush);
 }
 
+#define XFS_DQ_IS_LOCKED(dqp)  (mutex_is_locked(&((dqp)->q_qlock)))
 #define XFS_DQ_IS_ON_FREELIST(dqp)  ((dqp)->dq_flnext != (dqp))
 #define XFS_DQ_IS_DIRTY(dqp)   ((dqp)->dq_flags & XFS_DQ_DIRTY)
 #define XFS_QM_ISUDQ(dqp)      ((dqp)->dq_flags & XFS_DQ_USER)
index 7a2beb64314fee1f50d35b65b1b501669dd35c9b..5b6695049e0037849751e1fff5a908b012962c29 100644 (file)
@@ -55,7 +55,7 @@
  * quota functionality, including maintaining the freelist and hash
  * tables of dquots.
  */
-mutex_t                xfs_Gqm_lock;
+struct mutex   xfs_Gqm_lock;
 struct xfs_qm  *xfs_Gqm;
 uint           ndquot;
 
@@ -69,8 +69,6 @@ STATIC void   xfs_qm_list_destroy(xfs_dqlist_t *);
 
 STATIC void    xfs_qm_freelist_init(xfs_frlist_t *);
 STATIC void    xfs_qm_freelist_destroy(xfs_frlist_t *);
-STATIC int     xfs_qm_mplist_nowait(xfs_mount_t *);
-STATIC int     xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
 
 STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int     xfs_qm_init_quotainfo(xfs_mount_t *);
@@ -82,7 +80,7 @@ static struct shrinker xfs_qm_shaker = {
 };
 
 #ifdef DEBUG
-extern mutex_t qcheck_lock;
+extern struct mutex    qcheck_lock;
 #endif
 
 #ifdef QUOTADEBUG
@@ -219,7 +217,7 @@ xfs_qm_hold_quotafs_ref(
         * the structure could disappear between the entry to this routine and
         * a HOLD operation if not locked.
         */
-       XFS_QM_LOCK(xfs_Gqm);
+       mutex_lock(&xfs_Gqm_lock);
 
        if (xfs_Gqm == NULL)
                xfs_Gqm = xfs_Gqm_init();
@@ -228,8 +226,8 @@ xfs_qm_hold_quotafs_ref(
         * debugging and statistical purposes, but ...
         * Just take a reference and get out.
         */
-       XFS_QM_HOLD(xfs_Gqm);
-       XFS_QM_UNLOCK(xfs_Gqm);
+       xfs_Gqm->qm_nrefs++;
+       mutex_unlock(&xfs_Gqm_lock);
 
        return 0;
 }
@@ -277,13 +275,12 @@ xfs_qm_rele_quotafs_ref(
         * Destroy the entire XQM. If somebody mounts with quotaon, this'll
         * be restarted.
         */
-       XFS_QM_LOCK(xfs_Gqm);
-       XFS_QM_RELE(xfs_Gqm);
-       if (xfs_Gqm->qm_nrefs == 0) {
+       mutex_lock(&xfs_Gqm_lock);
+       if (--xfs_Gqm->qm_nrefs == 0) {
                xfs_qm_destroy(xfs_Gqm);
                xfs_Gqm = NULL;
        }
-       XFS_QM_UNLOCK(xfs_Gqm);
+       mutex_unlock(&xfs_Gqm_lock);
 }
 
 /*
@@ -577,10 +574,10 @@ xfs_qm_dqpurge_int(
                        continue;
                }
 
-               if (! xfs_qm_dqhashlock_nowait(dqp)) {
+               if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
                        nrecl = XFS_QI_MPLRECLAIMS(mp);
                        xfs_qm_mplist_unlock(mp);
-                       XFS_DQ_HASH_LOCK(dqp->q_hash);
+                       mutex_lock(&dqp->q_hash->qh_lock);
                        xfs_qm_mplist_lock(mp);
 
                        /*
@@ -590,7 +587,7 @@ xfs_qm_dqpurge_int(
                         * this point, but somebody might be taking things off.
                         */
                        if (nrecl != XFS_QI_MPLRECLAIMS(mp)) {
-                               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+                               mutex_unlock(&dqp->q_hash->qh_lock);
                                goto again;
                        }
                }
@@ -632,7 +629,6 @@ xfs_qm_dqattach_one(
        xfs_dqid_t      id,
        uint            type,
        uint            doalloc,
-       uint            dolock,
        xfs_dquot_t     *udqhint, /* hint */
        xfs_dquot_t     **IO_idqpp)
 {
@@ -641,16 +637,16 @@ xfs_qm_dqattach_one(
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        error = 0;
+
        /*
         * See if we already have it in the inode itself. IO_idqpp is
         * &i_udquot or &i_gdquot. This made the code look weird, but
         * made the logic a lot simpler.
         */
-       if ((dqp = *IO_idqpp)) {
-               if (dolock)
-                       xfs_dqlock(dqp);
+       dqp = *IO_idqpp;
+       if (dqp) {
                xfs_dqtrace_entry(dqp, "DQATTACH: found in ip");
-               goto done;
+               return 0;
        }
 
        /*
@@ -659,38 +655,38 @@ xfs_qm_dqattach_one(
         * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
         * the user dquot.
         */
-       ASSERT(!udqhint || type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
-       if (udqhint && !dolock)
+       if (udqhint) {
+               ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
                xfs_dqlock(udqhint);
 
-       /*
-        * No need to take dqlock to look at the id.
-        * The ID can't change until it gets reclaimed, and it won't
-        * be reclaimed as long as we have a ref from inode and we hold
-        * the ilock.
-        */
-       if (udqhint &&
-           (dqp = udqhint->q_gdquot) &&
-           (be32_to_cpu(dqp->q_core.d_id) == id)) {
-               ASSERT(XFS_DQ_IS_LOCKED(udqhint));
-               xfs_dqlock(dqp);
-               XFS_DQHOLD(dqp);
-               ASSERT(*IO_idqpp == NULL);
-               *IO_idqpp = dqp;
-               if (!dolock) {
+               /*
+                * No need to take dqlock to look at the id.
+                *
+                * The ID can't change until it gets reclaimed, and it won't
+                * be reclaimed as long as we have a ref from inode and we
+                * hold the ilock.
+                */
+               dqp = udqhint->q_gdquot;
+               if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
+                       xfs_dqlock(dqp);
+                       XFS_DQHOLD(dqp);
+                       ASSERT(*IO_idqpp == NULL);
+                       *IO_idqpp = dqp;
+
                        xfs_dqunlock(dqp);
                        xfs_dqunlock(udqhint);
+                       return 0;
                }
-               goto done;
-       }
-       /*
-        * We can't hold a dquot lock when we call the dqget code.
-        * We'll deadlock in no time, because of (not conforming to)
-        * lock ordering - the inodelock comes before any dquot lock,
-        * and we may drop and reacquire the ilock in xfs_qm_dqget().
-        */
-       if (udqhint)
+
+               /*
+                * We can't hold a dquot lock when we call the dqget code.
+                * We'll deadlock in no time, because of (not conforming to)
+                * lock ordering - the inodelock comes before any dquot lock,
+                * and we may drop and reacquire the ilock in xfs_qm_dqget().
+                */
                xfs_dqunlock(udqhint);
+       }
+
        /*
         * Find the dquot from somewhere. This bumps the
         * reference count of dquot and returns it locked.
@@ -698,48 +694,19 @@ xfs_qm_dqattach_one(
         * disk and we didn't ask it to allocate;
         * ESRCH if quotas got turned off suddenly.
         */
-       if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type,
-                                doalloc|XFS_QMOPT_DOWARN, &dqp))) {
-               if (udqhint && dolock)
-                       xfs_dqlock(udqhint);
-               goto done;
-       }
+       error = xfs_qm_dqget(ip->i_mount, ip, id, type, XFS_QMOPT_DOWARN, &dqp);
+       if (error)
+               return error;
 
        xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget");
+
        /*
         * dqget may have dropped and re-acquired the ilock, but it guarantees
         * that the dquot returned is the one that should go in the inode.
         */
        *IO_idqpp = dqp;
-       ASSERT(dqp);
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       if (! dolock) {
-               xfs_dqunlock(dqp);
-               goto done;
-       }
-       if (! udqhint)
-               goto done;
-
-       ASSERT(udqhint);
-       ASSERT(dolock);
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       if (! xfs_qm_dqlock_nowait(udqhint)) {
-               xfs_dqunlock(dqp);
-               xfs_dqlock(udqhint);
-               xfs_dqlock(dqp);
-       }
-      done:
-#ifdef QUOTADEBUG
-       if (udqhint) {
-               if (dolock)
-                       ASSERT(XFS_DQ_IS_LOCKED(udqhint));
-       }
-       if (! error) {
-               if (dolock)
-                       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       }
-#endif
-       return error;
+       xfs_dqunlock(dqp);
+       return 0;
 }
 
 
@@ -754,24 +721,15 @@ xfs_qm_dqattach_one(
 STATIC void
 xfs_qm_dqattach_grouphint(
        xfs_dquot_t     *udq,
-       xfs_dquot_t     *gdq,
-       uint            locked)
+       xfs_dquot_t     *gdq)
 {
        xfs_dquot_t     *tmp;
 
-#ifdef QUOTADEBUG
-       if (locked) {
-               ASSERT(XFS_DQ_IS_LOCKED(udq));
-               ASSERT(XFS_DQ_IS_LOCKED(gdq));
-       }
-#endif
-       if (! locked)
-               xfs_dqlock(udq);
+       xfs_dqlock(udq);
 
        if ((tmp = udq->q_gdquot)) {
                if (tmp == gdq) {
-                       if (! locked)
-                               xfs_dqunlock(udq);
+                       xfs_dqunlock(udq);
                        return;
                }
 
@@ -781,8 +739,6 @@ xfs_qm_dqattach_grouphint(
                 * because the freelist lock comes before dqlocks.
                 */
                xfs_dqunlock(udq);
-               if (locked)
-                       xfs_dqunlock(gdq);
                /*
                 * we took a hard reference once upon a time in dqget,
                 * so give it back when the udquot no longer points at it
@@ -795,9 +751,7 @@ xfs_qm_dqattach_grouphint(
 
        } else {
                ASSERT(XFS_DQ_IS_LOCKED(udq));
-               if (! locked) {
-                       xfs_dqlock(gdq);
-               }
+               xfs_dqlock(gdq);
        }
 
        ASSERT(XFS_DQ_IS_LOCKED(udq));
@@ -810,10 +764,9 @@ xfs_qm_dqattach_grouphint(
                XFS_DQHOLD(gdq);
                udq->q_gdquot = gdq;
        }
-       if (! locked) {
-               xfs_dqunlock(gdq);
-               xfs_dqunlock(udq);
-       }
+
+       xfs_dqunlock(gdq);
+       xfs_dqunlock(udq);
 }
 
 
@@ -821,8 +774,6 @@ xfs_qm_dqattach_grouphint(
  * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON
  * into account.
  * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
- * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty
- * much made this code a complete mess, but it has been pretty useful.
  * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
  * Inode may get unlocked and relocked in here, and the caller must deal with
  * the consequences.
@@ -851,7 +802,6 @@ xfs_qm_dqattach(
        if (XFS_IS_UQUOTA_ON(mp)) {
                error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
                                                flags & XFS_QMOPT_DQALLOC,
-                                               flags & XFS_QMOPT_DQLOCK,
                                                NULL, &ip->i_udquot);
                if (error)
                        goto done;
@@ -863,11 +813,9 @@ xfs_qm_dqattach(
                error = XFS_IS_GQUOTA_ON(mp) ?
                        xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
                                                flags & XFS_QMOPT_DQALLOC,
-                                               flags & XFS_QMOPT_DQLOCK,
                                                ip->i_udquot, &ip->i_gdquot) :
                        xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ,
                                                flags & XFS_QMOPT_DQALLOC,
-                                               flags & XFS_QMOPT_DQLOCK,
                                                ip->i_udquot, &ip->i_gdquot);
                /*
                 * Don't worry about the udquot that we may have
@@ -898,22 +846,13 @@ xfs_qm_dqattach(
                /*
                 * Attach i_gdquot to the gdquot hint inside the i_udquot.
                 */
-               xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot,
-                                        flags & XFS_QMOPT_DQLOCK);
+               xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
        }
 
       done:
 
 #ifdef QUOTADEBUG
        if (! error) {
-               if (ip->i_udquot) {
-                       if (flags & XFS_QMOPT_DQLOCK)
-                               ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot));
-               }
-               if (ip->i_gdquot) {
-                       if (flags & XFS_QMOPT_DQLOCK)
-                               ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot));
-               }
                if (XFS_IS_UQUOTA_ON(mp))
                        ASSERT(ip->i_udquot);
                if (XFS_IS_OQUOTA_ON(mp))
@@ -2086,7 +2025,7 @@ xfs_qm_shake_freelist(
                 * a dqlookup process that holds the hashlock that is
                 * waiting for the freelist lock.
                 */
-               if (! xfs_qm_dqhashlock_nowait(dqp)) {
+               if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
                        xfs_dqfunlock(dqp);
                        xfs_dqunlock(dqp);
                        dqp = dqp->dq_flnext;
@@ -2103,7 +2042,7 @@ xfs_qm_shake_freelist(
                        /* XXX put a sentinel so that we can come back here */
                        xfs_dqfunlock(dqp);
                        xfs_dqunlock(dqp);
-                       XFS_DQ_HASH_UNLOCK(hash);
+                       mutex_unlock(&hash->qh_lock);
                        xfs_qm_freelist_unlock(xfs_Gqm);
                        if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
                                return nreclaimed;
@@ -2120,7 +2059,7 @@ xfs_qm_shake_freelist(
                XQM_HASHLIST_REMOVE(hash, dqp);
                xfs_dqfunlock(dqp);
                xfs_qm_mplist_unlock(dqp->q_mount);
-               XFS_DQ_HASH_UNLOCK(hash);
+               mutex_unlock(&hash->qh_lock);
 
  off_freelist:
                XQM_FREELIST_REMOVE(dqp);
@@ -2262,7 +2201,7 @@ xfs_qm_dqreclaim_one(void)
                        continue;
                }
 
-               if (! xfs_qm_dqhashlock_nowait(dqp))
+               if (!mutex_trylock(&dqp->q_hash->qh_lock))
                        goto mplistunlock;
 
                ASSERT(dqp->q_nrefs == 0);
@@ -2271,7 +2210,7 @@ xfs_qm_dqreclaim_one(void)
                XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
                XQM_FREELIST_REMOVE(dqp);
                dqpout = dqp;
-               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+               mutex_unlock(&dqp->q_hash->qh_lock);
  mplistunlock:
                xfs_qm_mplist_unlock(dqp->q_mount);
                xfs_dqfunlock(dqp);
@@ -2774,34 +2713,3 @@ xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq)
 {
        xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq);
 }
-
-STATIC int
-xfs_qm_dqhashlock_nowait(
-       xfs_dquot_t *dqp)
-{
-       int locked;
-
-       locked = mutex_trylock(&((dqp)->q_hash->qh_lock));
-       return locked;
-}
-
-int
-xfs_qm_freelist_lock_nowait(
-       xfs_qm_t *xqm)
-{
-       int locked;
-
-       locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock));
-       return locked;
-}
-
-STATIC int
-xfs_qm_mplist_nowait(
-       xfs_mount_t     *mp)
-{
-       int locked;
-
-       ASSERT(mp->m_quotainfo);
-       locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp)));
-       return locked;
-}
index ddf09166387c0e89c168329b2c15ea34ca52cefd..a371954cae1b6a86eaf296181b0b7c513a4a3130 100644 (file)
@@ -27,7 +27,7 @@ struct xfs_qm;
 struct xfs_inode;
 
 extern uint            ndquot;
-extern mutex_t         xfs_Gqm_lock;
+extern struct mutex    xfs_Gqm_lock;
 extern struct xfs_qm   *xfs_Gqm;
 extern kmem_zone_t     *qm_dqzone;
 extern kmem_zone_t     *qm_dqtrxzone;
@@ -79,7 +79,7 @@ typedef xfs_dqhash_t  xfs_dqlist_t;
 typedef struct xfs_frlist {
        struct xfs_dquot *qh_next;
        struct xfs_dquot *qh_prev;
-       mutex_t          qh_lock;
+       struct mutex     qh_lock;
        uint             qh_version;
        uint             qh_nelems;
 } xfs_frlist_t;
@@ -115,7 +115,7 @@ typedef struct xfs_quotainfo {
        xfs_qwarncnt_t   qi_bwarnlimit;  /* limit for blks warnings */
        xfs_qwarncnt_t   qi_iwarnlimit;  /* limit for inodes warnings */
        xfs_qwarncnt_t   qi_rtbwarnlimit;/* limit for rt blks warnings */
-       mutex_t          qi_quotaofflock;/* to serialize quotaoff */
+       struct mutex     qi_quotaofflock;/* to serialize quotaoff */
        xfs_filblks_t    qi_dqchunklen;  /* # BBs in a chunk of dqs */
        uint             qi_dqperchunk;  /* # ondisk dqs in above chunk */
        xfs_qcnt_t       qi_bhardlimit;  /* default data blk hard limit */
@@ -158,11 +158,6 @@ typedef struct xfs_dquot_acct {
 #define XFS_QM_IWARNLIMIT      5
 #define XFS_QM_RTBWARNLIMIT    5
 
-#define XFS_QM_LOCK(xqm)       (mutex_lock(&xqm##_lock))
-#define XFS_QM_UNLOCK(xqm)     (mutex_unlock(&xqm##_lock))
-#define XFS_QM_HOLD(xqm)       ((xqm)->qm_nrefs++)
-#define XFS_QM_RELE(xqm)       ((xqm)->qm_nrefs--)
-
 extern void            xfs_qm_destroy_quotainfo(xfs_mount_t *);
 extern void            xfs_qm_mount_quotas(xfs_mount_t *);
 extern int             xfs_qm_quotacheck(xfs_mount_t *);
@@ -178,6 +173,16 @@ extern void                xfs_qm_dqdetach(xfs_inode_t *);
 extern int             xfs_qm_dqpurge_all(xfs_mount_t *, uint);
 extern void            xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
 
+/* quota ops */
+extern int             xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint);
+extern int             xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint,
+                                       fs_disk_quota_t *);
+extern int             xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint,
+                                       fs_disk_quota_t *);
+extern int             xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
+extern int             xfs_qm_scall_quotaon(xfs_mount_t *, uint);
+extern int             xfs_qm_scall_quotaoff(xfs_mount_t *, uint);
+
 /* vop stuff */
 extern int             xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *,
                                        uid_t, gid_t, prid_t, uint,
@@ -194,11 +199,6 @@ extern int         xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *,
 /* list stuff */
 extern void            xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
 extern void            xfs_qm_freelist_unlink(xfs_dquot_t *);
-extern int             xfs_qm_freelist_lock_nowait(xfs_qm_t *);
-
-/* system call interface */
-extern int             xfs_qm_quotactl(struct xfs_mount *, int, int,
-                               xfs_caddr_t);
 
 #ifdef DEBUG
 extern int             xfs_qm_internalqcheck(xfs_mount_t *);
index bc6c5cca3e1251d141d7e80084cb6757e9d41214..63037c689a4b2df95888afe7231ff7915ecfa73a 100644 (file)
@@ -235,7 +235,6 @@ struct xfs_qmops xfs_qmcore_xfs = {
        .xfs_dqvopchownresv     = xfs_qm_vop_chown_reserve,
        .xfs_dqstatvfs          = xfs_qm_statvfs,
        .xfs_dqsync             = xfs_qm_sync,
-       .xfs_quotactl           = xfs_qm_quotactl,
        .xfs_dqtrxops           = &xfs_trans_dquot_ops,
 };
 EXPORT_SYMBOL(xfs_qmcore_xfs);
index 68139b38aedef0f9e11806b3d69bab1537871a2e..c7b66f6506ced750585d266ae76e4c61debd2496 100644 (file)
 # define qdprintk(s, args...)  do { } while (0)
 #endif
 
-STATIC int     xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint);
-STATIC int     xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint,
-                                       fs_disk_quota_t *);
-STATIC int     xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
-STATIC int     xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint,
-                                       fs_disk_quota_t *);
-STATIC int     xfs_qm_scall_quotaon(xfs_mount_t *, uint);
-STATIC int     xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t);
 STATIC int     xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
 STATIC int     xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
                                        uint);
-STATIC uint    xfs_qm_import_flags(uint);
 STATIC uint    xfs_qm_export_flags(uint);
-STATIC uint    xfs_qm_import_qtype_flags(uint);
 STATIC uint    xfs_qm_export_qtype_flags(uint);
 STATIC void    xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
                                        fs_disk_quota_t *);
 
 
-/*
- * The main distribution switch of all XFS quotactl system calls.
- */
-int
-xfs_qm_quotactl(
-       xfs_mount_t     *mp,
-       int             cmd,
-       int             id,
-       xfs_caddr_t     addr)
-{
-       int             error;
-
-       ASSERT(addr != NULL || cmd == Q_XQUOTASYNC);
-
-       /*
-        * The following commands are valid even when quotaoff.
-        */
-       switch (cmd) {
-       case Q_XQUOTARM:
-               /*
-                * Truncate quota files. quota must be off.
-                */
-               if (XFS_IS_QUOTA_ON(mp))
-                       return XFS_ERROR(EINVAL);
-               if (mp->m_flags & XFS_MOUNT_RDONLY)
-                       return XFS_ERROR(EROFS);
-               return (xfs_qm_scall_trunc_qfiles(mp,
-                              xfs_qm_import_qtype_flags(*(uint *)addr)));
-
-       case Q_XGETQSTAT:
-               /*
-                * Get quota status information.
-                */
-               return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr));
-
-       case Q_XQUOTAON:
-               /*
-                * QUOTAON - enabling quota enforcement.
-                * Quota accounting must be turned on at mount time.
-                */
-               if (mp->m_flags & XFS_MOUNT_RDONLY)
-                       return XFS_ERROR(EROFS);
-               return (xfs_qm_scall_quotaon(mp,
-                                         xfs_qm_import_flags(*(uint *)addr)));
-
-       case Q_XQUOTAOFF:
-               if (mp->m_flags & XFS_MOUNT_RDONLY)
-                       return XFS_ERROR(EROFS);
-               break;
-
-       case Q_XQUOTASYNC:
-               return xfs_sync_inodes(mp, SYNC_DELWRI);
-
-       default:
-               break;
-       }
-
-       if (! XFS_IS_QUOTA_ON(mp))
-               return XFS_ERROR(ESRCH);
-
-       switch (cmd) {
-       case Q_XQUOTAOFF:
-               if (mp->m_flags & XFS_MOUNT_RDONLY)
-                       return XFS_ERROR(EROFS);
-               error = xfs_qm_scall_quotaoff(mp,
-                                           xfs_qm_import_flags(*(uint *)addr),
-                                           B_FALSE);
-               break;
-
-       case Q_XGETQUOTA:
-               error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER,
-                                       (fs_disk_quota_t *)addr);
-               break;
-       case Q_XGETGQUOTA:
-               error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
-                                       (fs_disk_quota_t *)addr);
-               break;
-       case Q_XGETPQUOTA:
-               error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_PROJ,
-                                       (fs_disk_quota_t *)addr);
-               break;
-
-       case Q_XSETQLIM:
-               if (mp->m_flags & XFS_MOUNT_RDONLY)
-                       return XFS_ERROR(EROFS);
-               error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER,
-                                            (fs_disk_quota_t *)addr);
-               break;
-       case Q_XSETGQLIM:
-               if (mp->m_flags & XFS_MOUNT_RDONLY)
-                       return XFS_ERROR(EROFS);
-               error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
-                                            (fs_disk_quota_t *)addr);
-               break;
-       case Q_XSETPQLIM:
-               if (mp->m_flags & XFS_MOUNT_RDONLY)
-                       return XFS_ERROR(EROFS);
-               error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_PROJ,
-                                            (fs_disk_quota_t *)addr);
-               break;
-
-       default:
-               error = XFS_ERROR(EINVAL);
-               break;
-       }
-
-       return (error);
-}
-
 /*
  * Turn off quota accounting and/or enforcement for all udquots and/or
  * gdquots. Called only at unmount time.
@@ -193,11 +74,10 @@ xfs_qm_quotactl(
  * incore, and modifies the ondisk dquot directly. Therefore, for example,
  * it is an error to call this twice, without purging the cache.
  */
-STATIC int
+int
 xfs_qm_scall_quotaoff(
        xfs_mount_t             *mp,
-       uint                    flags,
-       boolean_t               force)
+       uint                    flags)
 {
        uint                    dqtype;
        int                     error;
@@ -205,8 +85,6 @@ xfs_qm_scall_quotaoff(
        xfs_qoff_logitem_t      *qoffstart;
        int                     nculprits;
 
-       if (!force && !capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
        /*
         * No file system can have quotas enabled on disk but not in core.
         * Note that quota utilities (like quotaoff) _expect_
@@ -375,7 +253,7 @@ out_error:
        return (error);
 }
 
-STATIC int
+int
 xfs_qm_scall_trunc_qfiles(
        xfs_mount_t     *mp,
        uint            flags)
@@ -383,8 +261,6 @@ xfs_qm_scall_trunc_qfiles(
        int             error = 0, error2 = 0;
        xfs_inode_t     *qip;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
        if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0) {
                qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
                return XFS_ERROR(EINVAL);
@@ -416,7 +292,7 @@ xfs_qm_scall_trunc_qfiles(
  * effect immediately.
  * (Switching on quota accounting must be done at mount time.)
  */
-STATIC int
+int
 xfs_qm_scall_quotaon(
        xfs_mount_t     *mp,
        uint            flags)
@@ -426,9 +302,6 @@ xfs_qm_scall_quotaon(
        uint            accflags;
        __int64_t       sbflags;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
-
        flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
        /*
         * Switching on quota accounting must be done at mount time.
@@ -517,7 +390,7 @@ xfs_qm_scall_quotaon(
 /*
  * Return quota status information, such as uquota-off, enforcements, etc.
  */
-STATIC int
+int
 xfs_qm_scall_getqstat(
        xfs_mount_t     *mp,
        fs_quota_stat_t *out)
@@ -582,7 +455,7 @@ xfs_qm_scall_getqstat(
 /*
  * Adjust quota limits, and start/stop timers accordingly.
  */
-STATIC int
+int
 xfs_qm_scall_setqlim(
        xfs_mount_t             *mp,
        xfs_dqid_t              id,
@@ -595,9 +468,6 @@ xfs_qm_scall_setqlim(
        int                     error;
        xfs_qcnt_t              hard, soft;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
-
        if ((newlim->d_fieldmask &
            (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK|FS_DQ_WARNS_MASK)) == 0)
                return (0);
@@ -742,7 +612,7 @@ xfs_qm_scall_setqlim(
        return error;
 }
 
-STATIC int
+int
 xfs_qm_scall_getquota(
        xfs_mount_t     *mp,
        xfs_dqid_t      id,
@@ -934,30 +804,6 @@ xfs_qm_export_dquot(
 #endif
 }
 
-STATIC uint
-xfs_qm_import_qtype_flags(
-       uint            uflags)
-{
-       uint            oflags = 0;
-
-       /*
-        * Can't be more than one, or none.
-        */
-       if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ==
-                       (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
-           ((uflags & (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) ==
-                       (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) ||
-           ((uflags & (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) ==
-                       (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) ||
-           ((uflags & (XFS_GROUP_QUOTA|XFS_USER_QUOTA|XFS_PROJ_QUOTA)) == 0))
-               return (0);
-
-       oflags |= (uflags & XFS_USER_QUOTA) ? XFS_DQ_USER : 0;
-       oflags |= (uflags & XFS_PROJ_QUOTA) ? XFS_DQ_PROJ : 0;
-       oflags |= (uflags & XFS_GROUP_QUOTA) ? XFS_DQ_GROUP: 0;
-       return oflags;
-}
-
 STATIC uint
 xfs_qm_export_qtype_flags(
        uint flags)
@@ -978,26 +824,6 @@ xfs_qm_export_qtype_flags(
                        XFS_PROJ_QUOTA : XFS_GROUP_QUOTA;
 }
 
-STATIC uint
-xfs_qm_import_flags(
-       uint uflags)
-{
-       uint flags = 0;
-
-       if (uflags & XFS_QUOTA_UDQ_ACCT)
-               flags |= XFS_UQUOTA_ACCT;
-       if (uflags & XFS_QUOTA_PDQ_ACCT)
-               flags |= XFS_PQUOTA_ACCT;
-       if (uflags & XFS_QUOTA_GDQ_ACCT)
-               flags |= XFS_GQUOTA_ACCT;
-       if (uflags & XFS_QUOTA_UDQ_ENFD)
-               flags |= XFS_UQUOTA_ENFD;
-       if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD))
-               flags |= XFS_OQUOTA_ENFD;
-       return (flags);
-}
-
-
 STATIC uint
 xfs_qm_export_flags(
        uint flags)
@@ -1134,7 +960,7 @@ xfs_dqhash_t *qmtest_udqtab;
 xfs_dqhash_t *qmtest_gdqtab;
 int          qmtest_hashmask;
 int          qmtest_nfails;
-mutex_t              qcheck_lock;
+struct mutex  qcheck_lock;
 
 #define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
                                 (__psunsigned_t)(id)) & \
index c4fcea600bc2f15ed7087653bbe6728bc37a71a4..8286b2842b6bc01ef06a566b9c975b2107144ad4 100644 (file)
 #define XFS_QI_QOFFLOCK(mp)    ((mp)->m_quotainfo->qi_quotaofflock)
 
 #define XFS_QI_MPL_LIST(mp)    ((mp)->m_quotainfo->qi_dqlist)
-#define XFS_QI_MPLLOCK(mp)     ((mp)->m_quotainfo->qi_dqlist.qh_lock)
 #define XFS_QI_MPLNEXT(mp)     ((mp)->m_quotainfo->qi_dqlist.qh_next)
 #define XFS_QI_MPLNDQUOTS(mp)  ((mp)->m_quotainfo->qi_dqlist.qh_nelems)
 
-#define XQMLCK(h)                      (mutex_lock(&((h)->qh_lock)))
-#define XQMUNLCK(h)                    (mutex_unlock(&((h)->qh_lock)))
-#ifdef DEBUG
-struct xfs_dqhash;
-static inline int XQMISLCKD(struct xfs_dqhash *h)
-{
-       if (mutex_trylock(&h->qh_lock)) {
-               mutex_unlock(&h->qh_lock);
-               return 0;
-       }
-       return 1;
-}
-#endif
-
-#define XFS_DQ_HASH_LOCK(h)            XQMLCK(h)
-#define XFS_DQ_HASH_UNLOCK(h)          XQMUNLCK(h)
-#define XFS_DQ_IS_HASH_LOCKED(h)       XQMISLCKD(h)
-
-#define xfs_qm_mplist_lock(mp)         XQMLCK(&(XFS_QI_MPL_LIST(mp)))
-#define xfs_qm_mplist_unlock(mp)       XQMUNLCK(&(XFS_QI_MPL_LIST(mp)))
-#define XFS_QM_IS_MPLIST_LOCKED(mp)    XQMISLCKD(&(XFS_QI_MPL_LIST(mp)))
-
-#define xfs_qm_freelist_lock(qm)       XQMLCK(&((qm)->qm_dqfreelist))
-#define xfs_qm_freelist_unlock(qm)     XQMUNLCK(&((qm)->qm_dqfreelist))
+#define xfs_qm_mplist_lock(mp) \
+       mutex_lock(&(XFS_QI_MPL_LIST(mp).qh_lock))
+#define xfs_qm_mplist_nowait(mp) \
+       mutex_trylock(&(XFS_QI_MPL_LIST(mp).qh_lock))
+#define xfs_qm_mplist_unlock(mp) \
+       mutex_unlock(&(XFS_QI_MPL_LIST(mp).qh_lock))
+#define XFS_QM_IS_MPLIST_LOCKED(mp) \
+       mutex_is_locked(&(XFS_QI_MPL_LIST(mp).qh_lock))
+
+#define xfs_qm_freelist_lock(qm) \
+       mutex_lock(&((qm)->qm_dqfreelist.qh_lock))
+#define xfs_qm_freelist_lock_nowait(qm) \
+       mutex_trylock(&((qm)->qm_dqfreelist.qh_lock))
+#define xfs_qm_freelist_unlock(qm) \
+       mutex_unlock(&((qm)->qm_dqfreelist.qh_lock))
 
 /*
  * Hash into a bucket in the dquot hash table, based on <mp, id>.
index 99611381e74043f9974651d2179c08cbc83f9675..447173bcf96de899b7369e66e232363fb5cd5eae 100644 (file)
@@ -624,10 +624,9 @@ xfs_trans_dqresv(
        xfs_qcnt_t      *resbcountp;
        xfs_quotainfo_t *q = mp->m_quotainfo;
 
-       if (! (flags & XFS_QMOPT_DQLOCK)) {
-               xfs_dqlock(dqp);
-       }
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+       xfs_dqlock(dqp);
+
        if (flags & XFS_TRANS_DQ_RES_BLKS) {
                hardlimit = be64_to_cpu(dqp->q_core.d_blk_hardlimit);
                if (!hardlimit)
@@ -740,10 +739,8 @@ xfs_trans_dqresv(
        ASSERT(dqp->q_res_icount >= be64_to_cpu(dqp->q_core.d_icount));
 
 error_return:
-       if (! (flags & XFS_QMOPT_DQLOCK)) {
-               xfs_dqunlock(dqp);
-       }
-       return (error);
+       xfs_dqunlock(dqp);
+       return error;
 }
 
 
@@ -753,8 +750,7 @@ error_return:
  * grp/prj quotas is important, because this follows a both-or-nothing
  * approach.
  *
- * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
- *        XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
+ * flags = XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
  *        XFS_QMOPT_ENOSPC returns ENOSPC not EDQUOT.  Used by pquota.
  *        XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
  *        XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
index ae5482965424d9ae4dddbed76bbff558bb86bb5d..3f3610a7ee059210eea3beadbffe13f87609dce9 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_ag.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
+#include "xfs_error.h"
 
 static char            message[1024];  /* keep it off the stack */
 static DEFINE_SPINLOCK(xfs_err_lock);
index 5830c040ea7ebba66274eeebbdab553c206ab981..b83f76b6d4106d87928bc0c69c4d8be0d169d168 100644 (file)
  */
 #include <xfs.h>
 
-static DEFINE_MUTEX(uuid_monitor);
-static int     uuid_table_size;
-static uuid_t  *uuid_table;
-
 /* IRIX interpretation of an uuid_t */
 typedef struct {
        __be32  uu_timelow;
@@ -46,12 +42,6 @@ uuid_getnodeuniq(uuid_t *uuid, int fsid [2])
        fsid[1] = be32_to_cpu(uup->uu_timelow);
 }
 
-void
-uuid_create_nil(uuid_t *uuid)
-{
-       memset(uuid, 0, sizeof(*uuid));
-}
-
 int
 uuid_is_nil(uuid_t *uuid)
 {
@@ -71,64 +61,3 @@ uuid_equal(uuid_t *uuid1, uuid_t *uuid2)
 {
        return memcmp(uuid1, uuid2, sizeof(uuid_t)) ? 0 : 1;
 }
-
-/*
- * Given a 128-bit uuid, return a 64-bit value by adding the top and bottom
- * 64-bit words.  NOTE: This function can not be changed EVER.  Although
- * brain-dead, some applications depend on this 64-bit value remaining
- * persistent.  Specifically, DMI vendors store the value as a persistent
- * filehandle.
- */
-__uint64_t
-uuid_hash64(uuid_t *uuid)
-{
-       __uint64_t      *sp = (__uint64_t *)uuid;
-
-       return sp[0] + sp[1];
-}
-
-int
-uuid_table_insert(uuid_t *uuid)
-{
-       int     i, hole;
-
-       mutex_lock(&uuid_monitor);
-       for (i = 0, hole = -1; i < uuid_table_size; i++) {
-               if (uuid_is_nil(&uuid_table[i])) {
-                       hole = i;
-                       continue;
-               }
-               if (uuid_equal(uuid, &uuid_table[i])) {
-                       mutex_unlock(&uuid_monitor);
-                       return 0;
-               }
-       }
-       if (hole < 0) {
-               uuid_table = kmem_realloc(uuid_table,
-                       (uuid_table_size + 1) * sizeof(*uuid_table),
-                       uuid_table_size  * sizeof(*uuid_table),
-                       KM_SLEEP);
-               hole = uuid_table_size++;
-       }
-       uuid_table[hole] = *uuid;
-       mutex_unlock(&uuid_monitor);
-       return 1;
-}
-
-void
-uuid_table_remove(uuid_t *uuid)
-{
-       int     i;
-
-       mutex_lock(&uuid_monitor);
-       for (i = 0; i < uuid_table_size; i++) {
-               if (uuid_is_nil(&uuid_table[i]))
-                       continue;
-               if (!uuid_equal(uuid, &uuid_table[i]))
-                       continue;
-               uuid_create_nil(&uuid_table[i]);
-               break;
-       }
-       ASSERT(i < uuid_table_size);
-       mutex_unlock(&uuid_monitor);
-}
index cff5b607d445e80888a73de26c2a23952bf30a08..4732d71262cc3f6f3aca0f143a96f81094bf5a22 100644 (file)
@@ -22,12 +22,8 @@ typedef struct {
        unsigned char   __u_bits[16];
 } uuid_t;
 
-extern void uuid_create_nil(uuid_t *uuid);
 extern int uuid_is_nil(uuid_t *uuid);
 extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2);
 extern void uuid_getnodeuniq(uuid_t *uuid, int fsid [2]);
-extern __uint64_t uuid_hash64(uuid_t *uuid);
-extern int uuid_table_insert(uuid_t *uuid);
-extern void uuid_table_remove(uuid_t *uuid);
 
 #endif /* __XFS_SUPPORT_UUID_H__ */
index 143d63ecb20aa86725a1c6ae12b177d44d362d40..c8641f713caae0c97d9ad08481de1627626bb007 100644 (file)
@@ -223,8 +223,8 @@ typedef struct xfs_perag
                be32_to_cpu((a)->agf_levels[XFS_BTNUM_CNTi]), mp))
 #define        XFS_MIN_FREELIST_PAG(pag,mp)    \
        (XFS_MIN_FREELIST_RAW(          \
-               (uint_t)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
-               (uint_t)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
+               (unsigned int)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
+               (unsigned int)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
 
 #define XFS_AGB_TO_FSB(mp,agno,agbno)  \
        (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno))
index 028e44e58ea986946f2e4615f2b2c0088a6845c8..2cf944eb796daf4ca455865d3dd22c83ee6d13ee 100644 (file)
@@ -1871,6 +1871,25 @@ xfs_alloc_compute_maxlevels(
        mp->m_ag_maxlevels = level;
 }
 
+/*
+ * Find the length of the longest extent in an AG.
+ */
+xfs_extlen_t
+xfs_alloc_longest_free_extent(
+       struct xfs_mount        *mp,
+       struct xfs_perag        *pag)
+{
+       xfs_extlen_t            need, delta = 0;
+
+       need = XFS_MIN_FREELIST_PAG(pag, mp);
+       if (need > pag->pagf_flcount)
+               delta = need - pag->pagf_flcount;
+
+       if (pag->pagf_longest > delta)
+               return pag->pagf_longest - delta;
+       return pag->pagf_flcount > 0 || pag->pagf_longest > 0;
+}
+
 /*
  * Decide whether to use this allocation group for this allocation.
  * If so, fix up the btree freelist's size.
@@ -1923,15 +1942,12 @@ xfs_alloc_fix_freelist(
        }
 
        if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
-               need = XFS_MIN_FREELIST_PAG(pag, mp);
-               delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;
                /*
                 * If it looks like there isn't a long enough extent, or enough
                 * total blocks, reject it.
                 */
-               longest = (pag->pagf_longest > delta) ?
-                       (pag->pagf_longest - delta) :
-                       (pag->pagf_flcount > 0 || pag->pagf_longest > 0);
+               need = XFS_MIN_FREELIST_PAG(pag, mp);
+               longest = xfs_alloc_longest_free_extent(mp, pag);
                if ((args->minlen + args->alignment + args->minalignslop - 1) >
                                longest ||
                    ((int)(pag->pagf_freeblks + pag->pagf_flcount -
index 588172796f7b92c61f696591bb5241f1d8f42ccc..e704caee10dfaa2bca339969ad840cfc233e9003 100644 (file)
@@ -100,6 +100,12 @@ typedef struct xfs_alloc_arg {
 #define XFS_ALLOC_USERDATA             1       /* allocation is for user data*/
 #define XFS_ALLOC_INITIAL_USER_DATA    2       /* special case start of file */
 
+/*
+ * Find the length of the longest extent in an AG.
+ */
+xfs_extlen_t
+xfs_alloc_longest_free_extent(struct xfs_mount *mp,
+               struct xfs_perag *pag);
 
 #ifdef __KERNEL__
 
index 6c323f8a4cd19cb8b169bcc17446dd62ffb4ea75..afdc8911637d20c3f7f01ff4eb50ca832e27ab28 100644 (file)
@@ -155,7 +155,8 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
                 * minimum offset only needs to be the space required for 
                 * the btree root.
                 */ 
-               if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > mp->m_attroffset)
+               if (!dp->i_d.di_forkoff && dp->i_df.if_bytes >
+                   xfs_default_attroffset(dp))
                        dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
                break;
                
@@ -297,6 +298,26 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
        xfs_sbversion_add_attr2(mp, args->trans);
 }
 
+/*
+ * After the last attribute is removed revert to original inode format,
+ * making all literal area available to the data fork once more.
+ */
+STATIC void
+xfs_attr_fork_reset(
+       struct xfs_inode        *ip,
+       struct xfs_trans        *tp)
+{
+       xfs_idestroy_fork(ip, XFS_ATTR_FORK);
+       ip->i_d.di_forkoff = 0;
+       ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
+
+       ASSERT(ip->i_d.di_anextents == 0);
+       ASSERT(ip->i_afp == NULL);
+
+       ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t);
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+}
+
 /*
  * Remove an attribute from the shortform attribute list structure.
  */
@@ -344,22 +365,10 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
         */
        totsize -= size;
        if (totsize == sizeof(xfs_attr_sf_hdr_t) &&
-                               !(args->op_flags & XFS_DA_OP_ADDNAME) &&
-                               (mp->m_flags & XFS_MOUNT_ATTR2) &&
-                               (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) {
-               /*
-                * Last attribute now removed, revert to original
-                * inode format making all literal area available
-                * to the data fork once more.
-                */
-               xfs_idestroy_fork(dp, XFS_ATTR_FORK);
-               dp->i_d.di_forkoff = 0;
-               dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
-               ASSERT(dp->i_d.di_anextents == 0);
-               ASSERT(dp->i_afp == NULL);
-               dp->i_df.if_ext_max =
-                       XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
-               xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
+           (mp->m_flags & XFS_MOUNT_ATTR2) &&
+           (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
+           !(args->op_flags & XFS_DA_OP_ADDNAME)) {
+               xfs_attr_fork_reset(dp, args->trans);
        } else {
                xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
                dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
@@ -786,20 +795,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
        if (forkoff == -1) {
                ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2);
                ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE);
-
-               /*
-                * Last attribute was removed, revert to original
-                * inode format making all literal area available
-                * to the data fork once more.
-                */
-               xfs_idestroy_fork(dp, XFS_ATTR_FORK);
-               dp->i_d.di_forkoff = 0;
-               dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
-               ASSERT(dp->i_d.di_anextents == 0);
-               ASSERT(dp->i_afp == NULL);
-               dp->i_df.if_ext_max =
-                       XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
-               xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
+               xfs_attr_fork_reset(dp, args->trans);
                goto out;
        }
 
index c852cd65aaea59bdcf251c84dc5412ebef1c3c74..3a6ed426327ac15575fe0cf5e39b0a120dc3a373 100644 (file)
@@ -2479,7 +2479,7 @@ xfs_bmap_adjacent(
        fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
        /*
         * If allocating at eof, and there's a previous real block,
-        * try to use it's last block as our starting point.
+        * try to use its last block as our starting point.
         */
        if (ap->eof && ap->prevp->br_startoff != NULLFILEOFF &&
            !isnullstartblock(ap->prevp->br_startblock) &&
@@ -2712,9 +2712,6 @@ xfs_bmap_btalloc(
        xfs_agnumber_t  startag;
        xfs_alloc_arg_t args;
        xfs_extlen_t    blen;
-       xfs_extlen_t    delta;
-       xfs_extlen_t    longest;
-       xfs_extlen_t    need;
        xfs_extlen_t    nextminlen = 0;
        xfs_perag_t     *pag;
        int             nullfb;         /* true if ap->firstblock isn't set */
@@ -2796,13 +2793,8 @@ xfs_bmap_btalloc(
                         * See xfs_alloc_fix_freelist...
                         */
                        if (pag->pagf_init) {
-                               need = XFS_MIN_FREELIST_PAG(pag, mp);
-                               delta = need > pag->pagf_flcount ?
-                                       need - pag->pagf_flcount : 0;
-                               longest = (pag->pagf_longest > delta) ?
-                                       (pag->pagf_longest - delta) :
-                                       (pag->pagf_flcount > 0 ||
-                                        pag->pagf_longest > 0);
+                               xfs_extlen_t    longest;
+                               longest = xfs_alloc_longest_free_extent(mp, pag);
                                if (blen < longest)
                                        blen = longest;
                        } else
@@ -3576,6 +3568,27 @@ xfs_bmap_extents_to_btree(
        return 0;
 }
 
+/*
+ * Calculate the default attribute fork offset for newly created inodes.
+ */
+uint
+xfs_default_attroffset(
+       struct xfs_inode        *ip)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       uint                    offset;
+
+       if (mp->m_sb.sb_inodesize == 256) {
+               offset = XFS_LITINO(mp) -
+                               XFS_BMDR_SPACE_CALC(MINABTPTRS);
+       } else {
+               offset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS);
+       }
+
+       ASSERT(offset < XFS_LITINO(mp));
+       return offset;
+}
+
 /*
  * Helper routine to reset inode di_forkoff field when switching
  * attribute fork from local to extent format - we reset it where
@@ -3588,15 +3601,18 @@ xfs_bmap_forkoff_reset(
        int             whichfork)
 {
        if (whichfork == XFS_ATTR_FORK &&
-           (ip->i_d.di_format != XFS_DINODE_FMT_DEV) &&
-           (ip->i_d.di_format != XFS_DINODE_FMT_UUID) &&
-           (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
-           ((mp->m_attroffset >> 3) > ip->i_d.di_forkoff)) {
-               ip->i_d.di_forkoff = mp->m_attroffset >> 3;
-               ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) /
-                                       (uint)sizeof(xfs_bmbt_rec_t);
-               ip->i_afp->if_ext_max = XFS_IFORK_ASIZE(ip) /
-                                       (uint)sizeof(xfs_bmbt_rec_t);
+           ip->i_d.di_format != XFS_DINODE_FMT_DEV &&
+           ip->i_d.di_format != XFS_DINODE_FMT_UUID &&
+           ip->i_d.di_format != XFS_DINODE_FMT_BTREE) {
+               uint    dfl_forkoff = xfs_default_attroffset(ip) >> 3;
+
+               if (dfl_forkoff > ip->i_d.di_forkoff) {
+                       ip->i_d.di_forkoff = dfl_forkoff;
+                       ip->i_df.if_ext_max =
+                               XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t);
+                       ip->i_afp->if_ext_max =
+                               XFS_IFORK_ASIZE(ip) / sizeof(xfs_bmbt_rec_t);
+               }
        }
 }
 
@@ -4065,7 +4081,7 @@ xfs_bmap_add_attrfork(
        case XFS_DINODE_FMT_BTREE:
                ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
                if (!ip->i_d.di_forkoff)
-                       ip->i_d.di_forkoff = mp->m_attroffset >> 3;
+                       ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
                else if (mp->m_flags & XFS_MOUNT_ATTR2)
                        version = 2;
                break;
@@ -4212,12 +4228,12 @@ xfs_bmap_compute_maxlevels(
         * (a signed 16-bit number, xfs_aextnum_t).
         *
         * Note that we can no longer assume that if we are in ATTR1 that
-        * the fork offset of all the inodes will be (m_attroffset >> 3)
-        * because we could have mounted with ATTR2 and then mounted back
-        * with ATTR1, keeping the di_forkoff's fixed but probably at
-        * various positions. Therefore, for both ATTR1 and ATTR2
-        * we have to assume the worst case scenario of a minimum size
-        * available.
+        * the fork offset of all the inodes will be
+        * (xfs_default_attroffset(ip) >> 3) because we could have mounted
+        * with ATTR2 and then mounted back with ATTR1, keeping the
+        * di_forkoff's fixed but probably at various positions. Therefore,
+        * for both ATTR1 and ATTR2 we have to assume the worst case scenario
+        * of a minimum size available.
         */
        if (whichfork == XFS_DATA_FORK) {
                maxleafents = MAXEXTNUM;
@@ -4804,7 +4820,7 @@ xfs_bmapi(
        xfs_extlen_t    minlen;         /* min allocation size */
        xfs_mount_t     *mp;            /* xfs mount structure */
        int             n;              /* current extent index */
-       int             nallocs;        /* number of extents alloc\'d */
+       int             nallocs;        /* number of extents alloc'd */
        xfs_extnum_t    nextents;       /* number of extents in file */
        xfs_fileoff_t   obno;           /* old block number (offset) */
        xfs_bmbt_irec_t prev;           /* previous file extent record */
@@ -6204,7 +6220,7 @@ xfs_bmap_get_bp(
        return(bp);
 }
 
-void
+STATIC void
 xfs_check_block(
        struct xfs_btree_block  *block,
        xfs_mount_t             *mp,
@@ -6494,7 +6510,7 @@ xfs_bmap_count_tree(
        block = XFS_BUF_TO_BLOCK(bp);
 
        if (--level) {
-               /* Not at node above leafs, count this level of nodes */
+               /* Not at node above leaves, count this level of nodes */
                nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
                while (nextbno != NULLFSBLOCK) {
                        if ((error = xfs_btree_read_bufl(mp, tp, nextbno,
index be2979d88d326625a5df5fbe387dfa19c4a3ac8b..1b8ff9256bd0cba9515bc212c859a80c2335c157 100644 (file)
@@ -125,7 +125,7 @@ typedef struct xfs_bmalloca {
        struct xfs_bmbt_irec    *gotp;  /* extent after, or delayed */
        xfs_extlen_t            alen;   /* i/o length asked/allocated */
        xfs_extlen_t            total;  /* total blocks needed for xaction */
-       xfs_extlen_t            minlen; /* mininum allocation size (blocks) */
+       xfs_extlen_t            minlen; /* minimum allocation size (blocks) */
        xfs_extlen_t            minleft; /* amount must be left after alloc */
        char                    eof;    /* set if allocating past last extent */
        char                    wasdel; /* replacing a delayed allocation */
@@ -338,6 +338,10 @@ xfs_check_nostate_extents(
        xfs_extnum_t            idx,
        xfs_extnum_t            num);
 
+uint
+xfs_default_attroffset(
+       struct xfs_inode        *ip);
+
 #ifdef __KERNEL__
 
 /*
index e73c332eb23f92cce1c61fad98f6cc3fbc1870d1..e9df995748291047922ef29257e9423357d386db 100644 (file)
@@ -1883,7 +1883,7 @@ xfs_btree_lshift(
 
        /*
         * We add one entry to the left side and remove one for the right side.
-        * Accout for it here, the changes will be updated on disk and logged
+        * Account for it here, the changes will be updated on disk and logged
         * later.
         */
        lrecs++;
@@ -3535,7 +3535,7 @@ xfs_btree_delrec(
        XFS_BTREE_STATS_INC(cur, join);
 
        /*
-        * Fix up the the number of records and right block pointer in the
+        * Fix up the number of records and right block pointer in the
         * surviving block, and log it.
         */
        xfs_btree_set_numrecs(left, lrecs + rrecs);
index 789fffdf8b2f557bc1aa3ed3c51acc5081ee941b..4f852b735b961a37bb43f431937b52cbe1166212 100644 (file)
@@ -41,7 +41,7 @@ extern kmem_zone_t    *xfs_btree_cur_zone;
 /*
  * Generic btree header.
  *
- * This is a comination of the actual format used on disk for short and long
+ * This is a combination of the actual format used on disk for short and long
  * format btrees.  The first three fields are shared by both format, but
  * the pointers are different and should be used with care.
  *
index c45f74ff1a5b980bfb51f6d30ae306f2db880be4..9ff6e57a50758f10ddc076dc7875dad2172963a3 100644 (file)
@@ -1503,7 +1503,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
  * This is implemented with some source-level loop unrolling.
  */
 xfs_dahash_t
-xfs_da_hashname(const uchar_t *name, int namelen)
+xfs_da_hashname(const __uint8_t *name, int namelen)
 {
        xfs_dahash_t hash;
 
index 70b710c1792d33bfce9c94641b2e62016d48493e..8c536167bf754b030dcd333ed2c06c5a72c887a6 100644 (file)
@@ -91,9 +91,9 @@ enum xfs_dacmp {
  * Structure to ease passing around component names.
  */
 typedef struct xfs_da_args {
-       const uchar_t   *name;          /* string (maybe not NULL terminated) */
+       const __uint8_t *name;          /* string (maybe not NULL terminated) */
        int             namelen;        /* length of string (maybe no NULL) */
-       uchar_t         *value;         /* set of bytes (maybe contain NULLs) */
+       __uint8_t       *value;         /* set of bytes (maybe contain NULLs) */
        int             valuelen;       /* length of value */
        int             flags;          /* argument flags (eg: ATTR_NOCREATE) */
        xfs_dahash_t    hashval;        /* hash value of name */
@@ -185,7 +185,7 @@ typedef struct xfs_da_state {
        unsigned char           inleaf;         /* insert into 1->lf, 0->splf */
        unsigned char           extravalid;     /* T/F: extrablk is in use */
        unsigned char           extraafter;     /* T/F: extrablk is after new */
-       xfs_da_state_blk_t      extrablk;       /* for double-splits on leafs */
+       xfs_da_state_blk_t      extrablk;       /* for double-splits on leaves */
                                                /* for dirv2 extrablk is data */
 } xfs_da_state_t;
 
@@ -251,7 +251,7 @@ xfs_daddr_t xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp,
 int    xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
                                          xfs_dabuf_t *dead_buf);
 
-uint xfs_da_hashname(const uchar_t *name_string, int name_length);
+uint xfs_da_hashname(const __uint8_t *name_string, int name_length);
 enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args,
                                const char *name, int len);
 
@@ -268,5 +268,6 @@ xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf);
 
 extern struct kmem_zone *xfs_da_state_zone;
 extern struct kmem_zone *xfs_dabuf_zone;
+extern const struct xfs_nameops xfs_default_nameops;
 
 #endif /* __XFS_DA_BTREE_H__ */
index f8278cfcc1d328a1a9542663d448607de1c5f561..e6d839bddbf008b3bc522720e5f5e0711a954e10 100644 (file)
@@ -79,6 +79,12 @@ xfs_swapext(
                goto out_put_target_file;
        }
 
+       if (IS_SWAPFILE(file->f_path.dentry->d_inode) ||
+           IS_SWAPFILE(target_file->f_path.dentry->d_inode)) {
+               error = XFS_ERROR(EINVAL);
+               goto out_put_target_file;
+       }
+
        ip = XFS_I(file->f_path.dentry->d_inode);
        tip = XFS_I(target_file->f_path.dentry->d_inode);
 
@@ -118,19 +124,17 @@ xfs_swap_extents(
        xfs_bstat_t     *sbp = &sxp->sx_stat;
        xfs_ifork_t     *tempifp, *ifp, *tifp;
        int             ilf_fields, tilf_fields;
-       static uint     lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL;
        int             error = 0;
        int             aforkblks = 0;
        int             taforkblks = 0;
        __uint64_t      tmp;
-       char            locked = 0;
 
        mp = ip->i_mount;
 
        tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
        if (!tempifp) {
                error = XFS_ERROR(ENOMEM);
-               goto error0;
+               goto out;
        }
 
        sbp = &sxp->sx_stat;
@@ -143,25 +147,24 @@ xfs_swap_extents(
         */
        xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
        xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
-       locked = 1;
 
        /* Verify that both files have the same format */
        if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
                error = XFS_ERROR(EINVAL);
-               goto error0;
+               goto out_unlock;
        }
 
        /* Verify both files are either real-time or non-realtime */
        if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) {
                error = XFS_ERROR(EINVAL);
-               goto error0;
+               goto out_unlock;
        }
 
        /* Should never get a local format */
        if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL ||
            tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
                error = XFS_ERROR(EINVAL);
-               goto error0;
+               goto out_unlock;
        }
 
        if (VN_CACHED(VFS_I(tip)) != 0) {
@@ -169,13 +172,13 @@ xfs_swap_extents(
                error = xfs_flushinval_pages(tip, 0, -1,
                                FI_REMAPF_LOCKED);
                if (error)
-                       goto error0;
+                       goto out_unlock;
        }
 
        /* Verify O_DIRECT for ftmp */
        if (VN_CACHED(VFS_I(tip)) != 0) {
                error = XFS_ERROR(EINVAL);
-               goto error0;
+               goto out_unlock;
        }
 
        /* Verify all data are being swapped */
@@ -183,7 +186,7 @@ xfs_swap_extents(
            sxp->sx_length != ip->i_d.di_size ||
            sxp->sx_length != tip->i_d.di_size) {
                error = XFS_ERROR(EFAULT);
-               goto error0;
+               goto out_unlock;
        }
 
        /*
@@ -193,7 +196,7 @@ xfs_swap_extents(
         */
        if ( XFS_IFORK_Q(ip) != XFS_IFORK_Q(tip) ) {
                error = XFS_ERROR(EINVAL);
-               goto error0;
+               goto out_unlock;
        }
 
        /*
@@ -208,7 +211,7 @@ xfs_swap_extents(
            (sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) ||
            (sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) {
                error = XFS_ERROR(EBUSY);
-               goto error0;
+               goto out_unlock;
        }
 
        /* We need to fail if the file is memory mapped.  Once we have tossed
@@ -219,7 +222,7 @@ xfs_swap_extents(
         */
        if (VN_MAPPED(VFS_I(ip))) {
                error = XFS_ERROR(EBUSY);
-               goto error0;
+               goto out_unlock;
        }
 
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -242,8 +245,7 @@ xfs_swap_extents(
                xfs_iunlock(ip,  XFS_IOLOCK_EXCL);
                xfs_iunlock(tip, XFS_IOLOCK_EXCL);
                xfs_trans_cancel(tp, 0);
-               locked = 0;
-               goto error0;
+               goto out;
        }
        xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
 
@@ -253,19 +255,15 @@ xfs_swap_extents(
        if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) &&
             (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
                error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks);
-               if (error) {
-                       xfs_trans_cancel(tp, 0);
-                       goto error0;
-               }
+               if (error)
+                       goto out_trans_cancel;
        }
        if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) &&
             (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
                error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK,
                        &taforkblks);
-               if (error) {
-                       xfs_trans_cancel(tp, 0);
-                       goto error0;
-               }
+               if (error)
+                       goto out_trans_cancel;
        }
 
        /*
@@ -332,10 +330,10 @@ xfs_swap_extents(
 
 
        IHOLD(ip);
-       xfs_trans_ijoin(tp, ip, lock_flags);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
        IHOLD(tip);
-       xfs_trans_ijoin(tp, tip, lock_flags);
+       xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
        xfs_trans_log_inode(tp, ip,  ilf_fields);
        xfs_trans_log_inode(tp, tip, tilf_fields);
@@ -344,19 +342,19 @@ xfs_swap_extents(
         * If this is a synchronous mount, make sure that the
         * transaction goes to disk before returning to the user.
         */
-       if (mp->m_flags & XFS_MOUNT_WSYNC) {
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
                xfs_trans_set_sync(tp);
-       }
 
        error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT);
-       locked = 0;
 
- error0:
-       if (locked) {
-               xfs_iunlock(ip,  lock_flags);
-               xfs_iunlock(tip, lock_flags);
-       }
-       if (tempifp != NULL)
-               kmem_free(tempifp);
+out_unlock:
+       xfs_iunlock(ip,  XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+out:
+       kmem_free(tempifp);
        return error;
+
+out_trans_cancel:
+       xfs_trans_cancel(tp, 0);
+       goto out_unlock;
 }
index 162e8726df5e65b9666cee344aadda997909d878..e5b153b2e6a34b527ec65ec57e0b60d9ce9cb073 100644 (file)
@@ -103,7 +103,9 @@ typedef enum xfs_dinode_fmt {
 /*
  * Inode size for given fs.
  */
-#define        XFS_LITINO(mp)  ((mp)->m_litino)
+#define XFS_LITINO(mp) \
+       ((int)(((mp)->m_sb.sb_inodesize) - sizeof(struct xfs_dinode)))
+
 #define        XFS_BROOT_SIZE_ADJ      \
        (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
 
index 1afb12278b8d04b85eb42d0f67d0bd21936885be..c657bec6d9513849f2ad86dca172e88417742f14 100644 (file)
@@ -46,8 +46,6 @@
 
 struct xfs_name xfs_name_dotdot = {"..", 2};
 
-extern const struct xfs_nameops xfs_default_nameops;
-
 /*
  * ASCII case-insensitive (ie. A-Z) support for directories that was
  * used in IRIX.
index e1f0a06aaf042c945e02f07b872190414122a2b7..ab52e9e1c1eedd9c115161a4f786bf37d5bcff66 100644 (file)
@@ -448,7 +448,6 @@ xfs_dir2_block_getdents(
        xfs_mount_t             *mp;            /* filesystem mount point */
        char                    *ptr;           /* current data entry */
        int                     wantoff;        /* starting block offset */
-       xfs_ino_t               ino;
        xfs_off_t               cook;
 
        mp = dp->i_mount;
@@ -509,16 +508,12 @@ xfs_dir2_block_getdents(
 
                cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
                                            (char *)dep - (char *)block);
-               ino = be64_to_cpu(dep->inumber);
-#if XFS_BIG_INUMS
-               ino += mp->m_inoadd;
-#endif
 
                /*
                 * If it didn't fit, set the final offset to here & return.
                 */
                if (filldir(dirent, dep->name, dep->namelen, cook & 0x7fffffff,
-                           ino, DT_UNKNOWN)) {
+                           be64_to_cpu(dep->inumber), DT_UNKNOWN)) {
                        *offset = cook & 0x7fffffff;
                        xfs_da_brelse(NULL, bp);
                        return 0;
index b816e025273916ff02867b033acb0eeaa54a6751..efbc290c7fec1bee9a3914a0fb56d52acf32c41a 100644 (file)
@@ -38,7 +38,7 @@ struct xfs_trans;
 
 /*
  * Directory address space divided into sections,
- * spaces separated by 32gb.
+ * spaces separated by 32GB.
  */
 #define        XFS_DIR2_SPACE_SIZE     (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
 #define        XFS_DIR2_DATA_SPACE     0
index ef805a374eec174c21c77317da7c743ad47b21bf..fa913e4594421adefc392e80c254d492b8a9ec91 100644 (file)
@@ -549,7 +549,7 @@ xfs_dir2_leaf_addname(
  * Check the internal consistency of a leaf1 block.
  * Pop an assert if something is wrong.
  */
-void
+STATIC void
 xfs_dir2_leaf_check(
        xfs_inode_t             *dp,            /* incore directory inode */
        xfs_dabuf_t             *bp)            /* leaf's buffer */
@@ -780,7 +780,6 @@ xfs_dir2_leaf_getdents(
        int                     ra_index;       /* *map index for read-ahead */
        int                     ra_offset;      /* map entry offset for ra */
        int                     ra_want;        /* readahead count wanted */
-       xfs_ino_t               ino;
 
        /*
         * If the offset is at or past the largest allowed value,
@@ -1076,24 +1075,12 @@ xfs_dir2_leaf_getdents(
                        continue;
                }
 
-               /*
-                * Copy the entry into the putargs, and try formatting it.
-                */
                dep = (xfs_dir2_data_entry_t *)ptr;
-
                length = xfs_dir2_data_entsize(dep->namelen);
 
-               ino = be64_to_cpu(dep->inumber);
-#if XFS_BIG_INUMS
-               ino += mp->m_inoadd;
-#endif
-
-               /*
-                * Won't fit.  Return to caller.
-                */
                if (filldir(dirent, dep->name, dep->namelen,
                            xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff,
-                           ino, DT_UNKNOWN))
+                           be64_to_cpu(dep->inumber), DT_UNKNOWN))
                        break;
 
                /*
index fa6c3a5ddbc65fba6fa05dca30cdc0fd3664b567..5a81ccd1045b11ac762fc0978d6b4043c6d451b6 100644 (file)
@@ -1104,7 +1104,7 @@ xfs_dir2_leafn_remove(
        }
        xfs_dir2_leafn_check(dp, bp);
        /*
-        * Return indication of whether this leaf block is emtpy enough
+        * Return indication of whether this leaf block is empty enough
         * to justify trying to join it with a neighbor.
         */
        *rval =
index a8a8a6efad5b8142dad0689988a35597cbf32554..e89734e8464610a67797cc473951d91d1ce2fb90 100644 (file)
@@ -748,11 +748,7 @@ xfs_dir2_sf_getdents(
         * Put . entry unless we're starting past it.
         */
        if (*offset <= dot_offset) {
-               ino = dp->i_ino;
-#if XFS_BIG_INUMS
-               ino += mp->m_inoadd;
-#endif
-               if (filldir(dirent, ".", 1, dot_offset & 0x7fffffff, ino, DT_DIR)) {
+               if (filldir(dirent, ".", 1, dot_offset & 0x7fffffff, dp->i_ino, DT_DIR)) {
                        *offset = dot_offset & 0x7fffffff;
                        return 0;
                }
@@ -763,9 +759,6 @@ xfs_dir2_sf_getdents(
         */
        if (*offset <= dotdot_offset) {
                ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
-#if XFS_BIG_INUMS
-               ino += mp->m_inoadd;
-#endif
                if (filldir(dirent, "..", 2, dotdot_offset & 0x7fffffff, ino, DT_DIR)) {
                        *offset = dotdot_offset & 0x7fffffff;
                        return 0;
@@ -786,10 +779,6 @@ xfs_dir2_sf_getdents(
                }
 
                ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
-#if XFS_BIG_INUMS
-               ino += mp->m_inoadd;
-#endif
-
                if (filldir(dirent, sfep->name, sfep->namelen,
                            off & 0x7fffffff, ino, DT_UNKNOWN)) {
                        *offset = off & 0x7fffffff;
index 2f049f63e85f73ea3ae1763c5eb66e6798368635..0d22c56fdf64247f6f208ef0ed2f2a72a7b64e22 100644 (file)
@@ -33,12 +33,10 @@ typedef struct xfs_extent {
  * conversion routine.
  */
 
-#ifndef HAVE_FORMAT32
 typedef struct xfs_extent_32 {
        __uint64_t      ext_start;
        __uint32_t      ext_len;
 } __attribute__((packed)) xfs_extent_32_t;
-#endif
 
 typedef struct xfs_extent_64 {
        __uint64_t      ext_start;
@@ -59,7 +57,6 @@ typedef struct xfs_efi_log_format {
        xfs_extent_t            efi_extents[1]; /* array of extents to free */
 } xfs_efi_log_format_t;
 
-#ifndef HAVE_FORMAT32
 typedef struct xfs_efi_log_format_32 {
        __uint16_t              efi_type;       /* efi log item type */
        __uint16_t              efi_size;       /* size of this item */
@@ -67,7 +64,6 @@ typedef struct xfs_efi_log_format_32 {
        __uint64_t              efi_id;         /* efi identifier */
        xfs_extent_32_t         efi_extents[1]; /* array of extents to free */
 } __attribute__((packed)) xfs_efi_log_format_32_t;
-#endif
 
 typedef struct xfs_efi_log_format_64 {
        __uint16_t              efi_type;       /* efi log item type */
@@ -90,7 +86,6 @@ typedef struct xfs_efd_log_format {
        xfs_extent_t            efd_extents[1]; /* array of extents freed */
 } xfs_efd_log_format_t;
 
-#ifndef HAVE_FORMAT32
 typedef struct xfs_efd_log_format_32 {
        __uint16_t              efd_type;       /* efd log item type */
        __uint16_t              efd_size;       /* size of this item */
@@ -98,7 +93,6 @@ typedef struct xfs_efd_log_format_32 {
        __uint64_t              efd_efi_id;     /* id of corresponding efi */
        xfs_extent_32_t         efd_extents[1]; /* array of extents freed */
 } __attribute__((packed)) xfs_efd_log_format_32_t;
-#endif
 
 typedef struct xfs_efd_log_format_64 {
        __uint16_t              efd_type;       /* efd log item type */
index f3bb75da384e0919d30b6ba4722875ffe5736da3..6c87c8f304efb8f7d887c7c41a667e4c85105882 100644 (file)
@@ -140,7 +140,7 @@ _xfs_filestream_pick_ag(
        xfs_extlen_t    minlen)
 {
        int             err, trylock, nscan;
-       xfs_extlen_t    delta, longest, need, free, minfree, maxfree = 0;
+       xfs_extlen_t    longest, free, minfree, maxfree = 0;
        xfs_agnumber_t  ag, max_ag = NULLAGNUMBER;
        struct xfs_perag *pag;
 
@@ -186,12 +186,7 @@ _xfs_filestream_pick_ag(
                        goto next_ag;
                }
 
-               need = XFS_MIN_FREELIST_PAG(pag, mp);
-               delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;
-               longest = (pag->pagf_longest > delta) ?
-                         (pag->pagf_longest - delta) :
-                         (pag->pagf_flcount > 0 || pag->pagf_longest > 0);
-
+               longest = xfs_alloc_longest_free_extent(mp, pag);
                if (((minlen && longest >= minlen) ||
                     (!minlen && pag->pagf_freeblks >= minfree)) &&
                    (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||
index 680d0e0ec93298576f46686f219098c242e152d8..8379e3bca26cb08d865a8c4cda3c7f6f1c48c276 100644 (file)
@@ -576,7 +576,7 @@ out:
        if (fdblks_delta) {
                /*
                 * If we are putting blocks back here, m_resblks_avail is
-                * already at it's max so this will put it in the free pool.
+                * already at its max so this will put it in the free pool.
                 *
                 * If we need space, we'll either succeed in getting it
                 * from the free block count or we'll get an enospc. If
index ab016e5ae7be1567e6782bb17725e8b52c501ed8..3120a3a5e20f90a07186e9258d3767f315678be5 100644 (file)
@@ -230,7 +230,7 @@ xfs_ialloc_ag_alloc(
                args.minalignslop = xfs_ialloc_cluster_alignment(&args) - 1;
 
                /* Allow space for the inode btree to split. */
-               args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
+               args.minleft = args.mp->m_in_maxlevels - 1;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        } else
@@ -270,7 +270,7 @@ xfs_ialloc_ag_alloc(
                /*
                 * Allow space for the inode btree to split.
                 */
-               args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
+               args.minleft = args.mp->m_in_maxlevels - 1;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
@@ -349,7 +349,7 @@ xfs_ialloc_ag_alloc(
                 * Initialize all inodes in this buffer and then log them.
                 *
                 * XXX: It would be much better if we had just one transaction to
-                *      log a whole cluster of inodes instead of all the indivdual
+                *      log a whole cluster of inodes instead of all the individual
                 *      transactions causing a lot of log traffic.
                 */
                xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog);
@@ -943,7 +943,7 @@ nextag:
        ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
                                   XFS_INODES_PER_CHUNK) == 0);
        ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
-       XFS_INOBT_CLR_FREE(&rec, offset);
+       rec.ir_free &= ~XFS_INOBT_MASK(offset);
        rec.ir_freecount--;
        if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount,
                        rec.ir_free)))
@@ -1105,11 +1105,11 @@ xfs_difree(
         */
        off = agino - rec.ir_startino;
        ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK);
-       ASSERT(!XFS_INOBT_IS_FREE(&rec, off));
+       ASSERT(!(rec.ir_free & XFS_INOBT_MASK(off)));
        /*
         * Mark the inode free & increment the count.
         */
-       XFS_INOBT_SET_FREE(&rec, off);
+       rec.ir_free |= XFS_INOBT_MASK(off);
        rec.ir_freecount++;
 
        /*
index 99f2408e8d8e634ac446914a505982bba3d48deb..c282a9af5393da36022e471332dc45d37705bcbb 100644 (file)
@@ -164,7 +164,7 @@ xfs_inobt_init_rec_from_cur(
 }
 
 /*
- * intial value of ptr for lookup
+ * initial value of ptr for lookup
  */
 STATIC void
 xfs_inobt_init_ptr_from_cur(
index 5580e255ff06637e6b979f6671c21f3dd90d8029..f782ad0c4769483ae23ab25dade35ee737ea4c63 100644 (file)
@@ -32,14 +32,14 @@ struct xfs_mount;
 #define        XFS_IBT_MAGIC   0x49414254      /* 'IABT' */
 
 typedef        __uint64_t      xfs_inofree_t;
-#define        XFS_INODES_PER_CHUNK    (NBBY * sizeof(xfs_inofree_t))
+#define        XFS_INODES_PER_CHUNK            (NBBY * sizeof(xfs_inofree_t))
 #define        XFS_INODES_PER_CHUNK_LOG        (XFS_NBBYLOG + 3)
-#define        XFS_INOBT_ALL_FREE      ((xfs_inofree_t)-1)
+#define        XFS_INOBT_ALL_FREE              ((xfs_inofree_t)-1)
+#define        XFS_INOBT_MASK(i)               ((xfs_inofree_t)1 << (i))
 
 static inline xfs_inofree_t xfs_inobt_maskn(int i, int n)
 {
-       return (((n) >= XFS_INODES_PER_CHUNK ? \
-               (xfs_inofree_t)0 : ((xfs_inofree_t)1 << (n))) - 1) << (i);
+       return ((n >= XFS_INODES_PER_CHUNK ? 0 : XFS_INOBT_MASK(n)) - 1) << i;
 }
 
 /*
@@ -68,20 +68,6 @@ typedef struct xfs_inobt_key {
 /* btree pointer type */
 typedef __be32 xfs_inobt_ptr_t;
 
-/*
- * Bit manipulations for ir_free.
- */
-#define        XFS_INOBT_MASK(i)               ((xfs_inofree_t)1 << (i))
-#define        XFS_INOBT_IS_FREE(rp,i)         \
-               (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0)
-#define        XFS_INOBT_SET_FREE(rp,i)        ((rp)->ir_free |= XFS_INOBT_MASK(i))
-#define        XFS_INOBT_CLR_FREE(rp,i)        ((rp)->ir_free &= ~XFS_INOBT_MASK(i))
-
-/*
- * Maximum number of inode btree levels.
- */
-#define        XFS_IN_MAXLEVELS(mp)            ((mp)->m_in_maxlevels)
-
 /*
  * block numbers in the AG.
  */
index 1f175fa34b225df1da087a6fceadb201205fcbe8..f879c1bc4b96deba7ec1c42fb8bc9fcfd0109a1d 100644 (file)
@@ -122,7 +122,7 @@ typedef struct xfs_ictimestamp {
 
 /*
  * NOTE:  This structure must be kept identical to struct xfs_dinode
- *       in xfs_dinode.h except for the endianess annotations.
+ *       in xfs_dinode.h except for the endianness annotations.
  */
 typedef struct xfs_icdinode {
        __uint16_t      di_magic;       /* inode magic # = XFS_DINODE_MAGIC */
index 9957d0602d549d4688e0087d8fd4223cadaae402..a52ac125f0556a61c81fd2f375056b735740113f 100644 (file)
@@ -40,7 +40,6 @@ typedef struct xfs_inode_log_format {
        __int32_t               ilf_boffset;    /* off of inode in buffer */
 } xfs_inode_log_format_t;
 
-#ifndef HAVE_FORMAT32
 typedef struct xfs_inode_log_format_32 {
        __uint16_t              ilf_type;       /* inode log item type */
        __uint16_t              ilf_size;       /* size of this item */
@@ -56,7 +55,6 @@ typedef struct xfs_inode_log_format_32 {
        __int32_t               ilf_len;        /* len of inode buffer */
        __int32_t               ilf_boffset;    /* off of inode in buffer */
 } __attribute__((packed)) xfs_inode_log_format_32_t;
-#endif
 
 typedef struct xfs_inode_log_format_64 {
        __uint16_t              ilf_type;       /* inode log item type */
index ee1a0c134cc274479a8da663bca33f1e9745d38f..a1cc1322fc0f2123a1526dc00391689348488643 100644 (file)
@@ -63,7 +63,7 @@ typedef enum {
  */
 
 typedef struct xfs_iomap {
-       xfs_daddr_t             iomap_bn;       /* first 512b blk of mapping */
+       xfs_daddr_t             iomap_bn;       /* first 512B blk of mapping */
        xfs_buftarg_t           *iomap_target;
        xfs_off_t               iomap_offset;   /* offset of mapping, bytes */
        xfs_off_t               iomap_bsize;    /* size of mapping, bytes */
index cf98a805ec90308651303af993572dd75c0827a0..aeb2d2221c7ddb15b8e4efdae36ee94f40b7fbe3 100644 (file)
@@ -83,7 +83,12 @@ xfs_bulkstat_one_iget(
        buf->bs_uid = dic->di_uid;
        buf->bs_gid = dic->di_gid;
        buf->bs_size = dic->di_size;
-       vn_atime_to_bstime(VFS_I(ip), &buf->bs_atime);
+       /*
+        * We are reading the atime from the Linux inode because the
+        * dinode might not be uptodate.
+        */
+       buf->bs_atime.tv_sec = VFS_I(ip)->i_atime.tv_sec;
+       buf->bs_atime.tv_nsec = VFS_I(ip)->i_atime.tv_nsec;
        buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;
        buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;
        buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;
@@ -579,7 +584,7 @@ xfs_bulkstat(
                                 * first inode of the cluster.
                                 *
                                 * Careful with clustidx.   There can be
-                                * multple clusters per chunk, a single
+                                * multiple clusters per chunk, a single
                                 * cluster per chunk or a cluster that has
                                 * inodes represented from several different
                                 * chunks (if blocksize is large).
index f4726f702a9ea51e84ba08622c7f322dffab3a7c..f76c6d7cea21f9539b9ad21562d943c39c937fc7 100644 (file)
@@ -574,7 +574,7 @@ xfs_log_mount(
        error = xfs_trans_ail_init(mp);
        if (error) {
                cmn_err(CE_WARN, "XFS: AIL initialisation failed: error %d", error);
-               goto error;
+               goto out_free_log;
        }
        mp->m_log->l_ailp = mp->m_ail;
 
@@ -594,20 +594,22 @@ xfs_log_mount(
                        mp->m_flags |= XFS_MOUNT_RDONLY;
                if (error) {
                        cmn_err(CE_WARN, "XFS: log mount/recovery failed: error %d", error);
-                       goto error;
+                       goto out_destroy_ail;
                }
        }
 
        /* Normal transactions can now occur */
        mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY;
 
-       /* End mounting message in xfs_log_mount_finish */
        return 0;
-error:
-       xfs_log_unmount_dealloc(mp);
+
+out_destroy_ail:
+       xfs_trans_ail_destroy(mp);
+out_free_log:
+       xlog_dealloc_log(mp->m_log);
 out:
        return error;
-}      /* xfs_log_mount */
+}
 
 /*
  * Finish the recovery of the file system.  This is separate from
@@ -632,19 +634,6 @@ xfs_log_mount_finish(xfs_mount_t *mp)
        return error;
 }
 
-/*
- * Unmount processing for the log.
- */
-int
-xfs_log_unmount(xfs_mount_t *mp)
-{
-       int             error;
-
-       error = xfs_log_unmount_write(mp);
-       xfs_log_unmount_dealloc(mp);
-       return error;
-}
-
 /*
  * Final log writes as part of unmount.
  *
@@ -795,7 +784,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
  * and deallocate the log as the aild references the log.
  */
 void
-xfs_log_unmount_dealloc(xfs_mount_t *mp)
+xfs_log_unmount(xfs_mount_t *mp)
 {
        xfs_trans_ail_destroy(mp);
        xlog_dealloc_log(mp->m_log);
@@ -1109,7 +1098,7 @@ xlog_bdstrat_cb(struct xfs_buf *bp)
 /*
  * Return size of each in-core log record buffer.
  *
- * All machines get 8 x 32KB buffers by default, unless tuned otherwise.
+ * All machines get 8 x 32kB buffers by default, unless tuned otherwise.
  *
  * If the filesystem blocksize is too large, we may need to choose a
  * larger size since the directory code currently logs entire blocks.
@@ -1139,8 +1128,8 @@ xlog_get_iclog_buffer_size(xfs_mount_t    *mp,
                }
 
                if (xfs_sb_version_haslogv2(&mp->m_sb)) {
-                       /* # headers = size / 32K
-                        * one header holds cycles from 32K of data
+                       /* # headers = size / 32k
+                        * one header holds cycles from 32k of data
                         */
 
                        xhdrs = mp->m_logbsize / XLOG_HEADER_CYCLE_SIZE;
@@ -1156,7 +1145,7 @@ xlog_get_iclog_buffer_size(xfs_mount_t    *mp,
                goto done;
        }
 
-       /* All machines use 32KB buffers by default. */
+       /* All machines use 32kB buffers by default. */
        log->l_iclog_size = XLOG_BIG_RECORD_BSIZE;
        log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT;
 
@@ -1164,32 +1153,8 @@ xlog_get_iclog_buffer_size(xfs_mount_t   *mp,
        log->l_iclog_hsize = BBSIZE;
        log->l_iclog_heads = 1;
 
-       /*
-        * For 16KB, we use 3 32KB buffers.  For 32KB block sizes, we use
-        * 4 32KB buffers.  For 64KB block sizes, we use 8 32KB buffers.
-        */
-       if (mp->m_sb.sb_blocksize >= 16*1024) {
-               log->l_iclog_size = XLOG_BIG_RECORD_BSIZE;
-               log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT;
-               if (mp->m_logbufs <= 0) {
-                       switch (mp->m_sb.sb_blocksize) {
-                           case 16*1024:                       /* 16 KB */
-                               log->l_iclog_bufs = 3;
-                               break;
-                           case 32*1024:                       /* 32 KB */
-                               log->l_iclog_bufs = 4;
-                               break;
-                           case 64*1024:                       /* 64 KB */
-                               log->l_iclog_bufs = 8;
-                               break;
-                           default:
-                               xlog_panic("XFS: Invalid blocksize");
-                               break;
-                       }
-               }
-       }
-
-done:  /* are we being asked to make the sizes selected above visible? */
+done:
+       /* are we being asked to make the sizes selected above visible? */
        if (mp->m_logbufs == 0)
                mp->m_logbufs = log->l_iclog_bufs;
        if (mp->m_logbsize == 0)
@@ -3214,7 +3179,7 @@ xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog)
  */
 
 /*
- * Free a used ticket when it's refcount falls to zero.
+ * Free a used ticket when its refcount falls to zero.
  */
 void
 xfs_log_ticket_put(
index 8a3e84e900a34e5153a453eae896bb795576a57b..d0c9baa50b1adec129a74586558595672577c536 100644 (file)
@@ -170,9 +170,8 @@ int   xfs_log_write(struct xfs_mount *mp,
                        int              nentries,
                        xfs_log_ticket_t ticket,
                        xfs_lsn_t        *start_lsn);
-int      xfs_log_unmount(struct xfs_mount *mp);
 int      xfs_log_unmount_write(struct xfs_mount *mp);
-void      xfs_log_unmount_dealloc(struct xfs_mount *mp);
+void      xfs_log_unmount(struct xfs_mount *mp);
 int      xfs_log_force_umount(struct xfs_mount *mp, int logerror);
 int      xfs_log_need_covered(struct xfs_mount *mp);
 
index 654167be0efb6c29aa4288f6ee44bd4627753cef..bcad5f4c1fd1b3f0c31fc7c0bcb848c12aaa21ee 100644 (file)
@@ -359,7 +359,7 @@ typedef struct xlog_in_core {
        int                     ic_size;
        int                     ic_offset;
        int                     ic_bwritecnt;
-       ushort_t                ic_state;
+       unsigned short          ic_state;
        char                    *ic_datap;      /* pointer to iclog data */
 #ifdef XFS_LOG_TRACE
        struct ktrace           *ic_trace;
@@ -455,7 +455,6 @@ extern void  xlog_recover_process_iunlinks(xlog_t *log);
 
 extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
 extern void     xlog_put_bp(struct xfs_buf *);
-extern int      xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
 
 extern kmem_zone_t     *xfs_log_ticket_zone;
 
index 61af610d79b395248aeb10b0dac0225d15c388af..7ba450116d4ffc97f247c99a8a89f190bf5a89f2 100644 (file)
@@ -94,12 +94,30 @@ xlog_put_bp(
        xfs_buf_free(bp);
 }
 
+STATIC xfs_caddr_t
+xlog_align(
+       xlog_t          *log,
+       xfs_daddr_t     blk_no,
+       int             nbblks,
+       xfs_buf_t       *bp)
+{
+       xfs_caddr_t     ptr;
+
+       if (!log->l_sectbb_log)
+               return XFS_BUF_PTR(bp);
+
+       ptr = XFS_BUF_PTR(bp) + BBTOB((int)blk_no & log->l_sectbb_mask);
+       ASSERT(XFS_BUF_SIZE(bp) >=
+               BBTOB(nbblks + (blk_no & log->l_sectbb_mask)));
+       return ptr;
+}
+
 
 /*
  * nbblks should be uint, but oh well.  Just want to catch that 32-bit length.
  */
-int
-xlog_bread(
+STATIC int
+xlog_bread_noalign(
        xlog_t          *log,
        xfs_daddr_t     blk_no,
        int             nbblks,
@@ -137,6 +155,24 @@ xlog_bread(
        return error;
 }
 
+STATIC int
+xlog_bread(
+       xlog_t          *log,
+       xfs_daddr_t     blk_no,
+       int             nbblks,
+       xfs_buf_t       *bp,
+       xfs_caddr_t     *offset)
+{
+       int             error;
+
+       error = xlog_bread_noalign(log, blk_no, nbblks, bp);
+       if (error)
+               return error;
+
+       *offset = xlog_align(log, blk_no, nbblks, bp);
+       return 0;
+}
+
 /*
  * Write out the buffer at the given block for the given number of blocks.
  * The buffer is kept locked across the write and is returned locked.
@@ -180,24 +216,6 @@ xlog_bwrite(
        return error;
 }
 
-STATIC xfs_caddr_t
-xlog_align(
-       xlog_t          *log,
-       xfs_daddr_t     blk_no,
-       int             nbblks,
-       xfs_buf_t       *bp)
-{
-       xfs_caddr_t     ptr;
-
-       if (!log->l_sectbb_log)
-               return XFS_BUF_PTR(bp);
-
-       ptr = XFS_BUF_PTR(bp) + BBTOB((int)blk_no & log->l_sectbb_mask);
-       ASSERT(XFS_BUF_SIZE(bp) >=
-               BBTOB(nbblks + (blk_no & log->l_sectbb_mask)));
-       return ptr;
-}
-
 #ifdef DEBUG
 /*
  * dump debug superblock and log record information
@@ -211,11 +229,11 @@ xlog_header_check_dump(
 
        cmn_err(CE_DEBUG, "%s:  SB : uuid = ", __func__);
        for (b = 0; b < 16; b++)
-               cmn_err(CE_DEBUG, "%02x", ((uchar_t *)&mp->m_sb.sb_uuid)[b]);
+               cmn_err(CE_DEBUG, "%02x", ((__uint8_t *)&mp->m_sb.sb_uuid)[b]);
        cmn_err(CE_DEBUG, ", fmt = %d\n", XLOG_FMT);
        cmn_err(CE_DEBUG, "    log : uuid = ");
        for (b = 0; b < 16; b++)
-               cmn_err(CE_DEBUG, "%02x",((uchar_t *)&head->h_fs_uuid)[b]);
+               cmn_err(CE_DEBUG, "%02x", ((__uint8_t *)&head->h_fs_uuid)[b]);
        cmn_err(CE_DEBUG, ", fmt = %d\n", be32_to_cpu(head->h_fmt));
 }
 #else
@@ -321,9 +339,9 @@ xlog_find_cycle_start(
 
        mid_blk = BLK_AVG(first_blk, *last_blk);
        while (mid_blk != first_blk && mid_blk != *last_blk) {
-               if ((error = xlog_bread(log, mid_blk, 1, bp)))
+               error = xlog_bread(log, mid_blk, 1, bp, &offset);
+               if (error)
                        return error;
-               offset = xlog_align(log, mid_blk, 1, bp);
                mid_cycle = xlog_get_cycle(offset);
                if (mid_cycle == cycle) {
                        *last_blk = mid_blk;
@@ -379,10 +397,10 @@ xlog_find_verify_cycle(
 
                bcount = min(bufblks, (start_blk + nbblks - i));
 
-               if ((error = xlog_bread(log, i, bcount, bp)))
+               error = xlog_bread(log, i, bcount, bp, &buf);
+               if (error)
                        goto out;
 
-               buf = xlog_align(log, i, bcount, bp);
                for (j = 0; j < bcount; j++) {
                        cycle = xlog_get_cycle(buf);
                        if (cycle == stop_on_cycle_no) {
@@ -436,9 +454,9 @@ xlog_find_verify_log_record(
                        return ENOMEM;
                smallmem = 1;
        } else {
-               if ((error = xlog_bread(log, start_blk, num_blks, bp)))
+               error = xlog_bread(log, start_blk, num_blks, bp, &offset);
+               if (error)
                        goto out;
-               offset = xlog_align(log, start_blk, num_blks, bp);
                offset += ((num_blks - 1) << BBSHIFT);
        }
 
@@ -453,9 +471,9 @@ xlog_find_verify_log_record(
                }
 
                if (smallmem) {
-                       if ((error = xlog_bread(log, i, 1, bp)))
+                       error = xlog_bread(log, i, 1, bp, &offset);
+                       if (error)
                                goto out;
-                       offset = xlog_align(log, i, 1, bp);
                }
 
                head = (xlog_rec_header_t *)offset;
@@ -559,15 +577,18 @@ xlog_find_head(
        bp = xlog_get_bp(log, 1);
        if (!bp)
                return ENOMEM;
-       if ((error = xlog_bread(log, 0, 1, bp)))
+
+       error = xlog_bread(log, 0, 1, bp, &offset);
+       if (error)
                goto bp_err;
-       offset = xlog_align(log, 0, 1, bp);
+
        first_half_cycle = xlog_get_cycle(offset);
 
        last_blk = head_blk = log_bbnum - 1;    /* get cycle # of last block */
-       if ((error = xlog_bread(log, last_blk, 1, bp)))
+       error = xlog_bread(log, last_blk, 1, bp, &offset);
+       if (error)
                goto bp_err;
-       offset = xlog_align(log, last_blk, 1, bp);
+
        last_half_cycle = xlog_get_cycle(offset);
        ASSERT(last_half_cycle != 0);
 
@@ -817,9 +838,10 @@ xlog_find_tail(
        if (!bp)
                return ENOMEM;
        if (*head_blk == 0) {                           /* special case */
-               if ((error = xlog_bread(log, 0, 1, bp)))
+               error = xlog_bread(log, 0, 1, bp, &offset);
+               if (error)
                        goto bread_err;
-               offset = xlog_align(log, 0, 1, bp);
+
                if (xlog_get_cycle(offset) == 0) {
                        *tail_blk = 0;
                        /* leave all other log inited values alone */
@@ -832,9 +854,10 @@ xlog_find_tail(
         */
        ASSERT(*head_blk < INT_MAX);
        for (i = (int)(*head_blk) - 1; i >= 0; i--) {
-               if ((error = xlog_bread(log, i, 1, bp)))
+               error = xlog_bread(log, i, 1, bp, &offset);
+               if (error)
                        goto bread_err;
-               offset = xlog_align(log, i, 1, bp);
+
                if (XLOG_HEADER_MAGIC_NUM == be32_to_cpu(*(__be32 *)offset)) {
                        found = 1;
                        break;
@@ -848,9 +871,10 @@ xlog_find_tail(
         */
        if (!found) {
                for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) {
-                       if ((error = xlog_bread(log, i, 1, bp)))
+                       error = xlog_bread(log, i, 1, bp, &offset);
+                       if (error)
                                goto bread_err;
-                       offset = xlog_align(log, i, 1, bp);
+
                        if (XLOG_HEADER_MAGIC_NUM ==
                            be32_to_cpu(*(__be32 *)offset)) {
                                found = 2;
@@ -922,10 +946,10 @@ xlog_find_tail(
        if (*head_blk == after_umount_blk &&
            be32_to_cpu(rhead->h_num_logops) == 1) {
                umount_data_blk = (i + hblks) % log->l_logBBsize;
-               if ((error = xlog_bread(log, umount_data_blk, 1, bp))) {
+               error = xlog_bread(log, umount_data_blk, 1, bp, &offset);
+               if (error)
                        goto bread_err;
-               }
-               offset = xlog_align(log, umount_data_blk, 1, bp);
+
                op_head = (xlog_op_header_t *)offset;
                if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) {
                        /*
@@ -1017,9 +1041,10 @@ xlog_find_zeroed(
        bp = xlog_get_bp(log, 1);
        if (!bp)
                return ENOMEM;
-       if ((error = xlog_bread(log, 0, 1, bp)))
+       error = xlog_bread(log, 0, 1, bp, &offset);
+       if (error)
                goto bp_err;
-       offset = xlog_align(log, 0, 1, bp);
+
        first_cycle = xlog_get_cycle(offset);
        if (first_cycle == 0) {         /* completely zeroed log */
                *blk_no = 0;
@@ -1028,9 +1053,10 @@ xlog_find_zeroed(
        }
 
        /* check partially zeroed log */
-       if ((error = xlog_bread(log, log_bbnum-1, 1, bp)))
+       error = xlog_bread(log, log_bbnum-1, 1, bp, &offset);
+       if (error)
                goto bp_err;
-       offset = xlog_align(log, log_bbnum-1, 1, bp);
+
        last_cycle = xlog_get_cycle(offset);
        if (last_cycle != 0) {          /* log completely written to */
                xlog_put_bp(bp);
@@ -1152,10 +1178,10 @@ xlog_write_log_records(
         */
        balign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, start_block);
        if (balign != start_block) {
-               if ((error = xlog_bread(log, start_block, 1, bp))) {
-                       xlog_put_bp(bp);
-                       return error;
-               }
+               error = xlog_bread_noalign(log, start_block, 1, bp);
+               if (error)
+                       goto out_put_bp;
+
                j = start_block - balign;
        }
 
@@ -1175,10 +1201,14 @@ xlog_write_log_records(
                        balign = BBTOB(ealign - start_block);
                        error = XFS_BUF_SET_PTR(bp, offset + balign,
                                                BBTOB(sectbb));
-                       if (!error)
-                               error = xlog_bread(log, ealign, sectbb, bp);
-                       if (!error)
-                               error = XFS_BUF_SET_PTR(bp, offset, bufblks);
+                       if (error)
+                               break;
+
+                       error = xlog_bread_noalign(log, ealign, sectbb, bp);
+                       if (error)
+                               break;
+
+                       error = XFS_BUF_SET_PTR(bp, offset, bufblks);
                        if (error)
                                break;
                }
@@ -1195,6 +1225,8 @@ xlog_write_log_records(
                start_block += endcount;
                j = 0;
        }
+
+ out_put_bp:
        xlog_put_bp(bp);
        return error;
 }
@@ -2511,16 +2543,10 @@ xlog_recover_do_inode_trans(
        }
 
 write_inode_buffer:
-       if (ITEM_TYPE(item) == XFS_LI_INODE) {
-               ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
-               bp->b_mount = mp;
-               XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
-               xfs_bdwrite(mp, bp);
-       } else {
-               XFS_BUF_STALE(bp);
-               error = xfs_bwrite(mp, bp);
-       }
-
+       ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
+       bp->b_mount = mp;
+       XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
+       xfs_bdwrite(mp, bp);
 error:
        if (need_free)
                kmem_free(in_f);
@@ -2769,51 +2795,48 @@ xlog_recover_do_trans(
        int                     error = 0;
        xlog_recover_item_t     *item, *first_item;
 
-       if ((error = xlog_recover_reorder_trans(trans)))
+       error = xlog_recover_reorder_trans(trans);
+       if (error)
                return error;
+
        first_item = item = trans->r_itemq;
        do {
-               /*
-                * we don't need to worry about the block number being
-                * truncated in > 1 TB buffers because in user-land,
-                * we're now n32 or 64-bit so xfs_daddr_t is 64-bits so
-                * the blknos will get through the user-mode buffer
-                * cache properly.  The only bad case is o32 kernels
-                * where xfs_daddr_t is 32-bits but mount will warn us
-                * off a > 1 TB filesystem before we get here.
-                */
-               if ((ITEM_TYPE(item) == XFS_LI_BUF)) {
-                       if  ((error = xlog_recover_do_buffer_trans(log, item,
-                                                                pass)))
-                               break;
-               } else if ((ITEM_TYPE(item) == XFS_LI_INODE)) {
-                       if ((error = xlog_recover_do_inode_trans(log, item,
-                                                               pass)))
-                               break;
-               } else if (ITEM_TYPE(item) == XFS_LI_EFI) {
-                       if ((error = xlog_recover_do_efi_trans(log, item, trans->r_lsn,
-                                                 pass)))
-                               break;
-               } else if (ITEM_TYPE(item) == XFS_LI_EFD) {
+               switch (ITEM_TYPE(item)) {
+               case XFS_LI_BUF:
+                       error = xlog_recover_do_buffer_trans(log, item, pass);
+                       break;
+               case XFS_LI_INODE:
+                       error = xlog_recover_do_inode_trans(log, item, pass);
+                       break;
+               case XFS_LI_EFI:
+                       error = xlog_recover_do_efi_trans(log, item,
+                                                         trans->r_lsn, pass);
+                       break;
+               case XFS_LI_EFD:
                        xlog_recover_do_efd_trans(log, item, pass);
-               } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) {
-                       if ((error = xlog_recover_do_dquot_trans(log, item,
-                                                                  pass)))
-                                       break;
-               } else if ((ITEM_TYPE(item) == XFS_LI_QUOTAOFF)) {
-                       if ((error = xlog_recover_do_quotaoff_trans(log, item,
-                                                                  pass)))
-                                       break;
-               } else {
-                       xlog_warn("XFS: xlog_recover_do_trans");
+                       error = 0;
+                       break;
+               case XFS_LI_DQUOT:
+                       error = xlog_recover_do_dquot_trans(log, item, pass);
+                       break;
+               case XFS_LI_QUOTAOFF:
+                       error = xlog_recover_do_quotaoff_trans(log, item,
+                                                              pass);
+                       break;
+               default:
+                       xlog_warn(
+       "XFS: invalid item type (%d) xlog_recover_do_trans", ITEM_TYPE(item));
                        ASSERT(0);
                        error = XFS_ERROR(EIO);
                        break;
                }
+
+               if (error)
+                       return error;
                item = item->ri_next;
        } while (first_item != item);
 
-       return error;
+       return 0;
 }
 
 /*
@@ -3490,9 +3513,11 @@ xlog_do_recovery_pass(
                hbp = xlog_get_bp(log, 1);
                if (!hbp)
                        return ENOMEM;
-               if ((error = xlog_bread(log, tail_blk, 1, hbp)))
+
+               error = xlog_bread(log, tail_blk, 1, hbp, &offset);
+               if (error)
                        goto bread_err1;
-               offset = xlog_align(log, tail_blk, 1, hbp);
+
                rhead = (xlog_rec_header_t *)offset;
                error = xlog_valid_rec_header(log, rhead, tail_blk);
                if (error)
@@ -3526,9 +3551,10 @@ xlog_do_recovery_pass(
        memset(rhash, 0, sizeof(rhash));
        if (tail_blk <= head_blk) {
                for (blk_no = tail_blk; blk_no < head_blk; ) {
-                       if ((error = xlog_bread(log, blk_no, hblks, hbp)))
+                       error = xlog_bread(log, blk_no, hblks, hbp, &offset);
+                       if (error)
                                goto bread_err2;
-                       offset = xlog_align(log, blk_no, hblks, hbp);
+
                        rhead = (xlog_rec_header_t *)offset;
                        error = xlog_valid_rec_header(log, rhead, blk_no);
                        if (error)
@@ -3536,10 +3562,11 @@ xlog_do_recovery_pass(
 
                        /* blocks in data section */
                        bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
-                       error = xlog_bread(log, blk_no + hblks, bblks, dbp);
+                       error = xlog_bread(log, blk_no + hblks, bblks, dbp,
+                                          &offset);
                        if (error)
                                goto bread_err2;
-                       offset = xlog_align(log, blk_no + hblks, bblks, dbp);
+
                        xlog_unpack_data(rhead, offset, log);
                        if ((error = xlog_recover_process_data(log,
                                                rhash, rhead, offset, pass)))
@@ -3562,10 +3589,10 @@ xlog_do_recovery_pass(
                        wrapped_hblks = 0;
                        if (blk_no + hblks <= log->l_logBBsize) {
                                /* Read header in one read */
-                               error = xlog_bread(log, blk_no, hblks, hbp);
+                               error = xlog_bread(log, blk_no, hblks, hbp,
+                                                  &offset);
                                if (error)
                                        goto bread_err2;
-                               offset = xlog_align(log, blk_no, hblks, hbp);
                        } else {
                                /* This LR is split across physical log end */
                                if (blk_no != log->l_logBBsize) {
@@ -3573,12 +3600,13 @@ xlog_do_recovery_pass(
                                        ASSERT(blk_no <= INT_MAX);
                                        split_hblks = log->l_logBBsize - (int)blk_no;
                                        ASSERT(split_hblks > 0);
-                                       if ((error = xlog_bread(log, blk_no,
-                                                       split_hblks, hbp)))
+                                       error = xlog_bread(log, blk_no,
+                                                          split_hblks, hbp,
+                                                          &offset);
+                                       if (error)
                                                goto bread_err2;
-                                       offset = xlog_align(log, blk_no,
-                                                       split_hblks, hbp);
                                }
+
                                /*
                                 * Note: this black magic still works with
                                 * large sector sizes (non-512) only because:
@@ -3596,14 +3624,19 @@ xlog_do_recovery_pass(
                                error = XFS_BUF_SET_PTR(hbp,
                                                bufaddr + BBTOB(split_hblks),
                                                BBTOB(hblks - split_hblks));
-                               if (!error)
-                                       error = xlog_bread(log, 0,
-                                                       wrapped_hblks, hbp);
-                               if (!error)
-                                       error = XFS_BUF_SET_PTR(hbp, bufaddr,
+                               if (error)
+                                       goto bread_err2;
+
+                               error = xlog_bread_noalign(log, 0,
+                                                          wrapped_hblks, hbp);
+                               if (error)
+                                       goto bread_err2;
+
+                               error = XFS_BUF_SET_PTR(hbp, bufaddr,
                                                        BBTOB(hblks));
                                if (error)
                                        goto bread_err2;
+
                                if (!offset)
                                        offset = xlog_align(log, 0,
                                                        wrapped_hblks, hbp);
@@ -3619,10 +3652,10 @@ xlog_do_recovery_pass(
 
                        /* Read in data for log record */
                        if (blk_no + bblks <= log->l_logBBsize) {
-                               error = xlog_bread(log, blk_no, bblks, dbp);
+                               error = xlog_bread(log, blk_no, bblks, dbp,
+                                                  &offset);
                                if (error)
                                        goto bread_err2;
-                               offset = xlog_align(log, blk_no, bblks, dbp);
                        } else {
                                /* This log record is split across the
                                 * physical end of log */
@@ -3636,12 +3669,13 @@ xlog_do_recovery_pass(
                                        split_bblks =
                                                log->l_logBBsize - (int)blk_no;
                                        ASSERT(split_bblks > 0);
-                                       if ((error = xlog_bread(log, blk_no,
-                                                       split_bblks, dbp)))
+                                       error = xlog_bread(log, blk_no,
+                                                       split_bblks, dbp,
+                                                       &offset);
+                                       if (error)
                                                goto bread_err2;
-                                       offset = xlog_align(log, blk_no,
-                                                       split_bblks, dbp);
                                }
+
                                /*
                                 * Note: this black magic still works with
                                 * large sector sizes (non-512) only because:
@@ -3658,15 +3692,19 @@ xlog_do_recovery_pass(
                                error = XFS_BUF_SET_PTR(dbp,
                                                bufaddr + BBTOB(split_bblks),
                                                BBTOB(bblks - split_bblks));
-                               if (!error)
-                                       error = xlog_bread(log, wrapped_hblks,
-                                                       bblks - split_bblks,
-                                                       dbp);
-                               if (!error)
-                                       error = XFS_BUF_SET_PTR(dbp, bufaddr,
-                                                       h_size);
                                if (error)
                                        goto bread_err2;
+
+                               error = xlog_bread_noalign(log, wrapped_hblks,
+                                               bblks - split_bblks,
+                                               dbp);
+                               if (error)
+                                       goto bread_err2;
+
+                               error = XFS_BUF_SET_PTR(dbp, bufaddr, h_size);
+                               if (error)
+                                       goto bread_err2;
+
                                if (!offset)
                                        offset = xlog_align(log, wrapped_hblks,
                                                bblks - split_bblks, dbp);
@@ -3683,17 +3721,21 @@ xlog_do_recovery_pass(
 
                /* read first part of physical log */
                while (blk_no < head_blk) {
-                       if ((error = xlog_bread(log, blk_no, hblks, hbp)))
+                       error = xlog_bread(log, blk_no, hblks, hbp, &offset);
+                       if (error)
                                goto bread_err2;
-                       offset = xlog_align(log, blk_no, hblks, hbp);
+
                        rhead = (xlog_rec_header_t *)offset;
                        error = xlog_valid_rec_header(log, rhead, blk_no);
                        if (error)
                                goto bread_err2;
+
                        bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
-                       if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp)))
+                       error = xlog_bread(log, blk_no+hblks, bblks, dbp,
+                                          &offset);
+                       if (error)
                                goto bread_err2;
-                       offset = xlog_align(log, blk_no+hblks, bblks, dbp);
+
                        xlog_unpack_data(rhead, offset, log);
                        if ((error = xlog_recover_process_data(log, rhash,
                                                        rhead, offset, pass)))
index 35300250e86d55fa2d44c7b3b15173fd8aa93767..b101990df027120632ff4f486713bc9783e32f31 100644 (file)
@@ -45,7 +45,6 @@
 #include "xfs_fsops.h"
 #include "xfs_utils.h"
 
-STATIC int     xfs_uuid_mount(xfs_mount_t *);
 STATIC void    xfs_unmountfs_wait(xfs_mount_t *);
 
 
@@ -121,6 +120,84 @@ static const struct {
     { sizeof(xfs_sb_t),                         0 }
 };
 
+static DEFINE_MUTEX(xfs_uuid_table_mutex);
+static int xfs_uuid_table_size;
+static uuid_t *xfs_uuid_table;
+
+/*
+ * See if the UUID is unique among mounted XFS filesystems.
+ * Mount fails if UUID is nil or a FS with the same UUID is already mounted.
+ */
+STATIC int
+xfs_uuid_mount(
+       struct xfs_mount        *mp)
+{
+       uuid_t                  *uuid = &mp->m_sb.sb_uuid;
+       int                     hole, i;
+
+       if (mp->m_flags & XFS_MOUNT_NOUUID)
+               return 0;
+
+       if (uuid_is_nil(uuid)) {
+               cmn_err(CE_WARN,
+                       "XFS: Filesystem %s has nil UUID - can't mount",
+                       mp->m_fsname);
+               return XFS_ERROR(EINVAL);
+       }
+
+       mutex_lock(&xfs_uuid_table_mutex);
+       for (i = 0, hole = -1; i < xfs_uuid_table_size; i++) {
+               if (uuid_is_nil(&xfs_uuid_table[i])) {
+                       hole = i;
+                       continue;
+               }
+               if (uuid_equal(uuid, &xfs_uuid_table[i]))
+                       goto out_duplicate;
+       }
+
+       if (hole < 0) {
+               xfs_uuid_table = kmem_realloc(xfs_uuid_table,
+                       (xfs_uuid_table_size + 1) * sizeof(*xfs_uuid_table),
+                       xfs_uuid_table_size  * sizeof(*xfs_uuid_table),
+                       KM_SLEEP);
+               hole = xfs_uuid_table_size++;
+       }
+       xfs_uuid_table[hole] = *uuid;
+       mutex_unlock(&xfs_uuid_table_mutex);
+
+       return 0;
+
+ out_duplicate:
+       mutex_unlock(&xfs_uuid_table_mutex);
+       cmn_err(CE_WARN, "XFS: Filesystem %s has duplicate UUID - can't mount",
+                        mp->m_fsname);
+       return XFS_ERROR(EINVAL);
+}
+
+STATIC void
+xfs_uuid_unmount(
+       struct xfs_mount        *mp)
+{
+       uuid_t                  *uuid = &mp->m_sb.sb_uuid;
+       int                     i;
+
+       if (mp->m_flags & XFS_MOUNT_NOUUID)
+               return;
+
+       mutex_lock(&xfs_uuid_table_mutex);
+       for (i = 0; i < xfs_uuid_table_size; i++) {
+               if (uuid_is_nil(&xfs_uuid_table[i]))
+                       continue;
+               if (!uuid_equal(uuid, &xfs_uuid_table[i]))
+                       continue;
+               memset(&xfs_uuid_table[i], 0, sizeof(uuid_t));
+               break;
+       }
+       ASSERT(i < xfs_uuid_table_size);
+       mutex_unlock(&xfs_uuid_table_mutex);
+}
+
+
 /*
  * Free up the resources associated with a mount structure.  Assume that
  * the structure was initially zeroed, so we can tell which fields got
@@ -256,6 +333,22 @@ xfs_mount_validate_sb(
                return XFS_ERROR(ENOSYS);
        }
 
+       /*
+        * Currently only very few inode sizes are supported.
+        */
+       switch (sbp->sb_inodesize) {
+       case 256:
+       case 512:
+       case 1024:
+       case 2048:
+               break;
+       default:
+               xfs_fs_mount_cmn_err(flags,
+                       "inode size of %d bytes not supported",
+                       sbp->sb_inodesize);
+               return XFS_ERROR(ENOSYS);
+       }
+
        if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
            xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
                xfs_fs_mount_cmn_err(flags,
@@ -574,32 +667,10 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
        mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
        mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;
        mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
-       mp->m_litino = sbp->sb_inodesize - sizeof(struct xfs_dinode);
        mp->m_blockmask = sbp->sb_blocksize - 1;
        mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
        mp->m_blockwmask = mp->m_blockwsize - 1;
 
-       /*
-        * Setup for attributes, in case they get created.
-        * This value is for inodes getting attributes for the first time,
-        * the per-inode value is for old attribute values.
-        */
-       ASSERT(sbp->sb_inodesize >= 256 && sbp->sb_inodesize <= 2048);
-       switch (sbp->sb_inodesize) {
-       case 256:
-               mp->m_attroffset = XFS_LITINO(mp) -
-                                  XFS_BMDR_SPACE_CALC(MINABTPTRS);
-               break;
-       case 512:
-       case 1024:
-       case 2048:
-               mp->m_attroffset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS);
-               break;
-       default:
-               ASSERT(0);
-       }
-       ASSERT(mp->m_attroffset < XFS_LITINO(mp));
-
        mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
        mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
        mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
@@ -645,7 +716,7 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
        for (index = 0; index < agcount; index++) {
                /*
                 * read the agf, then the agi. This gets us
-                * all the inforamtion we need and populates the
+                * all the information we need and populates the
                 * per-ag structures for us.
                 */
                error = xfs_alloc_pagf_init(mp, NULL, index, 0);
@@ -886,8 +957,6 @@ xfs_check_sizes(xfs_mount_t *mp)
 }
 
 /*
- * xfs_mountfs
- *
  * This function does the following on an initial mount of a file system:
  *     - reads the superblock from disk and init the mount struct
  *     - if we're a 32-bit kernel, do a size check on the superblock
@@ -905,7 +974,6 @@ xfs_mountfs(
        xfs_inode_t     *rip;
        __uint64_t      resblks;
        uint            quotamount, quotaflags;
-       int             uuid_mounted = 0;
        int             error = 0;
 
        xfs_mount_common(mp, sbp);
@@ -960,7 +1028,7 @@ xfs_mountfs(
         */
        error = xfs_update_alignment(mp);
        if (error)
-               goto error1;
+               goto out;
 
        xfs_alloc_compute_maxlevels(mp);
        xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK);
@@ -971,19 +1039,9 @@ xfs_mountfs(
 
        mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog);
 
-       /*
-        * XFS uses the uuid from the superblock as the unique
-        * identifier for fsid.  We can not use the uuid from the volume
-        * since a single partition filesystem is identical to a single
-        * partition volume/filesystem.
-        */
-       if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
-               if (xfs_uuid_mount(mp)) {
-                       error = XFS_ERROR(EINVAL);
-                       goto error1;
-               }
-               uuid_mounted=1;
-       }
+       error = xfs_uuid_mount(mp);
+       if (error)
+               goto out;
 
        /*
         * Set the minimum read and write sizes
@@ -1007,7 +1065,7 @@ xfs_mountfs(
         */
        error = xfs_check_sizes(mp);
        if (error)
-               goto error1;
+               goto out_remove_uuid;
 
        /*
         * Initialize realtime fields in the mount structure
@@ -1015,7 +1073,7 @@ xfs_mountfs(
        error = xfs_rtmount_init(mp);
        if (error) {
                cmn_err(CE_WARN, "XFS: RT mount failed");
-               goto error1;
+               goto out_remove_uuid;
        }
 
        /*
@@ -1045,26 +1103,26 @@ xfs_mountfs(
        mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t),
                                  KM_MAYFAIL);
        if (!mp->m_perag)
-               goto error1;
+               goto out_remove_uuid;
 
        mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount);
 
+       if (!sbp->sb_logblocks) {
+               cmn_err(CE_WARN, "XFS: no log defined");
+               XFS_ERROR_REPORT("xfs_mountfs", XFS_ERRLEVEL_LOW, mp);
+               error = XFS_ERROR(EFSCORRUPTED);
+               goto out_free_perag;
+       }
+
        /*
         * log's mount-time initialization. Perform 1st part recovery if needed
         */
-       if (likely(sbp->sb_logblocks > 0)) {    /* check for volume case */
-               error = xfs_log_mount(mp, mp->m_logdev_targp,
-                                     XFS_FSB_TO_DADDR(mp, sbp->sb_logstart),
-                                     XFS_FSB_TO_BB(mp, sbp->sb_logblocks));
-               if (error) {
-                       cmn_err(CE_WARN, "XFS: log mount failed");
-                       goto error2;
-               }
-       } else {        /* No log has been defined */
-               cmn_err(CE_WARN, "XFS: no log defined");
-               XFS_ERROR_REPORT("xfs_mountfs_int(1)", XFS_ERRLEVEL_LOW, mp);
-               error = XFS_ERROR(EFSCORRUPTED);
-               goto error2;
+       error = xfs_log_mount(mp, mp->m_logdev_targp,
+                             XFS_FSB_TO_DADDR(mp, sbp->sb_logstart),
+                             XFS_FSB_TO_BB(mp, sbp->sb_logblocks));
+       if (error) {
+               cmn_err(CE_WARN, "XFS: log mount failed");
+               goto out_free_perag;
        }
 
        /*
@@ -1086,15 +1144,14 @@ xfs_mountfs(
         * If we are currently making the filesystem, the initialisation will
         * fail as the perag data is in an undefined state.
         */
-
        if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
            !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&
             !mp->m_sb.sb_inprogress) {
                error = xfs_initialize_perag_data(mp, sbp->sb_agcount);
-               if (error) {
-                       goto error2;
-               }
+               if (error)
+                       goto out_free_perag;
        }
+
        /*
         * Get and sanity-check the root inode.
         * Save the pointer to it in the mount structure.
@@ -1102,7 +1159,7 @@ xfs_mountfs(
        error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0);
        if (error) {
                cmn_err(CE_WARN, "XFS: failed to read root inode");
-               goto error3;
+               goto out_log_dealloc;
        }
 
        ASSERT(rip != NULL);
@@ -1116,7 +1173,7 @@ xfs_mountfs(
                XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
                                 mp);
                error = XFS_ERROR(EFSCORRUPTED);
-               goto error4;
+               goto out_rele_rip;
        }
        mp->m_rootip = rip;     /* save it */
 
@@ -1131,7 +1188,7 @@ xfs_mountfs(
                 * Free up the root inode.
                 */
                cmn_err(CE_WARN, "XFS: failed to read RT inodes");
-               goto error4;
+               goto out_rele_rip;
        }
 
        /*
@@ -1143,7 +1200,7 @@ xfs_mountfs(
                error = xfs_mount_log_sb(mp, mp->m_update_flags);
                if (error) {
                        cmn_err(CE_WARN, "XFS: failed to write sb changes");
-                       goto error4;
+                       goto out_rtunmount;
                }
        }
 
@@ -1152,7 +1209,7 @@ xfs_mountfs(
         */
        error = XFS_QM_INIT(mp, &quotamount, &quotaflags);
        if (error)
-               goto error4;
+               goto out_rtunmount;
 
        /*
         * Finish recovering the file system.  This part needed to be
@@ -1162,7 +1219,7 @@ xfs_mountfs(
        error = xfs_log_mount_finish(mp);
        if (error) {
                cmn_err(CE_WARN, "XFS: log mount finish failed");
-               goto error4;
+               goto out_rtunmount;
        }
 
        /*
@@ -1170,7 +1227,7 @@ xfs_mountfs(
         */
        error = XFS_QM_MOUNT(mp, quotamount, quotaflags);
        if (error)
-               goto error4;
+               goto out_rtunmount;
 
        /*
         * Now we are mounted, reserve a small amount of unused space for
@@ -1194,18 +1251,17 @@ xfs_mountfs(
 
        return 0;
 
- error4:
-       /*
-        * Free up the root inode.
-        */
+ out_rtunmount:
+       xfs_rtunmount_inodes(mp);
+ out_rele_rip:
        IRELE(rip);
error3:
-       xfs_log_unmount_dealloc(mp);
error2:
out_log_dealloc:
+       xfs_log_unmount(mp);
out_free_perag:
        xfs_free_perag(mp);
error1:
-       if (uuid_mounted)
-               uuid_table_remove(&mp->m_sb.sb_uuid);
out_remove_uuid:
+       xfs_uuid_unmount(mp);
+ out:
        return error;
 }
 
@@ -1226,15 +1282,12 @@ xfs_unmountfs(
         */
        XFS_QM_UNMOUNT(mp);
 
-       if (mp->m_rbmip)
-               IRELE(mp->m_rbmip);
-       if (mp->m_rsumip)
-               IRELE(mp->m_rsumip);
+       xfs_rtunmount_inodes(mp);
        IRELE(mp->m_rootip);
 
        /*
         * We can potentially deadlock here if we have an inode cluster
-        * that has been freed has it's buffer still pinned in memory because
+        * that has been freed has its buffer still pinned in memory because
         * the transaction is still sitting in a iclog. The stale inodes
         * on that buffer will have their flush locks held until the
         * transaction hits the disk and the callbacks run. the inode
@@ -1266,7 +1319,7 @@ xfs_unmountfs(
         * Unreserve any blocks we have so that when we unmount we don't account
         * the reserved free space as used. This is really only necessary for
         * lazy superblock counting because it trusts the incore superblock
-        * counters to be aboslutely correct on clean unmount.
+        * counters to be absolutely correct on clean unmount.
         *
         * We don't bother correcting this elsewhere for lazy superblock
         * counting because on mount of an unclean filesystem we reconstruct the
@@ -1288,10 +1341,9 @@ xfs_unmountfs(
                                "Freespace may not be correct on next mount.");
        xfs_unmountfs_writesb(mp);
        xfs_unmountfs_wait(mp);                 /* wait for async bufs */
-       xfs_log_unmount(mp);                    /* Done! No more fs ops. */
-
-       if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0)
-               uuid_table_remove(&mp->m_sb.sb_uuid);
+       xfs_log_unmount_write(mp);
+       xfs_log_unmount(mp);
+       xfs_uuid_unmount(mp);
 
 #if defined(DEBUG)
        xfs_errortag_clearall(mp, 0);
@@ -1792,29 +1844,6 @@ xfs_freesb(
        mp->m_sb_bp = NULL;
 }
 
-/*
- * See if the UUID is unique among mounted XFS filesystems.
- * Mount fails if UUID is nil or a FS with the same UUID is already mounted.
- */
-STATIC int
-xfs_uuid_mount(
-       xfs_mount_t     *mp)
-{
-       if (uuid_is_nil(&mp->m_sb.sb_uuid)) {
-               cmn_err(CE_WARN,
-                       "XFS: Filesystem %s has nil UUID - can't mount",
-                       mp->m_fsname);
-               return -1;
-       }
-       if (!uuid_table_insert(&mp->m_sb.sb_uuid)) {
-               cmn_err(CE_WARN,
-                       "XFS: Filesystem %s has duplicate UUID - can't mount",
-                       mp->m_fsname);
-               return -1;
-       }
-       return 0;
-}
-
 /*
  * Used to log changes to the superblock unit and width fields which could
  * be altered by the mount options, as well as any potential sb_features2
@@ -1868,7 +1897,7 @@ xfs_mount_log_sb(
  * we disable the per-cpu counter and go through the slow path.
  *
  * The slow path is the current xfs_mod_incore_sb() function.  This means that
- * when we disable a per-cpu counter, we need to drain it's resources back to
+ * when we disable a per-cpu counter, we need to drain its resources back to
  * the global superblock. We do this after disabling the counter to prevent
  * more threads from queueing up on the counter.
  *
index f5e9937f9bdb5266e2702c9c653cb7a683f09a2f..7af44adffc8f308a4b51100a25bd1f0e7dfb1465 100644 (file)
@@ -136,7 +136,6 @@ typedef int (*xfs_dqvopchownresv_t)(struct xfs_trans *, struct xfs_inode *,
                        struct xfs_dquot *, struct xfs_dquot *, uint);
 typedef void   (*xfs_dqstatvfs_t)(struct xfs_inode *, struct kstatfs *);
 typedef int    (*xfs_dqsync_t)(struct xfs_mount *, int flags);
-typedef int    (*xfs_quotactl_t)(struct xfs_mount *, int, int, xfs_caddr_t);
 
 typedef struct xfs_qmops {
        xfs_qminit_t            xfs_qminit;
@@ -154,7 +153,6 @@ typedef struct xfs_qmops {
        xfs_dqvopchownresv_t    xfs_dqvopchownresv;
        xfs_dqstatvfs_t         xfs_dqstatvfs;
        xfs_dqsync_t            xfs_dqsync;
-       xfs_quotactl_t          xfs_quotactl;
        struct xfs_dqtrxops     *xfs_dqtrxops;
 } xfs_qmops_t;
 
@@ -188,8 +186,6 @@ typedef struct xfs_qmops {
        (*(ip)->i_mount->m_qm_ops->xfs_dqstatvfs)(ip, statp)
 #define XFS_QM_DQSYNC(mp, flags) \
        (*(mp)->m_qm_ops->xfs_dqsync)(mp, flags)
-#define XFS_QM_QUOTACTL(mp, cmd, id, addr) \
-       (*(mp)->m_qm_ops->xfs_quotactl)(mp, cmd, id, addr)
 
 #ifdef HAVE_PERCPU_SB
 
@@ -273,19 +269,17 @@ typedef struct xfs_mount {
        uint                    m_inobt_mnr[2]; /* min inobt btree records */
        uint                    m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
        uint                    m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
-       uint                    m_in_maxlevels; /* XFS_IN_MAXLEVELS */
+       uint                    m_in_maxlevels; /* max inobt btree levels. */
        struct xfs_perag        *m_perag;       /* per-ag accounting info */
        struct rw_semaphore     m_peraglock;    /* lock for m_perag (pointer) */
        struct mutex            m_growlock;     /* growfs mutex */
        int                     m_fixedfsid[2]; /* unchanged for life of FS */
        uint                    m_dmevmask;     /* DMI events for this FS */
        __uint64_t              m_flags;        /* global mount flags */
-       uint                    m_attroffset;   /* inode attribute offset */
        uint                    m_dir_node_ents; /* #entries in a dir danode */
        uint                    m_attr_node_ents; /* #entries in attr danode */
        int                     m_ialloc_inos;  /* inodes in inode allocation */
        int                     m_ialloc_blks;  /* blocks in inode allocation */
-       int                     m_litino;       /* size of inode union area */
        int                     m_inoalign_mask;/* mask sb_inoalignmt if used */
        uint                    m_qflags;       /* quota status flags */
        xfs_trans_reservations_t m_reservations;/* precomputed res values */
@@ -293,9 +287,6 @@ typedef struct xfs_mount {
        __uint64_t              m_maxioffset;   /* maximum inode offset */
        __uint64_t              m_resblks;      /* total reserved blocks */
        __uint64_t              m_resblks_avail;/* available reserved blocks */
-#if XFS_BIG_INUMS
-       xfs_ino_t               m_inoadd;       /* add value for ino64_offset */
-#endif
        int                     m_dalign;       /* stripe unit */
        int                     m_swidth;       /* stripe width */
        int                     m_sinoalign;    /* stripe unit inode alignment */
@@ -337,7 +328,6 @@ typedef struct xfs_mount {
 #define XFS_MOUNT_WSYNC                (1ULL << 0)     /* for nfs - all metadata ops
                                                   must be synchronous except
                                                   for space allocations */
-#define XFS_MOUNT_INO64                (1ULL << 1)
 #define XFS_MOUNT_DMAPI                (1ULL << 2)     /* dmapi is enabled */
 #define XFS_MOUNT_WAS_CLEAN    (1ULL << 3)
 #define XFS_MOUNT_FS_SHUTDOWN  (1ULL << 4)     /* atomic stop of all filesystem
@@ -389,8 +379,8 @@ typedef struct xfs_mount {
  * Synchronous read and write sizes.  This should be
  * better for NFSv2 wsync filesystems.
  */
-#define        XFS_WSYNC_READIO_LOG    15      /* 32K */
-#define        XFS_WSYNC_WRITEIO_LOG   14      /* 16K */
+#define        XFS_WSYNC_READIO_LOG    15      /* 32k */
+#define        XFS_WSYNC_WRITEIO_LOG   14      /* 16k */
 
 /*
  * Allow large block sizes to be reported to userspace programs if the
@@ -500,9 +490,6 @@ typedef struct xfs_mod_sb {
        int64_t         msb_delta;      /* Change to make to specified field */
 } xfs_mod_sb_t;
 
-#define        XFS_MOUNT_ILOCK(mp)     mutex_lock(&((mp)->m_ilock))
-#define        XFS_MOUNT_IUNLOCK(mp)   mutex_unlock(&((mp)->m_ilock))
-
 extern int     xfs_log_sbcount(xfs_mount_t *, uint);
 extern int     xfs_mountfs(xfs_mount_t *mp);
 extern void    xfs_mountfs_check_barriers(xfs_mount_t *mp);
index 27f80581520ad2d19c138419a2e3bca42de86944..e101790ea8e795e3644b838885d8d3db700187b2 100644 (file)
@@ -126,7 +126,6 @@ static struct xfs_qmops xfs_qmcore_stub = {
        .xfs_dqvopchownresv     = (xfs_dqvopchownresv_t) fs_noerr,
        .xfs_dqstatvfs          = (xfs_dqstatvfs_t) fs_noval,
        .xfs_dqsync             = (xfs_dqsync_t) fs_noerr,
-       .xfs_quotactl           = (xfs_quotactl_t) fs_nosys,
 };
 
 int
index 48965ecaa1558589e5a1b9db4a829e9c367665e4..f5d1202dde258a85f806472e987e0f44fd9f4989 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef __XFS_QUOTA_H__
 #define __XFS_QUOTA_H__
 
+struct xfs_trans;
+
 /*
  * The ondisk form of a dquot structure.
  */
@@ -185,7 +187,6 @@ typedef struct xfs_qoff_logformat {
  * to a single function. None of these XFS_QMOPT_* flags are meant to have
  * persistent values (ie. their values can and will change between versions)
  */
-#define XFS_QMOPT_DQLOCK       0x0000001 /* dqlock */
 #define XFS_QMOPT_DQALLOC      0x0000002 /* alloc dquot ondisk if needed */
 #define XFS_QMOPT_UQUOTA       0x0000004 /* user dquot requested */
 #define XFS_QMOPT_PQUOTA       0x0000008 /* project dquot requested */
index c5bb86f3ec053e1d47cefe6ff806cf2772aa2114..385f6dceba5db357a8bf7361fc24adde3e1185a2 100644 (file)
@@ -2288,6 +2288,16 @@ xfs_rtmount_inodes(
        return 0;
 }
 
+void
+xfs_rtunmount_inodes(
+       struct xfs_mount        *mp)
+{
+       if (mp->m_rbmip)
+               IRELE(mp->m_rbmip);
+       if (mp->m_rsumip)
+               IRELE(mp->m_rsumip);
+}
+
 /*
  * Pick an extent for allocation at the start of a new realtime file.
  * Use the sequence number stored in the atime field of the bitmap inode.
index 8d8dcd215716262d5a9bdb2a46e6c7b359604769..b2d67adb6a08f4f9f801168337e0c81c4bb00d5d 100644 (file)
@@ -23,8 +23,8 @@ struct xfs_trans;
 
 /* Min and max rt extent sizes, specified in bytes */
 #define        XFS_MAX_RTEXTSIZE       (1024 * 1024 * 1024)    /* 1GB */
-#define        XFS_DFL_RTEXTSIZE       (64 * 1024)             /* 64KB */
-#define        XFS_MIN_RTEXTSIZE       (4 * 1024)              /* 4KB */
+#define        XFS_DFL_RTEXTSIZE       (64 * 1024)             /* 64kB */
+#define        XFS_MIN_RTEXTSIZE       (4 * 1024)              /* 4kB */
 
 /*
  * Constants for bit manipulations.
@@ -108,6 +108,9 @@ xfs_rtfree_extent(
 int                                    /* error */
 xfs_rtmount_init(
        struct xfs_mount        *mp);   /* file system mount structure */
+void
+xfs_rtunmount_inodes(
+       struct xfs_mount        *mp);
 
 /*
  * Get the bitmap and summary inodes into the mount structure
@@ -146,6 +149,7 @@ xfs_growfs_rt(
 # define xfs_growfs_rt(mp,in)                           (ENOSYS)
 # define xfs_rtmount_init(m)    (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
 # define xfs_rtmount_inodes(m)  (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
+# define xfs_rtunmount_inodes(m)
 #endif /* CONFIG_XFS_RT */
 
 #endif /* __KERNEL__ */
index d6fe4a88d79f0557bcdd2a46434a438debd9cb72..775249a54f6f9dc06584e6fe69617c6afa524697 100644 (file)
@@ -292,7 +292,7 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
  * In a write transaction we can allocate a maximum of 2
  * extents.  This gives:
  *    the inode getting the new extents: inode size
- *    the inode\'s bmap btree: max depth * block size
+ *    the inode's bmap btree: max depth * block size
  *    the agfs of the ags from which the extents are allocated: 2 * sector
  *    the superblock free block counter: sector size
  *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
@@ -321,7 +321,7 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
 /*
  * In truncating a file we free up to two extents at once.  We can modify:
  *    the inode being truncated: inode size
- *    the inode\'s bmap btree: (max depth + 1) * block size
+ *    the inode's bmap btree: (max depth + 1) * block size
  * And the bmap_finish transaction can free the blocks and bmap blocks:
  *    the agf for each of the ags: 4 * sector size
  *    the agfl for each of the ags: 4 * sector size
@@ -343,7 +343,7 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
          (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))) + \
          (128 * 5) + \
          XFS_ALLOCFREE_LOG_RES(mp, 1) + \
-          (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \
+          (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
            XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
 
 #define        XFS_ITRUNCATE_LOG_RES(mp)   ((mp)->m_reservations.tr_itruncate)
@@ -431,8 +431,8 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
  *    the new inode: inode size
  *    the inode btree entry: 1 block
  *    the directory btree: (max depth + v2) * dir block size
- *    the directory inode\'s bmap btree: (max depth + v2) * block size
- *    the blocks for the symlink: 1 KB
+ *    the directory inode's bmap btree: (max depth + v2) * block size
+ *    the blocks for the symlink: 1 kB
  * Or in the first xact we allocate some inodes giving:
  *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
  *    the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
@@ -449,9 +449,9 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
          (128 * (4 + XFS_DIROP_LOG_COUNT(mp)))), \
         (2 * (mp)->m_sb.sb_sectsize + \
          XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \
-         XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \
+         XFS_FSB_TO_B((mp), (mp)->m_in_maxlevels) + \
          XFS_ALLOCFREE_LOG_RES(mp, 1) + \
-         (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \
+         (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
           XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
 
 #define        XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink)
@@ -463,7 +463,7 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
  *    the inode btree entry: block size
  *    the superblock for the nlink flag: sector size
  *    the directory btree: (max depth + v2) * dir block size
- *    the directory inode\'s bmap btree: (max depth + v2) * block size
+ *    the directory inode's bmap btree: (max depth + v2) * block size
  * Or in the first xact we allocate some inodes giving:
  *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
  *    the superblock for the nlink flag: sector size
@@ -481,9 +481,9 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
          (128 * (3 + XFS_DIROP_LOG_COUNT(mp)))), \
         (3 * (mp)->m_sb.sb_sectsize + \
          XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \
-         XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \
+         XFS_FSB_TO_B((mp), (mp)->m_in_maxlevels) + \
          XFS_ALLOCFREE_LOG_RES(mp, 1) + \
-         (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \
+         (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
           XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
 
 #define        XFS_CREATE_LOG_RES(mp)  ((mp)->m_reservations.tr_create)
@@ -513,7 +513,7 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
         MAX((__uint16_t)XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \
         (128 * 5) + \
          XFS_ALLOCFREE_LOG_RES(mp, 1) + \
-         (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \
+         (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
           XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
 
 
@@ -637,7 +637,7 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
 /*
  * Removing the attribute fork of a file
  *    the inode being truncated: inode size
- *    the inode\'s bmap btree: max depth * block size
+ *    the inode's bmap btree: max depth * block size
  * And the bmap_finish transaction can free the blocks and bmap blocks:
  *    the agf for each of the ags: 4 * sector size
  *    the agfl for each of the ags: 4 * sector size
index 2d47f10f8bed4cbe9b2441a29649311c2aa0acae..f31271c30de9bc6edf1b2ac575195585f6f99f3a 100644 (file)
@@ -79,7 +79,7 @@ xfs_trans_ail_tail(
  * the push is run asynchronously in a separate thread, so we return the tail
  * of the log right now instead of the tail after the push. This means we will
  * either continue right away, or we will sleep waiting on the async thread to
- * do it's work.
+ * do its work.
  *
  * We do this unlocked - we only need to know whether there is anything in the
  * AIL at the time we are called. We don't need to access the contents of
@@ -160,7 +160,7 @@ xfs_trans_ail_cursor_next(
 /*
  * Now that the traversal is complete, we need to remove the cursor
  * from the list of traversing cursors. Avoid removing the embedded
- * push cursor, but use the fact it is alway present to make the
+ * push cursor, but use the fact it is always present to make the
  * list deletion simple.
  */
 void
index e110bf57d7f496ddd70ce9f4927da8d67fa20545..eb3fc57f9eef681d73e39e07e3546cb45c350929 100644 (file)
@@ -22,7 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
-/* XXX: from here down needed until struct xfs_trans has it's own ailp */
+/* XXX: from here down needed until struct xfs_trans has its own ailp */
 #include "xfs_bit.h"
 #include "xfs_buf_item.h"
 #include "xfs_sb.h"
index 4ea2e5074bdd2e68a7ea943191ddd60effdac791..7d2c920dfb9c01e0aac1fdc13576aa8f950bcf7a 100644 (file)
@@ -47,7 +47,7 @@
 #define        XFS_DIRREMOVE_SPACE_RES(mp)     \
        XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
 #define        XFS_IALLOC_SPACE_RES(mp)        \
-       (XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp)-1)
+       (XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels - 1)
 
 /*
  * Space reservation values for various transactions.
index b2f724502f1bfbeed0f38712a72c825fa91b3268..d725428c9df6f64734591ed3366932e7550fe2d9 100644 (file)
 
 #ifdef __KERNEL__
 
-/*
- * POSIX Extensions
- */
-typedef unsigned char          uchar_t;
-typedef unsigned short         ushort_t;
-typedef unsigned int           uint_t;
-typedef unsigned long          ulong_t;
-
 /*
  * Additional type declarations for XFS
  */
index fcc2285d03ed7c9be2c56586d631242e6fe06874..79b9e5ea53590c25f8fd85797202653124ae35f7 100644 (file)
@@ -374,7 +374,7 @@ xfs_truncate_file(
 
        /*
         * Follow the normal truncate locking protocol.  Since we
-        * hold the inode in the transaction, we know that it's number
+        * hold the inode in the transaction, we know that its number
         * of references will stay constant.
         */
        xfs_ilock(ip, XFS_ILOCK_EXCL);
index 0e55c5d7db5fd2bbcc13e88baa38a915c2db94b7..7394c7af5de5ab0822beae7e742929f6dad4742d 100644 (file)
@@ -1136,7 +1136,7 @@ xfs_inactive(
         * If the inode is already free, then there can be nothing
         * to clean up here.
         */
-       if (ip->i_d.di_mode == 0 || VN_BAD(VFS_I(ip))) {
+       if (ip->i_d.di_mode == 0 || is_bad_inode(VFS_I(ip))) {
                ASSERT(ip->i_df.if_real_bytes == 0);
                ASSERT(ip->i_df.if_broot_bytes == 0);
                return VN_INACTIVE_CACHE;
@@ -1387,23 +1387,28 @@ xfs_create(
        xfs_inode_t             **ipp,
        cred_t                  *credp)
 {
-       xfs_mount_t             *mp = dp->i_mount;
-       xfs_inode_t             *ip;
-       xfs_trans_t             *tp;
+       int                     is_dir = S_ISDIR(mode);
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_inode        *ip = NULL;
+       struct xfs_trans        *tp = NULL;
        int                     error;
        xfs_bmap_free_t         free_list;
        xfs_fsblock_t           first_block;
        boolean_t               unlock_dp_on_error = B_FALSE;
-       int                     dm_event_sent = 0;
        uint                    cancel_flags;
        int                     committed;
        xfs_prid_t              prid;
-       struct xfs_dquot        *udqp, *gdqp;
+       struct xfs_dquot        *udqp = NULL;
+       struct xfs_dquot        *gdqp = NULL;
        uint                    resblks;
+       uint                    log_res;
+       uint                    log_count;
 
-       ASSERT(!*ipp);
        xfs_itrace_entry(dp);
 
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
        if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
                error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
                                dp, DM_RIGHT_NULL, NULL,
@@ -1412,84 +1417,97 @@ xfs_create(
 
                if (error)
                        return error;
-               dm_event_sent = 1;
        }
 
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       /* Return through std_return after this point. */
-
-       udqp = gdqp = NULL;
        if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
                prid = dp->i_d.di_projid;
        else
-               prid = (xfs_prid_t)dfltprid;
+               prid = dfltprid;
 
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
        error = XFS_QM_DQVOPALLOC(mp, dp,
                        current_fsuid(), current_fsgid(), prid,
-                       XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
        if (error)
                goto std_return;
 
-       ip = NULL;
+       if (is_dir) {
+               rdev = 0;
+               resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
+               log_res = XFS_MKDIR_LOG_RES(mp);
+               log_count = XFS_MKDIR_LOG_COUNT;
+               tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
+       } else {
+               resblks = XFS_CREATE_SPACE_RES(mp, name->len);
+               log_res = XFS_CREATE_LOG_RES(mp);
+               log_count = XFS_CREATE_LOG_COUNT;
+               tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
+       }
 
-       tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
        cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-       resblks = XFS_CREATE_SPACE_RES(mp, name->len);
+
        /*
         * Initially assume that the file does not exist and
         * reserve the resources for that case.  If that is not
         * the case we'll drop the one we have and get a more
         * appropriate transaction later.
         */
-       error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);
+       error = xfs_trans_reserve(tp, resblks, log_res, 0,
+                       XFS_TRANS_PERM_LOG_RES, log_count);
        if (error == ENOSPC) {
                resblks = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0,
-                               XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);
+               error = xfs_trans_reserve(tp, 0, log_res, 0,
+                               XFS_TRANS_PERM_LOG_RES, log_count);
        }
        if (error) {
                cancel_flags = 0;
-               goto error_return;
+               goto out_trans_cancel;
        }
 
        xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
        unlock_dp_on_error = B_TRUE;
 
-       xfs_bmap_init(&free_list, &first_block);
+       /*
+        * Check for directory link count overflow.
+        */
+       if (is_dir && dp->i_d.di_nlink >= XFS_MAXLINK) {
+               error = XFS_ERROR(EMLINK);
+               goto out_trans_cancel;
+       }
 
-       ASSERT(ip == NULL);
+       xfs_bmap_init(&free_list, &first_block);
 
        /*
         * Reserve disk quota and the inode.
         */
        error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
        if (error)
-               goto error_return;
+               goto out_trans_cancel;
 
        error = xfs_dir_canenter(tp, dp, name, resblks);
        if (error)
-               goto error_return;
-       error = xfs_dir_ialloc(&tp, dp, mode, 1,
-                       rdev, credp, prid, resblks > 0,
-                       &ip, &committed);
+               goto out_trans_cancel;
+
+       /*
+        * A newly created regular or special file just has one directory
+        * entry pointing to them, but a directory also the "." entry
+        * pointing to itself.
+        */
+       error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, credp,
+                              prid, resblks > 0, &ip, &committed);
        if (error) {
                if (error == ENOSPC)
-                       goto error_return;
-               goto abort_return;
+                       goto out_trans_cancel;
+               goto out_trans_abort;
        }
-       xfs_itrace_ref(ip);
 
        /*
         * At this point, we've gotten a newly allocated inode.
         * It is locked (and joined to the transaction).
         */
-
+       xfs_itrace_ref(ip);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
        /*
@@ -1508,19 +1526,28 @@ xfs_create(
                                        resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
        if (error) {
                ASSERT(error != ENOSPC);
-               goto abort_return;
+               goto out_trans_abort;
        }
        xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
+       if (is_dir) {
+               error = xfs_dir_init(tp, ip, dp);
+               if (error)
+                       goto out_bmap_cancel;
+
+               error = xfs_bumplink(tp, dp);
+               if (error)
+                       goto out_bmap_cancel;
+       }
+
        /*
         * If this is a synchronous mount, make sure that the
         * create transaction goes to disk before returning to
         * the user.
         */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
+       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
                xfs_trans_set_sync(tp);
-       }
 
        /*
         * Attach the dquot(s) to the inodes and modify them incore.
@@ -1537,16 +1564,13 @@ xfs_create(
        IHOLD(ip);
 
        error = xfs_bmap_finish(&tp, &free_list, &committed);
-       if (error) {
-               xfs_bmap_cancel(&free_list);
-               goto abort_rele;
-       }
+       if (error)
+               goto out_abort_rele;
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
        if (error) {
                IRELE(ip);
-               tp = NULL;
-               goto error_return;
+               goto out_dqrele;
        }
 
        XFS_QM_DQRELE(mp, udqp);
@@ -1555,26 +1579,22 @@ xfs_create(
        *ipp = ip;
 
        /* Fallthrough to std_return with error = 0  */
-
-std_return:
-       if ((*ipp || (error != 0 && dm_event_sent != 0)) &&
-           DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
-                       dp, DM_RIGHT_NULL,
-                       *ipp ? ip : NULL,
-                       DM_RIGHT_NULL, name->name, NULL,
-                       mode, error, 0);
+ std_return:
+       if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) {
+               XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, dp, DM_RIGHT_NULL,
+                               ip, DM_RIGHT_NULL, name->name, NULL, mode,
+                               error, 0);
        }
+
        return error;
 
- abort_return:
+ out_bmap_cancel:
+       xfs_bmap_cancel(&free_list);
+ out_trans_abort:
        cancel_flags |= XFS_TRANS_ABORT;
-       /* FALLTHROUGH */
-
- error_return:
-       if (tp != NULL)
-               xfs_trans_cancel(tp, cancel_flags);
-
+ out_trans_cancel:
+       xfs_trans_cancel(tp, cancel_flags);
+ out_dqrele:
        XFS_QM_DQRELE(mp, udqp);
        XFS_QM_DQRELE(mp, gdqp);
 
@@ -1583,20 +1603,18 @@ std_return:
 
        goto std_return;
 
- abort_rele:
out_abort_rele:
        /*
         * Wait until after the current transaction is aborted to
         * release the inode.  This prevents recursive transactions
         * and deadlocks from xfs_inactive.
         */
+       xfs_bmap_cancel(&free_list);
        cancel_flags |= XFS_TRANS_ABORT;
        xfs_trans_cancel(tp, cancel_flags);
        IRELE(ip);
-
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-
-       goto std_return;
+       unlock_dp_on_error = B_FALSE;
+       goto out_dqrele;
 }
 
 #ifdef DEBUG
@@ -2004,8 +2022,10 @@ xfs_link(
        /* Return through std_return after this point. */
 
        error = XFS_QM_DQATTACH(mp, sip, 0);
-       if (!error && sip != tdp)
-               error = XFS_QM_DQATTACH(mp, tdp, 0);
+       if (error)
+               goto std_return;
+
+       error = XFS_QM_DQATTACH(mp, tdp, 0);
        if (error)
                goto std_return;
 
@@ -2110,209 +2130,6 @@ std_return:
        goto std_return;
 }
 
-
-int
-xfs_mkdir(
-       xfs_inode_t             *dp,
-       struct xfs_name         *dir_name,
-       mode_t                  mode,
-       xfs_inode_t             **ipp,
-       cred_t                  *credp)
-{
-       xfs_mount_t             *mp = dp->i_mount;
-       xfs_inode_t             *cdp;   /* inode of created dir */
-       xfs_trans_t             *tp;
-       int                     cancel_flags;
-       int                     error;
-       int                     committed;
-       xfs_bmap_free_t         free_list;
-       xfs_fsblock_t           first_block;
-       boolean_t               unlock_dp_on_error = B_FALSE;
-       boolean_t               created = B_FALSE;
-       int                     dm_event_sent = 0;
-       xfs_prid_t              prid;
-       struct xfs_dquot        *udqp, *gdqp;
-       uint                    resblks;
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       tp = NULL;
-
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
-                                       dp, DM_RIGHT_NULL, NULL,
-                                       DM_RIGHT_NULL, dir_name->name, NULL,
-                                       mode, 0, 0);
-               if (error)
-                       return error;
-               dm_event_sent = 1;
-       }
-
-       /* Return through std_return after this point. */
-
-       xfs_itrace_entry(dp);
-
-       mp = dp->i_mount;
-       udqp = gdqp = NULL;
-       if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               prid = dp->i_d.di_projid;
-       else
-               prid = (xfs_prid_t)dfltprid;
-
-       /*
-        * Make sure that we have allocated dquot(s) on disk.
-        */
-       error = XFS_QM_DQVOPALLOC(mp, dp,
-                       current_fsuid(), current_fsgid(), prid,
-                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
-       if (error)
-               goto std_return;
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-       resblks = XFS_MKDIR_SPACE_RES(mp, dir_name->len);
-       error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0,
-                                 XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT);
-       if (error == ENOSPC) {
-               resblks = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0,
-                                         XFS_TRANS_PERM_LOG_RES,
-                                         XFS_MKDIR_LOG_COUNT);
-       }
-       if (error) {
-               cancel_flags = 0;
-               goto error_return;
-       }
-
-       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
-       unlock_dp_on_error = B_TRUE;
-
-       /*
-        * Check for directory link count overflow.
-        */
-       if (dp->i_d.di_nlink >= XFS_MAXLINK) {
-               error = XFS_ERROR(EMLINK);
-               goto error_return;
-       }
-
-       /*
-        * Reserve disk quota and the inode.
-        */
-       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
-       if (error)
-               goto error_return;
-
-       error = xfs_dir_canenter(tp, dp, dir_name, resblks);
-       if (error)
-               goto error_return;
-       /*
-        * create the directory inode.
-        */
-       error = xfs_dir_ialloc(&tp, dp, mode, 2,
-                       0, credp, prid, resblks > 0,
-               &cdp, NULL);
-       if (error) {
-               if (error == ENOSPC)
-                       goto error_return;
-               goto abort_return;
-       }
-       xfs_itrace_ref(cdp);
-
-       /*
-        * Now we add the directory inode to the transaction.
-        * We waited until now since xfs_dir_ialloc might start
-        * a new transaction.  Had we joined the transaction
-        * earlier, the locks might have gotten released. An error
-        * from here on will result in the transaction cancel
-        * unlocking dp so don't do it explicitly in the error path.
-        */
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-       unlock_dp_on_error = B_FALSE;
-
-       xfs_bmap_init(&free_list, &first_block);
-
-       error = xfs_dir_createname(tp, dp, dir_name, cdp->i_ino,
-                                       &first_block, &free_list, resblks ?
-                                       resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
-       if (error) {
-               ASSERT(error != ENOSPC);
-               goto error1;
-       }
-       xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
-       error = xfs_dir_init(tp, cdp, dp);
-       if (error)
-               goto error2;
-
-       error = xfs_bumplink(tp, dp);
-       if (error)
-               goto error2;
-
-       created = B_TRUE;
-
-       *ipp = cdp;
-       IHOLD(cdp);
-
-       /*
-        * Attach the dquots to the new inode and modify the icount incore.
-        */
-       XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp);
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * mkdir transaction goes to disk before returning to
-        * the user.
-        */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
-               xfs_trans_set_sync(tp);
-       }
-
-       error = xfs_bmap_finish(&tp, &free_list, &committed);
-       if (error) {
-               IRELE(cdp);
-               goto error2;
-       }
-
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-       if (error) {
-               IRELE(cdp);
-       }
-
-       /* Fall through to std_return with error = 0 or errno from
-        * xfs_trans_commit. */
-
-std_return:
-       if ((created || (error != 0 && dm_event_sent != 0)) &&
-           DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
-                                       dp, DM_RIGHT_NULL,
-                                       created ? cdp : NULL,
-                                       DM_RIGHT_NULL,
-                                       dir_name->name, NULL,
-                                       mode, error, 0);
-       }
-       return error;
-
- error2:
- error1:
-       xfs_bmap_cancel(&free_list);
- abort_return:
-       cancel_flags |= XFS_TRANS_ABORT;
- error_return:
-       xfs_trans_cancel(tp, cancel_flags);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-
-       if (unlock_dp_on_error)
-               xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-       goto std_return;
-}
-
 int
 xfs_symlink(
        xfs_inode_t             *dp,
@@ -2586,51 +2403,6 @@ std_return:
        goto std_return;
 }
 
-int
-xfs_inode_flush(
-       xfs_inode_t     *ip,
-       int             flags)
-{
-       xfs_mount_t     *mp = ip->i_mount;
-       int             error = 0;
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       /*
-        * Bypass inodes which have already been cleaned by
-        * the inode flush clustering code inside xfs_iflush
-        */
-       if (xfs_inode_clean(ip))
-               return 0;
-
-       /*
-        * We make this non-blocking if the inode is contended,
-        * return EAGAIN to indicate to the caller that they
-        * did not succeed. This prevents the flush path from
-        * blocking on inodes inside another operation right
-        * now, they get caught later by xfs_sync.
-        */
-       if (flags & FLUSH_SYNC) {
-               xfs_ilock(ip, XFS_ILOCK_SHARED);
-               xfs_iflock(ip);
-       } else if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
-               if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) {
-                       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-                       return EAGAIN;
-               }
-       } else {
-               return EAGAIN;
-       }
-
-       error = xfs_iflush(ip, (flags & FLUSH_SYNC) ? XFS_IFLUSH_SYNC
-                                                   : XFS_IFLUSH_ASYNC_NOBLOCK);
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-       return error;
-}
-
-
 int
 xfs_set_dmattrs(
        xfs_inode_t     *ip,
@@ -2676,7 +2448,7 @@ xfs_reclaim(
        ASSERT(!VN_MAPPED(VFS_I(ip)));
 
        /* bad inode, get out here ASAP */
-       if (VN_BAD(VFS_I(ip))) {
+       if (is_bad_inode(VFS_I(ip))) {
                xfs_ireclaim(ip);
                return 0;
        }
@@ -3090,7 +2862,7 @@ xfs_free_file_space(
 
        /*
         * Need to zero the stuff we're not freeing, on disk.
-        * If its a realtime file & can't use unwritten extents then we
+        * If it's a realtime file & can't use unwritten extents then we
         * actually need to zero the extent edges.  Otherwise xfs_bunmapi
         * will take care of it for us.
         */
index 76df328c61b42c16641ed4e7a8a18021efba7253..04373c6c61ff83f71d49df2f3f4250e7eb81f56d 100644 (file)
@@ -31,14 +31,11 @@ int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
                struct xfs_inode *ip);
 int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
                struct xfs_name *target_name);
-int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name,
-               mode_t mode, struct xfs_inode **ipp, cred_t *credp);
 int xfs_readdir(struct xfs_inode       *dp, void *dirent, size_t bufsize,
                       xfs_off_t *offset, filldir_t filldir);
 int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
                const char *target_path, mode_t mode, struct xfs_inode **ipp,
                cred_t *credp);
-int xfs_inode_flush(struct xfs_inode *ip, int flags);
 int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state);
 int xfs_reclaim(struct xfs_inode *ip);
 int xfs_change_file_space(struct xfs_inode *ip, int cmd,
index 26cefcde5cee9abba5df2dc5627d4f38b4016f05..68e4677fb9e73f87bdb6194e2ad3dd24ca726606 100644 (file)
@@ -18,6 +18,7 @@
 #ifdef __KERNEL__
 
 #include <linux/init.h>
+#include <linux/highmem.h>
 #include <asm/mem-layout.h>
 #include <asm/spr-regs.h>
 #include <asm/mb-regs.h>
@@ -116,6 +117,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
        unsigned long paddr;
 
        pagefault_disable();
+       debug_kmap_atomic(type);
        paddr = page_to_phys(page);
 
        switch (type) {
diff --git a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h
deleted file mode 100644 (file)
index 189486c..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/* Copyright (C) 2002 by James.Bottomley@HansenPartnership.com 
- *
- * Implements the generic device dma API via the existing pci_ one
- * for unconverted architectures
- */
-
-#ifndef _ASM_GENERIC_DMA_MAPPING_H
-#define _ASM_GENERIC_DMA_MAPPING_H
-
-
-#ifdef CONFIG_PCI
-
-/* we implement the API below in terms of the existing PCI one,
- * so include it */
-#include <linux/pci.h>
-/* need struct page definitions */
-#include <linux/mm.h>
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_dma_supported(to_pci_dev(dev), mask);
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
-}
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                  gfp_t flag)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                   dma_addr_t dma_handle)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-            unsigned long offset, size_t size,
-            enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-          enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-            enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
-                                   size, (int)direction);
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-                          enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
-                                      size, (int)direction);
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-                   enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction);
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-                      enum dma_data_direction direction)
-{
-       BUG_ON(dev->bus != &pci_bus_type);
-
-       pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction);
-}
-
-static inline int
-dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return pci_dma_mapping_error(to_pci_dev(dev), dma_addr);
-}
-
-
-#else
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-       return 0;
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       BUG();
-       return 0;
-}
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                  gfp_t flag)
-{
-       BUG();
-       return NULL;
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                   dma_addr_t dma_handle)
-{
-       BUG();
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-            unsigned long offset, size_t size,
-            enum dma_data_direction direction)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-          enum dma_data_direction direction)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-            enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-                          enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-                   enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-                      enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int
-dma_error(dma_addr_t dma_addr)
-{
-       return 0;
-}
-
-#endif
-
-/* Now for the API extensions over the pci_ one */
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-#define dma_is_consistent(d, h)        (1)
-
-static inline int
-dma_get_cache_alignment(void)
-{
-       /* no easy way to get cache size on all processors, so return
-        * the maximum possible, to be safe */
-       return (1 << INTERNODE_CACHE_SHIFT);
-}
-
-static inline void
-dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                             unsigned long offset, size_t size,
-                             enum dma_data_direction direction)
-{
-       /* just sync everything, that's all the pci API can do */
-       dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
-}
-
-static inline void
-dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-                                unsigned long offset, size_t size,
-                                enum dma_data_direction direction)
-{
-       /* just sync everything, that's all the pci API can do */
-       dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
-}
-
-static inline void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-              enum dma_data_direction direction)
-{
-       /* could define this in terms of the dma_cache ... operations,
-        * but if you get this on a platform, you should convert the platform
-        * to using the generic device DMA API */
-       BUG();
-}
-
-#endif
-
index 81797ec9ab2917413ba28d166adb267726c8f177..d6c379dc64fac63797364c7e385dc91778df5ac4 100644 (file)
@@ -55,6 +55,10 @@ struct module;
  *     handled is (base + ngpio - 1).
  * @can_sleep: flag must be set iff get()/set() methods sleep, as they
  *     must while accessing GPIO expander chips over I2C or SPI
+ * @names: if set, must be an array of strings to use as alternative
+ *      names for the GPIOs in this chip. Any entry in the array
+ *      may be NULL if there is no alias for the GPIO, however the
+ *      array must be @ngpio entries long.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -92,6 +96,7 @@ struct gpio_chip {
                                                struct gpio_chip *chip);
        int                     base;
        u16                     ngpio;
+       char                    **names;
        unsigned                can_sleep:1;
        unsigned                exported:1;
 };
index 0e9e2bc0ee96e66d08beb37bb71933ab2ece7636..88bada2ebc4b1fb1bb980f96daa8409ac5933eb2 100644 (file)
 #ifndef cpumask_of_node
 #define cpumask_of_node(node)  ((void)node, cpu_online_mask)
 #endif
-#ifndef node_to_first_cpu
-#define node_to_first_cpu(node)        ((void)(node),0)
-#endif
 #ifndef pcibus_to_node
 #define pcibus_to_node(bus)    ((void)(bus), -1)
 #endif
 
-#ifndef pcibus_to_cpumask
-#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
-                                       CPU_MASK_ALL : \
-                                       node_to_cpumask(pcibus_to_node(bus)) \
-                               )
-#endif
-
 #ifndef cpumask_of_pcibus
 #define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ?            \
                                 cpu_all_mask :                         \
index f5cfba81ee10c1f59b007dcf34fd9db508a9bff5..dded923883b2549c52bebb63e5ba5fe664382cb8 100644 (file)
@@ -316,6 +316,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *lock)
        return 0;
 }
 
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 5256854c045342849f190715b4f4ebdd12ed0780..90f2abb04bfdc5178ab50645852fe04ab812d3da 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/highmem.h>
 #include <asm/kmap_types.h>
 #include <asm/pgtable.h>
 
@@ -77,6 +78,7 @@ static inline unsigned long kmap_atomic(struct page *page, enum km_type type)
        if (page < highmem_start_page)
                return page_address(page);
 
+       debug_kmap_atomic(type);
        idx = type + KM_TYPE_NR * smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #if HIGHMEM_DEBUG
index c7d4b2e606a5f73f5fbed9217449b16c504b7e4d..ec073d8288d9438005796a121dd6815d204d2bcc 100644 (file)
@@ -33,7 +33,6 @@
 #ifndef __DRM_CRTC_HELPER_H__
 #define __DRM_CRTC_HELPER_H__
 
-#include <linux/i2c.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/idr.h>
@@ -92,7 +91,7 @@ struct drm_connector_helper_funcs {
 extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
 extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
-extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
+extern bool drm_helper_initial_config(struct drm_device *dev);
 extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
 extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                                     struct drm_display_mode *mode,
index 013551d03c035c984d19e02b692a0ed5b5c3015f..26641e95e0a4be8cb0ce273c88eb65196bfe02af 100644 (file)
@@ -7,12 +7,12 @@
 #include <linux/delay.h>
 
 #ifndef readq
-static u64 readq(void __iomem *reg)
+static inline u64 readq(void __iomem *reg)
 {
        return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32);
 }
 
-static void writeq(u64 val, void __iomem *reg)
+static inline void writeq(u64 val, void __iomem *reg)
 {
        writel(val & 0xffffffff, reg);
        writel(val >> 32, reg + 0x4UL);
index a67b6227d272b772d8c9f78703b27ed426f9c0d6..ca9b9b9bd3311fc1e769b47251ed3ecb761a59a2 100644 (file)
@@ -67,6 +67,7 @@ header-y += falloc.h
 header-y += fd.h
 header-y += fdreg.h
 header-y += fib_rules.h
+header-y += fiemap.h
 header-y += firewire-cdev.h
 header-y += firewire-constants.h
 header-y += fuse.h
index 78199151c00b2b1a996f2723f5496159da66a6fb..d047f846c3ed6d434555f2734aee472627e9ef6b 100644 (file)
@@ -257,6 +257,40 @@ void __init acpi_no_s4_hw_signature(void);
 void __init acpi_old_suspend_ordering(void);
 void __init acpi_s4_no_nvs(void);
 #endif /* CONFIG_PM_SLEEP */
+
+#define OSC_QUERY_TYPE                 0
+#define OSC_SUPPORT_TYPE               1
+#define OSC_CONTROL_TYPE               2
+#define OSC_SUPPORT_MASKS              0x1f
+
+/* _OSC DW0 Definition */
+#define OSC_QUERY_ENABLE               1
+#define OSC_REQUEST_ERROR              2
+#define OSC_INVALID_UUID_ERROR         4
+#define OSC_INVALID_REVISION_ERROR     8
+#define OSC_CAPABILITIES_MASK_ERROR    16
+
+/* _OSC DW1 Definition (OS Support Fields) */
+#define OSC_EXT_PCI_CONFIG_SUPPORT             1
+#define OSC_ACTIVE_STATE_PWR_SUPPORT           2
+#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT       4
+#define OSC_PCI_SEGMENT_GROUPS_SUPPORT         8
+#define OSC_MSI_SUPPORT                                16
+
+/* _OSC DW1 Definition (OS Control Fields) */
+#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL      1
+#define OSC_SHPC_NATIVE_HP_CONTROL             2
+#define OSC_PCI_EXPRESS_PME_CONTROL            4
+#define OSC_PCI_EXPRESS_AER_CONTROL            8
+#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL  16
+
+#define OSC_CONTROL_MASKS      (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |    \
+                               OSC_SHPC_NATIVE_HP_CONTROL |            \
+                               OSC_PCI_EXPRESS_PME_CONTROL |           \
+                               OSC_PCI_EXPRESS_AER_CONTROL |           \
+                               OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+
+extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 #else  /* CONFIG_ACPI */
 
 static inline int early_acpi_boot_init(void)
index 45f6297821bd6c7afee48e247d8a25b027bc7445..5fc2ef8d97fac5851eb2d40f7b7e2d67a3be48e8 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 
+/* on architectures without dma-mapping capabilities we need to ensure
+ * that the asynchronous path compiles away
+ */
+#ifdef CONFIG_HAS_DMA
+#define __async_inline
+#else
+#define __async_inline __always_inline
+#endif
+
 /**
  * dma_chan_ref - object used to manage dma channels received from the
  *   dmaengine core.
index 91a773993a5c99d7c360e3944bece7d7b099d4c7..850f39b33e743f927acf0d2ca9777971c873e345 100644 (file)
 #ifndef _LINUX_AUTO_DEV_IOCTL_H
 #define _LINUX_AUTO_DEV_IOCTL_H
 
+#include <linux/auto_fs.h>
+
+#ifdef __KERNEL__
 #include <linux/string.h>
-#include <linux/types.h>
+#else
+#include <string.h>
+#endif /* __KERNEL__ */
 
 #define AUTOFS_DEVICE_NAME             "autofs"
 
index c21e5972a3e8a0c1d20531cfabe35b14bb2a0141..63265852b7d16216b377d27036375bc42de042e1 100644 (file)
 #ifdef __KERNEL__
 #include <linux/fs.h>
 #include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#else
 #include <asm/types.h>
+#include <sys/ioctl.h>
 #endif /* __KERNEL__ */
 
-#include <linux/ioctl.h>
-
 /* This file describes autofs v3 */
 #define AUTOFS_PROTO_VERSION   3
 
index 77b4a9e4600485318a141597a9cd226e2c922f4c..6638b8148de7d9a45635ca95b6952b6651df2542 100644 (file)
@@ -35,8 +35,7 @@ struct linux_binprm{
 #endif
        struct mm_struct *mm;
        unsigned long p; /* current top of mem */
-       unsigned int sh_bang:1,
-               misc_bang:1,
+       unsigned int
                cred_prepared:1,/* true if creds already prepared (multiple
                                 * preps happen for interpreters) */
                cap_effective:1;/* true if has elevated effective capabilities,
index 455d83219fae5f3e40bdf83575da34ea9c864da7..bc3ab70736955675afef688d4209c5bf8392b4b3 100644 (file)
@@ -146,10 +146,10 @@ extern void *alloc_large_system_hash(const char *tablename,
 
 #define HASH_EARLY     0x00000001      /* Allocating during early boot? */
 
-/* Only NUMA needs hash distribution.
- * IA64 and x86_64 have sufficient vmalloc space.
+/* Only NUMA needs hash distribution. 64bit NUMA architectures have
+ * sufficient vmalloc space.
  */
-#if defined(CONFIG_NUMA) && (defined(CONFIG_IA64) || defined(CONFIG_X86_64))
+#if defined(CONFIG_NUMA) && defined(CONFIG_64BIT)
 #define HASHDIST_DEFAULT 1
 #else
 #define HASHDIST_DEFAULT 0
index f19fd9045ea0a621e05bc6eb11d515a78656f8bb..7b73bb8f19708ebbfc672bf18b489ae198310939 100644 (file)
@@ -216,7 +216,7 @@ int cont_write_begin(struct file *, struct address_space *, loff_t,
                        get_block_t *, loff_t *);
 int generic_cont_expand_simple(struct inode *inode, loff_t size);
 int block_commit_write(struct page *page, unsigned from, unsigned to);
-int block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
                                get_block_t get_block);
 void block_sync_page(struct page *);
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
@@ -332,22 +332,10 @@ extern int __set_page_dirty_buffers(struct page *page);
 
 static inline void buffer_init(void) {}
 static inline int try_to_free_buffers(struct page *page) { return 1; }
-static inline int sync_blockdev(struct block_device *bdev) { return 0; }
 static inline int inode_has_buffers(struct inode *inode) { return 0; }
 static inline void invalidate_inode_buffers(struct inode *inode) {}
 static inline int remove_inode_buffers(struct inode *inode) { return 1; }
 static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; }
-static inline void invalidate_bdev(struct block_device *bdev) {}
-
-static inline struct super_block *freeze_bdev(struct block_device *sb)
-{
-       return NULL;
-}
-
-static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb)
-{
-       return 0;
-}
 
 #endif /* CONFIG_BLOCK */
 #endif /* _LINUX_BUFFER_HEAD_H */
index 499900d0cee7110748229ee3898b50734352e5e4..665fa70e4094166c76b85176f0fbb3f5f6fae7c5 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/cgroupstats.h>
 #include <linux/prio_heap.h>
 #include <linux/rwsem.h>
+#include <linux/idr.h>
 
 #ifdef CONFIG_CGROUPS
 
@@ -22,6 +23,7 @@ struct cgroupfs_root;
 struct cgroup_subsys;
 struct inode;
 struct cgroup;
+struct css_id;
 
 extern int cgroup_init_early(void);
 extern int cgroup_init(void);
@@ -47,18 +49,24 @@ enum cgroup_subsys_id {
 
 /* Per-subsystem/per-cgroup state maintained by the system. */
 struct cgroup_subsys_state {
-       /* The cgroup that this subsystem is attached to. Useful
+       /*
+        * The cgroup that this subsystem is attached to. Useful
         * for subsystems that want to know about the cgroup
-        * hierarchy structure */
+        * hierarchy structure
+        */
        struct cgroup *cgroup;
 
-       /* State maintained by the cgroup system to allow subsystems
+       /*
+        * State maintained by the cgroup system to allow subsystems
         * to be "busy". Should be accessed via css_get(),
-        * css_tryget() and and css_put(). */
+        * css_tryget() and and css_put().
+        */
 
        atomic_t refcnt;
 
        unsigned long flags;
+       /* ID for this css, if possible */
+       struct css_id *id;
 };
 
 /* bits in struct cgroup_subsys_state flags field */
@@ -120,19 +128,26 @@ static inline void css_put(struct cgroup_subsys_state *css)
 enum {
        /* Control Group is dead */
        CGRP_REMOVED,
-       /* Control Group has previously had a child cgroup or a task,
-        * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set) */
+       /*
+        * Control Group has previously had a child cgroup or a task,
+        * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set)
+        */
        CGRP_RELEASABLE,
        /* Control Group requires release notifications to userspace */
        CGRP_NOTIFY_ON_RELEASE,
+       /*
+        * A thread in rmdir() is wating for this cgroup.
+        */
+       CGRP_WAIT_ON_RMDIR,
 };
 
 struct cgroup {
        unsigned long flags;            /* "unsigned long" so bitops work */
 
-       /* count users of this cgroup. >0 means busy, but doesn't
-        * necessarily indicate the number of tasks in the
-        * cgroup */
+       /*
+        * count users of this cgroup. >0 means busy, but doesn't
+        * necessarily indicate the number of tasks in the cgroup
+        */
        atomic_t count;
 
        /*
@@ -142,7 +157,7 @@ struct cgroup {
        struct list_head sibling;       /* my parent's children */
        struct list_head children;      /* my children */
 
-       struct cgroup *parent;  /* my parent */
+       struct cgroup *parent;          /* my parent */
        struct dentry *dentry;          /* cgroup fs entry, RCU protected */
 
        /* Private pointers for each registered subsystem */
@@ -177,11 +192,12 @@ struct cgroup {
        struct rcu_head rcu_head;
 };
 
-/* A css_set is a structure holding pointers to a set of
+/*
+ * A css_set is a structure holding pointers to a set of
  * cgroup_subsys_state objects. This saves space in the task struct
  * object and speeds up fork()/exit(), since a single inc/dec and a
- * list_add()/del() can bump the reference count on the entire
- * cgroup set for a task.
+ * list_add()/del() can bump the reference count on the entire cgroup
+ * set for a task.
  */
 
 struct css_set {
@@ -226,13 +242,8 @@ struct cgroup_map_cb {
        void *state;
 };
 
-/* struct cftype:
- *
- * The files in the cgroup filesystem mostly have a very simple read/write
- * handling, some common function will take care of it. Nevertheless some cases
- * (read tasks) are special and therefore I define this structure for every
- * kind of file.
- *
+/*
+ * struct cftype: handler definitions for cgroup control files
  *
  * When reading/writing to a file:
  *     - the cgroup to use is file->f_dentry->d_parent->d_fsdata
@@ -241,10 +252,17 @@ struct cgroup_map_cb {
 
 #define MAX_CFTYPE_NAME 64
 struct cftype {
-       /* By convention, the name should begin with the name of the
-        * subsystem, followed by a period */
+       /*
+        * By convention, the name should begin with the name of the
+        * subsystem, followed by a period
+        */
        char name[MAX_CFTYPE_NAME];
        int private;
+       /*
+        * If not 0, file mode is set to this value, otherwise it will
+        * be figured out automatically
+        */
+       mode_t mode;
 
        /*
         * If non-zero, defines the maximum length of string that can
@@ -319,15 +337,20 @@ struct cgroup_scanner {
        void (*process_task)(struct task_struct *p,
                        struct cgroup_scanner *scan);
        struct ptr_heap *heap;
+       void *data;
 };
 
-/* Add a new file to the given cgroup directory. Should only be
- * called by subsystems from within a populate() method */
+/*
+ * Add a new file to the given cgroup directory. Should only be
+ * called by subsystems from within a populate() method
+ */
 int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
                       const struct cftype *cft);
 
-/* Add a set of new files to the given cgroup directory. Should
- * only be called by subsystems from within a populate() method */
+/*
+ * Add a set of new files to the given cgroup directory. Should
+ * only be called by subsystems from within a populate() method
+ */
 int cgroup_add_files(struct cgroup *cgrp,
                        struct cgroup_subsys *subsys,
                        const struct cftype cft[],
@@ -339,15 +362,18 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen);
 
 int cgroup_task_count(const struct cgroup *cgrp);
 
-/* Return true if the cgroup is a descendant of the current cgroup */
-int cgroup_is_descendant(const struct cgroup *cgrp);
+/* Return true if cgrp is a descendant of the task's cgroup */
+int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task);
 
-/* Control Group subsystem type. See Documentation/cgroups.txt for details */
+/*
+ * Control Group subsystem type.
+ * See Documentation/cgroups/cgroups.txt for details
+ */
 
 struct cgroup_subsys {
        struct cgroup_subsys_state *(*create)(struct cgroup_subsys *ss,
                                                  struct cgroup *cgrp);
-       void (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
+       int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
        void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
        int (*can_attach)(struct cgroup_subsys *ss,
                          struct cgroup *cgrp, struct task_struct *tsk);
@@ -364,6 +390,11 @@ struct cgroup_subsys {
        int active;
        int disabled;
        int early_init;
+       /*
+        * True if this subsys uses ID. ID is not available before cgroup_init()
+        * (not available in early_init time.)
+        */
+       bool use_id;
 #define MAX_CGROUP_TYPE_NAMELEN 32
        const char *name;
 
@@ -386,6 +417,9 @@ struct cgroup_subsys {
         */
        struct cgroupfs_root *root;
        struct list_head sibling;
+       /* used when use_id == true */
+       struct idr idr;
+       spinlock_t id_lock;
 };
 
 #define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys;
@@ -419,7 +453,8 @@ struct cgroup_iter {
        struct list_head *task;
 };
 
-/* To iterate across the tasks in a cgroup:
+/*
+ * To iterate across the tasks in a cgroup:
  *
  * 1) call cgroup_iter_start to intialize an iterator
  *
@@ -428,9 +463,10 @@ struct cgroup_iter {
  *
  * 3) call cgroup_iter_end() to destroy the iterator.
  *
- * Or, call cgroup_scan_tasks() to iterate through every task in a cpuset.
- *    - cgroup_scan_tasks() holds the css_set_lock when calling the test_task()
- *      callback, but not while calling the process_task() callback.
+ * Or, call cgroup_scan_tasks() to iterate through every task in a
+ * cgroup - cgroup_scan_tasks() holds the css_set_lock when calling
+ * the test_task() callback, but not while calling the process_task()
+ * callback.
  */
 void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it);
 struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
@@ -439,6 +475,44 @@ void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
 int cgroup_scan_tasks(struct cgroup_scanner *scan);
 int cgroup_attach_task(struct cgroup *, struct task_struct *);
 
+/*
+ * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
+ * if cgroup_subsys.use_id == true. It can be used for looking up and scanning.
+ * CSS ID is assigned at cgroup allocation (create) automatically
+ * and removed when subsys calls free_css_id() function. This is because
+ * the lifetime of cgroup_subsys_state is subsys's matter.
+ *
+ * Looking up and scanning function should be called under rcu_read_lock().
+ * Taking cgroup_mutex()/hierarchy_mutex() is not necessary for following calls.
+ * But the css returned by this routine can be "not populated yet" or "being
+ * destroyed". The caller should check css and cgroup's status.
+ */
+
+/*
+ * Typically Called at ->destroy(), or somewhere the subsys frees
+ * cgroup_subsys_state.
+ */
+void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css);
+
+/* Find a cgroup_subsys_state which has given ID */
+
+struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id);
+
+/*
+ * Get a cgroup whose id is greater than or equal to id under tree of root.
+ * Returning a cgroup_subsys_state or NULL.
+ */
+struct cgroup_subsys_state *css_get_next(struct cgroup_subsys *ss, int id,
+               struct cgroup_subsys_state *root, int *foundid);
+
+/* Returns true if root is ancestor of cg */
+bool css_is_ancestor(struct cgroup_subsys_state *cg,
+                    const struct cgroup_subsys_state *root);
+
+/* Get id and depth of css */
+unsigned short css_id(struct cgroup_subsys_state *css);
+unsigned short css_depth(struct cgroup_subsys_state *css);
+
 #else /* !CONFIG_CGROUPS */
 
 static inline int cgroup_init_early(void) { return 0; }
index b880864672de75e09cfd522f1f6df1fded3ba56b..9723edd6455cb8d612923f8a5706fb691e2a1525 100644 (file)
@@ -191,6 +191,12 @@ asmlinkage ssize_t compat_sys_readv(unsigned long fd,
                const struct compat_iovec __user *vec, unsigned long vlen);
 asmlinkage ssize_t compat_sys_writev(unsigned long fd,
                const struct compat_iovec __user *vec, unsigned long vlen);
+asmlinkage ssize_t compat_sys_preadv(unsigned long fd,
+               const struct compat_iovec __user *vec,
+               unsigned long vlen, u32 pos_high, u32 pos_low);
+asmlinkage ssize_t compat_sys_pwritev(unsigned long fd,
+               const struct compat_iovec __user *vec,
+               unsigned long vlen, u32 pos_high, u32 pos_low);
 
 int compat_do_execve(char * filename, compat_uptr_t __user *argv,
                compat_uptr_t __user *envp, struct pt_regs * regs);
index c2747ac2ae43b8a7b22bebdef63ee92cbcf1c31a..2643d848df9014df4776423028e223498f5a6d66 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/node.h>
 #include <linux/compiler.h>
 #include <linux/cpumask.h>
-#include <linux/mutex.h>
 
 struct cpu {
        int node_id;            /* The node which contains the CPU */
@@ -103,16 +102,6 @@ extern struct sysdev_class cpu_sysdev_class;
 #ifdef CONFIG_HOTPLUG_CPU
 /* Stop CPUs going up and down. */
 
-static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex)
-{
-       mutex_lock(cpu_hp_mutex);
-}
-
-static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex)
-{
-       mutex_unlock(cpu_hp_mutex);
-}
-
 extern void get_online_cpus(void);
 extern void put_online_cpus(void);
 #define hotcpu_notifier(fn, pri) {                             \
@@ -126,11 +115,6 @@ int cpu_down(unsigned int cpu);
 
 #else          /* CONFIG_HOTPLUG_CPU */
 
-static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex)
-{ }
-static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex)
-{ }
-
 #define get_online_cpus()      do { } while (0)
 #define put_online_cpus()      do { } while (0)
 #define hotcpu_notifier(fn, pri)       do { (void)(fn); } while (0)
index 90c6074a36cab42c47df2ac8f6239cfe2ae0ddfe..05ea1dd7d681d072a5ae1c9c7c2da56d75bbc6e6 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/cpumask.h>
 #include <linux/nodemask.h>
 #include <linux/cgroup.h>
+#include <linux/mm.h>
 
 #ifdef CONFIG_CPUSETS
 
@@ -29,19 +30,29 @@ void cpuset_init_current_mems_allowed(void);
 void cpuset_update_task_memory_state(void);
 int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask);
 
-extern int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask);
-extern int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask);
+extern int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask);
+extern int __cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask);
 
-static int inline cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+static inline int cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 {
        return number_of_cpusets <= 1 ||
-               __cpuset_zone_allowed_softwall(z, gfp_mask);
+               __cpuset_node_allowed_softwall(node, gfp_mask);
 }
 
-static int inline cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+static inline int cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
 {
        return number_of_cpusets <= 1 ||
-               __cpuset_zone_allowed_hardwall(z, gfp_mask);
+               __cpuset_node_allowed_hardwall(node, gfp_mask);
+}
+
+static inline int cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+{
+       return cpuset_node_allowed_softwall(zone_to_nid(z), gfp_mask);
+}
+
+static inline int cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+{
+       return cpuset_node_allowed_hardwall(zone_to_nid(z), gfp_mask);
 }
 
 extern int cpuset_mems_allowed_intersects(const struct task_struct *tsk1,
@@ -90,12 +101,12 @@ static inline void cpuset_init_smp(void) {}
 static inline void cpuset_cpus_allowed(struct task_struct *p,
                                       struct cpumask *mask)
 {
-       *mask = cpu_possible_map;
+       cpumask_copy(mask, cpu_possible_mask);
 }
 static inline void cpuset_cpus_allowed_locked(struct task_struct *p,
                                              struct cpumask *mask)
 {
-       *mask = cpu_possible_map;
+       cpumask_copy(mask, cpu_possible_mask);
 }
 
 static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
@@ -112,6 +123,16 @@ static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask)
        return 1;
 }
 
+static inline int cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
+{
+       return 1;
+}
+
+static inline int cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
+{
+       return 1;
+}
+
 static inline int cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
 {
        return 1;
index 8209e08969f9e4265e4fbbcd0c00b5a68467cad5..66ec05a5795558cef24450388e67ffd6bf0743f3 100644 (file)
@@ -139,6 +139,9 @@ struct target_type {
        dm_ioctl_fn ioctl;
        dm_merge_fn merge;
        dm_busy_fn busy;
+
+       /* For internal device-mapper use. */
+       struct list_head list;
 };
 
 struct io_restrictions {
index 600c5fb2daad4c231b53a4654316469895af9b0c..5e8b11d88f6f891a5c56328ca54ecb0fa4e2ce57 100644 (file)
@@ -28,6 +28,9 @@ struct dm_dirty_log_type {
        const char *name;
        struct module *module;
 
+       /* For internal device-mapper use */
+       struct list_head list;
+
        int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
                   unsigned argc, char **argv);
        void (*dtr)(struct dm_dirty_log *log);
@@ -113,6 +116,16 @@ struct dm_dirty_log_type {
         */
        int (*status)(struct dm_dirty_log *log, status_type_t status_type,
                      char *result, unsigned maxlen);
+
+       /*
+        * is_remote_recovering is necessary for cluster mirroring. It provides
+        * a way to detect recovery on another node, so we aren't writing
+        * concurrently.  This function is likely to block (when a cluster log
+        * is used).
+        *
+        * Returns: 0, 1
+        */
+       int (*is_remote_recovering)(struct dm_dirty_log *log, region_t region);
 };
 
 int dm_dirty_log_type_register(struct dm_dirty_log_type *type);
index af1dab41674bfdf3ceacbf49c6aca7ec24cd606d..1a455f1f86d763da366f178852e7adb652bc86ce 100644 (file)
@@ -11,6 +11,7 @@
 
 #define DMA_PTE_READ (1)
 #define DMA_PTE_WRITE (2)
+#define DMA_PTE_SNP (1 << 11)
 
 struct intel_iommu;
 struct dmar_domain;
index 1956c8d46d326ea98c2286a6f3f47e8e428518a1..2e2aa3df170cfb5f2be5f8097ee9e2324c759143 100644 (file)
@@ -23,9 +23,6 @@
 
 #include <linux/device.h>
 #include <linux/uio.h>
-#include <linux/kref.h>
-#include <linux/completion.h>
-#include <linux/rcupdate.h>
 #include <linux/dma-mapping.h>
 
 /**
@@ -205,6 +202,7 @@ struct dma_async_tx_descriptor {
 /**
  * struct dma_device - info on the entity supplying DMA services
  * @chancnt: how many DMA channels are supported
+ * @privatecnt: how many DMA channels are requested by dma_request_channel
  * @channels: the list of struct dma_chan
  * @global_node: list_head for global dma_device_list
  * @cap_mask: one or more dma_capability flags
@@ -227,6 +225,7 @@ struct dma_async_tx_descriptor {
 struct dma_device {
 
        unsigned int chancnt;
+       unsigned int privatecnt;
        struct list_head channels;
        struct list_head global_node;
        dma_cap_mask_t  cap_mask;
@@ -291,6 +290,24 @@ static inline void net_dmaengine_put(void)
 }
 #endif
 
+#ifdef CONFIG_ASYNC_TX_DMA
+#define async_dmaengine_get()  dmaengine_get()
+#define async_dmaengine_put()  dmaengine_put()
+#define async_dma_find_channel(type) dma_find_channel(type)
+#else
+static inline void async_dmaengine_get(void)
+{
+}
+static inline void async_dmaengine_put(void)
+{
+}
+static inline struct dma_chan *
+async_dma_find_channel(enum dma_transaction_type type)
+{
+       return NULL;
+}
+#endif
+
 dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan,
        void *dest, void *src, size_t len);
 dma_cookie_t dma_async_memcpy_buf_to_pg(struct dma_chan *chan,
@@ -337,6 +354,13 @@ __dma_cap_set(enum dma_transaction_type tx_type, dma_cap_mask_t *dstp)
        set_bit(tx_type, dstp->bits);
 }
 
+#define dma_cap_clear(tx, mask) __dma_cap_clear((tx), &(mask))
+static inline void
+__dma_cap_clear(enum dma_transaction_type tx_type, dma_cap_mask_t *dstp)
+{
+       clear_bit(tx_type, dstp->bits);
+}
+
 #define dma_cap_zero(mask) __dma_cap_zero(&(mask))
 static inline void __dma_cap_zero(dma_cap_mask_t *dstp)
 {
index d741b9ceb0e06ad75b032a9f3251ca038d98f5ac..bb5489c82c99495b6bf2900175e1c22c25dd610c 100644 (file)
@@ -47,7 +47,8 @@ extern int dmi_get_year(int field);
 extern int dmi_name_in_vendors(const char *str);
 extern int dmi_name_in_serial(const char *str);
 extern int dmi_available;
-extern int dmi_walk(void (*decode)(const struct dmi_header *));
+extern int dmi_walk(void (*decode)(const struct dmi_header *, void *),
+       void *private_data);
 extern bool dmi_match(enum dmi_field f, const char *str);
 
 #else
@@ -61,8 +62,8 @@ static inline int dmi_get_year(int year) { return 0; }
 static inline int dmi_name_in_vendors(const char *s) { return 0; }
 static inline int dmi_name_in_serial(const char *s) { return 0; }
 #define dmi_available 0
-static inline int dmi_walk(void (*decode)(const struct dmi_header *))
-       { return -1; }
+static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *),
+       void *private_data) { return -1; }
 static inline bool dmi_match(enum dmi_field f, const char *str)
        { return false; }
 static inline const struct dmi_system_id *
index d797dde247f763392427cac3d9cad4b1ba5cc595..c8aad713a0460bd1c66c0962f930602501b2f9e7 100644 (file)
@@ -74,4 +74,23 @@ struct dw_dma_slave {
 #define DWC_CFGL_HS_DST_POL    (1 << 18)       /* dst handshake active low */
 #define DWC_CFGL_HS_SRC_POL    (1 << 19)       /* src handshake active low */
 
+/* DMA API extensions */
+struct dw_cyclic_desc {
+       struct dw_desc  **desc;
+       unsigned long   periods;
+       void            (*period_callback)(void *param);
+       void            *period_callback_param;
+};
+
+struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
+               dma_addr_t buf_addr, size_t buf_len, size_t period_len,
+               enum dma_data_direction direction);
+void dw_dma_cyclic_free(struct dma_chan *chan);
+int dw_dma_cyclic_start(struct dma_chan *chan);
+void dw_dma_cyclic_stop(struct dma_chan *chan);
+
+dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan);
+
+dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan);
+
 #endif /* DW_DMAC_H */
index a667637b54e3912783c9f1e086c57df74784e05b..f45a8ae5f8281bc51348b942a36899b8355f13d9 100644 (file)
 /* For O_CLOEXEC and O_NONBLOCK */
 #include <linux/fcntl.h>
 
-/* Flags for eventfd2.  */
+/*
+ * CAREFUL: Check include/asm-generic/fcntl.h when defining
+ * new flags, since they might collide with O_* ones. We want
+ * to re-use O_* flags that couldn't possibly have a meaning
+ * from eventfd, in order to leave a free define-space for
+ * shared O_* flags.
+ */
+#define EFD_SEMAPHORE (1 << 0)
 #define EFD_CLOEXEC O_CLOEXEC
 #define EFD_NONBLOCK O_NONBLOCK
 
+#define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
+#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE)
+
 struct file *eventfd_fget(int fd);
 int eventfd_signal(struct file *file, int n);
 
index dd495b8c3091e21b3b55a25e8c8294e07f611113..634a5e5aba3e219844fbffadce72b0361c794203 100644 (file)
@@ -208,6 +208,7 @@ static inline __u32 ext3_mask_flags(umode_t mode, __u32 flags)
 #define EXT3_STATE_JDATA               0x00000001 /* journaled data exists */
 #define EXT3_STATE_NEW                 0x00000002 /* inode is newly created */
 #define EXT3_STATE_XATTR               0x00000004 /* has in-inode xattrs */
+#define EXT3_STATE_FLUSH_ON_CLOSE      0x00000008
 
 /* Used to pass group descriptor data when online resize is done */
 struct ext3_new_group_input {
@@ -893,9 +894,8 @@ extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                       u64 start, u64 len);
 
 /* ioctl.c */
-extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
-                      unsigned long);
-extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long);
+extern long ext3_ioctl(struct file *, unsigned int, unsigned long);
+extern long ext3_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* namei.c */
 extern int ext3_orphan_add(handle_t *, struct inode *);
index 31527e17076b7c8697dcf7fdeb9717d8dead779a..f563c50139325b98c11ec5ea492b36d9aa1b7ee3 100644 (file)
@@ -123,6 +123,7 @@ struct dentry;
 #define FB_ACCEL_TRIDENT_3DIMAGE 51    /* Trident 3DImage              */
 #define FB_ACCEL_TRIDENT_BLADE3D 52    /* Trident Blade3D              */
 #define FB_ACCEL_TRIDENT_BLADEXP 53    /* Trident BladeXP              */
+#define FB_ACCEL_CIRRUS_ALPINE   53    /* Cirrus Logic 543x/544x/5480  */
 #define FB_ACCEL_NEOMAGIC_NM2070 90    /* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91    /* NeoMagic NM2090              */
 #define FB_ACCEL_NEOMAGIC_NM2093 92    /* NeoMagic NM2093              */
@@ -960,15 +961,7 @@ extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
 extern struct class *fb_class;
 
-static inline int lock_fb_info(struct fb_info *info)
-{
-       mutex_lock(&info->lock);
-       if (!info->fbops) {
-               mutex_unlock(&info->lock);
-               return 0;
-       }
-       return 1;
-}
+extern int lock_fb_info(struct fb_info *info);
 
 static inline void unlock_fb_info(struct fb_info *info)
 {
index 87e7bfc5ebd7f5e198b324f4b7d6877f664856a7..a09e17c8f5fd9137720b008196aa29f45ff17bfb 100644 (file)
@@ -1741,6 +1741,8 @@ extern void drop_collected_mounts(struct vfsmount *);
 
 extern int vfs_statfs(struct dentry *, struct kstatfs *);
 
+extern int current_umask(void);
+
 /* /sys/fs */
 extern struct kobject *fs_kobj;
 
@@ -1878,12 +1880,25 @@ extern struct block_device *open_by_devnum(dev_t, fmode_t);
 extern void invalidate_bdev(struct block_device *);
 extern int sync_blockdev(struct block_device *bdev);
 extern struct super_block *freeze_bdev(struct block_device *);
+extern void emergency_thaw_all(void);
 extern int thaw_bdev(struct block_device *bdev, struct super_block *sb);
 extern int fsync_bdev(struct block_device *);
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(struct block_device *);
 #else
 static inline void bd_forget(struct inode *inode) {}
+static inline int sync_blockdev(struct block_device *bdev) { return 0; }
+static inline void invalidate_bdev(struct block_device *bdev) {}
+
+static inline struct super_block *freeze_bdev(struct block_device *sb)
+{
+       return NULL;
+}
+
+static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb)
+{
+       return 0;
+}
 #endif
 extern const struct file_operations def_blk_fops;
 extern const struct file_operations def_chr_fops;
index 18b467dbe278bf4b399274ff272355d2984530ce..78a05bfcd8ebd6075b2add0da9da064804e645d6 100644 (file)
@@ -4,12 +4,10 @@
 #include <linux/path.h>
 
 struct fs_struct {
-       atomic_t count; /* This usage count is used by check_unsafe_exec() for
-                        * security checking purposes - therefore it may not be
-                        * incremented, except by clone(CLONE_FS).
-                        */
+       int users;
        rwlock_t lock;
        int umask;
+       int in_exec;
        struct path root, pwd;
 };
 
@@ -19,6 +17,8 @@ extern void exit_fs(struct task_struct *);
 extern void set_fs_root(struct fs_struct *, struct path *);
 extern void set_fs_pwd(struct fs_struct *, struct path *);
 extern struct fs_struct *copy_fs_struct(struct fs_struct *);
-extern void put_fs_struct(struct fs_struct *);
+extern void free_fs_struct(struct fs_struct *);
+extern void daemonize_fs_struct(void);
+extern int unshare_fs_struct(void);
 
 #endif /* _LINUX_FS_STRUCT_H */
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
new file mode 100644 (file)
index 0000000..84d3532
--- /dev/null
@@ -0,0 +1,505 @@
+/* General filesystem caching backing cache interface
+ *
+ * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ *
+ * NOTE!!! See:
+ *
+ *     Documentation/filesystems/caching/backend-api.txt
+ *
+ * for a description of the cache backend interface declared here.
+ */
+
+#ifndef _LINUX_FSCACHE_CACHE_H
+#define _LINUX_FSCACHE_CACHE_H
+
+#include <linux/fscache.h>
+#include <linux/sched.h>
+#include <linux/slow-work.h>
+
+#define NR_MAXCACHES BITS_PER_LONG
+
+struct fscache_cache;
+struct fscache_cache_ops;
+struct fscache_object;
+struct fscache_operation;
+
+/*
+ * cache tag definition
+ */
+struct fscache_cache_tag {
+       struct list_head        link;
+       struct fscache_cache    *cache;         /* cache referred to by this tag */
+       unsigned long           flags;
+#define FSCACHE_TAG_RESERVED   0               /* T if tag is reserved for a cache */
+       atomic_t                usage;
+       char                    name[0];        /* tag name */
+};
+
+/*
+ * cache definition
+ */
+struct fscache_cache {
+       const struct fscache_cache_ops *ops;
+       struct fscache_cache_tag *tag;          /* tag representing this cache */
+       struct kobject          *kobj;          /* system representation of this cache */
+       struct list_head        link;           /* link in list of caches */
+       size_t                  max_index_size; /* maximum size of index data */
+       char                    identifier[36]; /* cache label */
+
+       /* node management */
+       struct work_struct      op_gc;          /* operation garbage collector */
+       struct list_head        object_list;    /* list of data/index objects */
+       struct list_head        op_gc_list;     /* list of ops to be deleted */
+       spinlock_t              object_list_lock;
+       spinlock_t              op_gc_list_lock;
+       atomic_t                object_count;   /* no. of live objects in this cache */
+       struct fscache_object   *fsdef;         /* object for the fsdef index */
+       unsigned long           flags;
+#define FSCACHE_IOERROR                0       /* cache stopped on I/O error */
+#define FSCACHE_CACHE_WITHDRAWN        1       /* cache has been withdrawn */
+};
+
+extern wait_queue_head_t fscache_cache_cleared_wq;
+
+/*
+ * operation to be applied to a cache object
+ * - retrieval initiation operations are done in the context of the process
+ *   that issued them, and not in an async thread pool
+ */
+typedef void (*fscache_operation_release_t)(struct fscache_operation *op);
+typedef void (*fscache_operation_processor_t)(struct fscache_operation *op);
+
+struct fscache_operation {
+       union {
+               struct work_struct fast_work;   /* record for fast ops */
+               struct slow_work slow_work;     /* record for (very) slow ops */
+       };
+       struct list_head        pend_link;      /* link in object->pending_ops */
+       struct fscache_object   *object;        /* object to be operated upon */
+
+       unsigned long           flags;
+#define FSCACHE_OP_TYPE                0x000f  /* operation type */
+#define FSCACHE_OP_FAST                0x0001  /* - fast op, processor may not sleep for disk */
+#define FSCACHE_OP_SLOW                0x0002  /* - (very) slow op, processor may sleep for disk */
+#define FSCACHE_OP_MYTHREAD    0x0003  /* - processing is done be issuing thread, not pool */
+#define FSCACHE_OP_WAITING     4       /* cleared when op is woken */
+#define FSCACHE_OP_EXCLUSIVE   5       /* exclusive op, other ops must wait */
+#define FSCACHE_OP_DEAD                6       /* op is now dead */
+
+       atomic_t                usage;
+       unsigned                debug_id;       /* debugging ID */
+
+       /* operation processor callback
+        * - can be NULL if FSCACHE_OP_WAITING is going to be used to perform
+        *   the op in a non-pool thread */
+       fscache_operation_processor_t processor;
+
+       /* operation releaser */
+       fscache_operation_release_t release;
+};
+
+extern atomic_t fscache_op_debug_id;
+extern const struct slow_work_ops fscache_op_slow_work_ops;
+
+extern void fscache_enqueue_operation(struct fscache_operation *);
+extern void fscache_put_operation(struct fscache_operation *);
+
+/**
+ * fscache_operation_init - Do basic initialisation of an operation
+ * @op: The operation to initialise
+ * @release: The release function to assign
+ *
+ * Do basic initialisation of an operation.  The caller must still set flags,
+ * object, either fast_work or slow_work if necessary, and processor if needed.
+ */
+static inline void fscache_operation_init(struct fscache_operation *op,
+                                         fscache_operation_release_t release)
+{
+       atomic_set(&op->usage, 1);
+       op->debug_id = atomic_inc_return(&fscache_op_debug_id);
+       op->release = release;
+       INIT_LIST_HEAD(&op->pend_link);
+}
+
+/**
+ * fscache_operation_init_slow - Do additional initialisation of a slow op
+ * @op: The operation to initialise
+ * @processor: The processor function to assign
+ *
+ * Do additional initialisation of an operation as required for slow work.
+ */
+static inline
+void fscache_operation_init_slow(struct fscache_operation *op,
+                                fscache_operation_processor_t processor)
+{
+       op->processor = processor;
+       slow_work_init(&op->slow_work, &fscache_op_slow_work_ops);
+}
+
+/*
+ * data read operation
+ */
+struct fscache_retrieval {
+       struct fscache_operation op;
+       struct address_space    *mapping;       /* netfs pages */
+       fscache_rw_complete_t   end_io_func;    /* function to call on I/O completion */
+       void                    *context;       /* netfs read context (pinned) */
+       struct list_head        to_do;          /* list of things to be done by the backend */
+       unsigned long           start_time;     /* time at which retrieval started */
+};
+
+typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op,
+                                            struct page *page,
+                                            gfp_t gfp);
+
+typedef int (*fscache_pages_retrieval_func_t)(struct fscache_retrieval *op,
+                                             struct list_head *pages,
+                                             unsigned *nr_pages,
+                                             gfp_t gfp);
+
+/**
+ * fscache_get_retrieval - Get an extra reference on a retrieval operation
+ * @op: The retrieval operation to get a reference on
+ *
+ * Get an extra reference on a retrieval operation.
+ */
+static inline
+struct fscache_retrieval *fscache_get_retrieval(struct fscache_retrieval *op)
+{
+       atomic_inc(&op->op.usage);
+       return op;
+}
+
+/**
+ * fscache_enqueue_retrieval - Enqueue a retrieval operation for processing
+ * @op: The retrieval operation affected
+ *
+ * Enqueue a retrieval operation for processing by the FS-Cache thread pool.
+ */
+static inline void fscache_enqueue_retrieval(struct fscache_retrieval *op)
+{
+       fscache_enqueue_operation(&op->op);
+}
+
+/**
+ * fscache_put_retrieval - Drop a reference to a retrieval operation
+ * @op: The retrieval operation affected
+ *
+ * Drop a reference to a retrieval operation.
+ */
+static inline void fscache_put_retrieval(struct fscache_retrieval *op)
+{
+       fscache_put_operation(&op->op);
+}
+
+/*
+ * cached page storage work item
+ * - used to do three things:
+ *   - batch writes to the cache
+ *   - do cache writes asynchronously
+ *   - defer writes until cache object lookup completion
+ */
+struct fscache_storage {
+       struct fscache_operation op;
+       pgoff_t                 store_limit;    /* don't write more than this */
+};
+
+/*
+ * cache operations
+ */
+struct fscache_cache_ops {
+       /* name of cache provider */
+       const char *name;
+
+       /* allocate an object record for a cookie */
+       struct fscache_object *(*alloc_object)(struct fscache_cache *cache,
+                                              struct fscache_cookie *cookie);
+
+       /* look up the object for a cookie */
+       void (*lookup_object)(struct fscache_object *object);
+
+       /* finished looking up */
+       void (*lookup_complete)(struct fscache_object *object);
+
+       /* increment the usage count on this object (may fail if unmounting) */
+       struct fscache_object *(*grab_object)(struct fscache_object *object);
+
+       /* pin an object in the cache */
+       int (*pin_object)(struct fscache_object *object);
+
+       /* unpin an object in the cache */
+       void (*unpin_object)(struct fscache_object *object);
+
+       /* store the updated auxilliary data on an object */
+       void (*update_object)(struct fscache_object *object);
+
+       /* discard the resources pinned by an object and effect retirement if
+        * necessary */
+       void (*drop_object)(struct fscache_object *object);
+
+       /* dispose of a reference to an object */
+       void (*put_object)(struct fscache_object *object);
+
+       /* sync a cache */
+       void (*sync_cache)(struct fscache_cache *cache);
+
+       /* notification that the attributes of a non-index object (such as
+        * i_size) have changed */
+       int (*attr_changed)(struct fscache_object *object);
+
+       /* reserve space for an object's data and associated metadata */
+       int (*reserve_space)(struct fscache_object *object, loff_t i_size);
+
+       /* request a backing block for a page be read or allocated in the
+        * cache */
+       fscache_page_retrieval_func_t read_or_alloc_page;
+
+       /* request backing blocks for a list of pages be read or allocated in
+        * the cache */
+       fscache_pages_retrieval_func_t read_or_alloc_pages;
+
+       /* request a backing block for a page be allocated in the cache so that
+        * it can be written directly */
+       fscache_page_retrieval_func_t allocate_page;
+
+       /* request backing blocks for pages be allocated in the cache so that
+        * they can be written directly */
+       fscache_pages_retrieval_func_t allocate_pages;
+
+       /* write a page to its backing block in the cache */
+       int (*write_page)(struct fscache_storage *op, struct page *page);
+
+       /* detach backing block from a page (optional)
+        * - must release the cookie lock before returning
+        * - may sleep
+        */
+       void (*uncache_page)(struct fscache_object *object,
+                            struct page *page);
+
+       /* dissociate a cache from all the pages it was backing */
+       void (*dissociate_pages)(struct fscache_cache *cache);
+};
+
+/*
+ * data file or index object cookie
+ * - a file will only appear in one cache
+ * - a request to cache a file may or may not be honoured, subject to
+ *   constraints such as disk space
+ * - indices are created on disk just-in-time
+ */
+struct fscache_cookie {
+       atomic_t                        usage;          /* number of users of this cookie */
+       atomic_t                        n_children;     /* number of children of this cookie */
+       spinlock_t                      lock;
+       struct hlist_head               backing_objects; /* object(s) backing this file/index */
+       const struct fscache_cookie_def *def;           /* definition */
+       struct fscache_cookie           *parent;        /* parent of this entry */
+       void                            *netfs_data;    /* back pointer to netfs */
+       struct radix_tree_root          stores;         /* pages to be stored on this cookie */
+#define FSCACHE_COOKIE_PENDING_TAG     0               /* pages tag: pending write to cache */
+
+       unsigned long                   flags;
+#define FSCACHE_COOKIE_LOOKING_UP      0       /* T if non-index cookie being looked up still */
+#define FSCACHE_COOKIE_CREATING                1       /* T if non-index object being created still */
+#define FSCACHE_COOKIE_NO_DATA_YET     2       /* T if new object with no cached data yet */
+#define FSCACHE_COOKIE_PENDING_FILL    3       /* T if pending initial fill on object */
+#define FSCACHE_COOKIE_FILLING         4       /* T if filling object incrementally */
+#define FSCACHE_COOKIE_UNAVAILABLE     5       /* T if cookie is unavailable (error, etc) */
+};
+
+extern struct fscache_cookie fscache_fsdef_index;
+
+/*
+ * on-disk cache file or index handle
+ */
+struct fscache_object {
+       enum fscache_object_state {
+               FSCACHE_OBJECT_INIT,            /* object in initial unbound state */
+               FSCACHE_OBJECT_LOOKING_UP,      /* looking up object */
+               FSCACHE_OBJECT_CREATING,        /* creating object */
+
+               /* active states */
+               FSCACHE_OBJECT_AVAILABLE,       /* cleaning up object after creation */
+               FSCACHE_OBJECT_ACTIVE,          /* object is usable */
+               FSCACHE_OBJECT_UPDATING,        /* object is updating */
+
+               /* terminal states */
+               FSCACHE_OBJECT_DYING,           /* object waiting for accessors to finish */
+               FSCACHE_OBJECT_LC_DYING,        /* object cleaning up after lookup/create */
+               FSCACHE_OBJECT_ABORT_INIT,      /* abort the init state */
+               FSCACHE_OBJECT_RELEASING,       /* releasing object */
+               FSCACHE_OBJECT_RECYCLING,       /* retiring object */
+               FSCACHE_OBJECT_WITHDRAWING,     /* withdrawing object */
+               FSCACHE_OBJECT_DEAD,            /* object is now dead */
+       } state;
+
+       int                     debug_id;       /* debugging ID */
+       int                     n_children;     /* number of child objects */
+       int                     n_ops;          /* number of ops outstanding on object */
+       int                     n_obj_ops;      /* number of object ops outstanding on object */
+       int                     n_in_progress;  /* number of ops in progress */
+       int                     n_exclusive;    /* number of exclusive ops queued */
+       spinlock_t              lock;           /* state and operations lock */
+
+       unsigned long           lookup_jif;     /* time at which lookup started */
+       unsigned long           event_mask;     /* events this object is interested in */
+       unsigned long           events;         /* events to be processed by this object
+                                                * (order is important - using fls) */
+#define FSCACHE_OBJECT_EV_REQUEUE      0       /* T if object should be requeued */
+#define FSCACHE_OBJECT_EV_UPDATE       1       /* T if object should be updated */
+#define FSCACHE_OBJECT_EV_CLEARED      2       /* T if accessors all gone */
+#define FSCACHE_OBJECT_EV_ERROR                3       /* T if fatal error occurred during processing */
+#define FSCACHE_OBJECT_EV_RELEASE      4       /* T if netfs requested object release */
+#define FSCACHE_OBJECT_EV_RETIRE       5       /* T if netfs requested object retirement */
+#define FSCACHE_OBJECT_EV_WITHDRAW     6       /* T if cache requested object withdrawal */
+
+       unsigned long           flags;
+#define FSCACHE_OBJECT_LOCK            0       /* T if object is busy being processed */
+#define FSCACHE_OBJECT_PENDING_WRITE   1       /* T if object has pending write */
+#define FSCACHE_OBJECT_WAITING         2       /* T if object is waiting on its parent */
+
+       struct list_head        cache_link;     /* link in cache->object_list */
+       struct hlist_node       cookie_link;    /* link in cookie->backing_objects */
+       struct fscache_cache    *cache;         /* cache that supplied this object */
+       struct fscache_cookie   *cookie;        /* netfs's file/index object */
+       struct fscache_object   *parent;        /* parent object */
+       struct slow_work        work;           /* attention scheduling record */
+       struct list_head        dependents;     /* FIFO of dependent objects */
+       struct list_head        dep_link;       /* link in parent's dependents list */
+       struct list_head        pending_ops;    /* unstarted operations on this object */
+       pgoff_t                 store_limit;    /* current storage limit */
+};
+
+extern const char *fscache_object_states[];
+
+#define fscache_object_is_active(obj)                        \
+       (!test_bit(FSCACHE_IOERROR, &(obj)->cache->flags) &&  \
+        (obj)->state >= FSCACHE_OBJECT_AVAILABLE &&          \
+        (obj)->state < FSCACHE_OBJECT_DYING)
+
+extern const struct slow_work_ops fscache_object_slow_work_ops;
+
+/**
+ * fscache_object_init - Initialise a cache object description
+ * @object: Object description
+ *
+ * Initialise a cache object description to its basic values.
+ *
+ * See Documentation/filesystems/caching/backend-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_object_init(struct fscache_object *object,
+                        struct fscache_cookie *cookie,
+                        struct fscache_cache *cache)
+{
+       atomic_inc(&cache->object_count);
+
+       object->state = FSCACHE_OBJECT_INIT;
+       spin_lock_init(&object->lock);
+       INIT_LIST_HEAD(&object->cache_link);
+       INIT_HLIST_NODE(&object->cookie_link);
+       vslow_work_init(&object->work, &fscache_object_slow_work_ops);
+       INIT_LIST_HEAD(&object->dependents);
+       INIT_LIST_HEAD(&object->dep_link);
+       INIT_LIST_HEAD(&object->pending_ops);
+       object->n_children = 0;
+       object->n_ops = object->n_in_progress = object->n_exclusive = 0;
+       object->events = object->event_mask = 0;
+       object->flags = 0;
+       object->store_limit = 0;
+       object->cache = cache;
+       object->cookie = cookie;
+       object->parent = NULL;
+}
+
+extern void fscache_object_lookup_negative(struct fscache_object *object);
+extern void fscache_obtained_object(struct fscache_object *object);
+
+/**
+ * fscache_object_destroyed - Note destruction of an object in a cache
+ * @cache: The cache from which the object came
+ *
+ * Note the destruction and deallocation of an object record in a cache.
+ */
+static inline void fscache_object_destroyed(struct fscache_cache *cache)
+{
+       if (atomic_dec_and_test(&cache->object_count))
+               wake_up_all(&fscache_cache_cleared_wq);
+}
+
+/**
+ * fscache_object_lookup_error - Note an object encountered an error
+ * @object: The object on which the error was encountered
+ *
+ * Note that an object encountered a fatal error (usually an I/O error) and
+ * that it should be withdrawn as soon as possible.
+ */
+static inline void fscache_object_lookup_error(struct fscache_object *object)
+{
+       set_bit(FSCACHE_OBJECT_EV_ERROR, &object->events);
+}
+
+/**
+ * fscache_set_store_limit - Set the maximum size to be stored in an object
+ * @object: The object to set the maximum on
+ * @i_size: The limit to set in bytes
+ *
+ * Set the maximum size an object is permitted to reach, implying the highest
+ * byte that may be written.  Intended to be called by the attr_changed() op.
+ *
+ * See Documentation/filesystems/caching/backend-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_set_store_limit(struct fscache_object *object, loff_t i_size)
+{
+       object->store_limit = i_size >> PAGE_SHIFT;
+       if (i_size & ~PAGE_MASK)
+               object->store_limit++;
+}
+
+/**
+ * fscache_end_io - End a retrieval operation on a page
+ * @op: The FS-Cache operation covering the retrieval
+ * @page: The page that was to be fetched
+ * @error: The error code (0 if successful)
+ *
+ * Note the end of an operation to retrieve a page, as covered by a particular
+ * operation record.
+ */
+static inline void fscache_end_io(struct fscache_retrieval *op,
+                                 struct page *page, int error)
+{
+       op->end_io_func(page, op->context, error);
+}
+
+/*
+ * out-of-line cache backend functions
+ */
+extern void fscache_init_cache(struct fscache_cache *cache,
+                              const struct fscache_cache_ops *ops,
+                              const char *idfmt,
+                              ...) __attribute__ ((format (printf, 3, 4)));
+
+extern int fscache_add_cache(struct fscache_cache *cache,
+                            struct fscache_object *fsdef,
+                            const char *tagname);
+extern void fscache_withdraw_cache(struct fscache_cache *cache);
+
+extern void fscache_io_error(struct fscache_cache *cache);
+
+extern void fscache_mark_pages_cached(struct fscache_retrieval *op,
+                                     struct pagevec *pagevec);
+
+extern enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
+                                              const void *data,
+                                              uint16_t datalen);
+
+#endif /* _LINUX_FSCACHE_CACHE_H */
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
new file mode 100644 (file)
index 0000000..6d8ee46
--- /dev/null
@@ -0,0 +1,618 @@
+/* General filesystem caching interface
+ *
+ * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ *
+ * NOTE!!! See:
+ *
+ *     Documentation/filesystems/caching/netfs-api.txt
+ *
+ * for a description of the network filesystem interface declared here.
+ */
+
+#ifndef _LINUX_FSCACHE_H
+#define _LINUX_FSCACHE_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/pagemap.h>
+#include <linux/pagevec.h>
+
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+#define fscache_available() (1)
+#define fscache_cookie_valid(cookie) (cookie)
+#else
+#define fscache_available() (0)
+#define fscache_cookie_valid(cookie) (0)
+#endif
+
+
+/*
+ * overload PG_private_2 to give us PG_fscache - this is used to indicate that
+ * a page is currently backed by a local disk cache
+ */
+#define PageFsCache(page)              PagePrivate2((page))
+#define SetPageFsCache(page)           SetPagePrivate2((page))
+#define ClearPageFsCache(page)         ClearPagePrivate2((page))
+#define TestSetPageFsCache(page)       TestSetPagePrivate2((page))
+#define TestClearPageFsCache(page)     TestClearPagePrivate2((page))
+
+/* pattern used to fill dead space in an index entry */
+#define FSCACHE_INDEX_DEADFILL_PATTERN 0x79
+
+struct pagevec;
+struct fscache_cache_tag;
+struct fscache_cookie;
+struct fscache_netfs;
+
+typedef void (*fscache_rw_complete_t)(struct page *page,
+                                     void *context,
+                                     int error);
+
+/* result of index entry consultation */
+enum fscache_checkaux {
+       FSCACHE_CHECKAUX_OKAY,          /* entry okay as is */
+       FSCACHE_CHECKAUX_NEEDS_UPDATE,  /* entry requires update */
+       FSCACHE_CHECKAUX_OBSOLETE,      /* entry requires deletion */
+};
+
+/*
+ * fscache cookie definition
+ */
+struct fscache_cookie_def {
+       /* name of cookie type */
+       char name[16];
+
+       /* cookie type */
+       uint8_t type;
+#define FSCACHE_COOKIE_TYPE_INDEX      0
+#define FSCACHE_COOKIE_TYPE_DATAFILE   1
+
+       /* select the cache into which to insert an entry in this index
+        * - optional
+        * - should return a cache identifier or NULL to cause the cache to be
+        *   inherited from the parent if possible or the first cache picked
+        *   for a non-index file if not
+        */
+       struct fscache_cache_tag *(*select_cache)(
+               const void *parent_netfs_data,
+               const void *cookie_netfs_data);
+
+       /* get an index key
+        * - should store the key data in the buffer
+        * - should return the amount of amount stored
+        * - not permitted to return an error
+        * - the netfs data from the cookie being used as the source is
+        *   presented
+        */
+       uint16_t (*get_key)(const void *cookie_netfs_data,
+                           void *buffer,
+                           uint16_t bufmax);
+
+       /* get certain file attributes from the netfs data
+        * - this function can be absent for an index
+        * - not permitted to return an error
+        * - the netfs data from the cookie being used as the source is
+        *   presented
+        */
+       void (*get_attr)(const void *cookie_netfs_data, uint64_t *size);
+
+       /* get the auxilliary data from netfs data
+        * - this function can be absent if the index carries no state data
+        * - should store the auxilliary data in the buffer
+        * - should return the amount of amount stored
+        * - not permitted to return an error
+        * - the netfs data from the cookie being used as the source is
+        *   presented
+        */
+       uint16_t (*get_aux)(const void *cookie_netfs_data,
+                           void *buffer,
+                           uint16_t bufmax);
+
+       /* consult the netfs about the state of an object
+        * - this function can be absent if the index carries no state data
+        * - the netfs data from the cookie being used as the target is
+        *   presented, as is the auxilliary data
+        */
+       enum fscache_checkaux (*check_aux)(void *cookie_netfs_data,
+                                          const void *data,
+                                          uint16_t datalen);
+
+       /* get an extra reference on a read context
+        * - this function can be absent if the completion function doesn't
+        *   require a context
+        */
+       void (*get_context)(void *cookie_netfs_data, void *context);
+
+       /* release an extra reference on a read context
+        * - this function can be absent if the completion function doesn't
+        *   require a context
+        */
+       void (*put_context)(void *cookie_netfs_data, void *context);
+
+       /* indicate pages that now have cache metadata retained
+        * - this function should mark the specified pages as now being cached
+        * - the pages will have been marked with PG_fscache before this is
+        *   called, so this is optional
+        */
+       void (*mark_pages_cached)(void *cookie_netfs_data,
+                                 struct address_space *mapping,
+                                 struct pagevec *cached_pvec);
+
+       /* indicate the cookie is no longer cached
+        * - this function is called when the backing store currently caching
+        *   a cookie is removed
+        * - the netfs should use this to clean up any markers indicating
+        *   cached pages
+        * - this is mandatory for any object that may have data
+        */
+       void (*now_uncached)(void *cookie_netfs_data);
+};
+
+/*
+ * fscache cached network filesystem type
+ * - name, version and ops must be filled in before registration
+ * - all other fields will be set during registration
+ */
+struct fscache_netfs {
+       uint32_t                        version;        /* indexing version */
+       const char                      *name;          /* filesystem name */
+       struct fscache_cookie           *primary_index;
+       struct list_head                link;           /* internal link */
+};
+
+/*
+ * slow-path functions for when there is actually caching available, and the
+ * netfs does actually have a valid token
+ * - these are not to be called directly
+ * - these are undefined symbols when FS-Cache is not configured and the
+ *   optimiser takes care of not using them
+ */
+extern int __fscache_register_netfs(struct fscache_netfs *);
+extern void __fscache_unregister_netfs(struct fscache_netfs *);
+extern struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *);
+extern void __fscache_release_cache_tag(struct fscache_cache_tag *);
+
+extern struct fscache_cookie *__fscache_acquire_cookie(
+       struct fscache_cookie *,
+       const struct fscache_cookie_def *,
+       void *);
+extern void __fscache_relinquish_cookie(struct fscache_cookie *, int);
+extern void __fscache_update_cookie(struct fscache_cookie *);
+extern int __fscache_attr_changed(struct fscache_cookie *);
+extern int __fscache_read_or_alloc_page(struct fscache_cookie *,
+                                       struct page *,
+                                       fscache_rw_complete_t,
+                                       void *,
+                                       gfp_t);
+extern int __fscache_read_or_alloc_pages(struct fscache_cookie *,
+                                        struct address_space *,
+                                        struct list_head *,
+                                        unsigned *,
+                                        fscache_rw_complete_t,
+                                        void *,
+                                        gfp_t);
+extern int __fscache_alloc_page(struct fscache_cookie *, struct page *, gfp_t);
+extern int __fscache_write_page(struct fscache_cookie *, struct page *, gfp_t);
+extern void __fscache_uncache_page(struct fscache_cookie *, struct page *);
+extern bool __fscache_check_page_write(struct fscache_cookie *, struct page *);
+extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct page *);
+
+/**
+ * fscache_register_netfs - Register a filesystem as desiring caching services
+ * @netfs: The description of the filesystem
+ *
+ * Register a filesystem as desiring caching services if they're available.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_register_netfs(struct fscache_netfs *netfs)
+{
+       if (fscache_available())
+               return __fscache_register_netfs(netfs);
+       else
+               return 0;
+}
+
+/**
+ * fscache_unregister_netfs - Indicate that a filesystem no longer desires
+ * caching services
+ * @netfs: The description of the filesystem
+ *
+ * Indicate that a filesystem no longer desires caching services for the
+ * moment.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_unregister_netfs(struct fscache_netfs *netfs)
+{
+       if (fscache_available())
+               __fscache_unregister_netfs(netfs);
+}
+
+/**
+ * fscache_lookup_cache_tag - Look up a cache tag
+ * @name: The name of the tag to search for
+ *
+ * Acquire a specific cache referral tag that can be used to select a specific
+ * cache in which to cache an index.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name)
+{
+       if (fscache_available())
+               return __fscache_lookup_cache_tag(name);
+       else
+               return NULL;
+}
+
+/**
+ * fscache_release_cache_tag - Release a cache tag
+ * @tag: The tag to release
+ *
+ * Release a reference to a cache referral tag previously looked up.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_release_cache_tag(struct fscache_cache_tag *tag)
+{
+       if (fscache_available())
+               __fscache_release_cache_tag(tag);
+}
+
+/**
+ * fscache_acquire_cookie - Acquire a cookie to represent a cache object
+ * @parent: The cookie that's to be the parent of this one
+ * @def: A description of the cache object, including callback operations
+ * @netfs_data: An arbitrary piece of data to be kept in the cookie to
+ * represent the cache object to the netfs
+ *
+ * This function is used to inform FS-Cache about part of an index hierarchy
+ * that can be used to locate files.  This is done by requesting a cookie for
+ * each index in the path to the file.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+struct fscache_cookie *fscache_acquire_cookie(
+       struct fscache_cookie *parent,
+       const struct fscache_cookie_def *def,
+       void *netfs_data)
+{
+       if (fscache_cookie_valid(parent))
+               return __fscache_acquire_cookie(parent, def, netfs_data);
+       else
+               return NULL;
+}
+
+/**
+ * fscache_relinquish_cookie - Return the cookie to the cache, maybe discarding
+ * it
+ * @cookie: The cookie being returned
+ * @retire: True if the cache object the cookie represents is to be discarded
+ *
+ * This function returns a cookie to the cache, forcibly discarding the
+ * associated cache object if retire is set to true.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
+{
+       if (fscache_cookie_valid(cookie))
+               __fscache_relinquish_cookie(cookie, retire);
+}
+
+/**
+ * fscache_update_cookie - Request that a cache object be updated
+ * @cookie: The cookie representing the cache object
+ *
+ * Request an update of the index data for the cache object associated with the
+ * cookie.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_update_cookie(struct fscache_cookie *cookie)
+{
+       if (fscache_cookie_valid(cookie))
+               __fscache_update_cookie(cookie);
+}
+
+/**
+ * fscache_pin_cookie - Pin a data-storage cache object in its cache
+ * @cookie: The cookie representing the cache object
+ *
+ * Permit data-storage cache objects to be pinned in the cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_pin_cookie(struct fscache_cookie *cookie)
+{
+       return -ENOBUFS;
+}
+
+/**
+ * fscache_pin_cookie - Unpin a data-storage cache object in its cache
+ * @cookie: The cookie representing the cache object
+ *
+ * Permit data-storage cache objects to be unpinned from the cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_unpin_cookie(struct fscache_cookie *cookie)
+{
+}
+
+/**
+ * fscache_attr_changed - Notify cache that an object's attributes changed
+ * @cookie: The cookie representing the cache object
+ *
+ * Send a notification to the cache indicating that an object's attributes have
+ * changed.  This includes the data size.  These attributes will be obtained
+ * through the get_attr() cookie definition op.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_attr_changed(struct fscache_cookie *cookie)
+{
+       if (fscache_cookie_valid(cookie))
+               return __fscache_attr_changed(cookie);
+       else
+               return -ENOBUFS;
+}
+
+/**
+ * fscache_reserve_space - Reserve data space for a cached object
+ * @cookie: The cookie representing the cache object
+ * @i_size: The amount of space to be reserved
+ *
+ * Reserve an amount of space in the cache for the cache object attached to a
+ * cookie so that a write to that object within the space can always be
+ * honoured.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_reserve_space(struct fscache_cookie *cookie, loff_t size)
+{
+       return -ENOBUFS;
+}
+
+/**
+ * fscache_read_or_alloc_page - Read a page from the cache or allocate a block
+ * in which to store it
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page to fill if possible
+ * @end_io_func: The callback to invoke when and if the page is filled
+ * @context: An arbitrary piece of data to pass on to end_io_func()
+ * @gfp: The conditions under which memory allocation should be made
+ *
+ * Read a page from the cache, or if that's not possible make a potential
+ * one-block reservation in the cache into which the page may be stored once
+ * fetched from the server.
+ *
+ * If the page is not backed by the cache object, or if it there's some reason
+ * it can't be, -ENOBUFS will be returned and nothing more will be done for
+ * that page.
+ *
+ * Else, if that page is backed by the cache, a read will be initiated directly
+ * to the netfs's page and 0 will be returned by this function.  The
+ * end_io_func() callback will be invoked when the operation terminates on a
+ * completion or failure.  Note that the callback may be invoked before the
+ * return.
+ *
+ * Else, if the page is unbacked, -ENODATA is returned and a block may have
+ * been allocated in the cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_read_or_alloc_page(struct fscache_cookie *cookie,
+                              struct page *page,
+                              fscache_rw_complete_t end_io_func,
+                              void *context,
+                              gfp_t gfp)
+{
+       if (fscache_cookie_valid(cookie))
+               return __fscache_read_or_alloc_page(cookie, page, end_io_func,
+                                                   context, gfp);
+       else
+               return -ENOBUFS;
+}
+
+/**
+ * fscache_read_or_alloc_pages - Read pages from the cache and/or allocate
+ * blocks in which to store them
+ * @cookie: The cookie representing the cache object
+ * @mapping: The netfs inode mapping to which the pages will be attached
+ * @pages: A list of potential netfs pages to be filled
+ * @end_io_func: The callback to invoke when and if each page is filled
+ * @context: An arbitrary piece of data to pass on to end_io_func()
+ * @gfp: The conditions under which memory allocation should be made
+ *
+ * Read a set of pages from the cache, or if that's not possible, attempt to
+ * make a potential one-block reservation for each page in the cache into which
+ * that page may be stored once fetched from the server.
+ *
+ * If some pages are not backed by the cache object, or if it there's some
+ * reason they can't be, -ENOBUFS will be returned and nothing more will be
+ * done for that pages.
+ *
+ * Else, if some of the pages are backed by the cache, a read will be initiated
+ * directly to the netfs's page and 0 will be returned by this function.  The
+ * end_io_func() callback will be invoked when the operation terminates on a
+ * completion or failure.  Note that the callback may be invoked before the
+ * return.
+ *
+ * Else, if a page is unbacked, -ENODATA is returned and a block may have
+ * been allocated in the cache.
+ *
+ * Because the function may want to return all of -ENOBUFS, -ENODATA and 0 in
+ * regard to different pages, the return values are prioritised in that order.
+ * Any pages submitted for reading are removed from the pages list.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
+                               struct address_space *mapping,
+                               struct list_head *pages,
+                               unsigned *nr_pages,
+                               fscache_rw_complete_t end_io_func,
+                               void *context,
+                               gfp_t gfp)
+{
+       if (fscache_cookie_valid(cookie))
+               return __fscache_read_or_alloc_pages(cookie, mapping, pages,
+                                                    nr_pages, end_io_func,
+                                                    context, gfp);
+       else
+               return -ENOBUFS;
+}
+
+/**
+ * fscache_alloc_page - Allocate a block in which to store a page
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page to allocate a page for
+ * @gfp: The conditions under which memory allocation should be made
+ *
+ * Request Allocation a block in the cache in which to store a netfs page
+ * without retrieving any contents from the cache.
+ *
+ * If the page is not backed by a file then -ENOBUFS will be returned and
+ * nothing more will be done, and no reservation will be made.
+ *
+ * Else, a block will be allocated if one wasn't already, and 0 will be
+ * returned
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_alloc_page(struct fscache_cookie *cookie,
+                      struct page *page,
+                      gfp_t gfp)
+{
+       if (fscache_cookie_valid(cookie))
+               return __fscache_alloc_page(cookie, page, gfp);
+       else
+               return -ENOBUFS;
+}
+
+/**
+ * fscache_write_page - Request storage of a page in the cache
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page to store
+ * @gfp: The conditions under which memory allocation should be made
+ *
+ * Request the contents of the netfs page be written into the cache.  This
+ * request may be ignored if no cache block is currently allocated, in which
+ * case it will return -ENOBUFS.
+ *
+ * If a cache block was already allocated, a write will be initiated and 0 will
+ * be returned.  The PG_fscache_write page bit is set immediately and will then
+ * be cleared at the completion of the write to indicate the success or failure
+ * of the operation.  Note that the completion may happen before the return.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+int fscache_write_page(struct fscache_cookie *cookie,
+                      struct page *page,
+                      gfp_t gfp)
+{
+       if (fscache_cookie_valid(cookie))
+               return __fscache_write_page(cookie, page, gfp);
+       else
+               return -ENOBUFS;
+}
+
+/**
+ * fscache_uncache_page - Indicate that caching is no longer required on a page
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page that was being cached.
+ *
+ * Tell the cache that we no longer want a page to be cached and that it should
+ * remove any knowledge of the netfs page it may have.
+ *
+ * Note that this cannot cancel any outstanding I/O operations between this
+ * page and the cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_uncache_page(struct fscache_cookie *cookie,
+                         struct page *page)
+{
+       if (fscache_cookie_valid(cookie))
+               __fscache_uncache_page(cookie, page);
+}
+
+/**
+ * fscache_check_page_write - Ask if a page is being writing to the cache
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page that is being cached.
+ *
+ * Ask the cache if a page is being written to the cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+bool fscache_check_page_write(struct fscache_cookie *cookie,
+                             struct page *page)
+{
+       if (fscache_cookie_valid(cookie))
+               return __fscache_check_page_write(cookie, page);
+       return false;
+}
+
+/**
+ * fscache_wait_on_page_write - Wait for a page to complete writing to the cache
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page that is being cached.
+ *
+ * Ask the cache to wake us up when a page is no longer being written to the
+ * cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_wait_on_page_write(struct fscache_cookie *cookie,
+                               struct page *page)
+{
+       if (fscache_cookie_valid(cookie))
+               __fscache_wait_on_page_write(cookie, page);
+}
+
+#endif /* _LINUX_FSCACHE_H */
index d9051d717d27e6c96798ca34fe6600fe5f4189db..7ef1caf5026962c4e49ab7c8d3b68430645a60a1 100644 (file)
@@ -95,14 +95,15 @@ struct fsl_usb2_platform_data {
 #define FSL_USB2_PORT0_ENABLED 0x00000001
 #define FSL_USB2_PORT1_ENABLED 0x00000002
 
+struct spi_device;
+
 struct fsl_spi_platform_data {
        u32     initial_spmode; /* initial SPMODE value */
-       u16     bus_num;
+       s16     bus_num;
        bool    qe_mode;
        /* board specific information */
        u16     max_chipselect;
-       void    (*activate_cs)(u8 cs, u8 polarity);
-       void    (*deactivate_cs)(u8 cs, u8 polarity);
+       void    (*cs_control)(struct spi_device *spi, bool on);
        u32     sysclk;
 };
 
index ed21bd3dbd2552a9322a45c943e078d0e6a4e2fc..29ee2873f4a878026595fe6ac1014a91ec8109d6 100644 (file)
@@ -1,68 +1,6 @@
 #ifndef _LINUX_HDREG_H
 #define _LINUX_HDREG_H
 
-#ifdef __KERNEL__
-#include <linux/ata.h>
-
-/*
- * This file contains some defines for the AT-hd-controller.
- * Various sources.
- */
-
-/* ide.c has its own port definitions in "ide.h" */
-
-#define HD_IRQ         14
-
-/* Hd controller regs. Ref: IBM AT Bios-listing */
-#define HD_DATA                0x1f0           /* _CTL when writing */
-#define HD_ERROR       0x1f1           /* see err-bits */
-#define HD_NSECTOR     0x1f2           /* nr of sectors to read/write */
-#define HD_SECTOR      0x1f3           /* starting sector */
-#define HD_LCYL                0x1f4           /* starting cylinder */
-#define HD_HCYL                0x1f5           /* high byte of starting cyl */
-#define HD_CURRENT     0x1f6           /* 101dhhhh , d=drive, hhhh=head */
-#define HD_STATUS      0x1f7           /* see status-bits */
-#define HD_FEATURE     HD_ERROR        /* same io address, read=error, write=feature */
-#define HD_PRECOMP     HD_FEATURE      /* obsolete use of this port - predates IDE */
-#define HD_COMMAND     HD_STATUS       /* same io address, read=status, write=cmd */
-
-#define HD_CMD         0x3f6           /* used for resets */
-#define HD_ALTSTATUS   0x3f6           /* same as HD_STATUS but doesn't clear irq */
-
-/* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
-
-/* Bits of HD_STATUS */
-#define ERR_STAT               0x01
-#define INDEX_STAT             0x02
-#define ECC_STAT               0x04    /* Corrected error */
-#define DRQ_STAT               0x08
-#define SEEK_STAT              0x10
-#define SRV_STAT               0x10
-#define WRERR_STAT             0x20
-#define READY_STAT             0x40
-#define BUSY_STAT              0x80
-
-/* Bits for HD_ERROR */
-#define MARK_ERR               0x01    /* Bad address mark */
-#define ILI_ERR                        0x01    /* Illegal Length Indication (ATAPI) */
-#define TRK0_ERR               0x02    /* couldn't find track 0 */
-#define EOM_ERR                        0x02    /* End Of Media (ATAPI) */
-#define ABRT_ERR               0x04    /* Command aborted */
-#define MCR_ERR                        0x08    /* media change request */
-#define ID_ERR                 0x10    /* ID field not found */
-#define MC_ERR                 0x20    /* media changed */
-#define ECC_ERR                        0x40    /* Uncorrectable ECC error */
-#define BBD_ERR                        0x80    /* pre-EIDE meaning:  block marked bad */
-#define ICRC_ERR               0x80    /* new meaning:  CRC error during transfer */
-#define LFS_ERR                        0xf0    /* Last Failed Sense (ATAPI) */
-
-/* Bits of HD_NSECTOR */
-#define CD                     0x01
-#define IO                     0x02
-#define REL                    0x04
-#define TAG_MASK               0xf8
-#endif /* __KERNEL__ */
-
 #include <linux/types.h>
 
 /*
@@ -191,6 +129,7 @@ typedef struct hd_drive_hob_hdr {
 #define TASKFILE_INVALID               0x7fff
 #endif
 
+#ifndef __KERNEL__
 /* ATA/ATAPI Commands pre T13 Spec */
 #define WIN_NOP                                0x00
 /*
@@ -379,6 +318,7 @@ typedef struct hd_drive_hob_hdr {
 #define SECURITY_ERASE_UNIT            0xBD
 #define SECURITY_FREEZE_LOCK           0xBE
 #define SECURITY_DISABLE_PASSWORD      0xBF
+#endif /* __KERNEL__ */
 
 struct hd_geometry {
       unsigned char heads;
@@ -448,6 +388,7 @@ enum {
 
 #define __NEW_HD_DRIVE_ID
 
+#ifndef __KERNEL__
 /*
  * Structure returned by HDIO_GET_IDENTITY, as per ANSI NCITS ATA6 rev.1b spec.
  *
@@ -699,6 +640,7 @@ struct hd_driveid {
                                         *  7:0 Signature
                                         */
 };
+#endif /* __KERNEL__ */
 
 /*
  * IDE "nice" flags. These are used on a per drive basis to determine
index fa8ee9cef7bec3e228f27304bb31e14d161c0673..a72876e435892cb3ce896e234e84084728434064 100644 (file)
@@ -270,6 +270,7 @@ struct hid_item {
 
 #define HID_QUIRK_INVERT                       0x00000001
 #define HID_QUIRK_NOTOUCH                      0x00000002
+#define HID_QUIRK_IGNORE                       0x00000004
 #define HID_QUIRK_NOGET                                0x00000008
 #define HID_QUIRK_BADPAD                       0x00000020
 #define HID_QUIRK_MULTI_INPUT                  0x00000040
@@ -603,12 +604,17 @@ struct hid_ll_driver {
        int (*open)(struct hid_device *hdev);
        void (*close)(struct hid_device *hdev);
 
+       int (*power)(struct hid_device *hdev, int level);
+
        int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
                        unsigned int code, int value);
 
        int (*parse)(struct hid_device *hdev);
 };
 
+#define        PM_HINT_FULLON  1<<5
+#define PM_HINT_NORMAL 1<<1
+
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
 #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002))
@@ -641,6 +647,7 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int
 void hid_output_report(struct hid_report *report, __u8 *data);
 struct hid_device *hid_allocate_device(void);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_check_keys_pressed(struct hid_device *hid);
 int hid_connect(struct hid_device *hid, unsigned int connect_mask);
 
 /**
@@ -791,21 +798,5 @@ dbg_hid(const char *fmt, ...)
                __FILE__ , ## arg)
 #endif /* HID_FF */
 
-#ifdef __KERNEL__
-#ifdef CONFIG_HID_COMPAT
-#define HID_COMPAT_LOAD_DRIVER(name)   \
-/* prototype to avoid sparse warning */        \
-extern void hid_compat_##name(void);   \
-void hid_compat_##name(void) { }       \
-EXPORT_SYMBOL(hid_compat_##name)
-#else
-#define HID_COMPAT_LOAD_DRIVER(name)
-#endif /* HID_COMPAT */
-#define HID_COMPAT_CALL_DRIVER(name)   do {    \
-       extern void hid_compat_##name(void);    \
-       hid_compat_##name();                    \
-} while (0)
-#endif /* __KERNEL__ */
-
 #endif
 
index 13875ce9112ac0163b28e0816f20164e1ec39bae..1fcb7126a01f1aa3e7a4c63abd46c4311946c843 100644 (file)
@@ -19,8 +19,21 @@ static inline void flush_kernel_dcache_page(struct page *page)
 }
 #endif
 
-#ifdef CONFIG_HIGHMEM
+#include <asm/kmap_types.h>
+
+#if defined(CONFIG_DEBUG_HIGHMEM) && defined(CONFIG_TRACE_IRQFLAGS_SUPPORT)
+
+void debug_kmap_atomic(enum km_type type);
 
+#else
+
+static inline void debug_kmap_atomic(enum km_type type)
+{
+}
+
+#endif
+
+#ifdef CONFIG_HIGHMEM
 #include <asm/highmem.h>
 
 /* declarations for linux/mm/highmem.c */
@@ -44,8 +57,6 @@ static inline void *kmap(struct page *page)
 
 #define kunmap(page) do { (void) (page); } while (0)
 
-#include <asm/kmap_types.h>
-
 static inline void *kmap_atomic(struct page *page, enum km_type idx)
 {
        pagefault_disable();
index f6edd522a929f0705b403328191c2fb8581aaebc..8ace93024d60f96cb054f404c3d6381b786eb105 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_AT24_H
 
 #include <linux/types.h>
+#include <linux/memory.h>
 
 /*
  * As seen through Linux I2C, differences between the most common types of I2C
@@ -23,6 +24,9 @@ struct at24_platform_data {
 #define AT24_FLAG_READONLY     0x40    /* sysfs-entry will be read-only */
 #define AT24_FLAG_IRUGO                0x20    /* sysfs-entry will be world-readable */
 #define AT24_FLAG_TAKE8ADDR    0x10    /* take always 8 addresses (24c00) */
+
+       void            (*setup)(struct memory_accessor *, void *context);
+       void            *context;
 };
 
 #endif /* _LINUX_AT24_H */
index 8137f660a5cc58a3768d498d6b77ed9dc25ad12f..0dc80ef249752dea6c1d1cb735d6200341f46a9e 100644 (file)
@@ -218,6 +218,53 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 
 /*----------------------------------------------------------------------*/
 
+/* Power bus message definitions */
+
+#define DEV_GRP_NULL           0x0
+#define DEV_GRP_P1             0x1
+#define DEV_GRP_P2             0x2
+#define DEV_GRP_P3             0x4
+
+#define RES_GRP_RES            0x0
+#define RES_GRP_PP             0x1
+#define RES_GRP_RC             0x2
+#define RES_GRP_PP_RC          0x3
+#define RES_GRP_PR             0x4
+#define RES_GRP_PP_PR          0x5
+#define RES_GRP_RC_PR          0x6
+#define RES_GRP_ALL            0x7
+
+#define RES_TYPE2_R0           0x0
+
+#define RES_TYPE_ALL           0x7
+
+#define RES_STATE_WRST         0xF
+#define RES_STATE_ACTIVE       0xE
+#define RES_STATE_SLEEP                0x8
+#define RES_STATE_OFF          0x0
+
+/*
+ * Power Bus Message Format ... these can be sent individually by Linux,
+ * but are usually part of downloaded scripts that are run when various
+ * power events are triggered.
+ *
+ *  Broadcast Message (16 Bits):
+ *    DEV_GRP[15:13] MT[12]  RES_GRP[11:9]  RES_TYPE2[8:7] RES_TYPE[6:4]
+ *    RES_STATE[3:0]
+ *
+ *  Singular Message (16 Bits):
+ *    DEV_GRP[15:13] MT[12]  RES_ID[11:4]  RES_STATE[3:0]
+ */
+
+#define MSG_BROADCAST(devgrp, grp, type, type2, state) \
+       ( (devgrp) << 13 | 1 << 12 | (grp) << 9 | (type2) << 7 \
+       | (type) << 4 | (state))
+
+#define MSG_SINGULAR(devgrp, id, state) \
+       ((devgrp) << 13 | 0 << 12 | (id) << 4 | (state))
+
+/*----------------------------------------------------------------------*/
+
 struct twl4030_bci_platform_data {
        int *battery_tmp_tbl;
        unsigned int tblsize;
index d5d832271f44255c8ae406d86ade64f7da7378a8..a5d26f66ef78b3b784b7ceebe32b459c09af4963 100644 (file)
@@ -265,7 +265,7 @@ enum {
        IDE_TFLAG_WRITE                 = (1 << 12),
        IDE_TFLAG_CUSTOM_HANDLER        = (1 << 13),
        IDE_TFLAG_DMA_PIO_FALLBACK      = (1 << 14),
-       IDE_TFLAG_IN_HOB_FEATURE        = (1 << 15),
+       IDE_TFLAG_IN_HOB_ERROR          = (1 << 15),
        IDE_TFLAG_IN_HOB_NSECT          = (1 << 16),
        IDE_TFLAG_IN_HOB_LBAL           = (1 << 17),
        IDE_TFLAG_IN_HOB_LBAM           = (1 << 18),
@@ -273,10 +273,10 @@ enum {
        IDE_TFLAG_IN_HOB_LBA            = IDE_TFLAG_IN_HOB_LBAL |
                                          IDE_TFLAG_IN_HOB_LBAM |
                                          IDE_TFLAG_IN_HOB_LBAH,
-       IDE_TFLAG_IN_HOB                = IDE_TFLAG_IN_HOB_FEATURE |
+       IDE_TFLAG_IN_HOB                = IDE_TFLAG_IN_HOB_ERROR |
                                          IDE_TFLAG_IN_HOB_NSECT |
                                          IDE_TFLAG_IN_HOB_LBA,
-       IDE_TFLAG_IN_FEATURE            = (1 << 20),
+       IDE_TFLAG_IN_ERROR              = (1 << 20),
        IDE_TFLAG_IN_NSECT              = (1 << 21),
        IDE_TFLAG_IN_LBAL               = (1 << 22),
        IDE_TFLAG_IN_LBAM               = (1 << 23),
@@ -310,8 +310,12 @@ enum {
 
 struct ide_taskfile {
        u8      hob_data;       /*  0: high data byte (for TASKFILE IOCTL) */
+                               /*  1-5: additional data to support LBA48 */
+       union {
+               u8 hob_error;   /*   read: error */
+               u8 hob_feature; /*  write: feature */
+       };
 
-       u8      hob_feature;    /*  1-5: additional data to support LBA48 */
        u8      hob_nsect;
        u8      hob_lbal;
        u8      hob_lbam;
@@ -352,6 +356,8 @@ struct ide_cmd {
 
        unsigned int            nbytes;
        unsigned int            nleft;
+       unsigned int            last_xfer_len;
+
        struct scatterlist      *cursg;
        unsigned int            cursg_ofs;
 
@@ -375,7 +381,7 @@ enum {
  * With each packet command, we allocate a buffer of IDE_PC_BUFFER_SIZE bytes.
  * This is used for several packet commands (not for READ/WRITE commands).
  */
-#define IDE_PC_BUFFER_SIZE     256
+#define IDE_PC_BUFFER_SIZE     64
 #define ATAPI_WAIT_PC          (60 * HZ)
 
 struct ide_atapi_pc {
@@ -413,9 +419,6 @@ struct ide_atapi_pc {
        struct idetape_bh *bh;
        char *b_data;
 
-       struct scatterlist *sg;
-       unsigned int sg_cnt;
-
        unsigned long timeout;
 };
 
@@ -456,11 +459,6 @@ enum {
        IDE_AFLAG_TOCADDR_AS_BCD        = (1 << 3),
        /* TOC track numbers are in BCD. */
        IDE_AFLAG_TOCTRACKS_AS_BCD      = (1 << 4),
-       /*
-        * Drive does not provide data in multiples of SECTOR_SIZE
-        * when more than one interrupt is needed.
-        */
-       IDE_AFLAG_LIMIT_NFRAMES         = (1 << 5),
        /* Saved TOC information is current. */
        IDE_AFLAG_TOC_VALID             = (1 << 6),
        /* We think that the drive door is locked. */
@@ -605,7 +603,7 @@ struct ide_drive_s {
 
        unsigned int    bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
        unsigned int    cyl;            /* "real" number of cyls */
-       unsigned int    drive_data;     /* used by set_pio_mode/selectproc */
+       unsigned int    drive_data;     /* used by set_pio_mode/dev_select() */
        unsigned int    failures;       /* current failure count */
        unsigned int    max_failures;   /* maximum allowed failure count */
        u64             probed_capacity;/* initial reported media capacity (ide-cd only currently) */
@@ -661,9 +659,9 @@ struct ide_tp_ops {
        void    (*exec_command)(struct hwif_s *, u8);
        u8      (*read_status)(struct hwif_s *);
        u8      (*read_altstatus)(struct hwif_s *);
+       void    (*write_devctl)(struct hwif_s *, u8);
 
-       void    (*set_irq)(struct hwif_s *, int);
-
+       void    (*dev_select)(ide_drive_t *);
        void    (*tf_load)(ide_drive_t *, struct ide_cmd *);
        void    (*tf_read)(ide_drive_t *, struct ide_cmd *);
 
@@ -681,7 +679,6 @@ extern const struct ide_tp_ops default_tp_ops;
  * @init_dev:          host specific initialization of a device
  * @set_pio_mode:      routine to program host for PIO mode
  * @set_dma_mode:      routine to program host for DMA mode
- * @selectproc:                tweaks hardware to select drive
  * @reset_poll:                chipset polling based on hba specifics
  * @pre_reset:         chipset specific changes to default for device-hba resets
  * @resetproc:         routine to reset controller after a disk reset
@@ -698,7 +695,6 @@ struct ide_port_ops {
        void    (*init_dev)(ide_drive_t *);
        void    (*set_pio_mode)(ide_drive_t *, const u8);
        void    (*set_dma_mode)(ide_drive_t *, const u8);
-       void    (*selectproc)(ide_drive_t *);
        int     (*reset_poll)(ide_drive_t *);
        void    (*pre_reset)(ide_drive_t *);
        void    (*resetproc)(ide_drive_t *);
@@ -719,8 +715,10 @@ struct ide_dma_ops {
        int     (*dma_end)(struct ide_drive_s *);
        int     (*dma_test_irq)(struct ide_drive_s *);
        void    (*dma_lost_irq)(struct ide_drive_s *);
+       /* below ones are optional */
+       int     (*dma_check)(struct ide_drive_s *, struct ide_cmd *);
        int     (*dma_timer_expiry)(struct ide_drive_s *);
-       void    (*dma_timeout)(struct ide_drive_s *);
+       void    (*dma_clear)(struct ide_drive_s *);
        /*
         * The following method is optional and only required to be
         * implemented for the SFF-8038i compatible controllers.
@@ -1169,18 +1167,15 @@ void ide_tf_dump(const char *, struct ide_taskfile *);
 void ide_exec_command(ide_hwif_t *, u8);
 u8 ide_read_status(ide_hwif_t *);
 u8 ide_read_altstatus(ide_hwif_t *);
+void ide_write_devctl(ide_hwif_t *, u8);
 
-void ide_set_irq(ide_hwif_t *, int);
-
+void ide_dev_select(ide_drive_t *);
 void ide_tf_load(ide_drive_t *, struct ide_cmd *);
 void ide_tf_read(ide_drive_t *, struct ide_cmd *);
 
 void ide_input_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int);
 void ide_output_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int);
 
-int ide_io_buffers(ide_drive_t *, struct ide_atapi_pc *, unsigned int, int);
-
-extern void SELECT_DRIVE(ide_drive_t *);
 void SELECT_MASK(ide_drive_t *, int);
 
 u8 ide_read_error(ide_drive_t *);
@@ -1226,6 +1221,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *, struct ide_cmd *);
 
 ide_startstop_t do_rw_taskfile(ide_drive_t *, struct ide_cmd *);
 
+void ide_pio_bytes(ide_drive_t *, struct ide_cmd *, unsigned int, unsigned int);
+
 void ide_finish_cmd(ide_drive_t *, struct ide_cmd *, u8);
 
 int ide_raw_taskfile(ide_drive_t *, struct ide_cmd *, u8 *, u16);
@@ -1443,8 +1440,8 @@ ide_startstop_t ide_dma_intr(ide_drive_t *);
 int ide_allocate_dma_engine(ide_hwif_t *);
 void ide_release_dma_engine(ide_hwif_t *);
 
-int ide_build_sglist(ide_drive_t *, struct ide_cmd *);
-void ide_destroy_dmatable(ide_drive_t *);
+int ide_dma_prepare(ide_drive_t *, struct ide_cmd *);
+void ide_dma_unmap_sg(ide_drive_t *, struct ide_cmd *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_SFF
 int config_drive_for_dma(ide_drive_t *);
@@ -1462,7 +1459,6 @@ static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
 #endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
 
 void ide_dma_lost_irq(ide_drive_t *);
-void ide_dma_timeout(ide_drive_t *);
 ide_startstop_t ide_dma_timeout_retry(ide_drive_t *, int);
 
 #else
@@ -1478,8 +1474,10 @@ static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
 static inline ide_startstop_t ide_dma_intr(ide_drive_t *drive) { return ide_stopped; }
 static inline ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { return ide_stopped; }
 static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; }
-static inline int ide_build_sglist(ide_drive_t *drive,
-                                  struct ide_cmd *cmd) { return 0; }
+static inline int ide_dma_prepare(ide_drive_t *drive,
+                                 struct ide_cmd *cmd) { return 1; }
+static inline void ide_dma_unmap_sg(ide_drive_t *drive,
+                                   struct ide_cmd *cmd) { ; }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
index dd846df8cd32182f6740ea59f6451079deb3060d..e968db71e33a94548160cb38c216289ab1577c30 100644 (file)
@@ -106,6 +106,7 @@ int idr_get_new(struct idr *idp, void *ptr, int *id);
 int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
 int idr_for_each(struct idr *idp,
                 int (*fn)(int id, void *p, void *data), void *data);
+void *idr_get_next(struct idr *idp, int *nextid);
 void *idr_replace(struct idr *idp, void *ptr, int id);
 void idr_remove(struct idr *idp, int id);
 void idr_remove_all(struct idr *idp);
index 1d6c71d96edeac0d730fb178e91120bebe695300..77214ead1a36343ee4267647c00fd9bd9e3d28c8 100644 (file)
@@ -123,7 +123,7 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 #define ecap_eim_support(e)    ((e >> 4) & 0x1)
 #define ecap_ir_support(e)     ((e >> 3) & 0x1)
 #define ecap_max_handle_mask(e) ((e >> 20) & 0xf)
-
+#define ecap_sc_support(e)     ((e >> 7) & 0x1) /* Snooping Control */
 
 /* IOTLB_REG */
 #define DMA_TLB_FLUSH_GRANU_OFFSET  60
index 0c9cb63e689530cfbc6a060b8a0b07ff2175bd62..c68bffd182bbe4d977848fd3507150da83be4d7b 100644 (file)
@@ -117,6 +117,15 @@ extern void disable_irq_nosync(unsigned int irq);
 extern void disable_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
 
+/* The following three functions are for the core kernel use only. */
+extern void suspend_device_irqs(void);
+extern void resume_device_irqs(void);
+#ifdef CONFIG_PM_SLEEP
+extern int check_wakeup_irqs(void);
+#else
+static inline int check_wakeup_irqs(void) { return 0; }
+#endif
+
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
 
 extern cpumask_var_t irq_default_affinity;
index 8a7bfb1b6ca09c4275b99187b74c807bd6bdb9ae..3af4ffd591b978c4f7f815a5952131a0b673aa13 100644 (file)
@@ -21,6 +21,7 @@
 
 #define IOMMU_READ     (1)
 #define IOMMU_WRITE    (2)
+#define IOMMU_CACHE    (4) /* DMA cache coherency */
 
 struct device;
 
@@ -28,6 +29,8 @@ struct iommu_domain {
        void *priv;
 };
 
+#define IOMMU_CAP_CACHE_COHERENCY      0x1
+
 struct iommu_ops {
        int (*domain_init)(struct iommu_domain *domain);
        void (*domain_destroy)(struct iommu_domain *domain);
@@ -39,6 +42,8 @@ struct iommu_ops {
                      size_t size);
        phys_addr_t (*iova_to_phys)(struct iommu_domain *domain,
                                    unsigned long iova);
+       int (*domain_has_cap)(struct iommu_domain *domain,
+                             unsigned long cap);
 };
 
 #ifdef CONFIG_IOMMU_API
@@ -57,6 +62,8 @@ extern void iommu_unmap_range(struct iommu_domain *domain, unsigned long iova,
                              size_t size);
 extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
                                      unsigned long iova);
+extern int iommu_domain_has_cap(struct iommu_domain *domain,
+                               unsigned long cap);
 
 #else /* CONFIG_IOMMU_API */
 
@@ -107,6 +114,12 @@ static inline phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
        return 0;
 }
 
+static inline int domain_has_cap(struct iommu_domain *domain,
+                                unsigned long cap)
+{
+       return 0;
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
index 62b73668b60247c06da84bc8cca6919a9a34f6d6..f7c9c75a277547e7a6e8278d6f4da77a62eb3746 100644 (file)
@@ -230,6 +230,6 @@ static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
    automatically be dstroyed when the interface is destroyed. */
 int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
                            read_proc_t *read_proc,
-                           void *data, struct module *owner);
+                           void *data);
 
 #endif /* __LINUX_IPMI_SMI_H */
index 9c62fbe2ef3016ccb087e9694c48e420b0f9fc0c..974890b3c52fbfe0048df3cf7d736798caf873b6 100644 (file)
@@ -67,6 +67,7 @@ typedef       void (*irq_flow_handler_t)(unsigned int irq,
 #define IRQ_SPURIOUS_DISABLED  0x00800000      /* IRQ was disabled by the spurious trap */
 #define IRQ_MOVE_PCNTXT                0x01000000      /* IRQ migration from process context */
 #define IRQ_AFFINITY_SET       0x02000000      /* IRQ affinity was set from userspace*/
+#define IRQ_SUSPENDED          0x04000000      /* IRQ has gone through suspend sequence */
 
 #ifdef CONFIG_IRQ_PER_CPU
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
index 74bde13224c926f5204a2c514609def00d465325..b02a3f1d46a0595788b86220bcbee174171ad78c 100644 (file)
@@ -24,8 +24,8 @@
 # define trace_softirqs_enabled(p)     ((p)->softirqs_enabled)
 # define trace_hardirq_enter() do { current->hardirq_context++; } while (0)
 # define trace_hardirq_exit()  do { current->hardirq_context--; } while (0)
-# define trace_softirq_enter() do { current->softirq_context++; } while (0)
-# define trace_softirq_exit()  do { current->softirq_context--; } while (0)
+# define lockdep_softirq_enter()       do { current->softirq_context++; } while (0)
+# define lockdep_softirq_exit()        do { current->softirq_context--; } while (0)
 # define INIT_TRACE_IRQFLAGS   .softirqs_enabled = 1,
 #else
 # define trace_hardirqs_on()           do { } while (0)
@@ -38,8 +38,8 @@
 # define trace_softirqs_enabled(p)     0
 # define trace_hardirq_enter()         do { } while (0)
 # define trace_hardirq_exit()          do { } while (0)
-# define trace_softirq_enter()         do { } while (0)
-# define trace_softirq_exit()          do { } while (0)
+# define lockdep_softirq_enter()       do { } while (0)
+# define lockdep_softirq_exit()                do { } while (0)
 # define INIT_TRACE_IRQFLAGS
 #endif
 
index 64246dce5663079b5f69afe9eabc05efc3e1229e..53ae4399da2d6e2e3867639183a768a43d1786ee 100644 (file)
@@ -35,7 +35,7 @@
 #define journal_oom_retry 1
 
 /*
- * Define JBD_PARANIOD_IOFAIL to cause a kernel BUG() if ext3 finds
+ * Define JBD_PARANOID_IOFAIL to cause a kernel BUG() if ext3 finds
  * certain classes of error which can occur due to failed IOs.  Under
  * normal use we want ext3 to continue after such errors, because
  * hardware _can_ fail, but for debugging purposes when running tests on
@@ -552,6 +552,11 @@ struct transaction_s
         */
        int t_handle_count;
 
+       /*
+        * This transaction is being forced and some process is
+        * waiting for it to finish.
+        */
+       int t_synchronous_commit:1;
 };
 
 /**
index 4d248b3f1323d828170a9de92d2aba1db7c5f0f4..8815a3456b3bf9a78915cabed347779667aefba3 100644 (file)
@@ -648,6 +648,12 @@ struct transaction_s
         */
        int t_handle_count;
 
+       /*
+        * This transaction is being forced and some process is
+        * waiting for it to finish.
+        */
+       int t_synchronous_commit:1;
+
        /*
         * For use by the filesystem to store fs-specific data
         * structures associated with the transaction
index 914918abfdd122a5bf9a6c564fd7c41693917c9b..556d781e69fe2220fd88696de68da014ae963d12 100644 (file)
@@ -242,6 +242,7 @@ extern struct ratelimit_state printk_ratelimit_state;
 extern int printk_ratelimit(void);
 extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
                                   unsigned int interval_msec);
+void log_buf_kexec_setup(void);
 #else
 static inline int vprintk(const char *s, va_list args)
        __attribute__ ((format (printf, 1, 0)));
@@ -253,6 +254,9 @@ static inline int printk_ratelimit(void) { return 0; }
 static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \
                                          unsigned int interval_msec)   \
                { return false; }
+static inline void log_buf_kexec_setup(void)
+{
+}
 #endif
 
 extern int printk_needs_cpu(int cpu);
@@ -353,6 +357,8 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
         printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_info(fmt, ...) \
         printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_cont(fmt, ...) \
+       printk(KERN_CONT fmt, ##__VA_ARGS__)
 
 /* If you are writing a driver, please use dev_dbg instead */
 #if defined(DEBUG)
@@ -379,18 +385,6 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
        ((unsigned char *)&addr)[3]
 #define NIPQUAD_FMT "%u.%u.%u.%u"
 
-#if defined(__LITTLE_ENDIAN)
-#define HIPQUAD(addr) \
-       ((unsigned char *)&addr)[3], \
-       ((unsigned char *)&addr)[2], \
-       ((unsigned char *)&addr)[1], \
-       ((unsigned char *)&addr)[0]
-#elif defined(__BIG_ENDIAN)
-#define HIPQUAD        NIPQUAD
-#else
-#error "Please fix asm/byteorder.h"
-#endif /* __LITTLE_ENDIAN */
-
 /*
  * min()/max()/clamp() macros that also do
  * strict type-checking.. See the
index 76262d83656bd108d4bca3b72be5fb16a5540539..b450a2628855214aea4057dc25c1bb5f7bee0279 100644 (file)
@@ -379,7 +379,7 @@ enum {
        ATA_HORKAGE_BRIDGE_OK   = (1 << 10),    /* no bridge limits */
        ATA_HORKAGE_ATAPI_MOD16_DMA = (1 << 11), /* use ATAPI DMA for commands
                                                    not multiple of 16 bytes */
-       ATA_HORKAGE_FIRMWARE_WARN = (1 << 12),  /* firwmare update warning */
+       ATA_HORKAGE_FIRMWARE_WARN = (1 << 12),  /* firmware update warning */
        ATA_HORKAGE_1_5_GBPS    = (1 << 13),    /* force 1.5 Gbps */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
index 23bf02fb124ffae0dfb282453582385ea34d1919..da5a5a1f4cd2ec17fb2a5f544cc71f8e800b2d10 100644 (file)
@@ -20,43 +20,10 @@ struct lockdep_map;
 #include <linux/stacktrace.h>
 
 /*
- * Lock-class usage-state bits:
+ * We'd rather not expose kernel/lockdep_states.h this wide, but we do need
+ * the total number of states... :-(
  */
-enum lock_usage_bit
-{
-       LOCK_USED = 0,
-       LOCK_USED_IN_HARDIRQ,
-       LOCK_USED_IN_SOFTIRQ,
-       LOCK_ENABLED_SOFTIRQS,
-       LOCK_ENABLED_HARDIRQS,
-       LOCK_USED_IN_HARDIRQ_READ,
-       LOCK_USED_IN_SOFTIRQ_READ,
-       LOCK_ENABLED_SOFTIRQS_READ,
-       LOCK_ENABLED_HARDIRQS_READ,
-       LOCK_USAGE_STATES
-};
-
-/*
- * Usage-state bitmasks:
- */
-#define LOCKF_USED                     (1 << LOCK_USED)
-#define LOCKF_USED_IN_HARDIRQ          (1 << LOCK_USED_IN_HARDIRQ)
-#define LOCKF_USED_IN_SOFTIRQ          (1 << LOCK_USED_IN_SOFTIRQ)
-#define LOCKF_ENABLED_HARDIRQS         (1 << LOCK_ENABLED_HARDIRQS)
-#define LOCKF_ENABLED_SOFTIRQS         (1 << LOCK_ENABLED_SOFTIRQS)
-
-#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS)
-#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ)
-
-#define LOCKF_USED_IN_HARDIRQ_READ     (1 << LOCK_USED_IN_HARDIRQ_READ)
-#define LOCKF_USED_IN_SOFTIRQ_READ     (1 << LOCK_USED_IN_SOFTIRQ_READ)
-#define LOCKF_ENABLED_HARDIRQS_READ    (1 << LOCK_ENABLED_HARDIRQS_READ)
-#define LOCKF_ENABLED_SOFTIRQS_READ    (1 << LOCK_ENABLED_SOFTIRQS_READ)
-
-#define LOCKF_ENABLED_IRQS_READ \
-               (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ)
-#define LOCKF_USED_IN_IRQ_READ \
-               (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ)
+#define XXX_LOCK_USAGE_STATES          (1+3*4)
 
 #define MAX_LOCKDEP_SUBCLASSES         8UL
 
@@ -97,7 +64,7 @@ struct lock_class {
         * IRQ/softirq usage tracking bits:
         */
        unsigned long                   usage_mask;
-       struct stack_trace              usage_traces[LOCK_USAGE_STATES];
+       struct stack_trace              usage_traces[XXX_LOCK_USAGE_STATES];
 
        /*
         * These fields represent a directed graph of lock dependencies,
@@ -324,7 +291,11 @@ static inline void lock_set_subclass(struct lockdep_map *lock,
        lock_set_class(lock, lock->name, lock->key, subclass, ip);
 }
 
-# define INIT_LOCKDEP                          .lockdep_recursion = 0,
+extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask);
+extern void lockdep_clear_current_reclaim_state(void);
+extern void lockdep_trace_alloc(gfp_t mask);
+
+# define INIT_LOCKDEP                          .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
 
 #define lockdep_depth(tsk)     (debug_locks ? (tsk)->lockdep_depth : 0)
 
@@ -342,6 +313,9 @@ static inline void lockdep_on(void)
 # define lock_release(l, n, i)                 do { } while (0)
 # define lock_set_class(l, n, k, s, i)         do { } while (0)
 # define lock_set_subclass(l, s, i)            do { } while (0)
+# define lockdep_set_current_reclaim_state(g)  do { } while (0)
+# define lockdep_clear_current_reclaim_state() do { } while (0)
+# define lockdep_trace_alloc(g)                        do { } while (0)
 # define lockdep_init()                                do { } while (0)
 # define lockdep_info()                                do { } while (0)
 # define lockdep_init_map(lock, name, key, sub) \
@@ -390,6 +364,23 @@ do {                                                               \
 
 #endif /* CONFIG_LOCK_STAT */
 
+#ifdef CONFIG_LOCKDEP
+
+/*
+ * On lockdep we dont want the hand-coded irq-enable of
+ * _raw_*_lock_flags() code, because lockdep assumes
+ * that interrupts are not re-enabled during lock-acquire:
+ */
+#define LOCK_CONTENDED_FLAGS(_lock, try, lock, lockfl, flags) \
+       LOCK_CONTENDED((_lock), (try), (lock))
+
+#else /* CONFIG_LOCKDEP */
+
+#define LOCK_CONTENDED_FLAGS(_lock, try, lock, lockfl, flags) \
+       lockfl((_lock), (flags))
+
+#endif /* CONFIG_LOCKDEP */
+
 #ifdef CONFIG_GENERIC_HARDIRQS
 extern void early_init_irq_lock_class(void);
 #else
index 6ffd6db5bb0d746c2a92deb358c450b2989b5c61..40725447f5e0e958ef58097636603f00ca3d04e0 100644 (file)
@@ -160,5 +160,6 @@ int loop_unregister_transfer(int number);
 #define LOOP_SET_STATUS64      0x4C04
 #define LOOP_GET_STATUS64      0x4C05
 #define LOOP_CHANGE_FD         0x4C06
+#define LOOP_SET_CAPACITY      0x4C07
 
 #endif
index 326f45c86530302c6e94ba8a872971bf7474646c..18146c980b68b33d5aafdd8403531f5548dd545a 100644 (file)
@@ -88,9 +88,6 @@ extern void mem_cgroup_end_migration(struct mem_cgroup *mem,
 /*
  * For memory reclaim.
  */
-extern int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem);
-extern long mem_cgroup_reclaim_imbalance(struct mem_cgroup *mem);
-
 extern int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem);
 extern void mem_cgroup_note_reclaim_priority(struct mem_cgroup *mem,
                                                        int priority);
@@ -104,6 +101,8 @@ struct zone_reclaim_stat *mem_cgroup_get_reclaim_stat(struct mem_cgroup *memcg,
                                                      struct zone *zone);
 struct zone_reclaim_stat*
 mem_cgroup_get_reclaim_stat_from_page(struct page *page);
+extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
+                                       struct task_struct *p);
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 extern int do_swap_account;
@@ -209,16 +208,6 @@ static inline void mem_cgroup_end_migration(struct mem_cgroup *mem,
 {
 }
 
-static inline int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem)
-{
-       return 0;
-}
-
-static inline int mem_cgroup_reclaim_imbalance(struct mem_cgroup *mem)
-{
-       return 0;
-}
-
 static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem)
 {
        return 0;
@@ -270,6 +259,11 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
        return NULL;
 }
 
+static inline void
+mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
+{
+}
+
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #endif /* _LINUX_MEMCONTROL_H */
index 3fdc10806d31b9f55470dc3fc3949653ceb1498d..42767d1a62e784e9ce25dfbc9cc37ab9232f226a 100644 (file)
@@ -99,4 +99,15 @@ enum mem_add_context { BOOT, HOTPLUG };
 #define hotplug_memory_notifier(fn, pri) do { } while (0)
 #endif
 
+/*
+ * 'struct memory_accessor' is a generic interface to provide
+ * in-kernel access to persistent memory such as i2c or SPI EEPROMs
+ */
+struct memory_accessor {
+       ssize_t (*read)(struct memory_accessor *, char *buf, off_t offset,
+                       size_t count);
+       ssize_t (*write)(struct memory_accessor *, const char *buf,
+                        off_t offset, size_t count);
+};
+
 #endif /* _LINUX_MEMORY_H_ */
index b1ea37fc7a24598956b766e33654253f156e8125..bff1f0d475c7593240d5a464ae8ecc7c03e07299 100644 (file)
@@ -135,6 +135,7 @@ extern pgprot_t protection_map[16];
 
 #define FAULT_FLAG_WRITE       0x01    /* Fault was a write access */
 #define FAULT_FLAG_NONLINEAR   0x02    /* Fault was via a nonlinear mapping */
+#define FAULT_FLAG_MKWRITE     0x04    /* Fault was mkwrite of existing pte */
 
 /*
  * This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -187,7 +188,7 @@ struct vm_operations_struct {
 
        /* notification that a previously read-only page is about to become
         * writable, if an error is returned it will cause a SIGBUS */
-       int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page);
+       int (*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf);
 
        /* called by access_process_vm when get_user_pages() fails, typically
         * for use by special VMAs that can switch between memory and hardware
@@ -834,6 +835,7 @@ int __set_page_dirty_nobuffers(struct page *page);
 int __set_page_dirty_no_writeback(struct page *page);
 int redirty_page_for_writepage(struct writeback_control *wbc,
                                struct page *page);
+void account_page_dirtied(struct page *page, struct address_space *mapping);
 int set_page_dirty(struct page *page);
 int set_page_dirty_lock(struct page *page);
 int clear_page_dirty_for_io(struct page *page);
@@ -1077,7 +1079,7 @@ static inline void setup_per_cpu_pageset(void) {}
 #endif
 
 /* nommu.c */
-extern atomic_t mmap_pages_allocated;
+extern atomic_long_t mmap_pages_allocated;
 
 /* prio_tree.c */
 void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old);
index d84feb7bdbf00b8fa054364c7fa2d80d2a20b2a6..0e80e26ecf21220104d8d2abbeb9cca6a1215e6e 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/rwsem.h>
 #include <linux/completion.h>
 #include <linux/cpumask.h>
+#include <linux/page-debug-flags.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 
@@ -94,6 +95,9 @@ struct page {
        void *virtual;                  /* Kernel virtual address (NULL if
                                           not kmapped, ie. highmem) */
 #endif /* WANT_PAGE_VIRTUAL */
+#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
+       unsigned long debug_flags;      /* Use atomic bitops on this */
+#endif
 };
 
 /*
index 4e457256bd33dd18734a0f292c23d2404ee0b60f..3e7615e9087e400c767332dfa3c64e5ec8483356 100644 (file)
@@ -192,5 +192,10 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
        wake_up_process(host->sdio_irq_thread);
 }
 
+struct regulator;
+
+int mmc_regulator_get_ocrmask(struct regulator *supply);
+int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
+
 #endif
 
index 1aca6cebbb78916aaeb4764b3ec7e7da3276cf91..26ef24076b76a391e94fb395dfc3c820da545155 100644 (file)
@@ -806,6 +806,14 @@ extern struct zone *next_zone(struct zone *zone);
             zone;                                      \
             zone = next_zone(zone))
 
+#define for_each_populated_zone(zone)                  \
+       for (zone = (first_online_pgdat())->node_zones; \
+            zone;                                      \
+            zone = next_zone(zone))                    \
+               if (!populated_zone(zone))              \
+                       ; /* do nothing */              \
+               else
+
 static inline struct zone *zonelist_zone(struct zoneref *zoneref)
 {
        return zoneref->zone;
index 830bbcd449d6c97c9e09a51bce33fabcd163d087..3a059298cc197e9c470c47d6338931557fd6ec43 100644 (file)
@@ -22,6 +22,8 @@ struct proc_mounts {
        int event;
 };
 
+struct fs_struct;
+
 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
                struct fs_struct *);
 extern void __put_mnt_ns(struct mnt_namespace *ns);
index 5c42821da2d19d7f010071b272e76147056646ab..068a0c9946af7e1f780f8cd287a517a14852286b 100644 (file)
  */
 #ifdef CONFIG_BLOCK
 
-struct mpage_data {
-       struct bio *bio;
-       sector_t last_block_in_bio;
-       get_block_t *get_block;
-       unsigned use_writepage;
-};
-
 struct writeback_control;
 
-struct bio *mpage_bio_submit(int rw, struct bio *bio);
 int mpage_readpages(struct address_space *mapping, struct list_head *pages,
                                unsigned nr_pages, get_block_t get_block);
 int mpage_readpage(struct page *page, get_block_t get_block);
-int __mpage_writepage(struct page *page, struct writeback_control *wbc,
-                     void *data);
 int mpage_writepages(struct address_space *mapping,
                struct writeback_control *wbc, get_block_t get_block);
 int mpage_writepage(struct page *page, get_block_t *get_block,
index d2b8a1e8ca11000cf622717ab3302bf9a64888c3..6991ab5b24d1bbfd736df4d27315a83ee7271779 100644 (file)
@@ -20,20 +20,23 @@ extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 struct msi_desc {
        struct {
-               __u8    type    : 5;    /* {0: unused, 5h:MSI, 11h:MSI-X} */
+               __u8    is_msix : 1;
+               __u8    multiple: 3;    /* log2 number of messages */
                __u8    maskbit : 1;    /* mask-pending bit supported ?   */
-               __u8    masked  : 1;
                __u8    is_64   : 1;    /* Address size: 0=32bit 1=64bit  */
                __u8    pos;            /* Location of the msi capability */
-               __u32   maskbits_mask;  /* mask bits mask */
                __u16   entry_nr;       /* specific enabled entry         */
                unsigned default_irq;   /* default pre-assigned irq       */
-       }msi_attrib;
+       } msi_attrib;
 
+       u32 masked;                     /* mask bits */
        unsigned int irq;
        struct list_head list;
 
-       void __iomem *mask_base;
+       union {
+               void __iomem *mask_base;
+               u8 mask_pos;
+       };
        struct pci_dev *dev;
 
        /* Last set MSI message */
index 7a0e5c4f8072c53f4b0d6a7dfa681355324e065f..3069ec7e0ab84ca54a282c72d73385e44e69d63a 100644 (file)
@@ -50,8 +50,10 @@ struct mutex {
        atomic_t                count;
        spinlock_t              wait_lock;
        struct list_head        wait_list;
-#ifdef CONFIG_DEBUG_MUTEXES
+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
        struct thread_info      *owner;
+#endif
+#ifdef CONFIG_DEBUG_MUTEXES
        const char              *name;
        void                    *magic;
 #endif
@@ -68,7 +70,6 @@ struct mutex_waiter {
        struct list_head        list;
        struct task_struct      *task;
 #ifdef CONFIG_DEBUG_MUTEXES
-       struct mutex            *lock;
        void                    *magic;
 #endif
 };
index de99025f2c5d5d6ba1fa48775ef6c51f203dd47a..2524267210d308894317f00e057c0d61bf81098d 100644 (file)
@@ -18,7 +18,7 @@ struct netpoll {
        const char *name;
        void (*rx_hook)(struct netpoll *, int, char *, int);
 
-       u32 local_ip, remote_ip;
+       __be32 local_ip, remote_ip;
        u16 local_port, remote_port;
        u8 remote_mac[ETH_ALEN];
 };
index 8cc8807f77d6da286c6225ccb4a8c69642b826e3..fdffb413b19276e7f7c9a2cc49bf7ec84e80a7cf 100644 (file)
@@ -166,8 +166,7 @@ struct nfs_inode {
         */
        struct radix_tree_root  nfs_page_tree;
 
-       unsigned long           ncommit,
-                               npages;
+       unsigned long           npages;
 
        /* Open contexts for shared mmap writes */
        struct list_head        open_files;
@@ -186,6 +185,9 @@ struct nfs_inode {
        fmode_t                  delegation_state;
        struct rw_semaphore     rwsem;
 #endif /* CONFIG_NFS_V4*/
+#ifdef CONFIG_NFS_FSCACHE
+       struct fscache_cookie   *fscache;
+#endif
        struct inode            vfs_inode;
 };
 
@@ -207,6 +209,9 @@ struct nfs_inode {
 #define NFS_INO_STALE          (1)             /* possible stale inode */
 #define NFS_INO_ACL_LRU_SET    (2)             /* Inode is on the LRU list */
 #define NFS_INO_MOUNTPOINT     (3)             /* inode is remote mountpoint */
+#define NFS_INO_FLUSHING       (4)             /* inode is flushing out data */
+#define NFS_INO_FSCACHE                (5)             /* inode can be cached by FS-Cache */
+#define NFS_INO_FSCACHE_LOCK   (6)             /* FS-Cache cookie management lock */
 
 static inline struct nfs_inode *NFS_I(const struct inode *inode)
 {
@@ -260,6 +265,11 @@ static inline int NFS_STALE(const struct inode *inode)
        return test_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
 }
 
+static inline int NFS_FSCACHE(const struct inode *inode)
+{
+       return test_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags);
+}
+
 static inline __u64 NFS_FILEID(const struct inode *inode)
 {
        return NFS_I(inode)->fileid;
@@ -506,6 +516,8 @@ extern int  nfs_readpages(struct file *, struct address_space *,
                struct list_head *, unsigned);
 extern int  nfs_readpage_result(struct rpc_task *, struct nfs_read_data *);
 extern void nfs_readdata_release(void *data);
+extern int  nfs_readpage_async(struct nfs_open_context *, struct inode *,
+                              struct page *);
 
 /*
  * Allocate nfs_read_data structures
@@ -583,6 +595,7 @@ extern void * nfs_root_data(void);
 #define NFSDBG_CALLBACK                0x0100
 #define NFSDBG_CLIENT          0x0200
 #define NFSDBG_MOUNT           0x0400
+#define NFSDBG_FSCACHE         0x0800
 #define NFSDBG_ALL             0xFFFF
 
 #ifdef __KERNEL__
index 9bb81aec91cf859de0591b4fb51b49ba9a622297..6ad75948cbf76613fb18c69069c0ccc8efdf580a 100644 (file)
@@ -64,6 +64,10 @@ struct nfs_client {
        char                    cl_ipaddr[48];
        unsigned char           cl_id_uniquifier;
 #endif
+
+#ifdef CONFIG_NFS_FSCACHE
+       struct fscache_cookie   *fscache;       /* client index cache cookie */
+#endif
 };
 
 /*
@@ -96,16 +100,28 @@ struct nfs_server {
        unsigned int            acdirmin;
        unsigned int            acdirmax;
        unsigned int            namelen;
+       unsigned int            options;        /* extra options enabled by mount */
+#define NFS_OPTION_FSCACHE     0x00000001      /* - local caching enabled */
 
        struct nfs_fsid         fsid;
        __u64                   maxfilesize;    /* maximum file size */
        unsigned long           mount_time;     /* when this fs was mounted */
        dev_t                   s_dev;          /* superblock dev numbers */
 
+#ifdef CONFIG_NFS_FSCACHE
+       struct nfs_fscache_key  *fscache_key;   /* unique key for superblock */
+       struct fscache_cookie   *fscache;       /* superblock cookie */
+#endif
+
 #ifdef CONFIG_NFS_V4
        u32                     attr_bitmask[2];/* V4 bitmask representing the set
                                                   of attributes supported on this
                                                   filesystem */
+       u32                     cache_consistency_bitmask[2];
+                                               /* V4 bitmask representing the subset
+                                                  of change attribute, size, ctime
+                                                  and mtime attributes supported by
+                                                  the server */
        u32                     acl_bitmask;    /* V4 bitmask representing the ACEs
                                                   that are supported on this
                                                   filesystem */
index 1cb9a3fed2b3bc953ad3a94a5008dc4a529fe275..68b10f5f8907fe0517d0bc5352686b34dd5be9e3 100644 (file)
@@ -116,4 +116,16 @@ enum nfs_stat_eventcounters {
        __NFSIOS_COUNTSMAX,
 };
 
+/*
+ * NFS local caching servicing counters
+ */
+enum nfs_stat_fscachecounters {
+       NFSIOS_FSCACHE_PAGES_READ_OK,
+       NFSIOS_FSCACHE_PAGES_READ_FAIL,
+       NFSIOS_FSCACHE_PAGES_WRITTEN_OK,
+       NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL,
+       NFSIOS_FSCACHE_PAGES_UNCACHED,
+       __NFSIOS_FSCACHEMAX,
+};
+
 #endif /* _LINUX_NFS_IOSTAT */
index 43a713fce11cbfbd25571424e7201758f15b4bf5..b89c34e40bc2b23e5d34485f8640a28197b7a3e5 100644 (file)
@@ -27,12 +27,8 @@ static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid
 }
 
 struct nfs_fattr {
-       unsigned short          valid;          /* which fields are valid */
-       __u64                   pre_size;       /* pre_op_attr.size       */
-       struct timespec         pre_mtime;      /* pre_op_attr.mtime      */
-       struct timespec         pre_ctime;      /* pre_op_attr.ctime      */
-       enum nfs_ftype          type;           /* always use NFSv2 types */
-       __u32                   mode;
+       unsigned int            valid;          /* which fields are valid */
+       umode_t                 mode;
        __u32                   nlink;
        __u32                   uid;
        __u32                   gid;
@@ -52,19 +48,55 @@ struct nfs_fattr {
        struct timespec         atime;
        struct timespec         mtime;
        struct timespec         ctime;
-       __u32                   bitmap[2];      /* NFSv4 returned attribute bitmap */
        __u64                   change_attr;    /* NFSv4 change attribute */
        __u64                   pre_change_attr;/* pre-op NFSv4 change attribute */
+       __u64                   pre_size;       /* pre_op_attr.size       */
+       struct timespec         pre_mtime;      /* pre_op_attr.mtime      */
+       struct timespec         pre_ctime;      /* pre_op_attr.ctime      */
        unsigned long           time_start;
        unsigned long           gencount;
 };
 
-#define NFS_ATTR_WCC           0x0001          /* pre-op WCC data    */
-#define NFS_ATTR_FATTR         0x0002          /* post-op attributes */
-#define NFS_ATTR_FATTR_V3      0x0004          /* NFSv3 attributes */
-#define NFS_ATTR_FATTR_V4      0x0008          /* NFSv4 change attribute */
-#define NFS_ATTR_WCC_V4                0x0010          /* pre-op change attribute */
-#define NFS_ATTR_FATTR_V4_REFERRAL     0x0020          /* NFSv4 referral */
+#define NFS_ATTR_FATTR_TYPE            (1U << 0)
+#define NFS_ATTR_FATTR_MODE            (1U << 1)
+#define NFS_ATTR_FATTR_NLINK           (1U << 2)
+#define NFS_ATTR_FATTR_OWNER           (1U << 3)
+#define NFS_ATTR_FATTR_GROUP           (1U << 4)
+#define NFS_ATTR_FATTR_RDEV            (1U << 5)
+#define NFS_ATTR_FATTR_SIZE            (1U << 6)
+#define NFS_ATTR_FATTR_PRESIZE         (1U << 7)
+#define NFS_ATTR_FATTR_BLOCKS_USED     (1U << 8)
+#define NFS_ATTR_FATTR_SPACE_USED      (1U << 9)
+#define NFS_ATTR_FATTR_FSID            (1U << 10)
+#define NFS_ATTR_FATTR_FILEID          (1U << 11)
+#define NFS_ATTR_FATTR_ATIME           (1U << 12)
+#define NFS_ATTR_FATTR_MTIME           (1U << 13)
+#define NFS_ATTR_FATTR_CTIME           (1U << 14)
+#define NFS_ATTR_FATTR_PREMTIME                (1U << 15)
+#define NFS_ATTR_FATTR_PRECTIME                (1U << 16)
+#define NFS_ATTR_FATTR_CHANGE          (1U << 17)
+#define NFS_ATTR_FATTR_PRECHANGE       (1U << 18)
+#define NFS_ATTR_FATTR_V4_REFERRAL     (1U << 19)      /* NFSv4 referral */
+
+#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
+               | NFS_ATTR_FATTR_MODE \
+               | NFS_ATTR_FATTR_NLINK \
+               | NFS_ATTR_FATTR_OWNER \
+               | NFS_ATTR_FATTR_GROUP \
+               | NFS_ATTR_FATTR_RDEV \
+               | NFS_ATTR_FATTR_SIZE \
+               | NFS_ATTR_FATTR_FSID \
+               | NFS_ATTR_FATTR_FILEID \
+               | NFS_ATTR_FATTR_ATIME \
+               | NFS_ATTR_FATTR_MTIME \
+               | NFS_ATTR_FATTR_CTIME)
+#define NFS_ATTR_FATTR_V2 (NFS_ATTR_FATTR \
+               | NFS_ATTR_FATTR_BLOCKS_USED)
+#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
+               | NFS_ATTR_FATTR_SPACE_USED)
+#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
+               | NFS_ATTR_FATTR_SPACE_USED \
+               | NFS_ATTR_FATTR_CHANGE)
 
 /*
  * Info on the file system
@@ -836,6 +868,7 @@ struct nfs_rpc_ops {
        int     (*lock)(struct file *, int, struct file_lock *);
        int     (*lock_check_bounds)(const struct file_lock *);
        void    (*clear_acl_cache)(struct inode *);
+       void    (*close_context)(struct nfs_open_context *ctx, int);
 };
 
 /*
index afad7dec1b36fd2fee9e967c804f6b3f87a69bf8..7b370c7cfeffb27db00d71fa2127381abdbfd518 100644 (file)
@@ -8,6 +8,7 @@ struct mnt_namespace;
 struct uts_namespace;
 struct ipc_namespace;
 struct pid_namespace;
+struct fs_struct;
 
 /*
  * A structure to contain pointers to all per-process
diff --git a/include/linux/page-debug-flags.h b/include/linux/page-debug-flags.h
new file mode 100644 (file)
index 0000000..b0638fd
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef LINUX_PAGE_DEBUG_FLAGS_H
+#define  LINUX_PAGE_DEBUG_FLAGS_H
+
+/*
+ * page->debug_flags bits:
+ *
+ * PAGE_DEBUG_FLAG_POISON is set for poisoned pages. This is used to
+ * implement generic debug pagealloc feature. The pages are filled with
+ * poison patterns and set this flag after free_pages(). The poisoned
+ * pages are verified whether the patterns are not corrupted and clear
+ * the flag before alloc_pages().
+ */
+
+enum page_debug_flags {
+       PAGE_DEBUG_FLAG_POISON,         /* Page is poisoned */
+};
+
+/*
+ * Ensure that CONFIG_WANT_PAGE_DEBUG_FLAGS reliably
+ * gets turned off when no debug features are enabling it!
+ */
+
+#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
+#if !defined(CONFIG_PAGE_POISONING) \
+/* && !defined(CONFIG_PAGE_DEBUG_SOMETHING_ELSE) && ... */
+#error WANT_PAGE_DEBUG_FLAGS is turned on with no debug features!
+#endif
+#endif /* CONFIG_WANT_PAGE_DEBUG_FLAGS */
+
+#endif /* LINUX_PAGE_DEBUG_FLAGS_H */
index 219a523ecdb0b5240f18710bc7a0da81c7538cae..62214c7d2d939e734352bf888e058001e44ccc30 100644 (file)
@@ -82,6 +82,7 @@ enum pageflags {
        PG_arch_1,
        PG_reserved,
        PG_private,             /* If pagecache, has fs-private data */
+       PG_private_2,           /* If pagecache, has fs aux data */
        PG_writeback,           /* Page is under writeback */
 #ifdef CONFIG_PAGEFLAGS_EXTENDED
        PG_head,                /* A head page */
@@ -96,6 +97,8 @@ enum pageflags {
        PG_swapbacked,          /* Page is backed by RAM/swap */
 #ifdef CONFIG_UNEVICTABLE_LRU
        PG_unevictable,         /* Page is "unevictable"  */
+#endif
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
        PG_mlocked,             /* Page is vma mlocked */
 #endif
 #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
@@ -106,6 +109,12 @@ enum pageflags {
        /* Filesystems */
        PG_checked = PG_owner_priv_1,
 
+       /* Two page bits are conscripted by FS-Cache to maintain local caching
+        * state.  These bits are set on pages belonging to the netfs's inodes
+        * when those inodes are being locally cached.
+        */
+       PG_fscache = PG_private_2,      /* page backed by cache */
+
        /* XEN */
        PG_pinned = PG_owner_priv_1,
        PG_savepinned = PG_dirty,
@@ -180,7 +189,7 @@ static inline int TestClearPage##uname(struct page *page) { return 0; }
 
 struct page;   /* forward declaration */
 
-TESTPAGEFLAG(Locked, locked)
+TESTPAGEFLAG(Locked, locked) TESTSETFLAG(Locked, locked)
 PAGEFLAG(Error, error)
 PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced)
 PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty)
@@ -192,8 +201,6 @@ PAGEFLAG(Checked, checked)          /* Used by some filesystems */
 PAGEFLAG(Pinned, pinned) TESTSCFLAG(Pinned, pinned)    /* Xen */
 PAGEFLAG(SavePinned, savepinned);                      /* Xen */
 PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved)
-PAGEFLAG(Private, private) __CLEARPAGEFLAG(Private, private)
-       __SETPAGEFLAG(Private, private)
 PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
 
 __PAGEFLAG(SlobPage, slob_page)
@@ -202,6 +209,16 @@ __PAGEFLAG(SlobFree, slob_free)
 __PAGEFLAG(SlubFrozen, slub_frozen)
 __PAGEFLAG(SlubDebug, slub_debug)
 
+/*
+ * Private page markings that may be used by the filesystem that owns the page
+ * for its own purposes.
+ * - PG_private and PG_private_2 cause releasepage() and co to be invoked
+ */
+PAGEFLAG(Private, private) __SETPAGEFLAG(Private, private)
+       __CLEARPAGEFLAG(Private, private)
+PAGEFLAG(Private2, private_2) TESTSCFLAG(Private2, private_2)
+PAGEFLAG(OwnerPriv1, owner_priv_1) TESTCLEARFLAG(OwnerPriv1, owner_priv_1)
+
 /*
  * Only test-and-set exist for PG_writeback.  The unconditional operators are
  * risky: they bypass page accounting.
@@ -234,20 +251,20 @@ PAGEFLAG_FALSE(SwapCache)
 #ifdef CONFIG_UNEVICTABLE_LRU
 PAGEFLAG(Unevictable, unevictable) __CLEARPAGEFLAG(Unevictable, unevictable)
        TESTCLEARFLAG(Unevictable, unevictable)
+#else
+PAGEFLAG_FALSE(Unevictable) TESTCLEARFLAG_FALSE(Unevictable)
+       SETPAGEFLAG_NOOP(Unevictable) CLEARPAGEFLAG_NOOP(Unevictable)
+       __CLEARPAGEFLAG_NOOP(Unevictable)
+#endif
 
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
 #define MLOCK_PAGES 1
 PAGEFLAG(Mlocked, mlocked) __CLEARPAGEFLAG(Mlocked, mlocked)
        TESTSCFLAG(Mlocked, mlocked)
-
 #else
-
 #define MLOCK_PAGES 0
 PAGEFLAG_FALSE(Mlocked)
        SETPAGEFLAG_NOOP(Mlocked) TESTCLEARFLAG_FALSE(Mlocked)
-
-PAGEFLAG_FALSE(Unevictable) TESTCLEARFLAG_FALSE(Unevictable)
-       SETPAGEFLAG_NOOP(Unevictable) CLEARPAGEFLAG_NOOP(Unevictable)
-       __CLEARPAGEFLAG_NOOP(Unevictable)
 #endif
 
 #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
@@ -367,9 +384,13 @@ static inline void __ClearPageTail(struct page *page)
 
 #ifdef CONFIG_UNEVICTABLE_LRU
 #define __PG_UNEVICTABLE       (1 << PG_unevictable)
-#define __PG_MLOCKED           (1 << PG_mlocked)
 #else
 #define __PG_UNEVICTABLE       0
+#endif
+
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
+#define __PG_MLOCKED           (1 << PG_mlocked)
+#else
 #define __PG_MLOCKED           0
 #endif
 
@@ -378,9 +399,10 @@ static inline void __ClearPageTail(struct page *page)
  * these flags set.  It they are, there is a problem.
  */
 #define PAGE_FLAGS_CHECK_AT_FREE \
-       (1 << PG_lru   | 1 << PG_private   | 1 << PG_locked | \
-        1 << PG_buddy | 1 << PG_writeback | 1 << PG_reserved | \
-        1 << PG_slab  | 1 << PG_swapcache | 1 << PG_active | \
+       (1 << PG_lru     | 1 << PG_locked    | \
+        1 << PG_private | 1 << PG_private_2 | \
+        1 << PG_buddy   | 1 << PG_writeback | 1 << PG_reserved | \
+        1 << PG_slab    | 1 << PG_swapcache | 1 << PG_active | \
         __PG_UNEVICTABLE | __PG_MLOCKED)
 
 /*
@@ -391,4 +413,16 @@ static inline void __ClearPageTail(struct page *page)
 #define PAGE_FLAGS_CHECK_AT_PREP       ((1 << NR_PAGEFLAGS) - 1)
 
 #endif /* !__GENERATING_BOUNDS_H */
+
+/**
+ * page_has_private - Determine if page has private stuff
+ * @page: The page to be checked
+ *
+ * Determine if a page has private stuff, indicating that release routines
+ * should be invoked upon it.
+ */
+#define page_has_private(page)                 \
+       ((page)->flags & ((1 << PG_private) |   \
+                         (1 << PG_private_2)))
+
 #endif /* PAGE_FLAGS_H */
index 602cc1fdee90c152dc458642256b623ce8cbfa78..7339c7bf73315e56a981b382229abfc39384e23b 100644 (file)
@@ -91,24 +91,23 @@ static inline void page_cgroup_init(void)
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 #include <linux/swap.h>
-extern struct mem_cgroup *
-swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem);
-extern struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent);
+extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
+extern unsigned short lookup_swap_cgroup(swp_entry_t ent);
 extern int swap_cgroup_swapon(int type, unsigned long max_pages);
 extern void swap_cgroup_swapoff(int type);
 #else
 #include <linux/swap.h>
 
 static inline
-struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 {
-       return NULL;
+       return 0;
 }
 
 static inline
-struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup(swp_entry_t ent)
 {
-       return NULL;
+       return 0;
 }
 
 static inline int
index 01ca0856caff38a8d910df0915e4bb6cc93be536..34da5230faab4617cfe9bba4c43ac83cc083ab12 100644 (file)
  * Bits in mapping->flags.  The lower __GFP_BITS_SHIFT bits are the page
  * allocation mode flags.
  */
-#define        AS_EIO          (__GFP_BITS_SHIFT + 0)  /* IO error on async write */
-#define AS_ENOSPC      (__GFP_BITS_SHIFT + 1)  /* ENOSPC on async write */
-#define AS_MM_ALL_LOCKS        (__GFP_BITS_SHIFT + 2)  /* under mm_take_all_locks() */
+enum mapping_flags {
+       AS_EIO          = __GFP_BITS_SHIFT + 0, /* IO error on async write */
+       AS_ENOSPC       = __GFP_BITS_SHIFT + 1, /* ENOSPC on async write */
+       AS_MM_ALL_LOCKS = __GFP_BITS_SHIFT + 2, /* under mm_take_all_locks() */
+#ifdef CONFIG_UNEVICTABLE_LRU
+       AS_UNEVICTABLE  = __GFP_BITS_SHIFT + 3, /* e.g., ramdisk, SHM_LOCK */
+#endif
+};
 
 static inline void mapping_set_error(struct address_space *mapping, int error)
 {
@@ -33,7 +38,6 @@ static inline void mapping_set_error(struct address_space *mapping, int error)
 }
 
 #ifdef CONFIG_UNEVICTABLE_LRU
-#define AS_UNEVICTABLE (__GFP_BITS_SHIFT + 2)  /* e.g., ramdisk, SHM_LOCK */
 
 static inline void mapping_set_unevictable(struct address_space *mapping)
 {
@@ -379,6 +383,11 @@ static inline void wait_on_page_writeback(struct page *page)
 
 extern void end_page_writeback(struct page *page);
 
+/*
+ * Add an arbitrary waiter to a page's wait queue
+ */
+extern void add_page_wait_queue(struct page *page, wait_queue_t *waiter);
+
 /*
  * Fault a userspace page into pagetables.  Return non-zero on a fault.
  *
index 7b2886fa7fdc2885972d0ba2286afe59f0d1b82b..bab82f4c571c611d91fb9f180dc2a69ed12c95e2 100644 (file)
@@ -24,7 +24,6 @@ void __pagevec_release(struct pagevec *pvec);
 void __pagevec_free(struct pagevec *pvec);
 void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru);
 void pagevec_strip(struct pagevec *pvec);
-void pagevec_swap_free(struct pagevec *pvec);
 unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
                pgoff_t start, unsigned nr_pages);
 unsigned pagevec_lookup_tag(struct pagevec *pvec,
index 042c166f65d5e155d46bacfbd6981268d928d376..092e82e0048c969e7b54b17dbd6dcd548969bb6c 100644 (file)
 
 #include <linux/acpi.h>
 
-#define OSC_QUERY_TYPE                 0
-#define OSC_SUPPORT_TYPE               1
-#define OSC_CONTROL_TYPE               2
-#define OSC_SUPPORT_MASKS              0x1f
-
-/*
- * _OSC DW0 Definition 
- */
-#define OSC_QUERY_ENABLE               1
-#define OSC_REQUEST_ERROR              2
-#define OSC_INVALID_UUID_ERROR         4
-#define OSC_INVALID_REVISION_ERROR     8
-#define OSC_CAPABILITIES_MASK_ERROR    16
-
-/*
- * _OSC DW1 Definition (OS Support Fields)
- */
-#define OSC_EXT_PCI_CONFIG_SUPPORT             1
-#define OSC_ACTIVE_STATE_PWR_SUPPORT           2
-#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT       4
-#define OSC_PCI_SEGMENT_GROUPS_SUPPORT         8
-#define OSC_MSI_SUPPORT                                16
-
-/*
- * _OSC DW1 Definition (OS Control Fields)
- */
-#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL      1
-#define OSC_SHPC_NATIVE_HP_CONTROL             2
-#define OSC_PCI_EXPRESS_PME_CONTROL            4
-#define OSC_PCI_EXPRESS_AER_CONTROL            8
-#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL  16
-
-#define OSC_CONTROL_MASKS      (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |    \
-                               OSC_SHPC_NATIVE_HP_CONTROL |            \
-                               OSC_PCI_EXPRESS_PME_CONTROL |           \
-                               OSC_PCI_EXPRESS_AER_CONTROL |           \
-                               OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
-
 #ifdef CONFIG_ACPI
-extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags);
-int pci_acpi_osc_support(acpi_handle handle, u32 flags);
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
-       /* Find root host bridge */
-       while (pdev->bus->self)
-               pdev = pdev->bus->self;
-
-       return acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus),
-                       pdev->bus->number);
+       struct pci_bus *pbus = pdev->bus;
+       /* Find a PCI root bus */
+       while (pbus->parent)
+               pbus = pbus->parent;
+       return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
+                                             pbus->number);
 }
 
 static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 {
-       int seg = pci_domain_nr(pbus), busnr = pbus->number;
-       struct pci_dev *bridge = pbus->self;
-       if (bridge)
-               return DEVICE_ACPI_HANDLE(&(bridge->dev));
-       return acpi_get_pci_rootbridge_handle(seg, busnr);
+       if (pbus->parent)
+               return DEVICE_ACPI_HANDLE(&(pbus->self->dev));
+       return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
+                                             pbus->number);
 }
 #else
-#if !defined(AE_ERROR)
-typedef u32            acpi_status;
-#define AE_ERROR       (acpi_status) (0x0001)
-#endif    
-static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
-{return AE_ERROR;}
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 { return NULL; }
 #endif
index 7bd624bfdcfd37945e3c59bf2a74f0d2f1dabb21..a7fe4bbd7ff1f7be9eb28952bffd8802c55e6ff8 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/atomic.h>
 #include <linux/device.h>
 #include <linux/io.h>
+#include <linux/irqreturn.h>
 
 /* Include the ID list */
 #include <linux/pci_ids.h>
@@ -93,6 +94,12 @@ enum {
        /* #6: expansion ROM resource */
        PCI_ROM_RESOURCE,
 
+       /* device specific resources */
+#ifdef CONFIG_PCI_IOV
+       PCI_IOV_RESOURCES,
+       PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1,
+#endif
+
        /* resources assigned to buses behind the bridge */
 #define PCI_BRIDGE_RESOURCE_NUM 4
 
@@ -180,6 +187,7 @@ struct pci_cap_saved_state {
 
 struct pcie_link_state;
 struct pci_vpd;
+struct pci_sriov;
 
 /*
  * The pci_dev structure is used to describe PCI devices.
@@ -257,6 +265,8 @@ struct pci_dev {
        unsigned int    is_managed:1;
        unsigned int    is_pcie:1;
        unsigned int    state_saved:1;
+       unsigned int    is_physfn:1;
+       unsigned int    is_virtfn:1;
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
 
@@ -270,6 +280,12 @@ struct pci_dev {
        struct list_head msi_list;
 #endif
        struct pci_vpd *vpd;
+#ifdef CONFIG_PCI_IOV
+       union {
+               struct pci_sriov *sriov;        /* SR-IOV capability related */
+               struct pci_dev *physfn; /* the PF this VF is associated with */
+       };
+#endif
 };
 
 extern struct pci_dev *alloc_pci_dev(void);
@@ -341,6 +357,15 @@ struct pci_bus {
 #define pci_bus_b(n)   list_entry(n, struct pci_bus, node)
 #define to_pci_bus(n)  container_of(n, struct pci_bus, dev)
 
+/*
+ * Returns true if the pci bus is root (behind host-pci bridge),
+ * false otherwise
+ */
+static inline bool pci_is_root_bus(struct pci_bus *pbus)
+{
+       return !(pbus->parent);
+}
+
 #ifdef CONFIG_PCI_MSI
 static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev)
 {
@@ -528,7 +553,7 @@ void pcibios_update_irq(struct pci_dev *, int irq);
 /* Generic PCI functions used internally */
 
 extern struct pci_bus *pci_find_bus(int domain, int busnr);
-void pci_bus_add_devices(struct pci_bus *bus);
+void pci_bus_add_devices(const struct pci_bus *bus);
 struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
                                      struct pci_ops *ops, void *sysdata);
 static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
@@ -689,6 +714,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
 /* Power management related routines */
 int pci_save_state(struct pci_dev *dev);
 int pci_restore_state(struct pci_dev *dev);
+int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
 int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
 bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
@@ -701,6 +727,9 @@ int pci_back_from_sleep(struct pci_dev *dev);
 
 /* Functions for PCI Hotplug drivers to use */
 int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
+#ifdef CONFIG_HOTPLUG
+unsigned int pci_rescan_bus(struct pci_bus *bus);
+#endif
 
 /* Vital product data routines */
 ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
@@ -708,7 +737,7 @@ ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void
 int pci_vpd_truncate(struct pci_dev *dev, size_t size);
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
-void pci_bus_assign_resources(struct pci_bus *bus);
+void pci_bus_assign_resources(const struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
@@ -789,7 +818,7 @@ struct msix_entry {
 
 
 #ifndef CONFIG_PCI_MSI
-static inline int pci_enable_msi(struct pci_dev *dev)
+static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
 {
        return -1;
 }
@@ -799,6 +828,10 @@ static inline void pci_msi_shutdown(struct pci_dev *dev)
 static inline void pci_disable_msi(struct pci_dev *dev)
 { }
 
+static inline int pci_msix_table_size(struct pci_dev *dev)
+{
+       return 0;
+}
 static inline int pci_enable_msix(struct pci_dev *dev,
                                  struct msix_entry *entries, int nvec)
 {
@@ -820,9 +853,10 @@ static inline int pci_msi_enabled(void)
        return 0;
 }
 #else
-extern int pci_enable_msi(struct pci_dev *dev);
+extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
 extern void pci_msi_shutdown(struct pci_dev *dev);
 extern void pci_disable_msi(struct pci_dev *dev);
+extern int pci_msix_table_size(struct pci_dev *dev);
 extern int pci_enable_msix(struct pci_dev *dev,
        struct msix_entry *entries, int nvec);
 extern void pci_msix_shutdown(struct pci_dev *dev);
@@ -841,6 +875,8 @@ static inline int pcie_aspm_enabled(void)
 extern int pcie_aspm_enabled(void);
 #endif
 
+#define pci_enable_msi(pdev)   pci_enable_msi_block(pdev, 1)
+
 #ifdef CONFIG_HT_IRQ
 /* The functions a driver should call */
 int  ht_create_irq(struct pci_dev *dev, int idx);
@@ -1194,5 +1230,23 @@ int pci_ext_cfg_avail(struct pci_dev *dev);
 
 void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
 
+#ifdef CONFIG_PCI_IOV
+extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+extern void pci_disable_sriov(struct pci_dev *dev);
+extern irqreturn_t pci_sriov_migration(struct pci_dev *dev);
+#else
+static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+       return -ENODEV;
+}
+static inline void pci_disable_sriov(struct pci_dev *dev)
+{
+}
+static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev)
+{
+       return IRQ_NONE;
+}
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
index e5816dd333713b2e4d8e6cc4fac8013b16cd055d..170f8b1f22db1dc7f065e0de8525cb1b80ce4898 100644 (file)
 #define PCI_DEVICE_ID_AMD_OPUS_7443    0x7443
 #define PCI_DEVICE_ID_AMD_VIPER_7443   0x7443
 #define PCI_DEVICE_ID_AMD_OPUS_7445    0x7445
+#define PCI_DEVICE_ID_AMD_8111_PCI     0x7460
 #define PCI_DEVICE_ID_AMD_8111_LPC     0x7468
 #define PCI_DEVICE_ID_AMD_8111_IDE     0x7469
 #define PCI_DEVICE_ID_AMD_8111_SMBUS2  0x746a
 #define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c
 #define PCI_DEVICE_ID_INTEL_82801DB_0  0x24c0
 #define PCI_DEVICE_ID_INTEL_82801DB_1  0x24c1
+#define PCI_DEVICE_ID_INTEL_82801DB_2  0x24c2
 #define PCI_DEVICE_ID_INTEL_82801DB_3  0x24c3
 #define PCI_DEVICE_ID_INTEL_82801DB_5  0x24c5
 #define PCI_DEVICE_ID_INTEL_82801DB_6  0x24c6
index 027815b4635e677ad441c73a19b0bf48a62f5243..e4d08c1b2e0b40689d74911624468762eea0e281 100644 (file)
 #define  PCI_PM_CAP_PME_SHIFT  11      /* Start of the PME Mask in PMC */
 #define PCI_PM_CTRL            4       /* PM control and status register */
 #define  PCI_PM_CTRL_STATE_MASK        0x0003  /* Current power state (D0 to D3) */
-#define  PCI_PM_CTRL_NO_SOFT_RESET     0x0004  /* No reset for D3hot->D0 */
+#define  PCI_PM_CTRL_NO_SOFT_RESET     0x0008  /* No reset for D3hot->D0 */
 #define  PCI_PM_CTRL_PME_ENABLE        0x0100  /* PME pin enable */
 #define  PCI_PM_CTRL_DATA_SEL_MASK     0x1e00  /* Data select (??) */
 #define  PCI_PM_CTRL_DATA_SCALE_MASK   0x6000  /* Data scale (??) */
 #define  PCI_EXP_TYPE_UPSTREAM 0x5     /* Upstream Port */
 #define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
 #define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCI/PCI-X Bridge */
+#define  PCI_EXP_TYPE_RC_END   0x9     /* Root Complex Integrated Endpoint */
 #define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
 #define PCI_EXP_FLAGS_IRQ      0x3e00  /* Interrupt message number */
 #define PCI_EXP_DEVCAP         4       /* Device capabilities */
 #define  PCI_EXP_DEVCAP2_ARI   0x20    /* Alternative Routing-ID */
 #define PCI_EXP_DEVCTL2                40      /* Device Control 2 */
 #define  PCI_EXP_DEVCTL2_ARI   0x20    /* Alternative Routing-ID */
+#define PCI_EXP_LNKCTL2                48      /* Link Control 2 */
+#define PCI_EXP_SLTCTL2                56      /* Slot Control 2 */
 
 /* Extended Capabilities (PCI-X 2.0 and Express) */
 #define PCI_EXT_CAP_ID(header)         (header & 0x0000ffff)
 #define PCI_EXT_CAP_ID_DSN     3
 #define PCI_EXT_CAP_ID_PWR     4
 #define PCI_EXT_CAP_ID_ARI     14
+#define PCI_EXT_CAP_ID_SRIOV   16
 
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS   4       /* Uncorrectable Error Status */
 #define  PCI_ARI_CTRL_ACS      0x0002  /* ACS Function Groups Enable */
 #define  PCI_ARI_CTRL_FG(x)    (((x) >> 4) & 7) /* Function Group */
 
+/* Single Root I/O Virtualization */
+#define PCI_SRIOV_CAP          0x04    /* SR-IOV Capabilities */
+#define  PCI_SRIOV_CAP_VFM     0x01    /* VF Migration Capable */
+#define  PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
+#define PCI_SRIOV_CTRL         0x08    /* SR-IOV Control */
+#define  PCI_SRIOV_CTRL_VFE    0x01    /* VF Enable */
+#define  PCI_SRIOV_CTRL_VFM    0x02    /* VF Migration Enable */
+#define  PCI_SRIOV_CTRL_INTR   0x04    /* VF Migration Interrupt Enable */
+#define  PCI_SRIOV_CTRL_MSE    0x08    /* VF Memory Space Enable */
+#define  PCI_SRIOV_CTRL_ARI    0x10    /* ARI Capable Hierarchy */
+#define PCI_SRIOV_STATUS       0x0a    /* SR-IOV Status */
+#define  PCI_SRIOV_STATUS_VFM  0x01    /* VF Migration Status */
+#define PCI_SRIOV_INITIAL_VF   0x0c    /* Initial VFs */
+#define PCI_SRIOV_TOTAL_VF     0x0e    /* Total VFs */
+#define PCI_SRIOV_NUM_VF       0x10    /* Number of VFs */
+#define PCI_SRIOV_FUNC_LINK    0x12    /* Function Dependency Link */
+#define PCI_SRIOV_VF_OFFSET    0x14    /* First VF Offset */
+#define PCI_SRIOV_VF_STRIDE    0x16    /* Following VF Stride */
+#define PCI_SRIOV_VF_DID       0x1a    /* VF Device ID */
+#define PCI_SRIOV_SUP_PGSIZE   0x1c    /* Supported Page Sizes */
+#define PCI_SRIOV_SYS_PGSIZE   0x20    /* System Page Size */
+#define PCI_SRIOV_BAR          0x24    /* VF BAR0 */
+#define  PCI_SRIOV_NUM_BARS    6       /* Number of VF BARs */
+#define PCI_SRIOV_VFM          0x3c    /* VF Migration State Array Offset*/
+#define  PCI_SRIOV_VFM_BIR(x)  ((x) & 7)       /* State BIR */
+#define  PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7)    /* State Offset */
+#define  PCI_SRIOV_VFM_UA      0x0     /* Inactive.Unavailable */
+#define  PCI_SRIOV_VFM_MI      0x1     /* Dormant.MigrateIn */
+#define  PCI_SRIOV_VFM_MO      0x2     /* Active.MigrateOut */
+#define  PCI_SRIOV_VFM_AV      0x3     /* Active.Available */
+
 #endif /* LINUX_PCI_REGS_H */
index 6cd91e3f982052df783c2ec9b9df130bff118659..b4c79545330be8b5ef8e061161b8a2d61ce868b2 100644 (file)
 #define PCIE_ANY_PORT                  7
 
 /* Service Type */
-#define PCIE_PORT_SERVICE_PME          1       /* Power Management Event */
-#define PCIE_PORT_SERVICE_AER          2       /* Advanced Error Reporting */
-#define PCIE_PORT_SERVICE_HP           4       /* Native Hotplug */
-#define PCIE_PORT_SERVICE_VC           8       /* Virtual Channel */
+#define PCIE_PORT_SERVICE_PME_SHIFT    0       /* Power Management Event */
+#define PCIE_PORT_SERVICE_PME          (1 << PCIE_PORT_SERVICE_PME_SHIFT)
+#define PCIE_PORT_SERVICE_AER_SHIFT    1       /* Advanced Error Reporting */
+#define PCIE_PORT_SERVICE_AER          (1 << PCIE_PORT_SERVICE_AER_SHIFT)
+#define PCIE_PORT_SERVICE_HP_SHIFT     2       /* Native Hotplug */
+#define PCIE_PORT_SERVICE_HP           (1 << PCIE_PORT_SERVICE_HP_SHIFT)
+#define PCIE_PORT_SERVICE_VC_SHIFT     3       /* Virtual Channel */
+#define PCIE_PORT_SERVICE_VC           (1 << PCIE_PORT_SERVICE_VC_SHIFT)
 
 /* Root/Upstream/Downstream Port's Interrupt Mode */
+#define PCIE_PORT_NO_IRQ               (-1)
 #define PCIE_PORT_INTx_MODE            0
 #define PCIE_PORT_MSI_MODE             1
 #define PCIE_PORT_MSIX_MODE            2
 
-struct pcie_port_service_id {
-       __u32 vendor, device;           /* Vendor and device ID or PCI_ANY_ID*/
-       __u32 subvendor, subdevice;     /* Subsystem ID's or PCI_ANY_ID */
-       __u32 class, class_mask;        /* (class,subclass,prog-if) triplet */
-       __u32 port_type, service_type;  /* Port Entity */
-       kernel_ulong_t driver_data;
+struct pcie_port_data {
+       int port_type;          /* Type of the port */
+       int port_irq_mode;      /* [0:INTx | 1:MSI | 2:MSI-X] */
 };
 
 struct pcie_device {
        int             irq;        /* Service IRQ/MSI/MSI-X Vector */
-       int             interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */        
-       struct pcie_port_service_id id; /* Service ID */
-       struct pci_dev  *port;      /* Root/Upstream/Downstream Port */
+       struct pci_dev *port;       /* Root/Upstream/Downstream Port */
+       u32             service;    /* Port service this device represents */
        void            *priv_data; /* Service Private Data */
        struct device   device;     /* Generic Device Interface */
 };
@@ -56,10 +57,9 @@ static inline void* get_service_data(struct pcie_device *dev)
 
 struct pcie_port_service_driver {
        const char *name;
-       int (*probe) (struct pcie_device *dev, 
-               const struct pcie_port_service_id *id);
+       int (*probe) (struct pcie_device *dev);
        void (*remove) (struct pcie_device *dev);
-       int (*suspend) (struct pcie_device *dev, pm_message_t state);
+       int (*suspend) (struct pcie_device *dev);
        int (*resume) (struct pcie_device *dev);
 
        /* Service Error Recovery Handler */
@@ -68,7 +68,9 @@ struct pcie_port_service_driver {
        /* Link Reset Capability - AER service driver specific */
        pci_ers_result_t (*reset_link) (struct pci_dev *dev);
 
-       const struct pcie_port_service_id *id_table;
+       int port_type;  /* Type of the port this driver can handle */
+       u32 service;    /* Port service this device represents */
+
        struct device_driver driver;
 };
 #define to_service_driver(d) \
index 9f31683728fd7e2c59f738ae35ab6835066270c1..6729f7dcd60e66cc0116878ad640256a7061bbfe 100644 (file)
@@ -17,6 +17,9 @@
  */
 #define TIMER_ENTRY_STATIC     ((void *) 0x74737461)
 
+/********** mm/debug-pagealloc.c **********/
+#define PAGE_POISON 0xaa
+
 /********** mm/slab.c **********/
 /*
  * Magic nums for obj red zoning.
index b8bdb96eff78b8112ddf4717b651c4ef1126ead7..fbfa3d44d33d819ef6af58c95e136ed6cc7e594a 100644 (file)
@@ -41,9 +41,6 @@ enum {
  * while parent/subdir create the directory structure (every
  * /proc file has a parent, but "subdir" is NULL for all
  * non-directory entries).
- *
- * "owner" is used to protect module
- * from unloading while proc_dir_entry is in use
  */
 
 typedef        int (read_proc_t)(char *page, char **start, off_t off,
@@ -70,7 +67,6 @@ struct proc_dir_entry {
         * somewhere.
         */
        const struct file_operations *proc_fops;
-       struct module *owner;
        struct proc_dir_entry *next, *parent, *subdir;
        void *data;
        read_proc_t *read_proc;
index 98b93ca4db064e5d6ebae919206fe5ed55a45427..67c15653fc230c9341ed1131c1e846156c6772bb 100644 (file)
@@ -94,6 +94,7 @@ extern void ptrace_notify(int exit_code);
 extern void __ptrace_link(struct task_struct *child,
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
+extern void exit_ptrace(struct task_struct *tracer);
 extern void ptrace_fork(struct task_struct *task, unsigned long clone_flags);
 #define PTRACE_MODE_READ   1
 #define PTRACE_MODE_ATTACH 2
index 3945f803d514536b30931aff8df5489fec1f0126..7c775751392c58003a896a0c2741cb134343ce9d 100644 (file)
@@ -28,4 +28,4 @@ int pwm_enable(struct pwm_device *pwm);
  */
 void pwm_disable(struct pwm_device *pwm);
 
-#endif /* __ASM_ARCH_PWM_H */
+#endif /* __LINUX_PWM_H */
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
deleted file mode 100644 (file)
index 82bea14..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-   md.h : Multiple Devices driver for Linux
-          Copyright (C) 1996-98 Ingo Molnar, Gadi Oxman
-          Copyright (C) 1994-96 Marc ZYNGIER
-         <zyngier@ufr-info-p7.ibp.fr> or
-         <maz@gloups.fdn.fr>
-         
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-*/
-
-#ifndef _MD_H
-#define _MD_H
-
-#include <linux/blkdev.h>
-#include <linux/seq_file.h>
-
-/*
- * 'md_p.h' holds the 'physical' layout of RAID devices
- * 'md_u.h' holds the user <=> kernel API
- *
- * 'md_k.h' holds kernel internal definitions
- */
-
-#include <linux/raid/md_p.h>
-#include <linux/raid/md_u.h>
-#include <linux/raid/md_k.h>
-
-#ifdef CONFIG_MD
-
-/*
- * Different major versions are not compatible.
- * Different minor versions are only downward compatible.
- * Different patchlevel versions are downward and upward compatible.
- */
-#define MD_MAJOR_VERSION                0
-#define MD_MINOR_VERSION                90
-/*
- * MD_PATCHLEVEL_VERSION indicates kernel functionality.
- * >=1 means different superblock formats are selectable using SET_ARRAY_INFO
- *     and major_version/minor_version accordingly
- * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
- *     in the super status byte
- * >=3 means that bitmap superblock version 4 is supported, which uses
- *     little-ending representation rather than host-endian
- */
-#define MD_PATCHLEVEL_VERSION           3
-
-extern int mdp_major;
-
-extern int register_md_personality(struct mdk_personality *p);
-extern int unregister_md_personality(struct mdk_personality *p);
-extern mdk_thread_t * md_register_thread(void (*run) (mddev_t *mddev),
-                               mddev_t *mddev, const char *name);
-extern void md_unregister_thread(mdk_thread_t *thread);
-extern void md_wakeup_thread(mdk_thread_t *thread);
-extern void md_check_recovery(mddev_t *mddev);
-extern void md_write_start(mddev_t *mddev, struct bio *bi);
-extern void md_write_end(mddev_t *mddev);
-extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
-extern void md_error(mddev_t *mddev, mdk_rdev_t *rdev);
-
-extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
-                          sector_t sector, int size, struct page *page);
-extern void md_super_wait(mddev_t *mddev);
-extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
-                       struct page *page, int rw);
-extern void md_do_sync(mddev_t *mddev);
-extern void md_new_event(mddev_t *mddev);
-extern int md_allow_write(mddev_t *mddev);
-extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
-
-#endif /* CONFIG_MD */
-#endif 
-
index 7192035fc4b0680094f3c4f0c2780a79c20dfd1b..fb1abb3367e9520a7e68cf738709e7510abe80f0 100644 (file)
 #ifndef _MD_U_H
 #define _MD_U_H
 
+/*
+ * Different major versions are not compatible.
+ * Different minor versions are only downward compatible.
+ * Different patchlevel versions are downward and upward compatible.
+ */
+#define MD_MAJOR_VERSION                0
+#define MD_MINOR_VERSION                90
+/*
+ * MD_PATCHLEVEL_VERSION indicates kernel functionality.
+ * >=1 means different superblock formats are selectable using SET_ARRAY_INFO
+ *     and major_version/minor_version accordingly
+ * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
+ *     in the super status byte
+ * >=3 means that bitmap superblock version 4 is supported, which uses
+ *     little-ending representation rather than host-endian
+ */
+#define MD_PATCHLEVEL_VERSION           3
+
 /* ioctls */
 
 /* status */
 #define STOP_ARRAY_RO          _IO (MD_MAJOR, 0x33)
 #define RESTART_ARRAY_RW       _IO (MD_MAJOR, 0x34)
 
+/* 63 partitions with the alternate major number (mdp) */
+#define MdpMinorShift 6
+#ifdef __KERNEL__
+extern int mdp_major;
+#endif
+
 typedef struct mdu_version_s {
        int major;
        int minor;
@@ -85,6 +109,17 @@ typedef struct mdu_array_info_s {
 
 } mdu_array_info_t;
 
+/* non-obvious values for 'level' */
+#define        LEVEL_MULTIPATH         (-4)
+#define        LEVEL_LINEAR            (-1)
+#define        LEVEL_FAULTY            (-5)
+
+/* we need a value for 'no level specified' and 0
+ * means 'raid0', so we need something else.  This is
+ * for internal use only
+ */
+#define        LEVEL_NONE              (-1000000)
+
 typedef struct mdu_disk_info_s {
        /*
         * configuration/status of one particular disk
similarity index 86%
rename from drivers/md/raid6.h
rename to include/linux/raid/pq.h
index 98dcde88470e4c23b8fc204e46587be0243bfa32..d92480f8285c76bec5b67fb5950fdc12f2d06c3c 100644 (file)
@@ -5,7 +5,7 @@
  *   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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
  *   (at your option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
 
 /* Set to 1 to use kernel-wide empty_zero_page */
 #define RAID6_USE_EMPTY_ZERO_PAGE 0
-
-#include <linux/raid/md.h>
-#include <linux/raid/raid5.h>
-
-typedef raid5_conf_t raid6_conf_t; /* Same configuration */
-
-/* Additional compute_parity mode -- updates the parity w/o LOCKING */
-#define UPDATE_PARITY  4
+#include <linux/blkdev.h>
 
 /* We need a pre-zeroed page... if we don't want to use the kernel-provided
    one define it here */
@@ -68,6 +61,10 @@ extern const char raid6_empty_zero_page[PAGE_SIZE];
 #define enable_kernel_altivec()
 #define disable_kernel_altivec()
 
+#define EXPORT_SYMBOL(sym)
+#define MODULE_LICENSE(licence)
+#define subsys_initcall(x)
+#define module_exit(x)
 #endif /* __KERNEL__ */
 
 /* Routine choices */
@@ -98,9 +95,11 @@ extern const u8 raid6_gfinv[256]      __attribute__((aligned(256)));
 extern const u8 raid6_gfexi[256]      __attribute__((aligned(256)));
 
 /* Recovery routines */
-void raid6_2data_recov(int disks, size_t bytes, int faila, int failb, void **ptrs);
+void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
+                      void **ptrs);
 void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs);
-void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs);
+void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
+                     void **ptrs);
 
 /* Some definitions to allow code to be compiled for testing in userspace */
 #ifndef __KERNEL__
@@ -108,8 +107,11 @@ void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs
 # define jiffies       raid6_jiffies()
 # define printk        printf
 # define GFP_KERNEL    0
-# define __get_free_pages(x,y) ((unsigned long)mmap(NULL, PAGE_SIZE << (y), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0))
-# define free_pages(x,y)       munmap((void *)(x), (y)*PAGE_SIZE)
+# define __get_free_pages(x, y)        ((unsigned long)mmap(NULL, PAGE_SIZE << (y), \
+                                                    PROT_READ|PROT_WRITE,   \
+                                                    MAP_PRIVATE|MAP_ANONYMOUS,\
+                                                    0, 0))
+# define free_pages(x, y)      munmap((void *)(x), (y)*PAGE_SIZE)
 
 static inline void cpu_relax(void)
 {
index 3e120587eadac53669053e040db23b747ad4a91f..5a210959e3f8a71f5251ccf325bc52f629df124a 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _XOR_H
 #define _XOR_H
 
-#include <linux/raid/md.h>
-
 #define MAX_XOR_BLOCKS 4
 
 extern void xor_blocks(unsigned int count, unsigned int bytes,
index e84b0a9feda579e64025fdbd67f4b4d5127f9620..a6d014005d49e6df67ded6c9b7cede3acbd40501 100644 (file)
@@ -10,6 +10,8 @@
  *
  */
 
+struct regulator_init_data;
+
 /**
  * bq24022_mach_info - platform data for bq24022
  * @gpio_nce: GPIO line connected to the nCE pin, used to enable / disable charging
@@ -18,4 +20,5 @@
 struct bq24022_mach_info {
        int gpio_nce;
        int gpio_iset2;
+       struct regulator_init_data *init_data;
 };
index 801bf77ff4e2c522f90ffafabc648f8679309cba..277f4b964df531a9f4cde24cbb8b60c3c1a0c8f7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
  *
- * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -88,6 +88,7 @@
  * FAIL           Regulator output has failed.
  * OVER_TEMP      Regulator over temp.
  * FORCE_DISABLE  Regulator shut down by software.
+ * VOLTAGE_CHANGE Regulator voltage changed.
  *
  * NOTE: These events can be OR'ed together when passed into handler.
  */
@@ -98,6 +99,7 @@
 #define REGULATOR_EVENT_FAIL                   0x08
 #define REGULATOR_EVENT_OVER_TEMP              0x10
 #define REGULATOR_EVENT_FORCE_DISABLE          0x20
+#define REGULATOR_EVENT_VOLTAGE_CHANGE         0x40
 
 struct regulator;
 
@@ -140,6 +142,8 @@ int regulator_bulk_disable(int num_consumers,
 void regulator_bulk_free(int num_consumers,
                         struct regulator_bulk_data *consumers);
 
+int regulator_count_voltages(struct regulator *regulator);
+int regulator_list_voltage(struct regulator *regulator, unsigned selector);
 int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
 int regulator_get_voltage(struct regulator *regulator);
 int regulator_set_current_limit(struct regulator *regulator,
index 2dae05705f13e21b9d3410b6c5dfb494a1b9bab8..4848d8dacd903b81edba899dd76d69eefed487a8 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
  *
- * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 struct regulator_dev;
 struct regulator_init_data;
 
+enum regulator_status {
+       REGULATOR_STATUS_OFF,
+       REGULATOR_STATUS_ON,
+       REGULATOR_STATUS_ERROR,
+       /* fast/normal/idle/standby are flavors of "on" */
+       REGULATOR_STATUS_FAST,
+       REGULATOR_STATUS_NORMAL,
+       REGULATOR_STATUS_IDLE,
+       REGULATOR_STATUS_STANDBY,
+};
+
 /**
  * struct regulator_ops - regulator operations.
  *
- * This struct describes regulator operations which can be implemented by
- * regulator chip drivers.
- *
- * @enable: Enable the regulator.
- * @disable: Disable the regulator.
+ * @enable: Configure the regulator as enabled.
+ * @disable: Configure the regulator as disabled.
  * @is_enabled: Return 1 if the regulator is enabled, 0 otherwise.
  *
  * @set_voltage: Set the voltage for the regulator within the range specified.
  *               The driver should select the voltage closest to min_uV.
  * @get_voltage: Return the currently configured voltage for the regulator.
+ * @list_voltage: Return one of the supported voltages, in microvolts; zero
+ *     if the selector indicates a voltage that is unusable on this system;
+ *     or negative errno.  Selectors range from zero to one less than
+ *     regulator_desc.n_voltages.  Voltages may be reported in any order.
  *
  * @set_current_limit: Configure a limit for a current-limited regulator.
- * @get_current_limit: Get the limit for a current-limited regulator.
+ * @get_current_limit: Get the configured limit for a current-limited regulator.
  *
- * @set_mode: Set the operating mode for the regulator.
- * @get_mode: Get the current operating mode for the regulator.
+ * @get_mode: Get the configured operating mode for the regulator.
+ * @get_status: Return actual (not as-configured) status of regulator, as a
+ *     REGULATOR_STATUS value (or negative errno)
  * @get_optimum_mode: Get the most efficient operating mode for the regulator
  *                    when running with the specified parameters.
  *
@@ -51,9 +64,15 @@ struct regulator_init_data;
  *                       suspended.
  * @set_suspend_mode: Set the operating mode for the regulator when the
  *                    system is suspended.
+ *
+ * This struct describes regulator operations which can be implemented by
+ * regulator chip drivers.
  */
 struct regulator_ops {
 
+       /* enumerate supported voltages */
+       int (*list_voltage) (struct regulator_dev *, unsigned selector);
+
        /* get/set regulator voltage */
        int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV);
        int (*get_voltage) (struct regulator_dev *);
@@ -72,6 +91,13 @@ struct regulator_ops {
        int (*set_mode) (struct regulator_dev *, unsigned int mode);
        unsigned int (*get_mode) (struct regulator_dev *);
 
+       /* report regulator status ... most other accessors report
+        * control inputs, this reports results of combining inputs
+        * from Linux (and other sources) with the actual load.
+        * returns REGULATOR_STATUS_* or negative errno.
+        */
+       int (*get_status)(struct regulator_dev *);
+
        /* get most efficient regulator operating mode for load */
        unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
                                          int output_uV, int load_uA);
@@ -106,6 +132,7 @@ enum regulator_type {
  *
  * @name: Identifying name for the regulator.
  * @id: Numerical identifier for the regulator.
+ * @n_voltages: Number of selectors available for ops.list_voltage().
  * @ops: Regulator operations table.
  * @irq: Interrupt number for the regulator.
  * @type: Indicates if the regulator is a voltage or current regulator.
@@ -114,14 +141,48 @@ enum regulator_type {
 struct regulator_desc {
        const char *name;
        int id;
+       unsigned n_voltages;
        struct regulator_ops *ops;
        int irq;
        enum regulator_type type;
        struct module *owner;
 };
 
+/*
+ * struct regulator_dev
+ *
+ * Voltage / Current regulator class device. One for each
+ * regulator.
+ *
+ * This should *not* be used directly by anything except the regulator
+ * core and notification injection (which should take the mutex and do
+ * no other direct access).
+ */
+struct regulator_dev {
+       struct regulator_desc *desc;
+       int use_count;
+
+       /* lists we belong to */
+       struct list_head list; /* list of all regulators */
+       struct list_head slist; /* list of supplied regulators */
+
+       /* lists we own */
+       struct list_head consumer_list; /* consumers we supply */
+       struct list_head supply_list; /* regulators we supply */
+
+       struct blocking_notifier_head notifier;
+       struct mutex mutex; /* consumer lock */
+       struct module *owner;
+       struct device dev;
+       struct regulation_constraints *constraints;
+       struct regulator_dev *supply;   /* for tree */
+
+       void *reg_data;         /* regulator_dev data */
+};
+
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-       struct device *dev, void *driver_data);
+       struct device *dev, struct regulator_init_data *init_data,
+       void *driver_data);
 void regulator_unregister(struct regulator_dev *rdev);
 
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
index 1387a5d2190e627801c90ec0308b538265f6d1c6..91b4da31f1b510a0c21bc5d579b0143e753152ec 100644 (file)
 #ifndef __REGULATOR_FIXED_H
 #define __REGULATOR_FIXED_H
 
+struct regulator_init_data;
+
 struct fixed_voltage_config {
        const char *supply_name;
        int microvolts;
+       struct regulator_init_data *init_data;
 };
 
 #endif
index 3794773b23d2cfed344b2c3b00efd9606e1ff41d..bac64fa390f20981c1dd8a1fc8b49657bc2ef30b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
  *
- * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -73,7 +73,9 @@ struct regulator_state {
  *
  * @always_on: Set if the regulator should never be disabled.
  * @boot_on: Set if the regulator is enabled when the system is initially
- *           started.
+ *           started.  If the regulator is not enabled by the hardware or
+ *           bootloader then it will be enabled when the constraints are
+ *           applied.
  * @apply_uV: Apply the voltage constraint when initialising.
  *
  * @input_uV: Input voltage for regulator when supplied by another regulator.
@@ -83,6 +85,7 @@ struct regulator_state {
  * @state_standby: State for regulator when system is suspended in standby
  *                 mode.
  * @initial_state: Suspend state to set by default.
+ * @initial_mode: Mode to set at startup.
  */
 struct regulation_constraints {
 
@@ -111,6 +114,9 @@ struct regulation_constraints {
        struct regulator_state state_standby;
        suspend_state_t initial_state; /* suspend state to set at init */
 
+       /* mode to set on startup */
+       unsigned int initial_mode;
+
        /* constriant flags */
        unsigned always_on:1;   /* regulator never off when system is on */
        unsigned boot_on:1;     /* bootloader/firmware enabled regulator */
@@ -160,4 +166,6 @@ struct regulator_init_data {
 
 int regulator_suspend_prepare(suspend_state_t state);
 
+void regulator_has_full_constraints(void);
+
 #endif
index 52240e02de026fdfd0657edf61a5b0aecdd0bb33..8cc65757e47adfc476ed4b2ca2c1d020c06ab6bf 100644 (file)
@@ -80,7 +80,8 @@ static inline int reiserfs_acl_chmod(struct inode *inode)
 }
 
 static inline int
-reiserfs_inherit_default_acl(const struct inode *dir, struct dentry *dentry,
+reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
+                            const struct inode *dir, struct dentry *dentry,
                             struct inode *inode)
 {
        return 0;
index bf74e63c98fec6d4249df6e5fdc00553e3104398..8ba646e610d9232ce6b9b1a0bff42844a866b456 100644 (file)
  * is used depends on the board. */
 struct v3020_platform_data {
        int leftshift; /* (1<<(leftshift)) & readl() */
+
+       int use_gpio:1;
+       unsigned int gpio_cs;
+       unsigned int gpio_wr;
+       unsigned int gpio_rd;
+       unsigned int gpio_io;
 };
 
 #define V3020_STATUS_0 0x00
index 4046b75563c1c26dc8d11352b77c73139d1b99ce..60f88a7fb13d71ec5abd0f174e6777fc77b0f5b9 100644 (file)
@@ -99,6 +99,7 @@ struct rtc_pll_info {
 
 #ifdef __KERNEL__
 
+#include <linux/types.h>
 #include <linux/interrupt.h>
 
 extern int rtc_month_days(unsigned int month, unsigned int year);
@@ -232,6 +233,11 @@ int rtc_register(rtc_task_t *task);
 int rtc_unregister(rtc_task_t *task);
 int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
 
+static inline bool is_leap_year(unsigned int year)
+{
+       return (!(year % 4) && (year % 100)) || !(year % 400);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_RTC_H_ */
index 1d19c025f9d2e78b34692b3f350d9bef6fe522ed..9da5aa0771ef906b7e09b6cde69f31ff952a4f07 100644 (file)
@@ -68,7 +68,7 @@ struct sched_param {
 #include <linux/smp.h>
 #include <linux/sem.h>
 #include <linux/signal.h>
-#include <linux/fs_struct.h>
+#include <linux/path.h>
 #include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/pid.h>
@@ -97,6 +97,7 @@ struct futex_pi_state;
 struct robust_list_head;
 struct bio;
 struct bts_tracer;
+struct fs_struct;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -331,7 +332,9 @@ extern signed long schedule_timeout(signed long timeout);
 extern signed long schedule_timeout_interruptible(signed long timeout);
 extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
+asmlinkage void __schedule(void);
 asmlinkage void schedule(void);
+extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner);
 
 struct nsproxy;
 struct user_namespace;
@@ -389,8 +392,15 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
                (mm)->hiwater_vm = (mm)->total_vm;      \
 } while (0)
 
-#define get_mm_hiwater_rss(mm) max((mm)->hiwater_rss, get_mm_rss(mm))
-#define get_mm_hiwater_vm(mm)  max((mm)->hiwater_vm, (mm)->total_vm)
+static inline unsigned long get_mm_hiwater_rss(struct mm_struct *mm)
+{
+       return max(mm->hiwater_rss, get_mm_rss(mm));
+}
+
+static inline unsigned long get_mm_hiwater_vm(struct mm_struct *mm)
+{
+       return max(mm->hiwater_vm, mm->total_vm);
+}
 
 extern void set_dumpable(struct mm_struct *mm, int value);
 extern int get_dumpable(struct mm_struct *mm);
@@ -538,25 +548,8 @@ struct signal_struct {
 
        struct list_head cpu_timers[3];
 
-       /* job control IDs */
-
-       /*
-        * pgrp and session fields are deprecated.
-        * use the task_session_Xnr and task_pgrp_Xnr routines below
-        */
-
-       union {
-               pid_t pgrp __deprecated;
-               pid_t __pgrp;
-       };
-
        struct pid *tty_old_pgrp;
 
-       union {
-               pid_t session __deprecated;
-               pid_t __session;
-       };
-
        /* boolean value for session group leader */
        int leader;
 
@@ -1334,6 +1327,7 @@ struct task_struct {
        int lockdep_depth;
        unsigned int lockdep_recursion;
        struct held_lock held_locks[MAX_LOCK_DEPTH];
+       gfp_t lockdep_reclaim_gfp;
 #endif
 
 /* journalling filesystem info */
@@ -1459,16 +1453,6 @@ static inline int rt_task(struct task_struct *p)
        return rt_prio(p->prio);
 }
 
-static inline void set_task_session(struct task_struct *tsk, pid_t session)
-{
-       tsk->signal->__session = session;
-}
-
-static inline void set_task_pgrp(struct task_struct *tsk, pid_t pgrp)
-{
-       tsk->signal->__pgrp = pgrp;
-}
-
 static inline struct pid *task_pid(struct task_struct *task)
 {
        return task->pids[PIDTYPE_PID].pid;
@@ -1479,6 +1463,11 @@ static inline struct pid *task_tgid(struct task_struct *task)
        return task->group_leader->pids[PIDTYPE_PID].pid;
 }
 
+/*
+ * Without tasklist or rcu lock it is not safe to dereference
+ * the result of task_pgrp/task_session even if task == current,
+ * we can race with another thread doing sys_setsid/sys_setpgid.
+ */
 static inline struct pid *task_pgrp(struct task_struct *task)
 {
        return task->group_leader->pids[PIDTYPE_PGID].pid;
@@ -1504,17 +1493,23 @@ struct pid_namespace;
  *
  * see also pid_nr() etc in include/linux/pid.h
  */
+pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
+                       struct pid_namespace *ns);
 
 static inline pid_t task_pid_nr(struct task_struct *tsk)
 {
        return tsk->pid;
 }
 
-pid_t task_pid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
+static inline pid_t task_pid_nr_ns(struct task_struct *tsk,
+                                       struct pid_namespace *ns)
+{
+       return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns);
+}
 
 static inline pid_t task_pid_vnr(struct task_struct *tsk)
 {
-       return pid_vnr(task_pid(tsk));
+       return __task_pid_nr_ns(tsk, PIDTYPE_PID, NULL);
 }
 
 
@@ -1531,31 +1526,34 @@ static inline pid_t task_tgid_vnr(struct task_struct *tsk)
 }
 
 
-static inline pid_t task_pgrp_nr(struct task_struct *tsk)
+static inline pid_t task_pgrp_nr_ns(struct task_struct *tsk,
+                                       struct pid_namespace *ns)
 {
-       return tsk->signal->__pgrp;
+       return __task_pid_nr_ns(tsk, PIDTYPE_PGID, ns);
 }
 
-pid_t task_pgrp_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-
 static inline pid_t task_pgrp_vnr(struct task_struct *tsk)
 {
-       return pid_vnr(task_pgrp(tsk));
+       return __task_pid_nr_ns(tsk, PIDTYPE_PGID, NULL);
 }
 
 
-static inline pid_t task_session_nr(struct task_struct *tsk)
+static inline pid_t task_session_nr_ns(struct task_struct *tsk,
+                                       struct pid_namespace *ns)
 {
-       return tsk->signal->__session;
+       return __task_pid_nr_ns(tsk, PIDTYPE_SID, ns);
 }
 
-pid_t task_session_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-
 static inline pid_t task_session_vnr(struct task_struct *tsk)
 {
-       return pid_vnr(task_session(tsk));
+       return __task_pid_nr_ns(tsk, PIDTYPE_SID, NULL);
 }
 
+/* obsolete, do not use */
+static inline pid_t task_pgrp_nr(struct task_struct *tsk)
+{
+       return task_pgrp_nr_ns(tsk, &init_pid_ns);
+}
 
 /**
  * pid_alive - check that a task structure is not stale
@@ -1965,7 +1963,8 @@ extern void mm_release(struct task_struct *, struct mm_struct *);
 /* Allocate a new mm structure and copy contents from tsk->mm */
 extern struct mm_struct *dup_mm(struct task_struct *tsk);
 
-extern int  copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
+extern int copy_thread(unsigned long, unsigned long, unsigned long,
+                       struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
 extern void exit_thread(void);
 
@@ -2050,6 +2049,11 @@ static inline int thread_group_empty(struct task_struct *p)
 #define delay_group_leader(p) \
                (thread_group_leader(p) && !thread_group_empty(p))
 
+static inline int task_detached(struct task_struct *p)
+{
+       return p->exit_signal == -1;
+}
+
 /*
  * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring
  * subscriptions and synchronises with wait4().  Also used in procfs.  Also
index f616f31576d719597cd91b25498fece72e24cc8d..004f3b3342c5d580664b73aab18a9229186c9ed9 100644 (file)
@@ -55,7 +55,7 @@ int seq_bitmap(struct seq_file *m, const unsigned long *bits,
                                   unsigned int nr_bits);
 static inline int seq_cpumask(struct seq_file *m, const struct cpumask *mask)
 {
-       return seq_bitmap(m, mask->bits, nr_cpu_ids);
+       return seq_bitmap(m, cpumask_bits(mask), nr_cpu_ids);
 }
 
 static inline int seq_nodemask(struct seq_file *m, nodemask_t *mask)
@@ -63,12 +63,13 @@ static inline int seq_nodemask(struct seq_file *m, nodemask_t *mask)
        return seq_bitmap(m, mask->bits, MAX_NUMNODES);
 }
 
-int seq_bitmap_list(struct seq_file *m, unsigned long *bits,
+int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
                unsigned int nr_bits);
 
-static inline int seq_cpumask_list(struct seq_file *m, cpumask_t *mask)
+static inline int seq_cpumask_list(struct seq_file *m,
+                                  const struct cpumask *mask)
 {
-       return seq_bitmap_list(m, mask->bits, NR_CPUS);
+       return seq_bitmap_list(m, cpumask_bits(mask), nr_cpu_ids);
 }
 
 static inline int seq_nodemask_list(struct seq_file *m, nodemask_t *mask)
index 55d67300fa10d128fd4254adff8a78fc05100a78..5fd389162f014ccb053d8563de6ce2a16cedd90f 100644 (file)
@@ -168,6 +168,7 @@ struct skb_shared_hwtstamps {
  * @software:          generate software time stamp
  * @in_progress:       device driver is going to provide
  *                     hardware time stamp
+ * @flags:             all shared_tx flags
  *
  * These flags are attached to packets as part of the
  * &skb_shared_info. Use skb_tx() to get a pointer.
diff --git a/include/linux/slow-work.h b/include/linux/slow-work.h
new file mode 100644 (file)
index 0000000..8595827
--- /dev/null
@@ -0,0 +1,95 @@
+/* Worker thread pool for slow items, such as filesystem lookups or mkdirs
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ *
+ * See Documentation/slow-work.txt
+ */
+
+#ifndef _LINUX_SLOW_WORK_H
+#define _LINUX_SLOW_WORK_H
+
+#ifdef CONFIG_SLOW_WORK
+
+#include <linux/sysctl.h>
+
+struct slow_work;
+
+/*
+ * The operations used to support slow work items
+ */
+struct slow_work_ops {
+       /* get a ref on a work item
+        * - return 0 if successful, -ve if not
+        */
+       int (*get_ref)(struct slow_work *work);
+
+       /* discard a ref to a work item */
+       void (*put_ref)(struct slow_work *work);
+
+       /* execute a work item */
+       void (*execute)(struct slow_work *work);
+};
+
+/*
+ * A slow work item
+ * - A reference is held on the parent object by the thread pool when it is
+ *   queued
+ */
+struct slow_work {
+       unsigned long           flags;
+#define SLOW_WORK_PENDING      0       /* item pending (further) execution */
+#define SLOW_WORK_EXECUTING    1       /* item currently executing */
+#define SLOW_WORK_ENQ_DEFERRED 2       /* item enqueue deferred */
+#define SLOW_WORK_VERY_SLOW    3       /* item is very slow */
+       const struct slow_work_ops *ops; /* operations table for this item */
+       struct list_head        link;   /* link in queue */
+};
+
+/**
+ * slow_work_init - Initialise a slow work item
+ * @work: The work item to initialise
+ * @ops: The operations to use to handle the slow work item
+ *
+ * Initialise a slow work item.
+ */
+static inline void slow_work_init(struct slow_work *work,
+                                 const struct slow_work_ops *ops)
+{
+       work->flags = 0;
+       work->ops = ops;
+       INIT_LIST_HEAD(&work->link);
+}
+
+/**
+ * slow_work_init - Initialise a very slow work item
+ * @work: The work item to initialise
+ * @ops: The operations to use to handle the slow work item
+ *
+ * Initialise a very slow work item.  This item will be restricted such that
+ * only a certain number of the pool threads will be able to execute items of
+ * this type.
+ */
+static inline void vslow_work_init(struct slow_work *work,
+                                  const struct slow_work_ops *ops)
+{
+       work->flags = 1 << SLOW_WORK_VERY_SLOW;
+       work->ops = ops;
+       INIT_LIST_HEAD(&work->link);
+}
+
+extern int slow_work_enqueue(struct slow_work *work);
+extern int slow_work_register_user(void);
+extern void slow_work_unregister_user(void);
+
+#ifdef CONFIG_SYSCTL
+extern ctl_table slow_work_sysctls[];
+#endif
+
+#endif /* CONFIG_SLOW_WORK */
+#endif /* _LINUX_SLOW_WORK_H */
index bbacb7baa44618b973a280a3aeac3eab68084009..a69db820eed6b33bfe71e6f946536209dd935372 100644 (file)
@@ -38,7 +38,7 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
 /*
  * main cross-CPU interfaces, handles INIT, TLB flush, STOP, etc.
  * (defined in asm header):
- */ 
+ */
 
 /*
  * stops all CPUs but the current one:
@@ -82,7 +82,8 @@ smp_call_function_mask(cpumask_t mask, void(*func)(void *info), void *info,
        return 0;
 }
 
-void __smp_call_function_single(int cpuid, struct call_single_data *data);
+void __smp_call_function_single(int cpuid, struct call_single_data *data,
+                               int wait);
 
 /*
  * Generic and arch helpers
@@ -121,6 +122,8 @@ extern unsigned int setup_max_cpus;
 
 #else /* !SMP */
 
+static inline void smp_send_stop(void) { }
+
 /*
  *     These macros fold the SMP functionality into a single CPU system
  */
index 1085212c446e2bf562e9b4e1867be002af9ebaf6..306e7b1c69edf30243836e89d7141e47934e7a98 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __LINUX_SPI_EEPROM_H
 #define __LINUX_SPI_EEPROM_H
 
+#include <linux/memory.h>
+
 /*
  * Put one of these structures in platform_data for SPI EEPROMS handled
  * by the "at25" driver.  On SPI, most EEPROMS understand the same core
@@ -17,6 +19,10 @@ struct spi_eeprom {
 #define        EE_ADDR2        0x0002                  /* 16 bit addrs */
 #define        EE_ADDR3        0x0004                  /* 24 bit addrs */
 #define        EE_READONLY     0x0008                  /* disallow writes */
+
+       /* for exporting this chip's data to other kernel code */
+       void (*setup)(struct memory_accessor *mem, void *context);
+       void *context;
 };
 
 #endif /* __LINUX_SPI_EEPROM_H */
index 0f01a0f1f40c9718a67dfc08f2561a0c13521fc7..ca6782ee4b9fce4f9208020e552129db6f0fbd5a 100644 (file)
  *     ...
  *     };
  *
+ * If chipselect is not used (there's only one device on the bus), assign
+ * SPI_GPIO_NO_CHIPSELECT to the controller_data:
+ *             .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT;
+ *
  * If the bitbanged bus is later switched to a "native" controller,
  * that platform_device and controller_data should be removed.
  */
 
+#define SPI_GPIO_NO_CHIPSELECT         ((unsigned long)-1l)
+
 /**
  * struct spi_gpio_platform_data - parameter for bitbanged SPI master
  * @sck: number of the GPIO used for clock output
index a0c66a2e00add24f97bfcc908dff123fa4a200c6..252b245cfcf4cb098658da65f60f02436b12902f 100644 (file)
@@ -153,9 +153,11 @@ do {                                                               \
  extern int _raw_spin_trylock(spinlock_t *lock);
  extern void _raw_spin_unlock(spinlock_t *lock);
  extern void _raw_read_lock(rwlock_t *lock);
+#define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock)
  extern int _raw_read_trylock(rwlock_t *lock);
  extern void _raw_read_unlock(rwlock_t *lock);
  extern void _raw_write_lock(rwlock_t *lock);
+#define _raw_write_lock_flags(lock, flags) _raw_write_lock(lock)
  extern int _raw_write_trylock(rwlock_t *lock);
  extern void _raw_write_unlock(rwlock_t *lock);
 #else
@@ -165,9 +167,13 @@ do {                                                               \
 # define _raw_spin_trylock(lock)       __raw_spin_trylock(&(lock)->raw_lock)
 # define _raw_spin_unlock(lock)                __raw_spin_unlock(&(lock)->raw_lock)
 # define _raw_read_lock(rwlock)                __raw_read_lock(&(rwlock)->raw_lock)
+# define _raw_read_lock_flags(lock, flags) \
+               __raw_read_lock_flags(&(lock)->raw_lock, *(flags))
 # define _raw_read_trylock(rwlock)     __raw_read_trylock(&(rwlock)->raw_lock)
 # define _raw_read_unlock(rwlock)      __raw_read_unlock(&(rwlock)->raw_lock)
 # define _raw_write_lock(rwlock)       __raw_write_lock(&(rwlock)->raw_lock)
+# define _raw_write_lock_flags(lock, flags) \
+               __raw_write_lock_flags(&(lock)->raw_lock, *(flags))
 # define _raw_write_trylock(rwlock)    __raw_write_trylock(&(rwlock)->raw_lock)
 # define _raw_write_unlock(rwlock)     __raw_write_unlock(&(rwlock)->raw_lock)
 #endif
index d18fc198aa2fd3c337e821e78eedc97e5ea8459b..8852739f36dfe94529ad3bdb09555741b0829b9e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/stddef.h>      /* for NULL */
 
 extern char *strndup_user(const char __user *, long);
+extern void *memdup_user(const void __user *, size_t);
 
 /*
  * Include machine specific inline routines
index 3435d24bfe5515d6abd41f3323316aadb68f0c11..d3a4c0231933c4e3e5885fd46362b15a6ce96a77 100644 (file)
@@ -69,7 +69,6 @@ struct svc_serv {
        struct list_head        sv_tempsocks;   /* all temporary sockets */
        int                     sv_tmpcnt;      /* count of temporary sockets */
        struct timer_list       sv_temptimer;   /* timer for aging temporary sockets */
-       sa_family_t             sv_family;      /* listener's address family */
 
        char *                  sv_name;        /* service name */
 
@@ -385,19 +384,19 @@ struct svc_procedure {
 /*
  * Function prototypes.
  */
-struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
+struct svc_serv *svc_create(struct svc_program *, unsigned int,
                            void (*shutdown)(struct svc_serv *));
 struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
                                        struct svc_pool *pool);
 void              svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
-                       sa_family_t, void (*shutdown)(struct svc_serv *),
+                       void (*shutdown)(struct svc_serv *),
                        svc_thread_fn, struct module *);
 int               svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 void              svc_destroy(struct svc_serv *);
 int               svc_process(struct svc_rqst *);
-int               svc_register(const struct svc_serv *, const unsigned short,
-                               const unsigned short);
+int               svc_register(const struct svc_serv *, const int,
+                               const unsigned short, const unsigned short);
 
 void              svc_wake_up(struct svc_serv *);
 void              svc_reserve(struct svc_rqst *rqstp, int space);
index 0127daca43548c85c219abc6445101165380eef9..0d9cb6ef28b00cf58c7b25824a0325e8909eb98a 100644 (file)
@@ -71,7 +71,8 @@ int   svc_reg_xprt_class(struct svc_xprt_class *);
 void   svc_unreg_xprt_class(struct svc_xprt_class *);
 void   svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
                      struct svc_serv *);
-int    svc_create_xprt(struct svc_serv *, char *, unsigned short, int);
+int    svc_create_xprt(struct svc_serv *, const char *, const int,
+                       const unsigned short, int);
 void   svc_xprt_enqueue(struct svc_xprt *xprt);
 void   svc_xprt_received(struct svc_xprt *);
 void   svc_xprt_put(struct svc_xprt *xprt);
@@ -80,7 +81,8 @@ void  svc_close_xprt(struct svc_xprt *xprt);
 void   svc_delete_xprt(struct svc_xprt *xprt);
 int    svc_port_is_privileged(struct sockaddr *sin);
 int    svc_print_xprts(char *buf, int maxlen);
-struct svc_xprt *svc_find_xprt(struct svc_serv *, char *, int, int);
+struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
+                       const sa_family_t af, const unsigned short port);
 int    svc_xprt_names(struct svc_serv *serv, char *buf, int buflen);
 
 static inline void svc_xprt_get(struct svc_xprt *xprt)
@@ -88,29 +90,32 @@ static inline void svc_xprt_get(struct svc_xprt *xprt)
        kref_get(&xprt->xpt_ref);
 }
 static inline void svc_xprt_set_local(struct svc_xprt *xprt,
-                                     struct sockaddr *sa, int salen)
+                                     const struct sockaddr *sa,
+                                     const size_t salen)
 {
        memcpy(&xprt->xpt_local, sa, salen);
        xprt->xpt_locallen = salen;
 }
 static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
-                                      struct sockaddr *sa, int salen)
+                                      const struct sockaddr *sa,
+                                      const size_t salen)
 {
        memcpy(&xprt->xpt_remote, sa, salen);
        xprt->xpt_remotelen = salen;
 }
-static inline unsigned short svc_addr_port(struct sockaddr *sa)
+static inline unsigned short svc_addr_port(const struct sockaddr *sa)
 {
-       unsigned short ret = 0;
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+
        switch (sa->sa_family) {
        case AF_INET:
-               ret = ntohs(((struct sockaddr_in *)sa)->sin_port);
-               break;
+               return ntohs(sin->sin_port);
        case AF_INET6:
-               ret = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
-               break;
+               return ntohs(sin6->sin6_port);
        }
-       return ret;
+
+       return 0;
 }
 
 static inline size_t svc_addr_len(struct sockaddr *sa)
@@ -124,36 +129,39 @@ static inline size_t svc_addr_len(struct sockaddr *sa)
        return -EAFNOSUPPORT;
 }
 
-static inline unsigned short svc_xprt_local_port(struct svc_xprt *xprt)
+static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt)
 {
-       return svc_addr_port((struct sockaddr *)&xprt->xpt_local);
+       return svc_addr_port((const struct sockaddr *)&xprt->xpt_local);
 }
 
-static inline unsigned short svc_xprt_remote_port(struct svc_xprt *xprt)
+static inline unsigned short svc_xprt_remote_port(const struct svc_xprt *xprt)
 {
-       return svc_addr_port((struct sockaddr *)&xprt->xpt_remote);
+       return svc_addr_port((const struct sockaddr *)&xprt->xpt_remote);
 }
 
-static inline char *__svc_print_addr(struct sockaddr *addr,
-                                    char *buf, size_t len)
+static inline char *__svc_print_addr(const struct sockaddr *addr,
+                                    char *buf, const size_t len)
 {
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)addr;
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr;
+
        switch (addr->sa_family) {
        case AF_INET:
-               snprintf(buf, len, "%pI4, port=%u",
-                       &((struct sockaddr_in *)addr)->sin_addr,
-                       ntohs(((struct sockaddr_in *) addr)->sin_port));
+               snprintf(buf, len, "%pI4, port=%u", &sin->sin_addr,
+                       ntohs(sin->sin_port));
                break;
 
        case AF_INET6:
                snprintf(buf, len, "%pI6, port=%u",
-                        &((struct sockaddr_in6 *)addr)->sin6_addr,
-                       ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
+                        &sin6->sin6_addr,
+                       ntohs(sin6->sin6_port));
                break;
 
        default:
                snprintf(buf, len, "unknown address type: %d", addr->sa_family);
                break;
        }
+
        return buf;
 }
 #endif /* SUNRPC_SVC_XPRT_H */
index 11fc71d50c1e8aa0806eb7d9ce24cbfd291831eb..1758d9f5b5c3bc1edda4dd0628feceacdd1b10df 100644 (file)
@@ -235,6 +235,7 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *
  */
 int                    xprt_register_transport(struct xprt_class *type);
 int                    xprt_unregister_transport(struct xprt_class *type);
+int                    xprt_load_transport(const char *);
 void                   xprt_set_retrans_timeout_def(struct rpc_task *task);
 void                   xprt_set_retrans_timeout_rtt(struct rpc_task *task);
 void                   xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
@@ -259,6 +260,7 @@ void                        xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
 #define XPRT_BOUND             (4)
 #define XPRT_BINDING           (5)
 #define XPRT_CLOSING           (6)
+#define XPRT_CONNECTION_ABORT  (7)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
index c7d9bb1832ba98ff88ea0fa19f7734b4f238103a..3e3a4364cbff4ef42d72e3341218296bdd9efe54 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef _LINUX_SUSPEND_H
 #define _LINUX_SUSPEND_H
 
-#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
-#include <asm/suspend.h>
-#endif
 #include <linux/swap.h>
 #include <linux/notifier.h>
 #include <linux/init.h>
index d30215578877e499e30cec085664c50619bc3056..62d81435347a7e2a7fa212fd9ae2b17e3e43224c 100644 (file)
@@ -212,7 +212,7 @@ static inline void lru_cache_add_active_file(struct page *page)
 
 /* linux/mm/vmscan.c */
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
-                                       gfp_t gfp_mask);
+                                       gfp_t gfp_mask, nodemask_t *mask);
 extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
                                                  gfp_t gfp_mask, bool noswap,
                                                  unsigned int swappiness);
@@ -382,6 +382,11 @@ static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
        return NULL;
 }
 
+static inline int swap_writepage(struct page *p, struct writeback_control *wbc)
+{
+       return 0;
+}
+
 static inline struct page *lookup_swap_cache(swp_entry_t swp)
 {
        return NULL;
index 99b8bdb17b2b9235cd9b937be79bacae78668835..0ff2779c44d09f28e773cdb5f2014198e7be7c42 100644 (file)
 #define MGSL_MODE_MONOSYNC     3
 #define MGSL_MODE_BISYNC       4
 #define MGSL_MODE_RAW          6
+#define MGSL_MODE_BASE_CLOCK    7
 
 #define MGSL_BUS_TYPE_ISA      1
 #define MGSL_BUS_TYPE_EISA     2
index f9f900cfd066f1ad19ac979dba0c48f2384b95e2..b299a82a05e7abd369f6b30d9b7182238112b685 100644 (file)
@@ -461,6 +461,10 @@ asmlinkage long sys_pread64(unsigned int fd, char __user *buf,
                            size_t count, loff_t pos);
 asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf,
                             size_t count, loff_t pos);
+asmlinkage long sys_preadv(unsigned long fd, const struct iovec __user *vec,
+                          unsigned long vlen, u32 pos_high, u32 pos_low);
+asmlinkage long sys_pwritev(unsigned long fd, const struct iovec __user *vec,
+                           unsigned long vlen, u32 pos_high, u32 pos_low);
 asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
 asmlinkage long sys_mkdir(const char __user *pathname, int mode);
 asmlinkage long sys_chdir(const char __user *filename);
index e2d662e3416e38026bbc7385f744481de1b7d0a0..6cdb6f3331f11b6a80d7cd2c85a45706937b16d3 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/ktime.h>
 #include <linux/stddef.h>
 #include <linux/debugobjects.h>
+#include <linux/stringify.h>
 
 struct tvec_base;
 
@@ -21,52 +22,126 @@ struct timer_list {
        char start_comm[16];
        int start_pid;
 #endif
+#ifdef CONFIG_LOCKDEP
+       struct lockdep_map lockdep_map;
+#endif
 };
 
 extern struct tvec_base boot_tvec_bases;
 
+#ifdef CONFIG_LOCKDEP
+/*
+ * NB: because we have to copy the lockdep_map, setting the lockdep_map key
+ * (second argument) here is required, otherwise it could be initialised to
+ * the copy of the lockdep_map later! We use the pointer to and the string
+ * "<file>:<line>" as the key resp. the name of the lockdep_map.
+ */
+#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)                           \
+       .lockdep_map = STATIC_LOCKDEP_MAP_INIT(_kn, &_kn),
+#else
+#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)
+#endif
+
 #define TIMER_INITIALIZER(_function, _expires, _data) {                \
                .entry = { .prev = TIMER_ENTRY_STATIC },        \
                .function = (_function),                        \
                .expires = (_expires),                          \
                .data = (_data),                                \
                .base = &boot_tvec_bases,                       \
+               __TIMER_LOCKDEP_MAP_INITIALIZER(                \
+                       __FILE__ ":" __stringify(__LINE__))     \
        }
 
 #define DEFINE_TIMER(_name, _function, _expires, _data)                \
        struct timer_list _name =                               \
                TIMER_INITIALIZER(_function, _expires, _data)
 
-void init_timer(struct timer_list *timer);
-void init_timer_deferrable(struct timer_list *timer);
+void init_timer_key(struct timer_list *timer,
+                   const char *name,
+                   struct lock_class_key *key);
+void init_timer_deferrable_key(struct timer_list *timer,
+                              const char *name,
+                              struct lock_class_key *key);
+
+#ifdef CONFIG_LOCKDEP
+#define init_timer(timer)                                              \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               init_timer_key((timer), #timer, &__key);                \
+       } while (0)
+
+#define init_timer_deferrable(timer)                                   \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               init_timer_deferrable_key((timer), #timer, &__key);     \
+       } while (0)
+
+#define init_timer_on_stack(timer)                                     \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               init_timer_on_stack_key((timer), #timer, &__key);       \
+       } while (0)
+
+#define setup_timer(timer, fn, data)                                   \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               setup_timer_key((timer), #timer, &__key, (fn), (data));\
+       } while (0)
+
+#define setup_timer_on_stack(timer, fn, data)                          \
+       do {                                                            \
+               static struct lock_class_key __key;                     \
+               setup_timer_on_stack_key((timer), #timer, &__key,       \
+                                        (fn), (data));                 \
+       } while (0)
+#else
+#define init_timer(timer)\
+       init_timer_key((timer), NULL, NULL)
+#define init_timer_deferrable(timer)\
+       init_timer_deferrable_key((timer), NULL, NULL)
+#define init_timer_on_stack(timer)\
+       init_timer_on_stack_key((timer), NULL, NULL)
+#define setup_timer(timer, fn, data)\
+       setup_timer_key((timer), NULL, NULL, (fn), (data))
+#define setup_timer_on_stack(timer, fn, data)\
+       setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
+#endif
 
 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
-extern void init_timer_on_stack(struct timer_list *timer);
+extern void init_timer_on_stack_key(struct timer_list *timer,
+                                   const char *name,
+                                   struct lock_class_key *key);
 extern void destroy_timer_on_stack(struct timer_list *timer);
 #else
 static inline void destroy_timer_on_stack(struct timer_list *timer) { }
-static inline void init_timer_on_stack(struct timer_list *timer)
+static inline void init_timer_on_stack_key(struct timer_list *timer,
+                                          const char *name,
+                                          struct lock_class_key *key)
 {
-       init_timer(timer);
+       init_timer_key(timer, name, key);
 }
 #endif
 
-static inline void setup_timer(struct timer_list * timer,
+static inline void setup_timer_key(struct timer_list * timer,
+                               const char *name,
+                               struct lock_class_key *key,
                                void (*function)(unsigned long),
                                unsigned long data)
 {
        timer->function = function;
        timer->data = data;
-       init_timer(timer);
+       init_timer_key(timer, name, key);
 }
 
-static inline void setup_timer_on_stack(struct timer_list *timer,
+static inline void setup_timer_on_stack_key(struct timer_list *timer,
+                                       const char *name,
+                                       struct lock_class_key *key,
                                        void (*function)(unsigned long),
                                        unsigned long data)
 {
        timer->function = function;
        timer->data = data;
-       init_timer_on_stack(timer);
+       init_timer_on_stack_key(timer, name, key);
 }
 
 /**
index dd253177f65fe3f53ccc737b4af7bb9dab8e9364..3e08a1c86830cafe031e0eea27e2eb0ee07ba4b7 100644 (file)
@@ -14,7 +14,7 @@ struct timeriomem_rng_data {
        struct completion       completion;
        unsigned int            present:1;
 
-       u32 __iomem             *address;
+       void __iomem            *address;
 
        /* measures in usecs */
        unsigned int            period;
index 6186a789d6c7a2f6d5c3ce7a3651a1db184b67ed..c7aa154f4bfcf97081048f4e8ab59ef6fa8147ed 100644 (file)
@@ -388,17 +388,14 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
  * tracehook_consider_ignored_signal - suppress short-circuit of ignored signal
  * @task:              task receiving the signal
  * @sig:               signal number being sent
- * @handler:           %SIG_IGN or %SIG_DFL
  *
  * Return zero iff tracing doesn't care to examine this ignored signal,
  * so it can short-circuit normal delivery and never even get queued.
- * Either @handler is %SIG_DFL and @sig's default is ignore, or it's %SIG_IGN.
  *
  * Called with @task->sighand->siglock held.
  */
 static inline int tracehook_consider_ignored_signal(struct task_struct *task,
-                                                   int sig,
-                                                   void __user *handler)
+                                                   int sig)
 {
        return (task_ptrace(task) & PT_PTRACED) != 0;
 }
@@ -407,19 +404,17 @@ static inline int tracehook_consider_ignored_signal(struct task_struct *task,
  * tracehook_consider_fatal_signal - suppress special handling of fatal signal
  * @task:              task receiving the signal
  * @sig:               signal number being sent
- * @handler:           %SIG_DFL or %SIG_IGN
  *
  * Return nonzero to prevent special handling of this termination signal.
- * Normally @handler is %SIG_DFL.  It can be %SIG_IGN if @sig is ignored,
- * in which case force_sig() is about to reset it to %SIG_DFL.
+ * Normally handler for signal is %SIG_DFL.  It can be %SIG_IGN if @sig is
+ * ignored, in which case force_sig() is about to reset it to %SIG_DFL.
  * When this returns zero, this signal might cause a quick termination
  * that does not give the debugger a chance to intercept the signal.
  *
  * Called with or without @task->sighand->siglock held.
  */
 static inline int tracehook_consider_fatal_signal(struct task_struct *task,
-                                                 int sig,
-                                                 void __user *handler)
+                                                 int sig)
 {
        return (task_ptrace(task) & PT_PTRACED) != 0;
 }
@@ -507,7 +502,7 @@ static inline int tracehook_notify_jctl(int notify, int why)
 static inline int tracehook_notify_death(struct task_struct *task,
                                         void **death_cookie, int group_dead)
 {
-       if (task->exit_signal == -1)
+       if (task_detached(task))
                return task->ptrace ? SIGCHLD : DEATH_REAP;
 
        /*
index 08e088334dba25288b8fba8423dfcb58774c833a..8615d661ab60c042fe8e8b5df420a4fde66a03d3 100644 (file)
@@ -252,8 +252,6 @@ struct tty_operations {
        void (*set_ldisc)(struct tty_struct *tty);
        void (*wait_until_sent)(struct tty_struct *tty, int timeout);
        void (*send_xchar)(struct tty_struct *tty, char ch);
-       int (*read_proc)(char *page, char **start, off_t off,
-                         int count, int *eof, void *data);
        int (*tiocmget)(struct tty_struct *tty, struct file *file);
        int (*tiocmset)(struct tty_struct *tty, struct file *file,
                        unsigned int set, unsigned int clear);
@@ -264,6 +262,7 @@ struct tty_operations {
        int (*poll_get_char)(struct tty_driver *driver, int line);
        void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
 #endif
+       const struct file_operations *proc_fops;
 };
 
 struct tty_driver {
index 5f401b644ed5794bc936b1dc631acdb13e88f254..429c631d2aad2b27c6e8da68bf7954ba2ea399b2 100644 (file)
@@ -80,8 +80,7 @@ struct wusb_ckhdid {
        u8 data[16];
 } __attribute__((packed));
 
-const static
-struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } };
+static const struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } };
 
 #define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1)
 
index a210ede73b568d25bc672b44c8bd17986d326b7e..5d631c17eaee339f4cbcc826622887278a24546f 100644 (file)
@@ -135,8 +135,11 @@ static inline void __remove_wait_queue(wait_queue_head_t *head,
 void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
                        int nr_exclusive, int sync, void *key);
 void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
-extern void __wake_up_locked(wait_queue_head_t *q, unsigned int mode);
-extern void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr);
+void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key);
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr,
+                       void *key);
+void __wake_up_locked(wait_queue_head_t *q, unsigned int mode);
+void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr);
 void __wake_up_bit(wait_queue_head_t *, void *, int);
 int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned);
 int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned);
@@ -155,21 +158,17 @@ wait_queue_head_t *bit_waitqueue(void *, int);
 #define wake_up_interruptible_all(x)   __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
 #define wake_up_interruptible_sync(x)  __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
 /*
- * macro to avoid include hell
+ * Wakeup macros to be used to report events to the targets.
  */
-#define wake_up_nested(x, s)                                           \
-do {                                                                   \
-       unsigned long flags;                                            \
-                                                                       \
-       spin_lock_irqsave_nested(&(x)->lock, flags, (s));               \
-       wake_up_locked(x);                                              \
-       spin_unlock_irqrestore(&(x)->lock, flags);                      \
-} while (0)
-#else
-#define wake_up_nested(x, s)           wake_up(x)
-#endif
+#define wake_up_poll(x, m)                             \
+       __wake_up(x, TASK_NORMAL, 1, (void *) (m))
+#define wake_up_locked_poll(x, m)                              \
+       __wake_up_locked_key((x), TASK_NORMAL, (void *) (m))
+#define wake_up_interruptible_poll(x, m)                       \
+       __wake_up(x, TASK_INTERRUPTIBLE, 1, (void *) (m))
+#define wake_up_interruptible_sync_poll(x, m)                          \
+       __wake_up_sync_key((x), TASK_INTERRUPTIBLE, 1, (void *) (m))
 
 #define __wait_event(wq, condition)                                    \
 do {                                                                   \
index 3cd51e579ab1c2cddd3960e1154b9c493794a85b..13e1adf55c4c7c0ba30d81bbc54abe6d56b93b5e 100644 (file)
@@ -41,6 +41,11 @@ struct delayed_work {
        struct timer_list timer;
 };
 
+static inline struct delayed_work *to_delayed_work(struct work_struct *work)
+{
+       return container_of(work, struct delayed_work, work);
+}
+
 struct execute_work {
        struct work_struct work;
 };
index 7300ecdc480c93b3e2010fecb41b9ceefb680799..93445477f86a7cdfe8352e15e21fbad77d9f7f0a 100644 (file)
@@ -109,8 +109,8 @@ extern int dirty_background_ratio;
 extern unsigned long dirty_background_bytes;
 extern int vm_dirty_ratio;
 extern unsigned long vm_dirty_bytes;
-extern int dirty_writeback_interval;
-extern int dirty_expire_interval;
+extern unsigned int dirty_writeback_interval;
+extern unsigned int dirty_expire_interval;
 extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
index e54c76d754951159c71a2bacdce45ec1a1dab593..1b94b9bfe2dc13754d4c2f6f4c9e26efd8b8c130 100644 (file)
@@ -616,21 +616,6 @@ static inline int tcp_skb_mss(const struct sk_buff *skb)
        return skb_shinfo(skb)->gso_size;
 }
 
-static inline void tcp_dec_pcount_approx_int(__u32 *count, const int decr)
-{
-       if (*count) {
-               *count -= decr;
-               if ((int)*count < 0)
-                       *count = 0;
-       }
-}
-
-static inline void tcp_dec_pcount_approx(__u32 *count,
-                                        const struct sk_buff *skb)
-{
-       tcp_dec_pcount_approx_int(count, tcp_skb_pcount(skb));
-}
-
 /* Events passed to congestion control interface */
 enum tcp_ca_event {
        CA_EVENT_TX_START,      /* first transmit when no packets in flight */
index 51ac69f05bdcc6d547a7671f2a072e0f6a20f353..f0851e3bb7cc0124656a4277d73b2da17173812a 100644 (file)
 #define PWR_MGT_SLOWDOWN_MCLK                  0x00002000
 
 #define PMI_PMSCR_REG                          0x60
-                                                                                
+
 /* used by ATI bug fix for hardware ROM */
 #define RAGE128_MPP_TB_CONFIG                   0x01c0
 
index b2776b6c86795de5a84b7fc5fdb53cdf77be6634..9a5e9ee30782a0943671e2055b43d1b3c0d4ed59 100644 (file)
@@ -32,7 +32,6 @@
 #define CL_VSSM2       0x3c3   /* Motherboard Sleep */
 
 /*** VGA Sequencer Registers ***/
-#define CL_SEQR0       0x0     /* Reset */
 /* the following are from the "extension registers" group */
 #define CL_SEQR6       0x6     /* Unlock ALL Extensions */
 #define CL_SEQR7       0x7     /* Extended Sequencer Mode */
@@ -71,6 +70,7 @@
 #define CL_CRT1B       0x1b    /* Extended Display Controls */
 #define CL_CRT1C       0x1c    /* Sync adjust and genlock register */
 #define CL_CRT1D       0x1d    /* Overlay Extended Control register */
+#define CL_CRT1E       0x1e    /* Another overflow register */
 #define CL_CRT25       0x25    /* Part Status Register */
 #define CL_CRT27       0x27    /* ID Register */
 #define CL_CRT51       0x51    /* P4 disable "flicker fixer" */
index 1f5ebeaa818f4241d98e7a7e5f8e4cb0f1a1625f..001b935e71c46287084b70552c0727b1b902d0fd 100644 (file)
@@ -453,7 +453,7 @@ static __inline__ int newport_wait(struct newport_regs *regs)
 {
        int t = BUSY_TIMEOUT;
 
-       while (t--)
+       while (--t)
                if (!(regs->cset.status & NPORT_STAT_GBUSY))
                        break;
        return !t;
@@ -463,7 +463,7 @@ static __inline__ int newport_bfwait(struct newport_regs *regs)
 {
        int t = BUSY_TIMEOUT;
 
-       while (t--)
+       while (--t)
                if(!(regs->cset.status & NPORT_STAT_BBUSY))
                        break;
        return !t;
index e072b16b39abf88bb0bb4e2281d0bf09dd00f0bc..56b188abfb54d5ee72f78c858c955debc5c7ffdf 100644 (file)
@@ -5,12 +5,12 @@
 #define RADEON_REGSIZE                 0x4000
 
 
-#define MM_INDEX                               0x0000  
-#define MM_DATA                                0x0004  
-#define BUS_CNTL                               0x0030  
-#define HI_STAT                                0x004C  
+#define MM_INDEX                               0x0000
+#define MM_DATA                                0x0004
+#define BUS_CNTL                               0x0030
+#define HI_STAT                                0x004C
 #define BUS_CNTL1                              0x0034
-#define I2C_CNTL_1                            0x0094  
+#define I2C_CNTL_1                            0x0094
 #define CNFG_CNTL                              0x00E0
 #define CNFG_MEMSIZE                           0x00F8
 #define CNFG_APER_0_BASE                       0x0100
@@ -18,8 +18,8 @@
 #define CNFG_APER_SIZE                         0x0108
 #define CNFG_REG_1_BASE                        0x010C
 #define CNFG_REG_APER_SIZE                     0x0110
-#define PAD_AGPINPUT_DELAY                     0x0164  
-#define PAD_CTLR_STRENGTH                      0x0168  
+#define PAD_AGPINPUT_DELAY                     0x0164
+#define PAD_CTLR_STRENGTH                      0x0168
 #define PAD_CTLR_UPDATE                        0x016C
 #define PAD_CTLR_MISC                          0x0aa0
 #define AGP_CNTL                               0x0174
 #define CAP0_TRIG_CNTL                        0x0950
 #define CAP1_TRIG_CNTL                        0x09c0
 #define VIPH_CONTROL                          0x0C40
-#define VENDOR_ID                              0x0F00  
-#define DEVICE_ID                              0x0F02  
-#define COMMAND                                0x0F04  
-#define STATUS                                 0x0F06  
-#define REVISION_ID                            0x0F08  
-#define REGPROG_INF                            0x0F09  
-#define SUB_CLASS                              0x0F0A  
-#define BASE_CODE                              0x0F0B  
-#define CACHE_LINE                             0x0F0C  
-#define LATENCY                                0x0F0D  
-#define HEADER                                 0x0F0E  
-#define BIST                                   0x0F0F  
-#define REG_MEM_BASE                           0x0F10  
-#define REG_IO_BASE                            0x0F14  
+#define VENDOR_ID                              0x0F00
+#define DEVICE_ID                              0x0F02
+#define COMMAND                                0x0F04
+#define STATUS                                 0x0F06
+#define REVISION_ID                            0x0F08
+#define REGPROG_INF                            0x0F09
+#define SUB_CLASS                              0x0F0A
+#define BASE_CODE                              0x0F0B
+#define CACHE_LINE                             0x0F0C
+#define LATENCY                                0x0F0D
+#define HEADER                                 0x0F0E
+#define BIST                                   0x0F0F
+#define REG_MEM_BASE                           0x0F10
+#define REG_IO_BASE                            0x0F14
 #define REG_REG_BASE                           0x0F18
 #define ADAPTER_ID                             0x0F2C
 #define BIOS_ROM                               0x0F30
-#define CAPABILITIES_PTR                       0x0F34  
-#define INTERRUPT_LINE                         0x0F3C  
-#define INTERRUPT_PIN                          0x0F3D  
-#define MIN_GRANT                              0x0F3E  
-#define MAX_LATENCY                            0x0F3F  
-#define ADAPTER_ID_W                           0x0F4C  
-#define PMI_CAP_ID                             0x0F50  
-#define PMI_NXT_CAP_PTR                        0x0F51  
-#define PMI_PMC_REG                            0x0F52  
-#define PM_STATUS                              0x0F54  
-#define PMI_DATA                               0x0F57  
-#define AGP_CAP_ID                             0x0F58  
-#define AGP_STATUS                             0x0F5C  
-#define AGP_COMMAND                            0x0F60  
+#define CAPABILITIES_PTR                       0x0F34
+#define INTERRUPT_LINE                         0x0F3C
+#define INTERRUPT_PIN                          0x0F3D
+#define MIN_GRANT                              0x0F3E
+#define MAX_LATENCY                            0x0F3F
+#define ADAPTER_ID_W                           0x0F4C
+#define PMI_CAP_ID                             0x0F50
+#define PMI_NXT_CAP_PTR                        0x0F51
+#define PMI_PMC_REG                            0x0F52
+#define PM_STATUS                              0x0F54
+#define PMI_DATA                               0x0F57
+#define AGP_CAP_ID                             0x0F58
+#define AGP_STATUS                             0x0F5C
+#define AGP_COMMAND                            0x0F60
 #define AIC_CTRL                               0x01D0
 #define AIC_STAT                               0x01D4
 #define AIC_PT_BASE                            0x01D8
-#define AIC_LO_ADDR                            0x01DC  
-#define AIC_HI_ADDR                            0x01E0  
-#define AIC_TLB_ADDR                           0x01E4  
-#define AIC_TLB_DATA                           0x01E8  
-#define DAC_CNTL                               0x0058  
+#define AIC_LO_ADDR                            0x01DC
+#define AIC_HI_ADDR                            0x01E0
+#define AIC_TLB_ADDR                           0x01E4
+#define AIC_TLB_DATA                           0x01E8
+#define DAC_CNTL                               0x0058
 #define DAC_CNTL2                              0x007c
-#define CRTC_GEN_CNTL                          0x0050  
-#define MEM_CNTL                               0x0140  
+#define CRTC_GEN_CNTL                          0x0050
+#define MEM_CNTL                               0x0140
 #define MC_CNTL                                0x0140
-#define EXT_MEM_CNTL                           0x0144  
+#define EXT_MEM_CNTL                           0x0144
 #define MC_TIMING_CNTL                         0x0144
-#define MC_AGP_LOCATION                        0x014C  
-#define MEM_IO_CNTL_A0                         0x0178  
+#define MC_AGP_LOCATION                        0x014C
+#define MEM_IO_CNTL_A0                         0x0178
 #define MEM_REFRESH_CNTL                       0x0178
-#define MEM_INIT_LATENCY_TIMER                 0x0154  
+#define MEM_INIT_LATENCY_TIMER                 0x0154
 #define MC_INIT_GFX_LAT_TIMER                  0x0154
-#define MEM_SDRAM_MODE_REG                     0x0158  
-#define AGP_BASE                               0x0170  
-#define MEM_IO_CNTL_A1                         0x017C  
+#define MEM_SDRAM_MODE_REG                     0x0158
+#define AGP_BASE                               0x0170
+#define MEM_IO_CNTL_A1                         0x017C
 #define MC_READ_CNTL_AB                        0x017C
 #define MEM_IO_CNTL_B0                         0x0180
 #define MC_INIT_MISC_LAT_TIMER                 0x0180
 #define MEM_IO_CNTL_B1                         0x0184
 #define MC_IOPAD_CNTL                          0x0184
 #define MC_DEBUG                               0x0188
-#define MC_STATUS                              0x0150  
-#define MEM_IO_OE_CNTL                         0x018C  
+#define MC_STATUS                              0x0150
+#define MEM_IO_OE_CNTL                         0x018C
 #define MC_CHIP_IO_OE_CNTL_AB                  0x018C
-#define MC_FB_LOCATION                         0x0148  
-#define HOST_PATH_CNTL                         0x0130  
-#define MEM_VGA_WP_SEL                         0x0038  
-#define MEM_VGA_RP_SEL                         0x003C  
-#define HDP_DEBUG                              0x0138  
+#define MC_FB_LOCATION                         0x0148
+#define HOST_PATH_CNTL                         0x0130
+#define MEM_VGA_WP_SEL                         0x0038
+#define MEM_VGA_RP_SEL                         0x003C
+#define HDP_DEBUG                              0x0138
 #define SW_SEMAPHORE                           0x013C
-#define CRTC2_GEN_CNTL                         0x03f8  
+#define CRTC2_GEN_CNTL                         0x03f8
 #define CRTC2_DISPLAY_BASE_ADDR                0x033c
-#define SURFACE_CNTL                           0x0B00  
-#define SURFACE0_LOWER_BOUND                   0x0B04  
-#define SURFACE1_LOWER_BOUND                   0x0B14  
-#define SURFACE2_LOWER_BOUND                   0x0B24  
-#define SURFACE3_LOWER_BOUND                   0x0B34  
-#define SURFACE4_LOWER_BOUND                   0x0B44  
+#define SURFACE_CNTL                           0x0B00
+#define SURFACE0_LOWER_BOUND                   0x0B04
+#define SURFACE1_LOWER_BOUND                   0x0B14
+#define SURFACE2_LOWER_BOUND                   0x0B24
+#define SURFACE3_LOWER_BOUND                   0x0B34
+#define SURFACE4_LOWER_BOUND                   0x0B44
 #define SURFACE5_LOWER_BOUND                   0x0B54
 #define SURFACE6_LOWER_BOUND                   0x0B64
 #define SURFACE7_LOWER_BOUND                   0x0B74
-#define SURFACE0_UPPER_BOUND                   0x0B08  
-#define SURFACE1_UPPER_BOUND                   0x0B18  
-#define SURFACE2_UPPER_BOUND                   0x0B28  
-#define SURFACE3_UPPER_BOUND                   0x0B38  
-#define SURFACE4_UPPER_BOUND                   0x0B48  
-#define SURFACE5_UPPER_BOUND                   0x0B58  
-#define SURFACE6_UPPER_BOUND                   0x0B68  
-#define SURFACE7_UPPER_BOUND                   0x0B78  
-#define SURFACE0_INFO                          0x0B0C  
-#define SURFACE1_INFO                          0x0B1C  
-#define SURFACE2_INFO                          0x0B2C  
-#define SURFACE3_INFO                          0x0B3C  
-#define SURFACE4_INFO                          0x0B4C  
-#define SURFACE5_INFO                          0x0B5C  
+#define SURFACE0_UPPER_BOUND                   0x0B08
+#define SURFACE1_UPPER_BOUND                   0x0B18
+#define SURFACE2_UPPER_BOUND                   0x0B28
+#define SURFACE3_UPPER_BOUND                   0x0B38
+#define SURFACE4_UPPER_BOUND                   0x0B48
+#define SURFACE5_UPPER_BOUND                   0x0B58
+#define SURFACE6_UPPER_BOUND                   0x0B68
+#define SURFACE7_UPPER_BOUND                   0x0B78
+#define SURFACE0_INFO                          0x0B0C
+#define SURFACE1_INFO                          0x0B1C
+#define SURFACE2_INFO                          0x0B2C
+#define SURFACE3_INFO                          0x0B3C
+#define SURFACE4_INFO                          0x0B4C
+#define SURFACE5_INFO                          0x0B5C
 #define SURFACE6_INFO                          0x0B6C
 #define SURFACE7_INFO                          0x0B7C
 #define SURFACE_ACCESS_FLAGS                   0x0BF8
-#define SURFACE_ACCESS_CLR                     0x0BFC  
-#define GEN_INT_CNTL                           0x0040  
-#define GEN_INT_STATUS                         0x0044  
+#define SURFACE_ACCESS_CLR                     0x0BFC
+#define GEN_INT_CNTL                           0x0040
+#define GEN_INT_STATUS                         0x0044
 #define CRTC_EXT_CNTL                          0x0054
-#define RB3D_CNTL                             0x1C3C  
-#define WAIT_UNTIL                             0x1720  
-#define ISYNC_CNTL                             0x1724  
-#define RBBM_GUICNTL                           0x172C  
-#define RBBM_STATUS                            0x0E40  
-#define RBBM_STATUS_alt_1                      0x1740  
-#define RBBM_CNTL                              0x00EC  
-#define RBBM_CNTL_alt_1                        0x0E44  
-#define RBBM_SOFT_RESET                        0x00F0  
-#define RBBM_SOFT_RESET_alt_1                  0x0E48  
-#define NQWAIT_UNTIL                           0x0E50  
+#define RB3D_CNTL                             0x1C3C
+#define WAIT_UNTIL                             0x1720
+#define ISYNC_CNTL                             0x1724
+#define RBBM_GUICNTL                           0x172C
+#define RBBM_STATUS                            0x0E40
+#define RBBM_STATUS_alt_1                      0x1740
+#define RBBM_CNTL                              0x00EC
+#define RBBM_CNTL_alt_1                        0x0E44
+#define RBBM_SOFT_RESET                        0x00F0
+#define RBBM_SOFT_RESET_alt_1                  0x0E48
+#define NQWAIT_UNTIL                           0x0E50
 #define RBBM_DEBUG                             0x0E6C
 #define RBBM_CMDFIFO_ADDR                      0x0E70
 #define RBBM_CMDFIFO_DATAL                     0x0E74
-#define RBBM_CMDFIFO_DATAH                     0x0E78  
-#define RBBM_CMDFIFO_STAT                      0x0E7C  
-#define CRTC_STATUS                            0x005C  
-#define GPIO_VGA_DDC                           0x0060  
-#define GPIO_DVI_DDC                           0x0064  
-#define GPIO_MONID                             0x0068  
+#define RBBM_CMDFIFO_DATAH                     0x0E78
+#define RBBM_CMDFIFO_STAT                      0x0E7C
+#define CRTC_STATUS                            0x005C
+#define GPIO_VGA_DDC                           0x0060
+#define GPIO_DVI_DDC                           0x0064
+#define GPIO_MONID                             0x0068
 #define GPIO_CRT2_DDC                          0x006c
-#define PALETTE_INDEX                          0x00B0  
-#define PALETTE_DATA                           0x00B4  
-#define PALETTE_30_DATA                        0x00B8  
-#define CRTC_H_TOTAL_DISP                      0x0200  
-#define CRTC_H_SYNC_STRT_WID                   0x0204  
-#define CRTC_V_TOTAL_DISP                      0x0208  
-#define CRTC_V_SYNC_STRT_WID                   0x020C  
-#define CRTC_VLINE_CRNT_VLINE                  0x0210  
+#define PALETTE_INDEX                          0x00B0
+#define PALETTE_DATA                           0x00B4
+#define PALETTE_30_DATA                        0x00B8
+#define CRTC_H_TOTAL_DISP                      0x0200
+#define CRTC_H_SYNC_STRT_WID                   0x0204
+#define CRTC_V_TOTAL_DISP                      0x0208
+#define CRTC_V_SYNC_STRT_WID                   0x020C
+#define CRTC_VLINE_CRNT_VLINE                  0x0210
 #define CRTC_CRNT_FRAME                        0x0214
 #define CRTC_GUI_TRIG_VLINE                    0x0218
 #define CRTC_DEBUG                             0x021C
-#define CRTC_OFFSET_RIGHT                      0x0220  
-#define CRTC_OFFSET                            0x0224  
-#define CRTC_OFFSET_CNTL                       0x0228  
-#define CRTC_PITCH                             0x022C  
-#define OVR_CLR                                0x0230  
-#define OVR_WID_LEFT_RIGHT                     0x0234  
-#define OVR_WID_TOP_BOTTOM                     0x0238  
-#define DISPLAY_BASE_ADDR                      0x023C  
-#define SNAPSHOT_VH_COUNTS                     0x0240  
-#define SNAPSHOT_F_COUNT                       0x0244  
-#define N_VIF_COUNT                            0x0248  
-#define SNAPSHOT_VIF_COUNT                     0x024C  
-#define FP_CRTC_H_TOTAL_DISP                   0x0250  
-#define FP_CRTC_V_TOTAL_DISP                   0x0254  
+#define CRTC_OFFSET_RIGHT                      0x0220
+#define CRTC_OFFSET                            0x0224
+#define CRTC_OFFSET_CNTL                       0x0228
+#define CRTC_PITCH                             0x022C
+#define OVR_CLR                                0x0230
+#define OVR_WID_LEFT_RIGHT                     0x0234
+#define OVR_WID_TOP_BOTTOM                     0x0238
+#define DISPLAY_BASE_ADDR                      0x023C
+#define SNAPSHOT_VH_COUNTS                     0x0240
+#define SNAPSHOT_F_COUNT                       0x0244
+#define N_VIF_COUNT                            0x0248
+#define SNAPSHOT_VIF_COUNT                     0x024C
+#define FP_CRTC_H_TOTAL_DISP                   0x0250
+#define FP_CRTC_V_TOTAL_DISP                   0x0254
 #define CRT_CRTC_H_SYNC_STRT_WID               0x0258
 #define CRT_CRTC_V_SYNC_STRT_WID               0x025C
 #define CUR_OFFSET                             0x0260
-#define CUR_HORZ_VERT_POSN                     0x0264  
-#define CUR_HORZ_VERT_OFF                      0x0268  
-#define CUR_CLR0                               0x026C  
-#define CUR_CLR1                               0x0270  
-#define FP_HORZ_VERT_ACTIVE                    0x0278  
-#define CRTC_MORE_CNTL                         0x027C  
+#define CUR_HORZ_VERT_POSN                     0x0264
+#define CUR_HORZ_VERT_OFF                      0x0268
+#define CUR_CLR0                               0x026C
+#define CUR_CLR1                               0x0270
+#define FP_HORZ_VERT_ACTIVE                    0x0278
+#define CRTC_MORE_CNTL                         0x027C
 #define CRTC_H_CUTOFF_ACTIVE_EN                (1<<4)
 #define CRTC_V_CUTOFF_ACTIVE_EN                (1<<5)
-#define DAC_EXT_CNTL                           0x0280  
-#define FP_GEN_CNTL                            0x0284  
-#define FP_HORZ_STRETCH                        0x028C  
-#define FP_VERT_STRETCH                        0x0290  
-#define FP_H_SYNC_STRT_WID                     0x02C4  
-#define FP_V_SYNC_STRT_WID                     0x02C8  
-#define AUX_WINDOW_HORZ_CNTL                   0x02D8  
-#define AUX_WINDOW_VERT_CNTL                   0x02DC  
+#define DAC_EXT_CNTL                           0x0280
+#define FP_GEN_CNTL                            0x0284
+#define FP_HORZ_STRETCH                        0x028C
+#define FP_VERT_STRETCH                        0x0290
+#define FP_H_SYNC_STRT_WID                     0x02C4
+#define FP_V_SYNC_STRT_WID                     0x02C8
+#define AUX_WINDOW_HORZ_CNTL                   0x02D8
+#define AUX_WINDOW_VERT_CNTL                   0x02DC
 //#define DDA_CONFIG                          0x02e0
 //#define DDA_ON_OFF                          0x02e4
 #define DVI_I2C_CNTL_1                        0x02e4
 #define GRPH2_BUFFER_CNTL                      0x03F0
 #define VGA_BUFFER_CNTL                        0x02F4
 #define OV0_Y_X_START                          0x0400
-#define OV0_Y_X_END                            0x0404  
-#define OV0_PIPELINE_CNTL                      0x0408  
-#define OV0_REG_LOAD_CNTL                      0x0410  
-#define OV0_SCALE_CNTL                         0x0420  
-#define OV0_V_INC                              0x0424  
-#define OV0_P1_V_ACCUM_INIT                    0x0428  
-#define OV0_P23_V_ACCUM_INIT                   0x042C  
-#define OV0_P1_BLANK_LINES_AT_TOP              0x0430  
-#define OV0_P23_BLANK_LINES_AT_TOP             0x0434  
-#define OV0_BASE_ADDR                          0x043C  
-#define OV0_VID_BUF0_BASE_ADRS                 0x0440  
-#define OV0_VID_BUF1_BASE_ADRS                 0x0444  
-#define OV0_VID_BUF2_BASE_ADRS                 0x0448  
-#define OV0_VID_BUF3_BASE_ADRS                 0x044C  
+#define OV0_Y_X_END                            0x0404
+#define OV0_PIPELINE_CNTL                      0x0408
+#define OV0_REG_LOAD_CNTL                      0x0410
+#define OV0_SCALE_CNTL                         0x0420
+#define OV0_V_INC                              0x0424
+#define OV0_P1_V_ACCUM_INIT                    0x0428
+#define OV0_P23_V_ACCUM_INIT                   0x042C
+#define OV0_P1_BLANK_LINES_AT_TOP              0x0430
+#define OV0_P23_BLANK_LINES_AT_TOP             0x0434
+#define OV0_BASE_ADDR                          0x043C
+#define OV0_VID_BUF0_BASE_ADRS                 0x0440
+#define OV0_VID_BUF1_BASE_ADRS                 0x0444
+#define OV0_VID_BUF2_BASE_ADRS                 0x0448
+#define OV0_VID_BUF3_BASE_ADRS                 0x044C
 #define OV0_VID_BUF4_BASE_ADRS                 0x0450
 #define OV0_VID_BUF5_BASE_ADRS                 0x0454
 #define OV0_VID_BUF_PITCH0_VALUE               0x0460
-#define OV0_VID_BUF_PITCH1_VALUE               0x0464  
-#define OV0_AUTO_FLIP_CNTRL                    0x0470  
-#define OV0_DEINTERLACE_PATTERN                0x0474  
-#define OV0_SUBMIT_HISTORY                     0x0478  
-#define OV0_H_INC                              0x0480  
-#define OV0_STEP_BY                            0x0484  
-#define OV0_P1_H_ACCUM_INIT                    0x0488  
-#define OV0_P23_H_ACCUM_INIT                   0x048C  
-#define OV0_P1_X_START_END                     0x0494  
-#define OV0_P2_X_START_END                     0x0498  
-#define OV0_P3_X_START_END                     0x049C  
-#define OV0_FILTER_CNTL                        0x04A0  
-#define OV0_FOUR_TAP_COEF_0                    0x04B0  
-#define OV0_FOUR_TAP_COEF_1                    0x04B4  
+#define OV0_VID_BUF_PITCH1_VALUE               0x0464
+#define OV0_AUTO_FLIP_CNTRL                    0x0470
+#define OV0_DEINTERLACE_PATTERN                0x0474
+#define OV0_SUBMIT_HISTORY                     0x0478
+#define OV0_H_INC                              0x0480
+#define OV0_STEP_BY                            0x0484
+#define OV0_P1_H_ACCUM_INIT                    0x0488
+#define OV0_P23_H_ACCUM_INIT                   0x048C
+#define OV0_P1_X_START_END                     0x0494
+#define OV0_P2_X_START_END                     0x0498
+#define OV0_P3_X_START_END                     0x049C
+#define OV0_FILTER_CNTL                        0x04A0
+#define OV0_FOUR_TAP_COEF_0                    0x04B0
+#define OV0_FOUR_TAP_COEF_1                    0x04B4
 #define OV0_FOUR_TAP_COEF_2                    0x04B8
 #define OV0_FOUR_TAP_COEF_3                    0x04BC
 #define OV0_FOUR_TAP_COEF_4                    0x04C0
-#define OV0_FLAG_CNTRL                         0x04DC  
-#define OV0_SLICE_CNTL                         0x04E0  
-#define OV0_VID_KEY_CLR_LOW                    0x04E4  
-#define OV0_VID_KEY_CLR_HIGH                   0x04E8  
-#define OV0_GRPH_KEY_CLR_LOW                   0x04EC  
-#define OV0_GRPH_KEY_CLR_HIGH                  0x04F0  
-#define OV0_KEY_CNTL                           0x04F4  
-#define OV0_TEST                               0x04F8  
-#define SUBPIC_CNTL                            0x0540  
-#define SUBPIC_DEFCOLCON                       0x0544  
-#define SUBPIC_Y_X_START                       0x054C  
-#define SUBPIC_Y_X_END                         0x0550  
-#define SUBPIC_V_INC                           0x0554  
-#define SUBPIC_H_INC                           0x0558  
+#define OV0_FLAG_CNTRL                         0x04DC
+#define OV0_SLICE_CNTL                         0x04E0
+#define OV0_VID_KEY_CLR_LOW                    0x04E4
+#define OV0_VID_KEY_CLR_HIGH                   0x04E8
+#define OV0_GRPH_KEY_CLR_LOW                   0x04EC
+#define OV0_GRPH_KEY_CLR_HIGH                  0x04F0
+#define OV0_KEY_CNTL                           0x04F4
+#define OV0_TEST                               0x04F8
+#define SUBPIC_CNTL                            0x0540
+#define SUBPIC_DEFCOLCON                       0x0544
+#define SUBPIC_Y_X_START                       0x054C
+#define SUBPIC_Y_X_END                         0x0550
+#define SUBPIC_V_INC                           0x0554
+#define SUBPIC_H_INC                           0x0558
 #define SUBPIC_BUF0_OFFSET                     0x055C
 #define SUBPIC_BUF1_OFFSET                     0x0560
 #define SUBPIC_LC0_OFFSET                      0x0564
-#define SUBPIC_LC1_OFFSET                      0x0568  
-#define SUBPIC_PITCH                           0x056C  
-#define SUBPIC_BTN_HLI_COLCON                  0x0570  
-#define SUBPIC_BTN_HLI_Y_X_START               0x0574  
-#define SUBPIC_BTN_HLI_Y_X_END                 0x0578  
-#define SUBPIC_PALETTE_INDEX                   0x057C  
-#define SUBPIC_PALETTE_DATA                    0x0580  
-#define SUBPIC_H_ACCUM_INIT                    0x0584  
-#define SUBPIC_V_ACCUM_INIT                    0x0588  
-#define DISP_MISC_CNTL                         0x0D00  
-#define DAC_MACRO_CNTL                         0x0D04  
-#define DISP_PWR_MAN                           0x0D08  
-#define DISP_TEST_DEBUG_CNTL                   0x0D10  
-#define DISP_HW_DEBUG                          0x0D14  
+#define SUBPIC_LC1_OFFSET                      0x0568
+#define SUBPIC_PITCH                           0x056C
+#define SUBPIC_BTN_HLI_COLCON                  0x0570
+#define SUBPIC_BTN_HLI_Y_X_START               0x0574
+#define SUBPIC_BTN_HLI_Y_X_END                 0x0578
+#define SUBPIC_PALETTE_INDEX                   0x057C
+#define SUBPIC_PALETTE_DATA                    0x0580
+#define SUBPIC_H_ACCUM_INIT                    0x0584
+#define SUBPIC_V_ACCUM_INIT                    0x0588
+#define DISP_MISC_CNTL                         0x0D00
+#define DAC_MACRO_CNTL                         0x0D04
+#define DISP_PWR_MAN                           0x0D08
+#define DISP_TEST_DEBUG_CNTL                   0x0D10
+#define DISP_HW_DEBUG                          0x0D14
 #define DAC_CRC_SIG1                           0x0D18
 #define DAC_CRC_SIG2                           0x0D1C
 #define OV0_LIN_TRANS_A                        0x0D20
-#define OV0_LIN_TRANS_B                        0x0D24  
-#define OV0_LIN_TRANS_C                        0x0D28  
-#define OV0_LIN_TRANS_D                        0x0D2C  
-#define OV0_LIN_TRANS_E                        0x0D30  
-#define OV0_LIN_TRANS_F                        0x0D34  
-#define OV0_GAMMA_0_F                          0x0D40  
-#define OV0_GAMMA_10_1F                        0x0D44  
-#define OV0_GAMMA_20_3F                        0x0D48  
-#define OV0_GAMMA_40_7F                        0x0D4C  
-#define OV0_GAMMA_380_3BF                      0x0D50  
-#define OV0_GAMMA_3C0_3FF                      0x0D54  
-#define DISP_MERGE_CNTL                        0x0D60  
-#define DISP_OUTPUT_CNTL                       0x0D64  
-#define DISP_LIN_TRANS_GRPH_A                  0x0D80  
+#define OV0_LIN_TRANS_B                        0x0D24
+#define OV0_LIN_TRANS_C                        0x0D28
+#define OV0_LIN_TRANS_D                        0x0D2C
+#define OV0_LIN_TRANS_E                        0x0D30
+#define OV0_LIN_TRANS_F                        0x0D34
+#define OV0_GAMMA_0_F                          0x0D40
+#define OV0_GAMMA_10_1F                        0x0D44
+#define OV0_GAMMA_20_3F                        0x0D48
+#define OV0_GAMMA_40_7F                        0x0D4C
+#define OV0_GAMMA_380_3BF                      0x0D50
+#define OV0_GAMMA_3C0_3FF                      0x0D54
+#define DISP_MERGE_CNTL                        0x0D60
+#define DISP_OUTPUT_CNTL                       0x0D64
+#define DISP_LIN_TRANS_GRPH_A                  0x0D80
 #define DISP_LIN_TRANS_GRPH_B                  0x0D84
 #define DISP_LIN_TRANS_GRPH_C                  0x0D88
 #define DISP_LIN_TRANS_GRPH_D                  0x0D8C
-#define DISP_LIN_TRANS_GRPH_E                  0x0D90  
-#define DISP_LIN_TRANS_GRPH_F                  0x0D94  
-#define DISP_LIN_TRANS_VID_A                   0x0D98  
-#define DISP_LIN_TRANS_VID_B                   0x0D9C  
-#define DISP_LIN_TRANS_VID_C                   0x0DA0  
-#define DISP_LIN_TRANS_VID_D                   0x0DA4  
-#define DISP_LIN_TRANS_VID_E                   0x0DA8  
-#define DISP_LIN_TRANS_VID_F                   0x0DAC  
-#define RMX_HORZ_FILTER_0TAP_COEF              0x0DB0  
-#define RMX_HORZ_FILTER_1TAP_COEF              0x0DB4  
-#define RMX_HORZ_FILTER_2TAP_COEF              0x0DB8  
-#define RMX_HORZ_PHASE                         0x0DBC  
-#define DAC_EMBEDDED_SYNC_CNTL                 0x0DC0  
-#define DAC_BROAD_PULSE                        0x0DC4  
+#define DISP_LIN_TRANS_GRPH_E                  0x0D90
+#define DISP_LIN_TRANS_GRPH_F                  0x0D94
+#define DISP_LIN_TRANS_VID_A                   0x0D98
+#define DISP_LIN_TRANS_VID_B                   0x0D9C
+#define DISP_LIN_TRANS_VID_C                   0x0DA0
+#define DISP_LIN_TRANS_VID_D                   0x0DA4
+#define DISP_LIN_TRANS_VID_E                   0x0DA8
+#define DISP_LIN_TRANS_VID_F                   0x0DAC
+#define RMX_HORZ_FILTER_0TAP_COEF              0x0DB0
+#define RMX_HORZ_FILTER_1TAP_COEF              0x0DB4
+#define RMX_HORZ_FILTER_2TAP_COEF              0x0DB8
+#define RMX_HORZ_PHASE                         0x0DBC
+#define DAC_EMBEDDED_SYNC_CNTL                 0x0DC0
+#define DAC_BROAD_PULSE                        0x0DC4
 #define DAC_SKEW_CLKS                          0x0DC8
 #define DAC_INCR                               0x0DCC
 #define DAC_NEG_SYNC_LEVEL                     0x0DD0
-#define DAC_POS_SYNC_LEVEL                     0x0DD4  
-#define DAC_BLANK_LEVEL                        0x0DD8  
-#define CLOCK_CNTL_INDEX                       0x0008  
-#define CLOCK_CNTL_DATA                        0x000C  
-#define CP_RB_CNTL                             0x0704  
-#define CP_RB_BASE                             0x0700  
-#define CP_RB_RPTR_ADDR                        0x070C  
-#define CP_RB_RPTR                             0x0710  
-#define CP_RB_WPTR                             0x0714  
-#define CP_RB_WPTR_DELAY                       0x0718  
-#define CP_IB_BASE                             0x0738  
-#define CP_IB_BUFSZ                            0x073C  
-#define SCRATCH_REG0                           0x15E0  
-#define GUI_SCRATCH_REG0                       0x15E0  
-#define SCRATCH_REG1                           0x15E4  
-#define GUI_SCRATCH_REG1                       0x15E4  
+#define DAC_POS_SYNC_LEVEL                     0x0DD4
+#define DAC_BLANK_LEVEL                        0x0DD8
+#define CLOCK_CNTL_INDEX                       0x0008
+#define CLOCK_CNTL_DATA                        0x000C
+#define CP_RB_CNTL                             0x0704
+#define CP_RB_BASE                             0x0700
+#define CP_RB_RPTR_ADDR                        0x070C
+#define CP_RB_RPTR                             0x0710
+#define CP_RB_WPTR                             0x0714
+#define CP_RB_WPTR_DELAY                       0x0718
+#define CP_IB_BASE                             0x0738
+#define CP_IB_BUFSZ                            0x073C
+#define SCRATCH_REG0                           0x15E0
+#define GUI_SCRATCH_REG0                       0x15E0
+#define SCRATCH_REG1                           0x15E4
+#define GUI_SCRATCH_REG1                       0x15E4
 #define SCRATCH_REG2                           0x15E8
 #define GUI_SCRATCH_REG2                       0x15E8
 #define SCRATCH_REG3                           0x15EC
-#define GUI_SCRATCH_REG3                       0x15EC  
-#define SCRATCH_REG4                           0x15F0  
-#define GUI_SCRATCH_REG4                       0x15F0  
-#define SCRATCH_REG5                           0x15F4  
-#define GUI_SCRATCH_REG5                       0x15F4  
-#define SCRATCH_UMSK                           0x0770  
-#define SCRATCH_ADDR                           0x0774  
-#define DP_BRUSH_FRGD_CLR                      0x147C  
+#define GUI_SCRATCH_REG3                       0x15EC
+#define SCRATCH_REG4                           0x15F0
+#define GUI_SCRATCH_REG4                       0x15F0
+#define SCRATCH_REG5                           0x15F4
+#define GUI_SCRATCH_REG5                       0x15F4
+#define SCRATCH_UMSK                           0x0770
+#define SCRATCH_ADDR                           0x0774
+#define DP_BRUSH_FRGD_CLR                      0x147C
 #define DP_BRUSH_BKGD_CLR                      0x1478
 #define DST_LINE_START                         0x1600
-#define DST_LINE_END                           0x1604  
-#define SRC_OFFSET                             0x15AC  
+#define DST_LINE_END                           0x1604
+#define SRC_OFFSET                             0x15AC
 #define SRC_PITCH                              0x15B0
 #define SRC_TILE                               0x1704
 #define SRC_PITCH_OFFSET                       0x1428
-#define SRC_X                                  0x1414  
-#define SRC_Y                                  0x1418  
-#define SRC_X_Y                                0x1590  
-#define SRC_Y_X                                0x1434  
+#define SRC_X                                  0x1414
+#define SRC_Y                                  0x1418
+#define SRC_X_Y                                0x1590
+#define SRC_Y_X                                0x1434
 #define DST_Y_X                                       0x1438
 #define DST_WIDTH_HEIGHT                      0x1598
 #define DST_HEIGHT_WIDTH                      0x143c
 #define DST_OFFSET                             0x1404
-#define SRC_CLUT_ADDRESS                       0x1780  
-#define SRC_CLUT_DATA                          0x1784  
-#define SRC_CLUT_DATA_RD                       0x1788  
-#define HOST_DATA0                             0x17C0  
-#define HOST_DATA1                             0x17C4  
-#define HOST_DATA2                             0x17C8  
-#define HOST_DATA3                             0x17CC  
-#define HOST_DATA4                             0x17D0  
-#define HOST_DATA5                             0x17D4  
-#define HOST_DATA6                             0x17D8  
+#define SRC_CLUT_ADDRESS                       0x1780
+#define SRC_CLUT_DATA                          0x1784
+#define SRC_CLUT_DATA_RD                       0x1788
+#define HOST_DATA0                             0x17C0
+#define HOST_DATA1                             0x17C4
+#define HOST_DATA2                             0x17C8
+#define HOST_DATA3                             0x17CC
+#define HOST_DATA4                             0x17D0
+#define HOST_DATA5                             0x17D4
+#define HOST_DATA6                             0x17D8
 #define HOST_DATA7                             0x17DC
 #define HOST_DATA_LAST                         0x17E0
 #define DP_SRC_ENDIAN                          0x15D4
-#define DP_SRC_FRGD_CLR                        0x15D8  
-#define DP_SRC_BKGD_CLR                        0x15DC  
-#define SC_LEFT                                0x1640  
-#define SC_RIGHT                               0x1644  
-#define SC_TOP                                 0x1648  
-#define SC_BOTTOM                              0x164C  
-#define SRC_SC_RIGHT                           0x1654  
-#define SRC_SC_BOTTOM                          0x165C  
-#define DP_CNTL                                0x16C0  
-#define DP_CNTL_XDIR_YDIR_YMAJOR               0x16D0  
-#define DP_DATATYPE                            0x16C4  
-#define DP_MIX                                 0x16C8  
-#define DP_WRITE_MSK                           0x16CC  
-#define DP_XOP                                 0x17F8  
+#define DP_SRC_FRGD_CLR                        0x15D8
+#define DP_SRC_BKGD_CLR                        0x15DC
+#define SC_LEFT                                0x1640
+#define SC_RIGHT                               0x1644
+#define SC_TOP                                 0x1648
+#define SC_BOTTOM                              0x164C
+#define SRC_SC_RIGHT                           0x1654
+#define SRC_SC_BOTTOM                          0x165C
+#define DP_CNTL                                0x16C0
+#define DP_CNTL_XDIR_YDIR_YMAJOR               0x16D0
+#define DP_DATATYPE                            0x16C4
+#define DP_MIX                                 0x16C8
+#define DP_WRITE_MSK                           0x16CC
+#define DP_XOP                                 0x17F8
 #define CLR_CMP_CLR_SRC                        0x15C4
 #define CLR_CMP_CLR_DST                        0x15C8
 #define CLR_CMP_CNTL                           0x15C0
-#define CLR_CMP_MSK                            0x15CC  
-#define DSTCACHE_MODE                          0x1710  
-#define DSTCACHE_CTLSTAT                       0x1714  
-#define DEFAULT_PITCH_OFFSET                   0x16E0  
-#define DEFAULT_SC_BOTTOM_RIGHT                0x16E8  
+#define CLR_CMP_MSK                            0x15CC
+#define DSTCACHE_MODE                          0x1710
+#define DSTCACHE_CTLSTAT                       0x1714
+#define DEFAULT_PITCH_OFFSET                   0x16E0
+#define DEFAULT_SC_BOTTOM_RIGHT                0x16E8
 #define DEFAULT_SC_TOP_LEFT                    0x16EC
 #define SRC_PITCH_OFFSET                       0x1428
 #define DST_PITCH_OFFSET                       0x142C
-#define DP_GUI_MASTER_CNTL                     0x146C  
-#define SC_TOP_LEFT                            0x16EC  
-#define SC_BOTTOM_RIGHT                        0x16F0  
-#define SRC_SC_BOTTOM_RIGHT                    0x16F4  
+#define DP_GUI_MASTER_CNTL                     0x146C
+#define SC_TOP_LEFT                            0x16EC
+#define SC_BOTTOM_RIGHT                        0x16F0
+#define SRC_SC_BOTTOM_RIGHT                    0x16F4
 #define RB2D_DSTCACHE_MODE                    0x3428
 #define RB2D_DSTCACHE_CTLSTAT_broken          0x342C /* do not use */
 #define LVDS_GEN_CNTL                         0x02d0
 #define VERT_FP_LOOP_STRETCH                      (0x7 << 28)
 #define VERT_STRETCH_RESERVED                     0xf1000000
 
-/* DAC_CNTL bit constants */   
+/* DAC_CNTL bit constants */
 #define DAC_8BIT_EN                                0x00000100
 #define DAC_4BPP_PIX_ORDER                         0x00000200
 #define DAC_CRC_EN                                 0x00080000
 #define DAC_CMP_EN                                 (1 <<  3)
 #define DAC_CMP_OUTPUT                             (1 <<  7)
 
-/* DAC_CNTL2 bit constants */   
+/* DAC_CNTL2 bit constants */
 #define DAC2_EXPAND_MODE                          (1 << 14)
 #define DAC2_CMP_EN                                (1 << 7)
 #define DAC2_PALETTE_ACCESS_CNTL                   (1 << 5)
index fe41b84079460033618a0598fa424aefc6c55576..c3b2a2aa7140afed4251baabb45a1671fe16ccc7 100644 (file)
 #define        S1D13XXXFB_H
 
 #define S1D_PALETTE_SIZE               256
-#define S1D13506_CHIP_REV              4       /* expected chip revision number for s1d13506 */
-#define S1D13806_CHIP_REV              7       /* expected chip revision number for s1d13806 */
-#define S1D_FBID                       "S1D13806"
-#define S1D_DEVICENAME                 "s1d13806fb"
+#define S1D_FBID                       "S1D13xxx"
+#define S1D_DEVICENAME                 "s1d13xxxfb"
+
+/* S1DREG_REV_CODE register = prod_id (6 bits) + revision (2 bits) */
+#define S1D13505_PROD_ID               0x3     /* 000011 */
+#define S1D13506_PROD_ID               0x4     /* 000100 */
+#define S1D13806_PROD_ID               0x7     /* 000111 */
 
 /* register definitions (tested on s1d13896) */
-#define S1DREG_REV_CODE                        0x0000  /* Revision Code Register */
+#define S1DREG_REV_CODE                        0x0000  /* Prod + Rev Code Register */
 #define S1DREG_MISC                    0x0001  /* Miscellaneous Register */
 #define S1DREG_GPIO_CNF0               0x0004  /* General IO Pins Configuration Register 0 */
 #define S1DREG_GPIO_CNF1               0x0005  /* General IO Pins Configuration Register 1 */
@@ -141,10 +144,11 @@ struct s1d13xxxfb_regval {
        u8      value;
 };
 
-
 struct s1d13xxxfb_par {
        void __iomem    *regs;
        unsigned char   display;
+       unsigned char   prod_id;
+       unsigned char   revision;
 
        unsigned int    pseudo_palette[16];
 #ifdef CONFIG_PM
index 14c483d2b7c90b4a5713b6ed116fa16260f1228d..90e884bb521646fb61bfd89b6ae39016870c3e83 100644 (file)
@@ -531,7 +531,7 @@ config CGROUP_DEVICE
 
 config CPUSETS
        bool "Cpuset support"
-       depends on SMP && CGROUPS
+       depends on CGROUPS
        help
          This option will let you create and manage CPUSETs which
          allow dynamically partitioning a system into sets of CPUs and
@@ -565,7 +565,7 @@ config CGROUP_MEM_RES_CTLR
        select MM_OWNER
        help
          Provides a memory resource controller that manages both anonymous
-         memory and page cache. (See Documentation/controllers/memory.txt)
+         memory and page cache. (See Documentation/cgroups/memory.txt)
 
          Note that setting this option increases fixed memory overhead
          associated with each page of memory in the system. By this,
@@ -597,6 +597,8 @@ config CGROUP_MEM_RES_CTLR_SWAP
          is disabled by boot option, this will be automatically disabled and
          there will be no overhead from this. Even when you set this config=y,
          if boot option "noswapaccount" is set, swap will not be accounted.
+         Now, memory usage of swap_cgroup is 2 bytes per entry. If swap page
+         size is 4096bytes, 512k per 1Gbytes of swap.
 
 endif # CGROUPS
 
@@ -687,7 +689,7 @@ config PID_NS
        depends on NAMESPACES && EXPERIMENTAL
        help
          Support process id namespaces.  This allows having multiple
-         process with the same pid as long as they are in different
+         processes with the same pid as long as they are in different
          pid namespaces.  This is a building block of containers.
 
          Unless you want to work with an experimental feature
@@ -952,7 +954,7 @@ config COMPAT_BRK
          Randomizing heap placement makes heap exploits harder, but it
          also breaks ancient binaries (including anything libc5 based).
          This option changes the bootup default to heap randomization
-         disabled, and can be overriden runtime by setting
+         disabled, and can be overridden at runtime by setting
          /proc/sys/kernel/randomize_va_space to 2.
 
          On non-ancient distros (post-2000 ones) N is usually a safe choice.
@@ -1012,6 +1014,18 @@ config MARKERS
 
 source "arch/Kconfig"
 
+config SLOW_WORK
+       default n
+       bool "Enable slow work thread pool"
+       help
+         The slow work thread pool provides a number of dynamically allocated
+         threads that can be used by the kernel to perform operations that
+         take a relatively long time.
+
+         An example of this would be CacheFiles doing a path lookup followed
+         by a series of mkdirs and a create call, all of which have to touch
+         disk.
+
 endmenu                # General setup
 
 config HAVE_GENERIC_DMA_COHERENT
@@ -1110,7 +1124,7 @@ config INIT_ALL_POSSIBLE
          cpu_possible_map, some of them chose to initialize cpu_possible_map
          with all 1s, and others with all 0s.  When they were centralised,
          it was better to provide this option than to break all the archs
-         and have several arch maintainers persuing me down dark alleys.
+         and have several arch maintainers pursuing me down dark alleys.
 
 config STOP_MACHINE
        bool
index 8d4ff5afc1d80b56963cbf119b162a3ebce61124..dd7ee5f203f3f9c476a92d9ef39257a2791b132f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/fs.h>
 #include <linux/initrd.h>
 #include <linux/async.h>
+#include <linux/fs_struct.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
index 9aa968d5432937a3aeb799d87ff42e87dfb5c871..f5b978a9bb92892a5e876ae3ce1338ad8a896e04 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
index 9bdddbcb3d6a62614b0d43783abc9a265948bdde..69aebbf8fd2dbf4ebeb301cf1fa590d3c864b9c9 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/delay.h>
-#include <linux/raid/md.h>
+#include <linux/raid/md_u.h>
+#include <linux/raid/md_p.h>
 
 #include "do_mounts.h"
 
@@ -112,8 +113,6 @@ static int __init md_setup(char *str)
        return 1;
 }
 
-#define MdpMinorShift 6
-
 static void __init md_setup_drive(void)
 {
        int minor, i, ent, partitioned;
index 619c1baf7701e8b6c8b42f07ca3f3521f4b5b97d..80cd713f6cc5cc8b3f09317534acebdf4983903a 100644 (file)
@@ -571,11 +571,11 @@ static int __init populate_rootfs(void)
        if (initrd_start) {
 #ifdef CONFIG_BLK_DEV_RAM
                int fd;
-               printk(KERN_INFO "checking if image is initramfs...");
+               printk(KERN_INFO "checking if image is initramfs...\n");
                err = unpack_to_rootfs((char *)initrd_start,
                        initrd_end - initrd_start);
                if (!err) {
-                       printk(" it is\n");
+                       printk(KERN_INFO "rootfs image is initramfs; unpacking...\n");
                        free_initrd();
                        return 0;
                } else {
@@ -583,7 +583,8 @@ static int __init populate_rootfs(void)
                        unpack_to_rootfs(__initramfs_start,
                                 __initramfs_end - __initramfs_start);
                }
-               printk("it isn't (%s); looks like an initrd\n", err);
+               printk(KERN_INFO "rootfs image is not initramfs (%s)"
+                               "; looks like an initrd\n", err);
                fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
                if (fd >= 0) {
                        sys_write(fd, (char *)initrd_start,
index 6bf83afd654da44b5b52383a4697d4d98e0ff6fa..07c8658ffca54d1cb6da86a12b9f7512575590c0 100644 (file)
@@ -407,8 +407,7 @@ static void __init smp_init(void)
         * Set up the current CPU as possible to migrate to.
         * The other ones will be done by cpu_up/cpu_down()
         */
-       cpu = smp_processor_id();
-       cpu_set(cpu, cpu_active_map);
+       set_cpu_active(smp_processor_id(), true);
 
        /* FIXME: This should be done in userspace --RR */
        for_each_present_cpu(cpu) {
@@ -794,6 +793,7 @@ static void run_init_process(char *init_filename)
  * makes it inline to init() and it becomes part of init.text section
  */
 static noinline int init_post(void)
+       __releases(kernel_lock)
 {
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
@@ -842,7 +842,7 @@ static int __init kernel_init(void * unused)
        /*
         * init can run on any cpu.
         */
-       set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR);
+       set_cpus_allowed_ptr(current, cpu_all_mask);
        /*
         * Tell the world that we're going to be the grim
         * reaper of innocent orphaned children.
index 4a7a12c95abeff95f5f50838ad8f6bf9da1262b1..40eab7314aeb6c38fcef65ea58cea52421e646ff 100644 (file)
@@ -26,7 +26,7 @@ static void *get_ipc(ctl_table *table)
        return which;
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
 static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
index a8ddadbc74594cc6822c706b92f9f429359d0cce..916785363f0f104ac6820fd27dfeaba71bde2727 100644 (file)
@@ -602,7 +602,7 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry,
                dentry->d_fsdata = attr;
        }
 
-       mode &= ~current->fs->umask;
+       mode &= ~current_umask();
        ret = mnt_want_write(mqueue_mnt);
        if (ret)
                goto out;
index f239d87e0d37eea4a83106804035432f6c91c331..faa46da99ebed7884ebb632f70ec7d79799d7f87 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -555,12 +555,14 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
        in_use = shm_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
+               struct kern_ipc_perm *ipc;
                struct shmid_kernel *shp;
                struct inode *inode;
 
-               shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
-               if (shp == NULL)
+               ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
+               if (ipc == NULL)
                        continue;
+               shp = container_of(ipc, struct shmid_kernel, shm_perm);
 
                inode = shp->shm_file->f_path.dentry->d_inode;
 
index e4791b3ba55d45c163f3dd8cc0551f0aa7a1e766..bab1dffe37e94013d19795e33c2754f8ea0222c0 100644 (file)
@@ -93,6 +93,7 @@ obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
 obj-$(CONFIG_FUNCTION_TRACER) += trace/
 obj-$(CONFIG_TRACING) += trace/
 obj-$(CONFIG_SMP) += sched_cpupri.o
+obj-$(CONFIG_SLOW_WORK) += slow-work.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
index 8cbddff6c283a569acb2b1c707b2448f67771e44..2bfc647867654874df4c36d8009e87c5f6764728 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/syscalls.h>
 #include <linux/inotify.h>
 #include <linux/capability.h>
+#include <linux/fs_struct.h>
 
 #include "audit.h"
 
index c500ca7239b21a465831e2b3f0454f14505ff3e9..382109b5baebc2a79d31f041ceb51babd1474c95 100644 (file)
@@ -94,7 +94,6 @@ struct cgroupfs_root {
        char release_agent_path[PATH_MAX];
 };
 
-
 /*
  * The "rootnode" hierarchy is the "dummy hierarchy", reserved for the
  * subsystems that are otherwise unattached - it never has more than a
@@ -102,6 +101,39 @@ struct cgroupfs_root {
  */
 static struct cgroupfs_root rootnode;
 
+/*
+ * CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when
+ * cgroup_subsys->use_id != 0.
+ */
+#define CSS_ID_MAX     (65535)
+struct css_id {
+       /*
+        * The css to which this ID points. This pointer is set to valid value
+        * after cgroup is populated. If cgroup is removed, this will be NULL.
+        * This pointer is expected to be RCU-safe because destroy()
+        * is called after synchronize_rcu(). But for safe use, css_is_removed()
+        * css_tryget() should be used for avoiding race.
+        */
+       struct cgroup_subsys_state *css;
+       /*
+        * ID of this css.
+        */
+       unsigned short id;
+       /*
+        * Depth in hierarchy which this ID belongs to.
+        */
+       unsigned short depth;
+       /*
+        * ID is freed by RCU. (and lookup routine is RCU safe.)
+        */
+       struct rcu_head rcu_head;
+       /*
+        * Hierarchy of CSS ID belongs to.
+        */
+       unsigned short stack[0]; /* Array of Length (depth+1) */
+};
+
+
 /* The list of hierarchy roots */
 
 static LIST_HEAD(roots);
@@ -185,6 +217,8 @@ struct cg_cgroup_link {
 static struct css_set init_css_set;
 static struct cg_cgroup_link init_css_set_link;
 
+static int cgroup_subsys_init_idr(struct cgroup_subsys *ss);
+
 /* css_set_lock protects the list of css_set objects, and the
  * chain of tasks off each css_set.  Nests outside task->alloc_lock
  * due to cgroup_iter_start() */
@@ -567,6 +601,9 @@ static struct backing_dev_info cgroup_backing_dev_info = {
        .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK,
 };
 
+static int alloc_css_id(struct cgroup_subsys *ss,
+                       struct cgroup *parent, struct cgroup *child);
+
 static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
 {
        struct inode *inode = new_inode(sb);
@@ -585,13 +622,18 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
  * Call subsys's pre_destroy handler.
  * This is called before css refcnt check.
  */
-static void cgroup_call_pre_destroy(struct cgroup *cgrp)
+static int cgroup_call_pre_destroy(struct cgroup *cgrp)
 {
        struct cgroup_subsys *ss;
+       int ret = 0;
+
        for_each_subsys(cgrp->root, ss)
-               if (ss->pre_destroy)
-                       ss->pre_destroy(ss, cgrp);
-       return;
+               if (ss->pre_destroy) {
+                       ret = ss->pre_destroy(ss, cgrp);
+                       if (ret)
+                               break;
+               }
+       return ret;
 }
 
 static void free_cgroup_rcu(struct rcu_head *obj)
@@ -685,6 +727,22 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
        remove_dir(dentry);
 }
 
+/*
+ * A queue for waiters to do rmdir() cgroup. A tasks will sleep when
+ * cgroup->count == 0 && list_empty(&cgroup->children) && subsys has some
+ * reference to css->refcnt. In general, this refcnt is expected to goes down
+ * to zero, soon.
+ *
+ * CGRP_WAIT_ON_RMDIR flag is modified under cgroup's inode->i_mutex;
+ */
+DECLARE_WAIT_QUEUE_HEAD(cgroup_rmdir_waitq);
+
+static void cgroup_wakeup_rmdir_waiters(const struct cgroup *cgrp)
+{
+       if (unlikely(test_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags)))
+               wake_up_all(&cgroup_rmdir_waitq);
+}
+
 static int rebind_subsystems(struct cgroupfs_root *root,
                              unsigned long final_bits)
 {
@@ -857,16 +915,16 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        }
 
        ret = rebind_subsystems(root, opts.subsys_bits);
+       if (ret)
+               goto out_unlock;
 
        /* (re)populate subsystem files */
-       if (!ret)
-               cgroup_populate_dir(cgrp);
+       cgroup_populate_dir(cgrp);
 
        if (opts.release_agent)
                strcpy(root->release_agent_path, opts.release_agent);
  out_unlock:
-       if (opts.release_agent)
-               kfree(opts.release_agent);
+       kfree(opts.release_agent);
        mutex_unlock(&cgroup_mutex);
        mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
        return ret;
@@ -969,15 +1027,13 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
        /* First find the desired set of subsystems */
        ret = parse_cgroupfs_options(data, &opts);
        if (ret) {
-               if (opts.release_agent)
-                       kfree(opts.release_agent);
+               kfree(opts.release_agent);
                return ret;
        }
 
        root = kzalloc(sizeof(*root), GFP_KERNEL);
        if (!root) {
-               if (opts.release_agent)
-                       kfree(opts.release_agent);
+               kfree(opts.release_agent);
                return -ENOMEM;
        }
 
@@ -1280,6 +1336,12 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
        set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
        synchronize_rcu();
        put_css_set(cg);
+
+       /*
+        * wake up rmdir() waiter. the rmdir should fail since the cgroup
+        * is no longer empty.
+        */
+       cgroup_wakeup_rmdir_waiters(cgrp);
        return 0;
 }
 
@@ -1625,7 +1687,7 @@ static struct inode_operations cgroup_dir_inode_operations = {
        .rename = cgroup_rename,
 };
 
-static int cgroup_create_file(struct dentry *dentry, int mode,
+static int cgroup_create_file(struct dentry *dentry, mode_t mode,
                                struct super_block *sb)
 {
        static const struct dentry_operations cgroup_dops = {
@@ -1671,7 +1733,7 @@ static int cgroup_create_file(struct dentry *dentry, int mode,
  * @mode: mode to set on new directory.
  */
 static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry,
-                               int mode)
+                               mode_t mode)
 {
        struct dentry *parent;
        int error = 0;
@@ -1689,6 +1751,33 @@ static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry,
        return error;
 }
 
+/**
+ * cgroup_file_mode - deduce file mode of a control file
+ * @cft: the control file in question
+ *
+ * returns cft->mode if ->mode is not 0
+ * returns S_IRUGO|S_IWUSR if it has both a read and a write handler
+ * returns S_IRUGO if it has only a read handler
+ * returns S_IWUSR if it has only a write hander
+ */
+static mode_t cgroup_file_mode(const struct cftype *cft)
+{
+       mode_t mode = 0;
+
+       if (cft->mode)
+               return cft->mode;
+
+       if (cft->read || cft->read_u64 || cft->read_s64 ||
+           cft->read_map || cft->read_seq_string)
+               mode |= S_IRUGO;
+
+       if (cft->write || cft->write_u64 || cft->write_s64 ||
+           cft->write_string || cft->trigger)
+               mode |= S_IWUSR;
+
+       return mode;
+}
+
 int cgroup_add_file(struct cgroup *cgrp,
                       struct cgroup_subsys *subsys,
                       const struct cftype *cft)
@@ -1696,6 +1785,7 @@ int cgroup_add_file(struct cgroup *cgrp,
        struct dentry *dir = cgrp->dentry;
        struct dentry *dentry;
        int error;
+       mode_t mode;
 
        char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
        if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
@@ -1706,7 +1796,8 @@ int cgroup_add_file(struct cgroup *cgrp,
        BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex));
        dentry = lookup_one_len(name, dir, strlen(name));
        if (!IS_ERR(dentry)) {
-               error = cgroup_create_file(dentry, 0644 | S_IFREG,
+               mode = cgroup_file_mode(cft);
+               error = cgroup_create_file(dentry, mode | S_IFREG,
                                                cgrp->root->sb);
                if (!error)
                        dentry->d_fsdata = (void *)cft;
@@ -2288,6 +2379,7 @@ static struct cftype files[] = {
                .write_u64 = cgroup_tasks_write,
                .release = cgroup_tasks_release,
                .private = FILE_TASKLIST,
+               .mode = S_IRUGO | S_IWUSR,
        },
 
        {
@@ -2327,6 +2419,17 @@ static int cgroup_populate_dir(struct cgroup *cgrp)
                if (ss->populate && (err = ss->populate(ss, cgrp)) < 0)
                        return err;
        }
+       /* This cgroup is ready now */
+       for_each_subsys(cgrp->root, ss) {
+               struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+               /*
+                * Update id->css pointer and make this css visible from
+                * CSS ID functions. This pointer will be dereferened
+                * from RCU-read-side without locks.
+                */
+               if (css->id)
+                       rcu_assign_pointer(css->id->css, css);
+       }
 
        return 0;
 }
@@ -2338,6 +2441,7 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
        css->cgroup = cgrp;
        atomic_set(&css->refcnt, 1);
        css->flags = 0;
+       css->id = NULL;
        if (cgrp == dummytop)
                set_bit(CSS_ROOT, &css->flags);
        BUG_ON(cgrp->subsys[ss->subsys_id]);
@@ -2376,7 +2480,7 @@ static void cgroup_unlock_hierarchy(struct cgroupfs_root *root)
  * Must be called with the mutex on the parent inode held
  */
 static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
-                            int mode)
+                            mode_t mode)
 {
        struct cgroup *cgrp;
        struct cgroupfs_root *root = parent->root;
@@ -2413,6 +2517,10 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                        goto err_destroy;
                }
                init_cgroup_css(css, ss, cgrp);
+               if (ss->use_id)
+                       if (alloc_css_id(ss, parent, cgrp))
+                               goto err_destroy;
+               /* At error, ->destroy() callback has to free assigned ID. */
        }
 
        cgroup_lock_hierarchy(root);
@@ -2555,9 +2663,11 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        struct cgroup *cgrp = dentry->d_fsdata;
        struct dentry *d;
        struct cgroup *parent;
+       DEFINE_WAIT(wait);
+       int ret;
 
        /* the vfs holds both inode->i_mutex already */
-
+again:
        mutex_lock(&cgroup_mutex);
        if (atomic_read(&cgrp->count) != 0) {
                mutex_unlock(&cgroup_mutex);
@@ -2573,17 +2683,39 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
         * Call pre_destroy handlers of subsys. Notify subsystems
         * that rmdir() request comes.
         */
-       cgroup_call_pre_destroy(cgrp);
+       ret = cgroup_call_pre_destroy(cgrp);
+       if (ret)
+               return ret;
 
        mutex_lock(&cgroup_mutex);
        parent = cgrp->parent;
-
-       if (atomic_read(&cgrp->count)
-           || !list_empty(&cgrp->children)
-           || !cgroup_clear_css_refs(cgrp)) {
+       if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children)) {
                mutex_unlock(&cgroup_mutex);
                return -EBUSY;
        }
+       /*
+        * css_put/get is provided for subsys to grab refcnt to css. In typical
+        * case, subsystem has no reference after pre_destroy(). But, under
+        * hierarchy management, some *temporal* refcnt can be hold.
+        * To avoid returning -EBUSY to a user, waitqueue is used. If subsys
+        * is really busy, it should return -EBUSY at pre_destroy(). wake_up
+        * is called when css_put() is called and refcnt goes down to 0.
+        */
+       set_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
+       prepare_to_wait(&cgroup_rmdir_waitq, &wait, TASK_INTERRUPTIBLE);
+
+       if (!cgroup_clear_css_refs(cgrp)) {
+               mutex_unlock(&cgroup_mutex);
+               schedule();
+               finish_wait(&cgroup_rmdir_waitq, &wait);
+               clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
+               if (signal_pending(current))
+                       return -EINTR;
+               goto again;
+       }
+       /* NO css_tryget() can success after here. */
+       finish_wait(&cgroup_rmdir_waitq, &wait);
+       clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
 
        spin_lock(&release_list_lock);
        set_bit(CGRP_REMOVED, &cgrp->flags);
@@ -2708,6 +2840,8 @@ int __init cgroup_init(void)
                struct cgroup_subsys *ss = subsys[i];
                if (!ss->early_init)
                        cgroup_init_subsys(ss);
+               if (ss->use_id)
+                       cgroup_subsys_init_idr(ss);
        }
 
        /* Add init_css_set to the hash table */
@@ -3084,18 +3218,19 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
 }
 
 /**
- * cgroup_is_descendant - see if @cgrp is a descendant of current task's cgrp
+ * cgroup_is_descendant - see if @cgrp is a descendant of @task's cgrp
  * @cgrp: the cgroup in question
+ * @task: the task in question
  *
- * See if @cgrp is a descendant of the current task's cgroup in
- * the appropriate hierarchy.
+ * See if @cgrp is a descendant of @task's cgroup in the appropriate
+ * hierarchy.
  *
  * If we are sending in dummytop, then presumably we are creating
  * the top cgroup in the subsystem.
  *
  * Called only by the ns (nsproxy) cgroup.
  */
-int cgroup_is_descendant(const struct cgroup *cgrp)
+int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task)
 {
        int ret;
        struct cgroup *target;
@@ -3105,7 +3240,7 @@ int cgroup_is_descendant(const struct cgroup *cgrp)
                return 1;
 
        get_first_subsys(cgrp, NULL, &subsys_id);
-       target = task_cgroup(current, subsys_id);
+       target = task_cgroup(task, subsys_id);
        while (cgrp != target && cgrp!= cgrp->top_cgroup)
                cgrp = cgrp->parent;
        ret = (cgrp == target);
@@ -3138,10 +3273,12 @@ void __css_put(struct cgroup_subsys_state *css)
 {
        struct cgroup *cgrp = css->cgroup;
        rcu_read_lock();
-       if ((atomic_dec_return(&css->refcnt) == 1) &&
-           notify_on_release(cgrp)) {
-               set_bit(CGRP_RELEASABLE, &cgrp->flags);
-               check_for_release(cgrp);
+       if (atomic_dec_return(&css->refcnt) == 1) {
+               if (notify_on_release(cgrp)) {
+                       set_bit(CGRP_RELEASABLE, &cgrp->flags);
+                       check_for_release(cgrp);
+               }
+               cgroup_wakeup_rmdir_waiters(cgrp);
        }
        rcu_read_unlock();
 }
@@ -3241,3 +3378,232 @@ static int __init cgroup_disable(char *str)
        return 1;
 }
 __setup("cgroup_disable=", cgroup_disable);
+
+/*
+ * Functons for CSS ID.
+ */
+
+/*
+ *To get ID other than 0, this should be called when !cgroup_is_removed().
+ */
+unsigned short css_id(struct cgroup_subsys_state *css)
+{
+       struct css_id *cssid = rcu_dereference(css->id);
+
+       if (cssid)
+               return cssid->id;
+       return 0;
+}
+
+unsigned short css_depth(struct cgroup_subsys_state *css)
+{
+       struct css_id *cssid = rcu_dereference(css->id);
+
+       if (cssid)
+               return cssid->depth;
+       return 0;
+}
+
+bool css_is_ancestor(struct cgroup_subsys_state *child,
+                   const struct cgroup_subsys_state *root)
+{
+       struct css_id *child_id = rcu_dereference(child->id);
+       struct css_id *root_id = rcu_dereference(root->id);
+
+       if (!child_id || !root_id || (child_id->depth < root_id->depth))
+               return false;
+       return child_id->stack[root_id->depth] == root_id->id;
+}
+
+static void __free_css_id_cb(struct rcu_head *head)
+{
+       struct css_id *id;
+
+       id = container_of(head, struct css_id, rcu_head);
+       kfree(id);
+}
+
+void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
+{
+       struct css_id *id = css->id;
+       /* When this is called before css_id initialization, id can be NULL */
+       if (!id)
+               return;
+
+       BUG_ON(!ss->use_id);
+
+       rcu_assign_pointer(id->css, NULL);
+       rcu_assign_pointer(css->id, NULL);
+       spin_lock(&ss->id_lock);
+       idr_remove(&ss->idr, id->id);
+       spin_unlock(&ss->id_lock);
+       call_rcu(&id->rcu_head, __free_css_id_cb);
+}
+
+/*
+ * This is called by init or create(). Then, calls to this function are
+ * always serialized (By cgroup_mutex() at create()).
+ */
+
+static struct css_id *get_new_cssid(struct cgroup_subsys *ss, int depth)
+{
+       struct css_id *newid;
+       int myid, error, size;
+
+       BUG_ON(!ss->use_id);
+
+       size = sizeof(*newid) + sizeof(unsigned short) * (depth + 1);
+       newid = kzalloc(size, GFP_KERNEL);
+       if (!newid)
+               return ERR_PTR(-ENOMEM);
+       /* get id */
+       if (unlikely(!idr_pre_get(&ss->idr, GFP_KERNEL))) {
+               error = -ENOMEM;
+               goto err_out;
+       }
+       spin_lock(&ss->id_lock);
+       /* Don't use 0. allocates an ID of 1-65535 */
+       error = idr_get_new_above(&ss->idr, newid, 1, &myid);
+       spin_unlock(&ss->id_lock);
+
+       /* Returns error when there are no free spaces for new ID.*/
+       if (error) {
+               error = -ENOSPC;
+               goto err_out;
+       }
+       if (myid > CSS_ID_MAX)
+               goto remove_idr;
+
+       newid->id = myid;
+       newid->depth = depth;
+       return newid;
+remove_idr:
+       error = -ENOSPC;
+       spin_lock(&ss->id_lock);
+       idr_remove(&ss->idr, myid);
+       spin_unlock(&ss->id_lock);
+err_out:
+       kfree(newid);
+       return ERR_PTR(error);
+
+}
+
+static int __init cgroup_subsys_init_idr(struct cgroup_subsys *ss)
+{
+       struct css_id *newid;
+       struct cgroup_subsys_state *rootcss;
+
+       spin_lock_init(&ss->id_lock);
+       idr_init(&ss->idr);
+
+       rootcss = init_css_set.subsys[ss->subsys_id];
+       newid = get_new_cssid(ss, 0);
+       if (IS_ERR(newid))
+               return PTR_ERR(newid);
+
+       newid->stack[0] = newid->id;
+       newid->css = rootcss;
+       rootcss->id = newid;
+       return 0;
+}
+
+static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent,
+                       struct cgroup *child)
+{
+       int subsys_id, i, depth = 0;
+       struct cgroup_subsys_state *parent_css, *child_css;
+       struct css_id *child_id, *parent_id = NULL;
+
+       subsys_id = ss->subsys_id;
+       parent_css = parent->subsys[subsys_id];
+       child_css = child->subsys[subsys_id];
+       depth = css_depth(parent_css) + 1;
+       parent_id = parent_css->id;
+
+       child_id = get_new_cssid(ss, depth);
+       if (IS_ERR(child_id))
+               return PTR_ERR(child_id);
+
+       for (i = 0; i < depth; i++)
+               child_id->stack[i] = parent_id->stack[i];
+       child_id->stack[depth] = child_id->id;
+       /*
+        * child_id->css pointer will be set after this cgroup is available
+        * see cgroup_populate_dir()
+        */
+       rcu_assign_pointer(child_css->id, child_id);
+
+       return 0;
+}
+
+/**
+ * css_lookup - lookup css by id
+ * @ss: cgroup subsys to be looked into.
+ * @id: the id
+ *
+ * Returns pointer to cgroup_subsys_state if there is valid one with id.
+ * NULL if not. Should be called under rcu_read_lock()
+ */
+struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id)
+{
+       struct css_id *cssid = NULL;
+
+       BUG_ON(!ss->use_id);
+       cssid = idr_find(&ss->idr, id);
+
+       if (unlikely(!cssid))
+               return NULL;
+
+       return rcu_dereference(cssid->css);
+}
+
+/**
+ * css_get_next - lookup next cgroup under specified hierarchy.
+ * @ss: pointer to subsystem
+ * @id: current position of iteration.
+ * @root: pointer to css. search tree under this.
+ * @foundid: position of found object.
+ *
+ * Search next css under the specified hierarchy of rootid. Calling under
+ * rcu_read_lock() is necessary. Returns NULL if it reaches the end.
+ */
+struct cgroup_subsys_state *
+css_get_next(struct cgroup_subsys *ss, int id,
+            struct cgroup_subsys_state *root, int *foundid)
+{
+       struct cgroup_subsys_state *ret = NULL;
+       struct css_id *tmp;
+       int tmpid;
+       int rootid = css_id(root);
+       int depth = css_depth(root);
+
+       if (!rootid)
+               return NULL;
+
+       BUG_ON(!ss->use_id);
+       /* fill start point for scan */
+       tmpid = id;
+       while (1) {
+               /*
+                * scan next entry from bitmap(tree), tmpid is updated after
+                * idr_get_next().
+                */
+               spin_lock(&ss->id_lock);
+               tmp = idr_get_next(&ss->idr, &tmpid);
+               spin_unlock(&ss->id_lock);
+
+               if (!tmp)
+                       break;
+               if (tmp->depth >= depth && tmp->stack[depth] == rootid) {
+                       ret = rcu_dereference(tmp->css);
+                       if (ret) {
+                               *foundid = tmpid;
+                               break;
+                       }
+               }
+               /* continue to scan from next id */
+               tmpid = tmpid + 1;
+       }
+       return ret;
+}
+
index daca6209202df4a84df7e0fc41025e33c7642131..0c92d797baa6d163853245481597f7fc03236da4 100644 (file)
@@ -40,9 +40,7 @@ static u64 taskcount_read(struct cgroup *cont, struct cftype *cft)
 {
        u64 count;
 
-       cgroup_lock();
        count = cgroup_task_count(cont);
-       cgroup_unlock();
        return count;
 }
 
index 79e40f00dcb89b8b3b5dedb5cc1c7da507e6b322..395b6974dc8d56ccb2d91ede756069fe9b10c975 100644 (file)
@@ -281,7 +281,7 @@ int __ref cpu_down(unsigned int cpu)
                goto out;
        }
 
-       cpu_clear(cpu, cpu_active_map);
+       set_cpu_active(cpu, false);
 
        /*
         * Make sure the all cpus did the reschedule and are not
@@ -296,7 +296,7 @@ int __ref cpu_down(unsigned int cpu)
        err = _cpu_down(cpu, 0);
 
        if (cpu_online(cpu))
-               cpu_set(cpu, cpu_active_map);
+               set_cpu_active(cpu, true);
 
 out:
        cpu_maps_update_done();
@@ -333,7 +333,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
 
-       cpu_set(cpu, cpu_active_map);
+       set_cpu_active(cpu, true);
 
        /* Now call notifier in preparation. */
        raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
index f76db9dcaa05e592f3138f5389ae4c22827b58d9..026faccca869e396d378693422e29e9c82f739ac 100644 (file)
@@ -128,10 +128,6 @@ static inline struct cpuset *task_cs(struct task_struct *task)
        return container_of(task_subsys_state(task, cpuset_subsys_id),
                            struct cpuset, css);
 }
-struct cpuset_hotplug_scanner {
-       struct cgroup_scanner scan;
-       struct cgroup *to;
-};
 
 /* bits in struct cpuset flags field */
 typedef enum {
@@ -521,6 +517,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
        return 0;
 }
 
+#ifdef CONFIG_SMP
 /*
  * Helper routine for generate_sched_domains().
  * Do cpusets a, b have overlapping cpus_allowed masks?
@@ -815,6 +812,18 @@ static void do_rebuild_sched_domains(struct work_struct *unused)
 
        put_online_cpus();
 }
+#else /* !CONFIG_SMP */
+static void do_rebuild_sched_domains(struct work_struct *unused)
+{
+}
+
+static int generate_sched_domains(struct cpumask **domains,
+                       struct sched_domain_attr **attributes)
+{
+       *domains = NULL;
+       return 1;
+}
+#endif /* CONFIG_SMP */
 
 static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains);
 
@@ -1026,101 +1035,70 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
        mutex_unlock(&callback_mutex);
 }
 
+/*
+ * Rebind task's vmas to cpuset's new mems_allowed, and migrate pages to new
+ * nodes if memory_migrate flag is set. Called with cgroup_mutex held.
+ */
+static void cpuset_change_nodemask(struct task_struct *p,
+                                  struct cgroup_scanner *scan)
+{
+       struct mm_struct *mm;
+       struct cpuset *cs;
+       int migrate;
+       const nodemask_t *oldmem = scan->data;
+
+       mm = get_task_mm(p);
+       if (!mm)
+               return;
+
+       cs = cgroup_cs(scan->cg);
+       migrate = is_memory_migrate(cs);
+
+       mpol_rebind_mm(mm, &cs->mems_allowed);
+       if (migrate)
+               cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed);
+       mmput(mm);
+}
+
 static void *cpuset_being_rebound;
 
 /**
  * update_tasks_nodemask - Update the nodemasks of tasks in the cpuset.
  * @cs: the cpuset in which each task's mems_allowed mask needs to be changed
  * @oldmem: old mems_allowed of cpuset cs
+ * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
  *
  * Called with cgroup_mutex held
- * Return 0 if successful, -errno if not.
+ * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * if @heap != NULL.
  */
-static int update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem)
+static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem,
+                                struct ptr_heap *heap)
 {
-       struct task_struct *p;
-       struct mm_struct **mmarray;
-       int i, n, ntasks;
-       int migrate;
-       int fudge;
-       struct cgroup_iter it;
-       int retval;
+       struct cgroup_scanner scan;
 
        cpuset_being_rebound = cs;              /* causes mpol_dup() rebind */
 
-       fudge = 10;                             /* spare mmarray[] slots */
-       fudge += cpumask_weight(cs->cpus_allowed);/* imagine 1 fork-bomb/cpu */
-       retval = -ENOMEM;
-
-       /*
-        * Allocate mmarray[] to hold mm reference for each task
-        * in cpuset cs.  Can't kmalloc GFP_KERNEL while holding
-        * tasklist_lock.  We could use GFP_ATOMIC, but with a
-        * few more lines of code, we can retry until we get a big
-        * enough mmarray[] w/o using GFP_ATOMIC.
-        */
-       while (1) {
-               ntasks = cgroup_task_count(cs->css.cgroup);  /* guess */
-               ntasks += fudge;
-               mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL);
-               if (!mmarray)
-                       goto done;
-               read_lock(&tasklist_lock);              /* block fork */
-               if (cgroup_task_count(cs->css.cgroup) <= ntasks)
-                       break;                          /* got enough */
-               read_unlock(&tasklist_lock);            /* try again */
-               kfree(mmarray);
-       }
-
-       n = 0;
-
-       /* Load up mmarray[] with mm reference for each task in cpuset. */
-       cgroup_iter_start(cs->css.cgroup, &it);
-       while ((p = cgroup_iter_next(cs->css.cgroup, &it))) {
-               struct mm_struct *mm;
-
-               if (n >= ntasks) {
-                       printk(KERN_WARNING
-                               "Cpuset mempolicy rebind incomplete.\n");
-                       break;
-               }
-               mm = get_task_mm(p);
-               if (!mm)
-                       continue;
-               mmarray[n++] = mm;
-       }
-       cgroup_iter_end(cs->css.cgroup, &it);
-       read_unlock(&tasklist_lock);
+       scan.cg = cs->css.cgroup;
+       scan.test_task = NULL;
+       scan.process_task = cpuset_change_nodemask;
+       scan.heap = heap;
+       scan.data = (nodemask_t *)oldmem;
 
        /*
-        * Now that we've dropped the tasklist spinlock, we can
-        * rebind the vma mempolicies of each mm in mmarray[] to their
-        * new cpuset, and release that mm.  The mpol_rebind_mm()
-        * call takes mmap_sem, which we couldn't take while holding
-        * tasklist_lock.  Forks can happen again now - the mpol_dup()
-        * cpuset_being_rebound check will catch such forks, and rebind
-        * their vma mempolicies too.  Because we still hold the global
-        * cgroup_mutex, we know that no other rebind effort will
-        * be contending for the global variable cpuset_being_rebound.
+        * The mpol_rebind_mm() call takes mmap_sem, which we couldn't
+        * take while holding tasklist_lock.  Forks can happen - the
+        * mpol_dup() cpuset_being_rebound check will catch such forks,
+        * and rebind their vma mempolicies too.  Because we still hold
+        * the global cgroup_mutex, we know that no other rebind effort
+        * will be contending for the global variable cpuset_being_rebound.
         * It's ok if we rebind the same mm twice; mpol_rebind_mm()
         * is idempotent.  Also migrate pages in each mm to new nodes.
         */
-       migrate = is_memory_migrate(cs);
-       for (i = 0; i < n; i++) {
-               struct mm_struct *mm = mmarray[i];
-
-               mpol_rebind_mm(mm, &cs->mems_allowed);
-               if (migrate)
-                       cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed);
-               mmput(mm);
-       }
+       cgroup_scan_tasks(&scan);
 
        /* We're done rebinding vmas to this cpuset's new mems_allowed. */
-       kfree(mmarray);
        cpuset_being_rebound = NULL;
-       retval = 0;
-done:
-       return retval;
 }
 
 /*
@@ -1141,6 +1119,7 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
 {
        nodemask_t oldmem;
        int retval;
+       struct ptr_heap heap;
 
        /*
         * top_cpuset.mems_allowed tracks node_stats[N_HIGH_MEMORY];
@@ -1175,12 +1154,18 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
        if (retval < 0)
                goto done;
 
+       retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL);
+       if (retval < 0)
+               goto done;
+
        mutex_lock(&callback_mutex);
        cs->mems_allowed = trialcs->mems_allowed;
        cs->mems_generation = cpuset_mems_generation++;
        mutex_unlock(&callback_mutex);
 
-       retval = update_tasks_nodemask(cs, &oldmem);
+       update_tasks_nodemask(cs, &oldmem, &heap);
+
+       heap_free(&heap);
 done:
        return retval;
 }
@@ -1192,8 +1177,10 @@ int current_cpuset_is_being_rebound(void)
 
 static int update_relax_domain_level(struct cpuset *cs, s64 val)
 {
+#ifdef CONFIG_SMP
        if (val < -1 || val >= SD_LV_MAX)
                return -EINVAL;
+#endif
 
        if (val != cs->relax_domain_level) {
                cs->relax_domain_level = val;
@@ -1355,19 +1342,22 @@ static int cpuset_can_attach(struct cgroup_subsys *ss,
                             struct cgroup *cont, struct task_struct *tsk)
 {
        struct cpuset *cs = cgroup_cs(cont);
-       int ret = 0;
 
        if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
                return -ENOSPC;
 
-       if (tsk->flags & PF_THREAD_BOUND) {
-               mutex_lock(&callback_mutex);
-               if (!cpumask_equal(&tsk->cpus_allowed, cs->cpus_allowed))
-                       ret = -EINVAL;
-               mutex_unlock(&callback_mutex);
-       }
+       /*
+        * Kthreads bound to specific cpus cannot be moved to a new cpuset; we
+        * cannot change their cpu affinity and isolating such threads by their
+        * set of allowed nodes is unnecessary.  Thus, cpusets are not
+        * applicable for such threads.  This prevents checking for success of
+        * set_cpus_allowed_ptr() on all attached tasks before cpus_allowed may
+        * be changed.
+        */
+       if (tsk->flags & PF_THREAD_BOUND)
+               return -EINVAL;
 
-       return ret < 0 ? ret : security_task_setscheduler(tsk, 0, NULL);
+       return security_task_setscheduler(tsk, 0, NULL);
 }
 
 static void cpuset_attach(struct cgroup_subsys *ss,
@@ -1706,6 +1696,7 @@ static struct cftype files[] = {
                .read_u64 = cpuset_read_u64,
                .write_u64 = cpuset_write_u64,
                .private = FILE_MEMORY_PRESSURE,
+               .mode = S_IRUGO,
        },
 
        {
@@ -1913,10 +1904,9 @@ int __init cpuset_init(void)
 static void cpuset_do_move_task(struct task_struct *tsk,
                                struct cgroup_scanner *scan)
 {
-       struct cpuset_hotplug_scanner *chsp;
+       struct cgroup *new_cgroup = scan->data;
 
-       chsp = container_of(scan, struct cpuset_hotplug_scanner, scan);
-       cgroup_attach_task(chsp->to, tsk);
+       cgroup_attach_task(new_cgroup, tsk);
 }
 
 /**
@@ -1932,15 +1922,15 @@ static void cpuset_do_move_task(struct task_struct *tsk,
  */
 static void move_member_tasks_to_cpuset(struct cpuset *from, struct cpuset *to)
 {
-       struct cpuset_hotplug_scanner scan;
+       struct cgroup_scanner scan;
 
-       scan.scan.cg = from->css.cgroup;
-       scan.scan.test_task = NULL; /* select all tasks in cgroup */
-       scan.scan.process_task = cpuset_do_move_task;
-       scan.scan.heap = NULL;
-       scan.to = to->css.cgroup;
+       scan.cg = from->css.cgroup;
+       scan.test_task = NULL; /* select all tasks in cgroup */
+       scan.process_task = cpuset_do_move_task;
+       scan.heap = NULL;
+       scan.data = to->css.cgroup;
 
-       if (cgroup_scan_tasks(&scan.scan))
+       if (cgroup_scan_tasks(&scan))
                printk(KERN_ERR "move_member_tasks_to_cpuset: "
                                "cgroup_scan_tasks failed\n");
 }
@@ -2033,7 +2023,7 @@ static void scan_for_empty_cpusets(struct cpuset *root)
                        remove_tasks_in_empty_cpuset(cp);
                else {
                        update_tasks_cpumask(cp, NULL);
-                       update_tasks_nodemask(cp, &oldmems);
+                       update_tasks_nodemask(cp, &oldmems, NULL);
                }
        }
 }
@@ -2069,7 +2059,9 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
        }
 
        cgroup_lock();
+       mutex_lock(&callback_mutex);
        cpumask_copy(top_cpuset.cpus_allowed, cpu_online_mask);
+       mutex_unlock(&callback_mutex);
        scan_for_empty_cpusets(&top_cpuset);
        ndoms = generate_sched_domains(&doms, &attr);
        cgroup_unlock();
@@ -2092,11 +2084,12 @@ static int cpuset_track_online_nodes(struct notifier_block *self,
        cgroup_lock();
        switch (action) {
        case MEM_ONLINE:
-               top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-               break;
        case MEM_OFFLINE:
+               mutex_lock(&callback_mutex);
                top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-               scan_for_empty_cpusets(&top_cpuset);
+               mutex_unlock(&callback_mutex);
+               if (action == MEM_OFFLINE)
+                       scan_for_empty_cpusets(&top_cpuset);
                break;
        default:
                break;
@@ -2206,26 +2199,24 @@ static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
 }
 
 /**
- * cpuset_zone_allowed_softwall - Can we allocate on zone z's memory node?
- * @z: is this zone on an allowed node?
+ * cpuset_node_allowed_softwall - Can we allocate on a memory node?
+ * @node: is this an allowed node?
  * @gfp_mask: memory allocation flags
  *
- * If we're in interrupt, yes, we can always allocate.  If
- * __GFP_THISNODE is set, yes, we can always allocate.  If zone
- * z's node is in our tasks mems_allowed, yes.  If it's not a
- * __GFP_HARDWALL request and this zone's nodes is in the nearest
- * hardwalled cpuset ancestor to this tasks cpuset, yes.
- * If the task has been OOM killed and has access to memory reserves
- * as specified by the TIF_MEMDIE flag, yes.
+ * If we're in interrupt, yes, we can always allocate.  If __GFP_THISNODE is
+ * set, yes, we can always allocate.  If node is in our task's mems_allowed,
+ * yes.  If it's not a __GFP_HARDWALL request and this node is in the nearest
+ * hardwalled cpuset ancestor to this task's cpuset, yes.  If the task has been
+ * OOM killed and has access to memory reserves as specified by the TIF_MEMDIE
+ * flag, yes.
  * Otherwise, no.
  *
- * If __GFP_HARDWALL is set, cpuset_zone_allowed_softwall()
- * reduces to cpuset_zone_allowed_hardwall().  Otherwise,
- * cpuset_zone_allowed_softwall() might sleep, and might allow a zone
- * from an enclosing cpuset.
+ * If __GFP_HARDWALL is set, cpuset_node_allowed_softwall() reduces to
+ * cpuset_node_allowed_hardwall().  Otherwise, cpuset_node_allowed_softwall()
+ * might sleep, and might allow a node from an enclosing cpuset.
  *
- * cpuset_zone_allowed_hardwall() only handles the simpler case of
- * hardwall cpusets, and never sleeps.
+ * cpuset_node_allowed_hardwall() only handles the simpler case of hardwall
+ * cpusets, and never sleeps.
  *
  * The __GFP_THISNODE placement logic is really handled elsewhere,
  * by forcibly using a zonelist starting at a specified node, and by
@@ -2264,20 +2255,17 @@ static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
  *     GFP_USER     - only nodes in current tasks mems allowed ok.
  *
  * Rule:
- *    Don't call cpuset_zone_allowed_softwall if you can't sleep, unless you
+ *    Don't call cpuset_node_allowed_softwall if you can't sleep, unless you
  *    pass in the __GFP_HARDWALL flag set in gfp_flag, which disables
  *    the code that might scan up ancestor cpusets and sleep.
  */
-
-int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 {
-       int node;                       /* node that zone z is on */
        const struct cpuset *cs;        /* current cpuset ancestors */
        int allowed;                    /* is allocation in zone z allowed? */
 
        if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
                return 1;
-       node = zone_to_nid(z);
        might_sleep_if(!(gfp_mask & __GFP_HARDWALL));
        if (node_isset(node, current->mems_allowed))
                return 1;
@@ -2306,15 +2294,15 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
 }
 
 /*
- * cpuset_zone_allowed_hardwall - Can we allocate on zone z's memory node?
- * @z: is this zone on an allowed node?
+ * cpuset_node_allowed_hardwall - Can we allocate on a memory node?
+ * @node: is this an allowed node?
  * @gfp_mask: memory allocation flags
  *
- * If we're in interrupt, yes, we can always allocate.
- * If __GFP_THISNODE is set, yes, we can always allocate.  If zone
- * z's node is in our tasks mems_allowed, yes.   If the task has been
- * OOM killed and has access to memory reserves as specified by the
- * TIF_MEMDIE flag, yes.  Otherwise, no.
+ * If we're in interrupt, yes, we can always allocate.  If __GFP_THISNODE is
+ * set, yes, we can always allocate.  If node is in our task's mems_allowed,
+ * yes.  If the task has been OOM killed and has access to memory reserves as
+ * specified by the TIF_MEMDIE flag, yes.
+ * Otherwise, no.
  *
  * The __GFP_THISNODE placement logic is really handled elsewhere,
  * by forcibly using a zonelist starting at a specified node, and by
@@ -2322,20 +2310,16 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
  * any node on the zonelist except the first.  By the time any such
  * calls get to this routine, we should just shut up and say 'yes'.
  *
- * Unlike the cpuset_zone_allowed_softwall() variant, above,
- * this variant requires that the zone be in the current tasks
+ * Unlike the cpuset_node_allowed_softwall() variant, above,
+ * this variant requires that the node be in the current task's
  * mems_allowed or that we're in interrupt.  It does not scan up the
  * cpuset hierarchy for the nearest enclosing mem_exclusive cpuset.
  * It never sleeps.
  */
-
-int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+int __cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
 {
-       int node;                       /* node that zone z is on */
-
        if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
                return 1;
-       node = zone_to_nid(z);
        if (node_isset(node, current->mems_allowed))
                return 1;
        /*
index 667c841c2952d6966a08ba9b11e00ad99d06520a..c35452cadded85de8e4505def877b3c5561c991f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/syscalls.h>
 #include <linux/sysctl.h>
 #include <linux/types.h>
+#include <linux/fs_struct.h>
 
 
 static void default_handler(int, struct pt_regs *);
@@ -145,28 +146,6 @@ __set_personality(u_long personality)
                return 0;
        }
 
-       if (atomic_read(&current->fs->count) != 1) {
-               struct fs_struct *fsp, *ofsp;
-
-               fsp = copy_fs_struct(current->fs);
-               if (fsp == NULL) {
-                       module_put(ep->module);
-                       return -ENOMEM;
-               }
-
-               task_lock(current);
-               ofsp = current->fs;
-               current->fs = fsp;
-               task_unlock(current);
-
-               put_fs_struct(ofsp);
-       }
-
-       /*
-        * At that point we are guaranteed to be the sole owner of
-        * current->fs.
-        */
-
        current->personality = personality;
        oep = current_thread_info()->exec_domain;
        current_thread_info()->exec_domain = ep;
index 167e1e3ad7c61f5c0a73db9dc457c30a97527a91..6686ed1e4aa3aedd25a613d3ad7282798392f224 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/blkdev.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/tracehook.h>
+#include <linux/fs_struct.h>
 #include <linux/init_task.h>
 #include <trace/sched.h>
 
@@ -61,11 +62,6 @@ DEFINE_TRACE(sched_process_wait);
 
 static void exit_mm(struct task_struct * tsk);
 
-static inline int task_detached(struct task_struct *p)
-{
-       return p->exit_signal == -1;
-}
-
 static void __unhash_process(struct task_struct *p)
 {
        nr_threads--;
@@ -362,16 +358,12 @@ static void reparent_to_kthreadd(void)
 void __set_special_pids(struct pid *pid)
 {
        struct task_struct *curr = current->group_leader;
-       pid_t nr = pid_nr(pid);
 
-       if (task_session(curr) != pid) {
+       if (task_session(curr) != pid)
                change_pid(curr, PIDTYPE_SID, pid);
-               set_task_session(curr, nr);
-       }
-       if (task_pgrp(curr) != pid) {
+
+       if (task_pgrp(curr) != pid)
                change_pid(curr, PIDTYPE_PGID, pid);
-               set_task_pgrp(curr, nr);
-       }
 }
 
 static void set_special_pids(struct pid *pid)
@@ -429,7 +421,6 @@ EXPORT_SYMBOL(disallow_signal);
 void daemonize(const char *name, ...)
 {
        va_list args;
-       struct fs_struct *fs;
        sigset_t blocked;
 
        va_start(args, name);
@@ -462,11 +453,7 @@ void daemonize(const char *name, ...)
 
        /* Become as one with the init task */
 
-       exit_fs(current);       /* current->fs->count--; */
-       fs = init_task.fs;
-       current->fs = fs;
-       atomic_inc(&fs->count);
-
+       daemonize_fs_struct();
        exit_files(current);
        current->files = init_task.files;
        atomic_inc(&current->files->count);
@@ -565,30 +552,6 @@ void exit_files(struct task_struct *tsk)
        }
 }
 
-void put_fs_struct(struct fs_struct *fs)
-{
-       /* No need to hold fs->lock if we are killing it */
-       if (atomic_dec_and_test(&fs->count)) {
-               path_put(&fs->root);
-               path_put(&fs->pwd);
-               kmem_cache_free(fs_cachep, fs);
-       }
-}
-
-void exit_fs(struct task_struct *tsk)
-{
-       struct fs_struct * fs = tsk->fs;
-
-       if (fs) {
-               task_lock(tsk);
-               tsk->fs = NULL;
-               task_unlock(tsk);
-               put_fs_struct(fs);
-       }
-}
-
-EXPORT_SYMBOL_GPL(exit_fs);
-
 #ifdef CONFIG_MM_OWNER
 /*
  * Task p is exiting and it owned mm, lets find a new owner for it
@@ -731,119 +694,6 @@ static void exit_mm(struct task_struct * tsk)
        mmput(mm);
 }
 
-/*
- * Return nonzero if @parent's children should reap themselves.
- *
- * Called with write_lock_irq(&tasklist_lock) held.
- */
-static int ignoring_children(struct task_struct *parent)
-{
-       int ret;
-       struct sighand_struct *psig = parent->sighand;
-       unsigned long flags;
-       spin_lock_irqsave(&psig->siglock, flags);
-       ret = (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
-              (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT));
-       spin_unlock_irqrestore(&psig->siglock, flags);
-       return ret;
-}
-
-/*
- * Detach all tasks we were using ptrace on.
- * Any that need to be release_task'd are put on the @dead list.
- *
- * Called with write_lock(&tasklist_lock) held.
- */
-static void ptrace_exit(struct task_struct *parent, struct list_head *dead)
-{
-       struct task_struct *p, *n;
-       int ign = -1;
-
-       list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) {
-               __ptrace_unlink(p);
-
-               if (p->exit_state != EXIT_ZOMBIE)
-                       continue;
-
-               /*
-                * If it's a zombie, our attachedness prevented normal
-                * parent notification or self-reaping.  Do notification
-                * now if it would have happened earlier.  If it should
-                * reap itself, add it to the @dead list.  We can't call
-                * release_task() here because we already hold tasklist_lock.
-                *
-                * If it's our own child, there is no notification to do.
-                * But if our normal children self-reap, then this child
-                * was prevented by ptrace and we must reap it now.
-                */
-               if (!task_detached(p) && thread_group_empty(p)) {
-                       if (!same_thread_group(p->real_parent, parent))
-                               do_notify_parent(p, p->exit_signal);
-                       else {
-                               if (ign < 0)
-                                       ign = ignoring_children(parent);
-                               if (ign)
-                                       p->exit_signal = -1;
-                       }
-               }
-
-               if (task_detached(p)) {
-                       /*
-                        * Mark it as in the process of being reaped.
-                        */
-                       p->exit_state = EXIT_DEAD;
-                       list_add(&p->ptrace_entry, dead);
-               }
-       }
-}
-
-/*
- * Finish up exit-time ptrace cleanup.
- *
- * Called without locks.
- */
-static void ptrace_exit_finish(struct task_struct *parent,
-                              struct list_head *dead)
-{
-       struct task_struct *p, *n;
-
-       BUG_ON(!list_empty(&parent->ptraced));
-
-       list_for_each_entry_safe(p, n, dead, ptrace_entry) {
-               list_del_init(&p->ptrace_entry);
-               release_task(p);
-       }
-}
-
-static void reparent_thread(struct task_struct *p, struct task_struct *father)
-{
-       if (p->pdeath_signal)
-               /* We already hold the tasklist_lock here.  */
-               group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
-
-       list_move_tail(&p->sibling, &p->real_parent->children);
-
-       /* If this is a threaded reparent there is no need to
-        * notify anyone anything has happened.
-        */
-       if (same_thread_group(p->real_parent, father))
-               return;
-
-       /* We don't want people slaying init.  */
-       if (!task_detached(p))
-               p->exit_signal = SIGCHLD;
-
-       /* If we'd notified the old parent about this child's death,
-        * also notify the new parent.
-        */
-       if (!ptrace_reparented(p) &&
-           p->exit_state == EXIT_ZOMBIE &&
-           !task_detached(p) && thread_group_empty(p))
-               do_notify_parent(p, p->exit_signal);
-
-       kill_orphaned_pgrp(p, father);
-}
-
 /*
  * When we die, we re-parent all our children.
  * Try to give them to another thread in our thread
@@ -883,17 +733,51 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
        return pid_ns->child_reaper;
 }
 
+/*
+* Any that need to be release_task'd are put on the @dead list.
+ */
+static void reparent_thread(struct task_struct *father, struct task_struct *p,
+                               struct list_head *dead)
+{
+       if (p->pdeath_signal)
+               group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
+
+       list_move_tail(&p->sibling, &p->real_parent->children);
+
+       if (task_detached(p))
+               return;
+       /*
+        * If this is a threaded reparent there is no need to
+        * notify anyone anything has happened.
+        */
+       if (same_thread_group(p->real_parent, father))
+               return;
+
+       /* We don't want people slaying init.  */
+       p->exit_signal = SIGCHLD;
+
+       /* If it has exited notify the new parent about this child's death. */
+       if (!p->ptrace &&
+           p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
+               do_notify_parent(p, p->exit_signal);
+               if (task_detached(p)) {
+                       p->exit_state = EXIT_DEAD;
+                       list_move_tail(&p->sibling, dead);
+               }
+       }
+
+       kill_orphaned_pgrp(p, father);
+}
+
 static void forget_original_parent(struct task_struct *father)
 {
        struct task_struct *p, *n, *reaper;
-       LIST_HEAD(ptrace_dead);
+       LIST_HEAD(dead_children);
+
+       exit_ptrace(father);
 
        write_lock_irq(&tasklist_lock);
        reaper = find_new_reaper(father);
-       /*
-        * First clean up ptrace if we were using it.
-        */
-       ptrace_exit(father, &ptrace_dead);
 
        list_for_each_entry_safe(p, n, &father->children, sibling) {
                p->real_parent = reaper;
@@ -901,13 +785,16 @@ static void forget_original_parent(struct task_struct *father)
                        BUG_ON(p->ptrace);
                        p->parent = p->real_parent;
                }
-               reparent_thread(p, father);
+               reparent_thread(father, p, &dead_children);
        }
-
        write_unlock_irq(&tasklist_lock);
+
        BUG_ON(!list_empty(&father->children));
 
-       ptrace_exit_finish(father, &ptrace_dead);
+       list_for_each_entry_safe(p, n, &dead_children, sibling) {
+               list_del_init(&p->sibling);
+               release_task(p);
+       }
 }
 
 /*
@@ -1417,6 +1304,18 @@ static int wait_task_zombie(struct task_struct *p, int options,
        return retval;
 }
 
+static int *task_stopped_code(struct task_struct *p, bool ptrace)
+{
+       if (ptrace) {
+               if (task_is_stopped_or_traced(p))
+                       return &p->exit_code;
+       } else {
+               if (p->signal->flags & SIGNAL_STOP_STOPPED)
+                       return &p->signal->group_exit_code;
+       }
+       return NULL;
+}
+
 /*
  * Handle sys_wait4 work for one task in state TASK_STOPPED.  We hold
  * read_lock(&tasklist_lock) on entry.  If we return zero, we still hold
@@ -1427,7 +1326,7 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
                             int options, struct siginfo __user *infop,
                             int __user *stat_addr, struct rusage __user *ru)
 {
-       int retval, exit_code, why;
+       int retval, exit_code, *p_code, why;
        uid_t uid = 0; /* unneeded, required by compiler */
        pid_t pid;
 
@@ -1437,22 +1336,16 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
        exit_code = 0;
        spin_lock_irq(&p->sighand->siglock);
 
-       if (unlikely(!task_is_stopped_or_traced(p)))
-               goto unlock_sig;
-
-       if (!ptrace && p->signal->group_stop_count > 0)
-               /*
-                * A group stop is in progress and this is the group leader.
-                * We won't report until all threads have stopped.
-                */
+       p_code = task_stopped_code(p, ptrace);
+       if (unlikely(!p_code))
                goto unlock_sig;
 
-       exit_code = p->exit_code;
+       exit_code = *p_code;
        if (!exit_code)
                goto unlock_sig;
 
        if (!unlikely(options & WNOWAIT))
-               p->exit_code = 0;
+               *p_code = 0;
 
        /* don't need the RCU readlock here as we're holding a spinlock */
        uid = __task_cred(p)->uid;
@@ -1608,7 +1501,7 @@ static int wait_consider_task(struct task_struct *parent, int ptrace,
         */
        *notask_error = 0;
 
-       if (task_is_stopped_or_traced(p))
+       if (task_stopped_code(p, ptrace))
                return wait_task_stopped(ptrace, p, options,
                                         infop, stat_addr, ru);
 
@@ -1812,7 +1705,7 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
                pid = find_get_pid(-upid);
        } else if (upid == 0) {
                type = PIDTYPE_PGID;
-               pid = get_pid(task_pgrp(current));
+               pid = get_task_pid(current, PIDTYPE_PGID);
        } else /* upid > 0 */ {
                type = PIDTYPE_PID;
                pid = find_get_pid(upid);
index 6715ebc3761de3ed10eeda84ff932e59ff8289c5..660c2b8765bce0e112c26460fe037714b6ea3ac5 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
 #include <linux/blkdev.h>
+#include <linux/fs_struct.h>
 #include <trace/sched.h>
 #include <linux/magic.h>
 
@@ -284,7 +285,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
        mm->free_area_cache = oldmm->mmap_base;
        mm->cached_hole_size = ~0UL;
        mm->map_count = 0;
-       cpus_clear(mm->cpu_vm_mask);
+       cpumask_clear(mm_cpumask(mm));
        mm->mm_rb = RB_ROOT;
        rb_link = &mm->mm_rb.rb_node;
        rb_parent = NULL;
@@ -681,38 +682,21 @@ fail_nomem:
        return retval;
 }
 
-static struct fs_struct *__copy_fs_struct(struct fs_struct *old)
-{
-       struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
-       /* We don't need to lock fs - think why ;-) */
-       if (fs) {
-               atomic_set(&fs->count, 1);
-               rwlock_init(&fs->lock);
-               fs->umask = old->umask;
-               read_lock(&old->lock);
-               fs->root = old->root;
-               path_get(&old->root);
-               fs->pwd = old->pwd;
-               path_get(&old->pwd);
-               read_unlock(&old->lock);
-       }
-       return fs;
-}
-
-struct fs_struct *copy_fs_struct(struct fs_struct *old)
-{
-       return __copy_fs_struct(old);
-}
-
-EXPORT_SYMBOL_GPL(copy_fs_struct);
-
 static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
 {
+       struct fs_struct *fs = current->fs;
        if (clone_flags & CLONE_FS) {
-               atomic_inc(&current->fs->count);
+               /* tsk->fs is already what we want */
+               write_lock(&fs->lock);
+               if (fs->in_exec) {
+                       write_unlock(&fs->lock);
+                       return -EAGAIN;
+               }
+               fs->users++;
+               write_unlock(&fs->lock);
                return 0;
        }
-       tsk->fs = __copy_fs_struct(current->fs);
+       tsk->fs = copy_fs_struct(fs);
        if (!tsk->fs)
                return -ENOMEM;
        return 0;
@@ -841,6 +825,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        atomic_set(&sig->live, 1);
        init_waitqueue_head(&sig->wait_chldexit);
        sig->flags = 0;
+       if (clone_flags & CLONE_NEWPID)
+               sig->flags |= SIGNAL_UNKILLABLE;
        sig->group_exit_code = 0;
        sig->group_exit_task = NULL;
        sig->group_stop_count = 0;
@@ -1125,7 +1111,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                goto bad_fork_cleanup_mm;
        if ((retval = copy_io(clone_flags, p)))
                goto bad_fork_cleanup_namespaces;
-       retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
+       retval = copy_thread(clone_flags, stack_start, stack_size, p, regs);
        if (retval)
                goto bad_fork_cleanup_io;
 
@@ -1263,8 +1249,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        p->signal->leader_pid = pid;
                        tty_kref_put(p->signal->tty);
                        p->signal->tty = tty_kref_get(current->signal->tty);
-                       set_task_pgrp(p, task_pgrp_nr(current));
-                       set_task_session(p, task_session_nr(current));
                        attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
                        attach_pid(p, PIDTYPE_SID, task_session(current));
                        list_add_tail_rcu(&p->tasks, &init_task.tasks);
@@ -1488,6 +1472,7 @@ void __init proc_caches_init(void)
        mm_cachep = kmem_cache_create("mm_struct",
                        sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+       vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC);
        mmap_init();
 }
 
@@ -1543,12 +1528,16 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
 {
        struct fs_struct *fs = current->fs;
 
-       if ((unshare_flags & CLONE_FS) &&
-           (fs && atomic_read(&fs->count) > 1)) {
-               *new_fsp = __copy_fs_struct(current->fs);
-               if (!*new_fsp)
-                       return -ENOMEM;
-       }
+       if (!(unshare_flags & CLONE_FS) || !fs)
+               return 0;
+
+       /* don't need lock here; in the worst case we'll do useless copy */
+       if (fs->users == 1)
+               return 0;
+
+       *new_fsp = copy_fs_struct(fs);
+       if (!*new_fsp)
+               return -ENOMEM;
 
        return 0;
 }
@@ -1664,8 +1653,13 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
 
                if (new_fs) {
                        fs = current->fs;
+                       write_lock(&fs->lock);
                        current->fs = new_fs;
-                       new_fs = fs;
+                       if (--fs->users)
+                               new_fs = NULL;
+                       else
+                               new_fs = fs;
+                       write_unlock(&fs->lock);
                }
 
                if (new_mm) {
@@ -1704,7 +1698,7 @@ bad_unshare_cleanup_sigh:
 
 bad_unshare_cleanup_fs:
        if (new_fs)
-               put_fs_struct(new_fs);
+               free_fs_struct(new_fs);
 
 bad_unshare_cleanup_thread:
 bad_unshare_out:
index 4dd5b1edac984bca7326297ecee3daf0239301f1..3394f8f52964b3d9b4433a3560ff94eb32b20cb8 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_NUMA_MIGRATE_IRQ_DESC) += numa_migrate.o
+obj-$(CONFIG_PM_SLEEP) += pm.o
index ee1aa9f8e8b9341af0c81ec9073f52e48375eb5b..01ce20eab38fed96a7b5a861940ba58d47c18fbf 100644 (file)
@@ -12,6 +12,8 @@ extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
 
 extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                unsigned long flags);
+extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
+extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
 
 extern struct lock_class_key irq_desc_lock_class;
 extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr);
index 6458e99984c08f3af7a108ac0f7db03b21a7e5e8..1516ab77355c928bd1e1f5c8b6759e53d3b0c7e3 100644 (file)
@@ -162,6 +162,20 @@ static inline int setup_affinity(unsigned int irq, struct irq_desc *desc)
 }
 #endif
 
+void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
+{
+       if (suspend) {
+               if (!desc->action || (desc->action->flags & IRQF_TIMER))
+                       return;
+               desc->status |= IRQ_SUSPENDED;
+       }
+
+       if (!desc->depth++) {
+               desc->status |= IRQ_DISABLED;
+               desc->chip->disable(irq);
+       }
+}
+
 /**
  *     disable_irq_nosync - disable an irq without waiting
  *     @irq: Interrupt to disable
@@ -182,10 +196,7 @@ void disable_irq_nosync(unsigned int irq)
                return;
 
        spin_lock_irqsave(&desc->lock, flags);
-       if (!desc->depth++) {
-               desc->status |= IRQ_DISABLED;
-               desc->chip->disable(irq);
-       }
+       __disable_irq(desc, irq, false);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 EXPORT_SYMBOL(disable_irq_nosync);
@@ -215,15 +226,21 @@ void disable_irq(unsigned int irq)
 }
 EXPORT_SYMBOL(disable_irq);
 
-static void __enable_irq(struct irq_desc *desc, unsigned int irq)
+void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
 {
+       if (resume)
+               desc->status &= ~IRQ_SUSPENDED;
+
        switch (desc->depth) {
        case 0:
+ err_out:
                WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
                break;
        case 1: {
                unsigned int status = desc->status & ~IRQ_DISABLED;
 
+               if (desc->status & IRQ_SUSPENDED)
+                       goto err_out;
                /* Prevent probing on this irq: */
                desc->status = status | IRQ_NOPROBE;
                check_irq_resend(desc, irq);
@@ -253,7 +270,7 @@ void enable_irq(unsigned int irq)
                return;
 
        spin_lock_irqsave(&desc->lock, flags);
-       __enable_irq(desc, irq);
+       __enable_irq(desc, irq, false);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 EXPORT_SYMBOL(enable_irq);
@@ -511,7 +528,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         */
        if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
                desc->status &= ~IRQ_SPURIOUS_DISABLED;
-               __enable_irq(desc, irq);
+               __enable_irq(desc, irq, false);
        }
 
        spin_unlock_irqrestore(&desc->lock, flags);
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
new file mode 100644 (file)
index 0000000..638d8be
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * linux/kernel/irq/pm.c
+ *
+ * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file contains power management functions related to interrupts.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include "internals.h"
+
+/**
+ * suspend_device_irqs - disable all currently enabled interrupt lines
+ *
+ * During system-wide suspend or hibernation device interrupts need to be
+ * disabled at the chip level and this function is provided for this purpose.
+ * It disables all interrupt lines that are enabled at the moment and sets the
+ * IRQ_SUSPENDED flag for them.
+ */
+void suspend_device_irqs(void)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       for_each_irq_desc(irq, desc) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&desc->lock, flags);
+               __disable_irq(desc, irq, true);
+               spin_unlock_irqrestore(&desc->lock, flags);
+       }
+
+       for_each_irq_desc(irq, desc)
+               if (desc->status & IRQ_SUSPENDED)
+                       synchronize_irq(irq);
+}
+EXPORT_SYMBOL_GPL(suspend_device_irqs);
+
+/**
+ * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs()
+ *
+ * Enable all interrupt lines previously disabled by suspend_device_irqs() that
+ * have the IRQ_SUSPENDED flag set.
+ */
+void resume_device_irqs(void)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       for_each_irq_desc(irq, desc) {
+               unsigned long flags;
+
+               if (!(desc->status & IRQ_SUSPENDED))
+                       continue;
+
+               spin_lock_irqsave(&desc->lock, flags);
+               __enable_irq(desc, irq, true);
+               spin_unlock_irqrestore(&desc->lock, flags);
+       }
+}
+EXPORT_SYMBOL_GPL(resume_device_irqs);
+
+/**
+ * check_wakeup_irqs - check if any wake-up interrupts are pending
+ */
+int check_wakeup_irqs(void)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       for_each_irq_desc(irq, desc)
+               if ((desc->status & IRQ_WAKEUP) && (desc->status & IRQ_PENDING))
+                       return -EBUSY;
+
+       return 0;
+}
index c7fd6692939d6bd03c13019996874677f296d83c..5a758c6e4950492fcb15248c91ed4f5f6b824dbc 100644 (file)
@@ -42,7 +42,7 @@
 note_buf_t* crash_notes;
 
 /* vmcoreinfo stuff */
-unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
+static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
 u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
 size_t vmcoreinfo_size;
 size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
@@ -1409,6 +1409,7 @@ static int __init crash_save_vmcoreinfo_init(void)
        VMCOREINFO_OFFSET(list_head, prev);
        VMCOREINFO_OFFSET(vm_struct, addr);
        VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
+       log_buf_kexec_setup();
        VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
        VMCOREINFO_NUMBER(NR_FREE_PAGES);
        VMCOREINFO_NUMBER(PG_lru);
@@ -1450,11 +1451,7 @@ int kernel_kexec(void)
                error = device_suspend(PMSG_FREEZE);
                if (error)
                        goto Resume_console;
-               error = disable_nonboot_cpus();
-               if (error)
-                       goto Resume_devices;
                device_pm_lock();
-               local_irq_disable();
                /* At this point, device_suspend() has been called,
                 * but *not* device_power_down(). We *must*
                 * device_power_down() now.  Otherwise, drivers for
@@ -1464,12 +1461,15 @@ int kernel_kexec(void)
                 */
                error = device_power_down(PMSG_FREEZE);
                if (error)
-                       goto Enable_irqs;
-
+                       goto Resume_devices;
+               error = disable_nonboot_cpus();
+               if (error)
+                       goto Enable_cpus;
+               local_irq_disable();
                /* Suspend system devices */
                error = sysdev_suspend(PMSG_FREEZE);
                if (error)
-                       goto Power_up_devices;
+                       goto Enable_irqs;
        } else
 #endif
        {
@@ -1483,13 +1483,13 @@ int kernel_kexec(void)
 #ifdef CONFIG_KEXEC_JUMP
        if (kexec_image->preserve_context) {
                sysdev_resume();
- Power_up_devices:
-               device_power_up(PMSG_RESTORE);
  Enable_irqs:
                local_irq_enable();
-               device_pm_unlock();
+ Enable_cpus:
                enable_nonboot_cpus();
+               device_power_up(PMSG_RESTORE);
  Resume_devices:
+               device_pm_unlock();
                device_resume(PMSG_RESTORE);
  Resume_console:
                resume_console();
index a27a5f64443dc5c9a27d04679171cf15dfc1eabf..f0c8f545180d13193960d3171a1e58272488e72f 100644 (file)
@@ -167,7 +167,7 @@ static int ____call_usermodehelper(void *data)
        }
 
        /* We can run anywhere, unlike our parent keventd(). */
-       set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR);
+       set_cpus_allowed_ptr(current, cpu_all_mask);
 
        /*
         * Our parent is keventd, which runs with elevated scheduling priority.
index 4fbc456f393d0b1fb328667d9e93cc214c39da06..84bbadd4d0213c1558ade617ab49695df0b1bd9f 100644 (file)
@@ -110,7 +110,7 @@ static void create_kthread(struct kthread_create_info *create)
                 */
                sched_setscheduler(create->result, SCHED_NORMAL, &param);
                set_user_nice(create->result, KTHREAD_NICE_LEVEL);
-               set_cpus_allowed_ptr(create->result, CPU_MASK_ALL_PTR);
+               set_cpus_allowed_ptr(create->result, cpu_all_mask);
        }
        complete(&create->done);
 }
@@ -240,7 +240,7 @@ int kthreadd(void *unused)
        set_task_comm(tsk, "kthreadd");
        ignore_signals(tsk);
        set_user_nice(tsk, KTHREAD_NICE_LEVEL);
-       set_cpus_allowed_ptr(tsk, CPU_MASK_ALL_PTR);
+       set_cpus_allowed_ptr(tsk, cpu_all_mask);
 
        current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG;
 
index 06b0c3568f0b230a8c6b669d055c8c442a7eb790..981cd4854281458cc78e2e4730ee93df075287f4 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/utsname.h>
 #include <linux/hash.h>
 #include <linux/ftrace.h>
+#include <linux/stringify.h>
 
 #include <asm/sections.h>
 
@@ -310,12 +311,14 @@ EXPORT_SYMBOL(lockdep_on);
 #if VERBOSE
 # define HARDIRQ_VERBOSE       1
 # define SOFTIRQ_VERBOSE       1
+# define RECLAIM_VERBOSE       1
 #else
 # define HARDIRQ_VERBOSE       0
 # define SOFTIRQ_VERBOSE       0
+# define RECLAIM_VERBOSE       0
 #endif
 
-#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE
+#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE || RECLAIM_VERBOSE
 /*
  * Quick filtering for interesting events:
  */
@@ -430,30 +433,24 @@ atomic_t nr_find_usage_forwards_checks;
 atomic_t nr_find_usage_forwards_recursions;
 atomic_t nr_find_usage_backwards_checks;
 atomic_t nr_find_usage_backwards_recursions;
-# define debug_atomic_inc(ptr)         atomic_inc(ptr)
-# define debug_atomic_dec(ptr)         atomic_dec(ptr)
-# define debug_atomic_read(ptr)                atomic_read(ptr)
-#else
-# define debug_atomic_inc(ptr)         do { } while (0)
-# define debug_atomic_dec(ptr)         do { } while (0)
-# define debug_atomic_read(ptr)                0
 #endif
 
 /*
  * Locking printouts:
  */
 
+#define __USAGE(__STATE)                                               \
+       [LOCK_USED_IN_##__STATE] = "IN-"__stringify(__STATE)"-W",       \
+       [LOCK_ENABLED_##__STATE] = __stringify(__STATE)"-ON-W",         \
+       [LOCK_USED_IN_##__STATE##_READ] = "IN-"__stringify(__STATE)"-R",\
+       [LOCK_ENABLED_##__STATE##_READ] = __stringify(__STATE)"-ON-R",
+
 static const char *usage_str[] =
 {
-       [LOCK_USED] =                   "initial-use ",
-       [LOCK_USED_IN_HARDIRQ] =        "in-hardirq-W",
-       [LOCK_USED_IN_SOFTIRQ] =        "in-softirq-W",
-       [LOCK_ENABLED_SOFTIRQS] =       "softirq-on-W",
-       [LOCK_ENABLED_HARDIRQS] =       "hardirq-on-W",
-       [LOCK_USED_IN_HARDIRQ_READ] =   "in-hardirq-R",
-       [LOCK_USED_IN_SOFTIRQ_READ] =   "in-softirq-R",
-       [LOCK_ENABLED_SOFTIRQS_READ] =  "softirq-on-R",
-       [LOCK_ENABLED_HARDIRQS_READ] =  "hardirq-on-R",
+#define LOCKDEP_STATE(__STATE) __USAGE(__STATE)
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+       [LOCK_USED] = "INITIAL USE",
 };
 
 const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
@@ -461,46 +458,45 @@ const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
        return kallsyms_lookup((unsigned long)key, NULL, NULL, NULL, str);
 }
 
-void
-get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4)
+static inline unsigned long lock_flag(enum lock_usage_bit bit)
 {
-       *c1 = '.', *c2 = '.', *c3 = '.', *c4 = '.';
-
-       if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
-               *c1 = '+';
-       else
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS)
-                       *c1 = '-';
+       return 1UL << bit;
+}
 
-       if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
-               *c2 = '+';
-       else
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS)
-                       *c2 = '-';
+static char get_usage_char(struct lock_class *class, enum lock_usage_bit bit)
+{
+       char c = '.';
 
-       if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
-               *c3 = '-';
-       if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ) {
-               *c3 = '+';
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
-                       *c3 = '?';
+       if (class->usage_mask & lock_flag(bit + 2))
+               c = '+';
+       if (class->usage_mask & lock_flag(bit)) {
+               c = '-';
+               if (class->usage_mask & lock_flag(bit + 2))
+                       c = '?';
        }
 
-       if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
-               *c4 = '-';
-       if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ) {
-               *c4 = '+';
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
-                       *c4 = '?';
-       }
+       return c;
+}
+
+void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS])
+{
+       int i = 0;
+
+#define LOCKDEP_STATE(__STATE)                                                 \
+       usage[i++] = get_usage_char(class, LOCK_USED_IN_##__STATE);     \
+       usage[i++] = get_usage_char(class, LOCK_USED_IN_##__STATE##_READ);
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+
+       usage[i] = '\0';
 }
 
 static void print_lock_name(struct lock_class *class)
 {
-       char str[KSYM_NAME_LEN], c1, c2, c3, c4;
+       char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS];
        const char *name;
 
-       get_usage_chars(class, &c1, &c2, &c3, &c4);
+       get_usage_chars(class, usage);
 
        name = class->name;
        if (!name) {
@@ -513,7 +509,7 @@ static void print_lock_name(struct lock_class *class)
                if (class->subclass)
                        printk("/%d", class->subclass);
        }
-       printk("){%c%c%c%c}", c1, c2, c3, c4);
+       printk("){%s}", usage);
 }
 
 static void print_lockdep_cache(struct lockdep_map *lock)
@@ -1263,9 +1259,49 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
                        bit_backwards, bit_forwards, irqclass);
 }
 
-static int
-check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
-               struct held_lock *next)
+static const char *state_names[] = {
+#define LOCKDEP_STATE(__STATE) \
+       __stringify(__STATE),
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
+static const char *state_rnames[] = {
+#define LOCKDEP_STATE(__STATE) \
+       __stringify(__STATE)"-READ",
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
+static inline const char *state_name(enum lock_usage_bit bit)
+{
+       return (bit & 1) ? state_rnames[bit >> 2] : state_names[bit >> 2];
+}
+
+static int exclusive_bit(int new_bit)
+{
+       /*
+        * USED_IN
+        * USED_IN_READ
+        * ENABLED
+        * ENABLED_READ
+        *
+        * bit 0 - write/read
+        * bit 1 - used_in/enabled
+        * bit 2+  state
+        */
+
+       int state = new_bit & ~3;
+       int dir = new_bit & 2;
+
+       /*
+        * keep state, bit flip the direction and strip read.
+        */
+       return state | (dir ^ 2);
+}
+
+static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
+                          struct held_lock *next, enum lock_usage_bit bit)
 {
        /*
         * Prove that the new dependency does not connect a hardirq-safe
@@ -1273,38 +1309,34 @@ check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
         * the backwards-subgraph starting at <prev>, and the
         * forwards-subgraph starting at <next>:
         */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ,
-                                       LOCK_ENABLED_HARDIRQS, "hard"))
+       if (!check_usage(curr, prev, next, bit,
+                          exclusive_bit(bit), state_name(bit)))
                return 0;
 
+       bit++; /* _READ */
+
        /*
         * Prove that the new dependency does not connect a hardirq-safe-read
         * lock with a hardirq-unsafe lock - to achieve this we search
         * the backwards-subgraph starting at <prev>, and the
         * forwards-subgraph starting at <next>:
         */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ_READ,
-                                       LOCK_ENABLED_HARDIRQS, "hard-read"))
+       if (!check_usage(curr, prev, next, bit,
+                          exclusive_bit(bit), state_name(bit)))
                return 0;
 
-       /*
-        * Prove that the new dependency does not connect a softirq-safe
-        * lock with a softirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ,
-                                       LOCK_ENABLED_SOFTIRQS, "soft"))
-               return 0;
-       /*
-        * Prove that the new dependency does not connect a softirq-safe-read
-        * lock with a softirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ_READ,
-                                       LOCK_ENABLED_SOFTIRQS, "soft"))
+       return 1;
+}
+
+static int
+check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
+               struct held_lock *next)
+{
+#define LOCKDEP_STATE(__STATE)                                         \
+       if (!check_irq_usage(curr, prev, next, LOCK_USED_IN_##__STATE)) \
                return 0;
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
 
        return 1;
 }
@@ -1861,9 +1893,9 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other,
                curr->comm, task_pid_nr(curr));
        print_lock(this);
        if (forwards)
-               printk("but this lock took another, %s-irq-unsafe lock in the past:\n", irqclass);
+               printk("but this lock took another, %s-unsafe lock in the past:\n", irqclass);
        else
-               printk("but this lock was taken by another, %s-irq-safe lock in the past:\n", irqclass);
+               printk("but this lock was taken by another, %s-safe lock in the past:\n", irqclass);
        print_lock_name(other);
        printk("\n\nand interrupts could create inverse lock ordering between them.\n\n");
 
@@ -1933,7 +1965,7 @@ void print_irqtrace_events(struct task_struct *curr)
        print_ip_sym(curr->softirq_disable_ip);
 }
 
-static int hardirq_verbose(struct lock_class *class)
+static int HARDIRQ_verbose(struct lock_class *class)
 {
 #if HARDIRQ_VERBOSE
        return class_filter(class);
@@ -1941,7 +1973,7 @@ static int hardirq_verbose(struct lock_class *class)
        return 0;
 }
 
-static int softirq_verbose(struct lock_class *class)
+static int SOFTIRQ_verbose(struct lock_class *class)
 {
 #if SOFTIRQ_VERBOSE
        return class_filter(class);
@@ -1949,185 +1981,95 @@ static int softirq_verbose(struct lock_class *class)
        return 0;
 }
 
+static int RECLAIM_FS_verbose(struct lock_class *class)
+{
+#if RECLAIM_VERBOSE
+       return class_filter(class);
+#endif
+       return 0;
+}
+
 #define STRICT_READ_CHECKS     1
 
-static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
+static int (*state_verbose_f[])(struct lock_class *class) = {
+#define LOCKDEP_STATE(__STATE) \
+       __STATE##_verbose,
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
+static inline int state_verbose(enum lock_usage_bit bit,
+                               struct lock_class *class)
+{
+       return state_verbose_f[bit >> 2](class);
+}
+
+typedef int (*check_usage_f)(struct task_struct *, struct held_lock *,
+                            enum lock_usage_bit bit, const char *name);
+
+static int
+mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                enum lock_usage_bit new_bit)
 {
-       int ret = 1;
+       int excl_bit = exclusive_bit(new_bit);
+       int read = new_bit & 1;
+       int dir = new_bit & 2;
 
-       switch(new_bit) {
-       case LOCK_USED_IN_HARDIRQ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_ENABLED_HARDIRQS_READ))
-                       return 0;
-               /*
-                * just marked it hardirq-safe, check that this lock
-                * took no hardirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_HARDIRQS, "hard"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it hardirq-safe, check that this lock
-                * took no hardirq-unsafe-read lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                               LOCK_ENABLED_HARDIRQS_READ, "hard-read"))
-                       return 0;
-#endif
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_USED_IN_SOFTIRQ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_SOFTIRQS))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_ENABLED_SOFTIRQS_READ))
-                       return 0;
-               /*
-                * just marked it softirq-safe, check that this lock
-                * took no softirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_SOFTIRQS, "soft"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it softirq-safe, check that this lock
-                * took no softirq-unsafe-read lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                               LOCK_ENABLED_SOFTIRQS_READ, "soft-read"))
-                       return 0;
-#endif
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_USED_IN_HARDIRQ_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS))
-                       return 0;
-               /*
-                * just marked it hardirq-read-safe, check that this lock
-                * took no hardirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_HARDIRQS, "hard"))
-                       return 0;
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_USED_IN_SOFTIRQ_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_ENABLED_SOFTIRQS))
-                       return 0;
-               /*
-                * just marked it softirq-read-safe, check that this lock
-                * took no softirq-unsafe lock in the past:
-                */
-               if (!check_usage_forwards(curr, this,
-                                         LOCK_ENABLED_SOFTIRQS, "soft"))
-                       return 0;
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_HARDIRQS:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_USED_IN_HARDIRQ_READ))
-                       return 0;
-               /*
-                * just marked it hardirq-unsafe, check that no hardirq-safe
-                * lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_HARDIRQ, "hard"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it hardirq-unsafe, check that no
-                * hardirq-safe-read lock in the system ever took
-                * it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                  LOCK_USED_IN_HARDIRQ_READ, "hard-read"))
-                       return 0;
-#endif
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_SOFTIRQS:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_SOFTIRQ))
-                       return 0;
-               if (!valid_state(curr, this, new_bit,
-                                LOCK_USED_IN_SOFTIRQ_READ))
-                       return 0;
-               /*
-                * just marked it softirq-unsafe, check that no softirq-safe
-                * lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_SOFTIRQ, "soft"))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it softirq-unsafe, check that no
-                * softirq-safe-read lock in the system ever took
-                * it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                  LOCK_USED_IN_SOFTIRQ_READ, "soft-read"))
-                       return 0;
-#endif
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_HARDIRQS_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ))
-                       return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it hardirq-read-unsafe, check that no
-                * hardirq-safe lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_HARDIRQ, "hard"))
-                       return 0;
-#endif
-               if (hardirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       case LOCK_ENABLED_SOFTIRQS_READ:
-               if (!valid_state(curr, this, new_bit, LOCK_USED_IN_SOFTIRQ))
+       /*
+        * mark USED_IN has to look forwards -- to ensure no dependency
+        * has ENABLED state, which would allow recursion deadlocks.
+        *
+        * mark ENABLED has to look backwards -- to ensure no dependee
+        * has USED_IN state, which, again, would allow  recursion deadlocks.
+        */
+       check_usage_f usage = dir ?
+               check_usage_backwards : check_usage_forwards;
+
+       /*
+        * Validate that this particular lock does not have conflicting
+        * usage states.
+        */
+       if (!valid_state(curr, this, new_bit, excl_bit))
+               return 0;
+
+       /*
+        * Validate that the lock dependencies don't have conflicting usage
+        * states.
+        */
+       if ((!read || !dir || STRICT_READ_CHECKS) &&
+                       !usage(curr, this, excl_bit, state_name(new_bit & ~1)))
+               return 0;
+
+       /*
+        * Check for read in write conflicts
+        */
+       if (!read) {
+               if (!valid_state(curr, this, new_bit, excl_bit + 1))
                        return 0;
-#if STRICT_READ_CHECKS
-               /*
-                * just marked it softirq-read-unsafe, check that no
-                * softirq-safe lock in the system ever took it in the past:
-                */
-               if (!check_usage_backwards(curr, this,
-                                          LOCK_USED_IN_SOFTIRQ, "soft"))
+
+               if (STRICT_READ_CHECKS &&
+                       !usage(curr, this, excl_bit + 1,
+                               state_name(new_bit + 1)))
                        return 0;
-#endif
-               if (softirq_verbose(hlock_class(this)))
-                       ret = 2;
-               break;
-       default:
-               WARN_ON(1);
-               break;
        }
 
-       return ret;
+       if (state_verbose(new_bit, hlock_class(this)))
+               return 2;
+
+       return 1;
 }
 
+enum mark_type {
+#define LOCKDEP_STATE(__STATE) __STATE,
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+};
+
 /*
  * Mark all held locks with a usage bit:
  */
 static int
-mark_held_locks(struct task_struct *curr, int hardirq)
+mark_held_locks(struct task_struct *curr, enum mark_type mark)
 {
        enum lock_usage_bit usage_bit;
        struct held_lock *hlock;
@@ -2136,17 +2078,12 @@ mark_held_locks(struct task_struct *curr, int hardirq)
        for (i = 0; i < curr->lockdep_depth; i++) {
                hlock = curr->held_locks + i;
 
-               if (hardirq) {
-                       if (hlock->read)
-                               usage_bit = LOCK_ENABLED_HARDIRQS_READ;
-                       else
-                               usage_bit = LOCK_ENABLED_HARDIRQS;
-               } else {
-                       if (hlock->read)
-                               usage_bit = LOCK_ENABLED_SOFTIRQS_READ;
-                       else
-                               usage_bit = LOCK_ENABLED_SOFTIRQS;
-               }
+               usage_bit = 2 + (mark << 2); /* ENABLED */
+               if (hlock->read)
+                       usage_bit += 1; /* READ */
+
+               BUG_ON(usage_bit >= LOCK_USAGE_STATES);
+
                if (!mark_lock(curr, hlock, usage_bit))
                        return 0;
        }
@@ -2200,7 +2137,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
         * We are going to turn hardirqs on, so set the
         * usage bit for all held locks:
         */
-       if (!mark_held_locks(curr, 1))
+       if (!mark_held_locks(curr, HARDIRQ))
                return;
        /*
         * If we have softirqs enabled, then set the usage
@@ -2208,7 +2145,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
         * this bit from being set before)
         */
        if (curr->softirqs_enabled)
-               if (!mark_held_locks(curr, 0))
+               if (!mark_held_locks(curr, SOFTIRQ))
                        return;
 
        curr->hardirq_enable_ip = ip;
@@ -2288,7 +2225,7 @@ void trace_softirqs_on(unsigned long ip)
         * enabled too:
         */
        if (curr->hardirqs_enabled)
-               mark_held_locks(curr, 0);
+               mark_held_locks(curr, SOFTIRQ);
 }
 
 /*
@@ -2317,6 +2254,48 @@ void trace_softirqs_off(unsigned long ip)
                debug_atomic_inc(&redundant_softirqs_off);
 }
 
+static void __lockdep_trace_alloc(gfp_t gfp_mask, unsigned long flags)
+{
+       struct task_struct *curr = current;
+
+       if (unlikely(!debug_locks))
+               return;
+
+       /* no reclaim without waiting on it */
+       if (!(gfp_mask & __GFP_WAIT))
+               return;
+
+       /* this guy won't enter reclaim */
+       if ((curr->flags & PF_MEMALLOC) && !(gfp_mask & __GFP_NOMEMALLOC))
+               return;
+
+       /* We're only interested __GFP_FS allocations for now */
+       if (!(gfp_mask & __GFP_FS))
+               return;
+
+       if (DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags)))
+               return;
+
+       mark_held_locks(curr, RECLAIM_FS);
+}
+
+static void check_flags(unsigned long flags);
+
+void lockdep_trace_alloc(gfp_t gfp_mask)
+{
+       unsigned long flags;
+
+       if (unlikely(current->lockdep_recursion))
+               return;
+
+       raw_local_irq_save(flags);
+       check_flags(flags);
+       current->lockdep_recursion = 1;
+       __lockdep_trace_alloc(gfp_mask, flags);
+       current->lockdep_recursion = 0;
+       raw_local_irq_restore(flags);
+}
+
 static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
 {
        /*
@@ -2345,19 +2324,35 @@ static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
        if (!hlock->hardirqs_off) {
                if (hlock->read) {
                        if (!mark_lock(curr, hlock,
-                                       LOCK_ENABLED_HARDIRQS_READ))
+                                       LOCK_ENABLED_HARDIRQ_READ))
                                return 0;
                        if (curr->softirqs_enabled)
                                if (!mark_lock(curr, hlock,
-                                               LOCK_ENABLED_SOFTIRQS_READ))
+                                               LOCK_ENABLED_SOFTIRQ_READ))
                                        return 0;
                } else {
                        if (!mark_lock(curr, hlock,
-                                       LOCK_ENABLED_HARDIRQS))
+                                       LOCK_ENABLED_HARDIRQ))
                                return 0;
                        if (curr->softirqs_enabled)
                                if (!mark_lock(curr, hlock,
-                                               LOCK_ENABLED_SOFTIRQS))
+                                               LOCK_ENABLED_SOFTIRQ))
+                                       return 0;
+               }
+       }
+
+       /*
+        * We reuse the irq context infrastructure more broadly as a general
+        * context checking code. This tests GFP_FS recursion (a lock taken
+        * during reclaim for a GFP_FS allocation is held over a GFP_FS
+        * allocation).
+        */
+       if (!hlock->trylock && (curr->lockdep_reclaim_gfp & __GFP_FS)) {
+               if (hlock->read) {
+                       if (!mark_lock(curr, hlock, LOCK_USED_IN_RECLAIM_FS_READ))
+                                       return 0;
+               } else {
+                       if (!mark_lock(curr, hlock, LOCK_USED_IN_RECLAIM_FS))
                                        return 0;
                }
        }
@@ -2412,6 +2407,10 @@ static inline int separate_irq_context(struct task_struct *curr,
        return 0;
 }
 
+void lockdep_trace_alloc(gfp_t gfp_mask)
+{
+}
+
 #endif
 
 /*
@@ -2445,14 +2444,13 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
                return 0;
 
        switch (new_bit) {
-       case LOCK_USED_IN_HARDIRQ:
-       case LOCK_USED_IN_SOFTIRQ:
-       case LOCK_USED_IN_HARDIRQ_READ:
-       case LOCK_USED_IN_SOFTIRQ_READ:
-       case LOCK_ENABLED_HARDIRQS:
-       case LOCK_ENABLED_SOFTIRQS:
-       case LOCK_ENABLED_HARDIRQS_READ:
-       case LOCK_ENABLED_SOFTIRQS_READ:
+#define LOCKDEP_STATE(__STATE)                 \
+       case LOCK_USED_IN_##__STATE:            \
+       case LOCK_USED_IN_##__STATE##_READ:     \
+       case LOCK_ENABLED_##__STATE:            \
+       case LOCK_ENABLED_##__STATE##_READ:
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
                ret = mark_lock_irq(curr, this, new_bit);
                if (!ret)
                        return 0;
@@ -2966,6 +2964,16 @@ void lock_release(struct lockdep_map *lock, int nested,
 }
 EXPORT_SYMBOL_GPL(lock_release);
 
+void lockdep_set_current_reclaim_state(gfp_t gfp_mask)
+{
+       current->lockdep_reclaim_gfp = gfp_mask;
+}
+
+void lockdep_clear_current_reclaim_state(void)
+{
+       current->lockdep_reclaim_gfp = 0;
+}
+
 #ifdef CONFIG_LOCK_STAT
 static int
 print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock,
index 56b196932c081e915568d4fef27a92c08e129758..a2cc7e9a6e841b9e955709b9139cd96b3d803f2e 100644 (file)
@@ -6,6 +6,45 @@
  * lockdep subsystem internal functions and variables.
  */
 
+/*
+ * Lock-class usage-state bits:
+ */
+enum lock_usage_bit {
+#define LOCKDEP_STATE(__STATE)         \
+       LOCK_USED_IN_##__STATE,         \
+       LOCK_USED_IN_##__STATE##_READ,  \
+       LOCK_ENABLED_##__STATE,         \
+       LOCK_ENABLED_##__STATE##_READ,
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+       LOCK_USED,
+       LOCK_USAGE_STATES
+};
+
+/*
+ * Usage-state bitmasks:
+ */
+#define __LOCKF(__STATE)       LOCKF_##__STATE = (1 << LOCK_##__STATE),
+
+enum {
+#define LOCKDEP_STATE(__STATE)                                         \
+       __LOCKF(USED_IN_##__STATE)                                      \
+       __LOCKF(USED_IN_##__STATE##_READ)                               \
+       __LOCKF(ENABLED_##__STATE)                                      \
+       __LOCKF(ENABLED_##__STATE##_READ)
+#include "lockdep_states.h"
+#undef LOCKDEP_STATE
+       __LOCKF(USED)
+};
+
+#define LOCKF_ENABLED_IRQ (LOCKF_ENABLED_HARDIRQ | LOCKF_ENABLED_SOFTIRQ)
+#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ)
+
+#define LOCKF_ENABLED_IRQ_READ \
+               (LOCKF_ENABLED_HARDIRQ_READ | LOCKF_ENABLED_SOFTIRQ_READ)
+#define LOCKF_USED_IN_IRQ_READ \
+               (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ)
+
 /*
  * MAX_LOCKDEP_ENTRIES is the maximum number of lock dependencies
  * we track.
 extern struct list_head all_lock_classes;
 extern struct lock_chain lock_chains[];
 
-extern void
-get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4);
+#define LOCK_USAGE_CHARS (1+LOCK_USAGE_STATES/2)
+
+extern void get_usage_chars(struct lock_class *class,
+                           char usage[LOCK_USAGE_CHARS]);
 
 extern const char * __get_key_name(struct lockdep_subclass_key *key, char *str);
 
index 13716b8138961ee9f5feffe23ad9115fc27766e3..d7135aa2d2c4ccc0f3638cfa6fb3b2742e33c43c 100644 (file)
@@ -84,7 +84,7 @@ static int l_show(struct seq_file *m, void *v)
 {
        struct lock_class *class = v;
        struct lock_list *entry;
-       char c1, c2, c3, c4;
+       char usage[LOCK_USAGE_CHARS];
 
        if (v == SEQ_START_TOKEN) {
                seq_printf(m, "all lock classes:\n");
@@ -100,8 +100,8 @@ static int l_show(struct seq_file *m, void *v)
        seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class));
 #endif
 
-       get_usage_chars(class, &c1, &c2, &c3, &c4);
-       seq_printf(m, " %c%c%c%c", c1, c2, c3, c4);
+       get_usage_chars(class, usage);
+       seq_printf(m, " %s", usage);
 
        seq_printf(m, ": ");
        print_name(m, class);
@@ -300,27 +300,27 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
                        nr_uncategorized++;
                if (class->usage_mask & LOCKF_USED_IN_IRQ)
                        nr_irq_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_IRQS)
+               if (class->usage_mask & LOCKF_ENABLED_IRQ)
                        nr_irq_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
                        nr_softirq_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS)
+               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ)
                        nr_softirq_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
                        nr_hardirq_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS)
+               if (class->usage_mask & LOCKF_ENABLED_HARDIRQ)
                        nr_hardirq_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_IRQ_READ)
                        nr_irq_read_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_IRQS_READ)
+               if (class->usage_mask & LOCKF_ENABLED_IRQ_READ)
                        nr_irq_read_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ)
                        nr_softirq_read_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
+               if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ_READ)
                        nr_softirq_read_unsafe++;
                if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ)
                        nr_hardirq_read_safe++;
-               if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
+               if (class->usage_mask & LOCKF_ENABLED_HARDIRQ_READ)
                        nr_hardirq_read_unsafe++;
 
 #ifdef CONFIG_PROVE_LOCKING
@@ -601,6 +601,10 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
 static void seq_header(struct seq_file *m)
 {
        seq_printf(m, "lock_stat version 0.3\n");
+
+       if (unlikely(!debug_locks))
+               seq_printf(m, "*WARNING* lock debugging disabled!! - possibly due to a lockdep warning\n");
+
        seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
        seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s "
                        "%14s %14s\n",
diff --git a/kernel/lockdep_states.h b/kernel/lockdep_states.h
new file mode 100644 (file)
index 0000000..995b0cc
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Lockdep states,
+ *
+ * please update XXX_LOCK_USAGE_STATES in include/linux/lockdep.h whenever
+ * you add one, or come up with a nice dynamic solution.
+ */
+LOCKDEP_STATE(HARDIRQ)
+LOCKDEP_STATE(SOFTIRQ)
+LOCKDEP_STATE(RECLAIM_FS)
index 1d94160eb5326e94c0222da947b8c1ee4ee44875..50d022e5a5606dd64d985afbff9d33621f06ab96 100644 (file)
 /*
  * Must be called with lock->wait_lock held.
  */
-void debug_mutex_set_owner(struct mutex *lock, struct thread_info *new_owner)
-{
-       lock->owner = new_owner;
-}
-
 void debug_mutex_lock_common(struct mutex *lock, struct mutex_waiter *waiter)
 {
        memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter));
@@ -59,7 +54,6 @@ void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
 
        /* Mark the current thread as blocked on the lock: */
        ti->task->blocked_on = waiter;
-       waiter->lock = lock;
 }
 
 void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
@@ -82,7 +76,7 @@ void debug_mutex_unlock(struct mutex *lock)
        DEBUG_LOCKS_WARN_ON(lock->magic != lock);
        DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info());
        DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next);
-       DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info());
+       mutex_clear_owner(lock);
 }
 
 void debug_mutex_init(struct mutex *lock, const char *name,
@@ -95,7 +89,6 @@ void debug_mutex_init(struct mutex *lock, const char *name,
        debug_check_no_locks_freed((void *)lock, sizeof(*lock));
        lockdep_init_map(&lock->dep_map, name, key, 0);
 #endif
-       lock->owner = NULL;
        lock->magic = lock;
 }
 
index babfbdfc534b7127e3769405433499f1929a44a5..6b2d735846a56f17425749b6501fe2023c0e6cdb 100644 (file)
 /*
  * This must be called with lock->wait_lock held.
  */
-extern void
-debug_mutex_set_owner(struct mutex *lock, struct thread_info *new_owner);
-
-static inline void debug_mutex_clear_owner(struct mutex *lock)
-{
-       lock->owner = NULL;
-}
-
 extern void debug_mutex_lock_common(struct mutex *lock,
                                    struct mutex_waiter *waiter);
 extern void debug_mutex_wake_waiter(struct mutex *lock,
@@ -35,6 +27,16 @@ extern void debug_mutex_unlock(struct mutex *lock);
 extern void debug_mutex_init(struct mutex *lock, const char *name,
                             struct lock_class_key *key);
 
+static inline void mutex_set_owner(struct mutex *lock)
+{
+       lock->owner = current_thread_info();
+}
+
+static inline void mutex_clear_owner(struct mutex *lock)
+{
+       lock->owner = NULL;
+}
+
 #define spin_lock_mutex(lock, flags)                   \
        do {                                            \
                struct mutex *l = container_of(lock, struct mutex, wait_lock); \
index 4f45d4b658ef6ab1fda9357725b01361a6768a76..5d79781394a306e75048668262a6c3f49f5321ef 100644 (file)
  * Many thanks to Arjan van de Ven, Thomas Gleixner, Steven Rostedt and
  * David Howells for suggestions and improvements.
  *
+ *  - Adaptive spinning for mutexes by Peter Zijlstra. (Ported to mainline
+ *    from the -rt tree, where it was originally implemented for rtmutexes
+ *    by Steven Rostedt, based on work by Gregory Haskins, Peter Morreale
+ *    and Sven Dietrich.
+ *
  * Also see Documentation/mutex-design.txt.
  */
 #include <linux/mutex.h>
@@ -46,6 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
        atomic_set(&lock->count, 1);
        spin_lock_init(&lock->wait_lock);
        INIT_LIST_HEAD(&lock->wait_list);
+       mutex_clear_owner(lock);
 
        debug_mutex_init(lock, name, key);
 }
@@ -91,6 +97,7 @@ void inline __sched mutex_lock(struct mutex *lock)
         * 'unlocked' into 'locked' state.
         */
        __mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
+       mutex_set_owner(lock);
 }
 
 EXPORT_SYMBOL(mutex_lock);
@@ -115,6 +122,14 @@ void __sched mutex_unlock(struct mutex *lock)
         * The unlocking fastpath is the 0->1 transition from 'locked'
         * into 'unlocked' state:
         */
+#ifndef CONFIG_DEBUG_MUTEXES
+       /*
+        * When debugging is enabled we must not clear the owner before time,
+        * the slow path will always be taken, and that clears the owner field
+        * after verifying that it was indeed current.
+        */
+       mutex_clear_owner(lock);
+#endif
        __mutex_fastpath_unlock(&lock->count, __mutex_unlock_slowpath);
 }
 
@@ -129,21 +144,75 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
 {
        struct task_struct *task = current;
        struct mutex_waiter waiter;
-       unsigned int old_val;
        unsigned long flags;
 
+       preempt_disable();
+       mutex_acquire(&lock->dep_map, subclass, 0, ip);
+#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES)
+       /*
+        * Optimistic spinning.
+        *
+        * We try to spin for acquisition when we find that there are no
+        * pending waiters and the lock owner is currently running on a
+        * (different) CPU.
+        *
+        * The rationale is that if the lock owner is running, it is likely to
+        * release the lock soon.
+        *
+        * Since this needs the lock owner, and this mutex implementation
+        * doesn't track the owner atomically in the lock field, we need to
+        * track it non-atomically.
+        *
+        * We can't do this for DEBUG_MUTEXES because that relies on wait_lock
+        * to serialize everything.
+        */
+
+       for (;;) {
+               struct thread_info *owner;
+
+               /*
+                * If there's an owner, wait for it to either
+                * release the lock or go to sleep.
+                */
+               owner = ACCESS_ONCE(lock->owner);
+               if (owner && !mutex_spin_on_owner(lock, owner))
+                       break;
+
+               if (atomic_cmpxchg(&lock->count, 1, 0) == 1) {
+                       lock_acquired(&lock->dep_map, ip);
+                       mutex_set_owner(lock);
+                       preempt_enable();
+                       return 0;
+               }
+
+               /*
+                * When there's no owner, we might have preempted between the
+                * owner acquiring the lock and setting the owner field. If
+                * we're an RT task that will live-lock because we won't let
+                * the owner complete.
+                */
+               if (!owner && (need_resched() || rt_task(task)))
+                       break;
+
+               /*
+                * The cpu_relax() call is a compiler barrier which forces
+                * everything in this loop to be re-loaded. We don't need
+                * memory barriers as we'll eventually observe the right
+                * values at the cost of a few extra spins.
+                */
+               cpu_relax();
+       }
+#endif
        spin_lock_mutex(&lock->wait_lock, flags);
 
        debug_mutex_lock_common(lock, &waiter);
-       mutex_acquire(&lock->dep_map, subclass, 0, ip);
        debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
 
        /* add waiting tasks to the end of the waitqueue (FIFO): */
        list_add_tail(&waiter.list, &lock->wait_list);
        waiter.task = task;
 
-       old_val = atomic_xchg(&lock->count, -1);
-       if (old_val == 1)
+       if (atomic_xchg(&lock->count, -1) == 1)
                goto done;
 
        lock_contended(&lock->dep_map, ip);
@@ -158,8 +227,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * that when we release the lock, we properly wake up the
                 * other waiters:
                 */
-               old_val = atomic_xchg(&lock->count, -1);
-               if (old_val == 1)
+               if (atomic_xchg(&lock->count, -1) == 1)
                        break;
 
                /*
@@ -173,21 +241,22 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                        spin_unlock_mutex(&lock->wait_lock, flags);
 
                        debug_mutex_free_waiter(&waiter);
+                       preempt_enable();
                        return -EINTR;
                }
                __set_task_state(task, state);
 
                /* didnt get the lock, go to sleep: */
                spin_unlock_mutex(&lock->wait_lock, flags);
-               schedule();
+               __schedule();
                spin_lock_mutex(&lock->wait_lock, flags);
        }
 
 done:
        lock_acquired(&lock->dep_map, ip);
        /* got the lock - rejoice! */
-       mutex_remove_waiter(lock, &waiter, task_thread_info(task));
-       debug_mutex_set_owner(lock, task_thread_info(task));
+       mutex_remove_waiter(lock, &waiter, current_thread_info());
+       mutex_set_owner(lock);
 
        /* set it to 0 if there are no waiters left: */
        if (likely(list_empty(&lock->wait_list)))
@@ -196,6 +265,7 @@ done:
        spin_unlock_mutex(&lock->wait_lock, flags);
 
        debug_mutex_free_waiter(&waiter);
+       preempt_enable();
 
        return 0;
 }
@@ -222,7 +292,8 @@ int __sched
 mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE,
+                                  subclass, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
@@ -260,8 +331,6 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
                wake_up_process(waiter->task);
        }
 
-       debug_mutex_clear_owner(lock);
-
        spin_unlock_mutex(&lock->wait_lock, flags);
 }
 
@@ -298,18 +367,30 @@ __mutex_lock_interruptible_slowpath(atomic_t *lock_count);
  */
 int __sched mutex_lock_interruptible(struct mutex *lock)
 {
+       int ret;
+
        might_sleep();
-       return __mutex_fastpath_lock_retval
+       ret =  __mutex_fastpath_lock_retval
                        (&lock->count, __mutex_lock_interruptible_slowpath);
+       if (!ret)
+               mutex_set_owner(lock);
+
+       return ret;
 }
 
 EXPORT_SYMBOL(mutex_lock_interruptible);
 
 int __sched mutex_lock_killable(struct mutex *lock)
 {
+       int ret;
+
        might_sleep();
-       return __mutex_fastpath_lock_retval
+       ret = __mutex_fastpath_lock_retval
                        (&lock->count, __mutex_lock_killable_slowpath);
+       if (!ret)
+               mutex_set_owner(lock);
+
+       return ret;
 }
 EXPORT_SYMBOL(mutex_lock_killable);
 
@@ -352,9 +433,10 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
 
        prev = atomic_xchg(&lock->count, -1);
        if (likely(prev == 1)) {
-               debug_mutex_set_owner(lock, current_thread_info());
+               mutex_set_owner(lock);
                mutex_acquire(&lock->dep_map, 0, 1, _RET_IP_);
        }
+
        /* Set it back to 0 if there are no waiters: */
        if (likely(list_empty(&lock->wait_list)))
                atomic_set(&lock->count, 0);
@@ -380,8 +462,13 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
  */
 int __sched mutex_trylock(struct mutex *lock)
 {
-       return __mutex_fastpath_trylock(&lock->count,
-                                       __mutex_trylock_slowpath);
+       int ret;
+
+       ret = __mutex_fastpath_trylock(&lock->count, __mutex_trylock_slowpath);
+       if (ret)
+               mutex_set_owner(lock);
+
+       return ret;
 }
 
 EXPORT_SYMBOL(mutex_trylock);
index a075dafbb290c18bdf8972c361d8063f2478fa69..67578ca48f94e1dad6f7cf3760c28d20a86605e2 100644 (file)
 #define mutex_remove_waiter(lock, waiter, ti) \
                __list_del((waiter)->list.prev, (waiter)->list.next)
 
-#define debug_mutex_set_owner(lock, new_owner)         do { } while (0)
-#define debug_mutex_clear_owner(lock)                  do { } while (0)
+#ifdef CONFIG_SMP
+static inline void mutex_set_owner(struct mutex *lock)
+{
+       lock->owner = current_thread_info();
+}
+
+static inline void mutex_clear_owner(struct mutex *lock)
+{
+       lock->owner = NULL;
+}
+#else
+static inline void mutex_set_owner(struct mutex *lock)
+{
+}
+
+static inline void mutex_clear_owner(struct mutex *lock)
+{
+}
+#endif
+
 #define debug_mutex_wake_waiter(lock, waiter)          do { } while (0)
 #define debug_mutex_free_waiter(waiter)                        do { } while (0)
 #define debug_mutex_add_waiter(lock, waiter, ti)       do { } while (0)
index 78bc3fdac0d262f019d1c1c4caee95e9c26aa147..5aa854f9e5ae0cae90d37d7594d265cdbab6fc01 100644 (file)
@@ -34,7 +34,7 @@ int ns_cgroup_clone(struct task_struct *task, struct pid *pid)
 
 /*
  * Rules:
- *   1. you can only enter a cgroup which is a child of your current
+ *   1. you can only enter a cgroup which is a descendant of your current
  *     cgroup
  *   2. you can only place another process into a cgroup if
  *     a. you have CAP_SYS_ADMIN
@@ -45,21 +45,15 @@ int ns_cgroup_clone(struct task_struct *task, struct pid *pid)
 static int ns_can_attach(struct cgroup_subsys *ss,
                struct cgroup *new_cgroup, struct task_struct *task)
 {
-       struct cgroup *orig;
-
        if (current != task) {
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
-               if (!cgroup_is_descendant(new_cgroup))
+               if (!cgroup_is_descendant(new_cgroup, current))
                        return -EPERM;
        }
 
-       if (atomic_read(&new_cgroup->count) != 0)
-               return -EPERM;
-
-       orig = task_cgroup(task, ns_subsys_id);
-       if (orig && orig != new_cgroup->parent)
+       if (!cgroup_is_descendant(new_cgroup, task))
                return -EPERM;
 
        return 0;
@@ -77,7 +71,7 @@ static struct cgroup_subsys_state *ns_create(struct cgroup_subsys *ss,
 
        if (!capable(CAP_SYS_ADMIN))
                return ERR_PTR(-EPERM);
-       if (!cgroup_is_descendant(cgroup))
+       if (!cgroup_is_descendant(cgroup, current))
                return ERR_PTR(-EPERM);
 
        ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL);
index 32fe4eff1b89ecf75af7c229fc8db2e46179c924..3fd8c5bf8b394dd94fee9ce22fa8c20135c76c4f 100644 (file)
@@ -8,19 +8,19 @@
  * This function is used through-out the kernel (including mm and fs)
  * to indicate a major problem.
  */
+#include <linux/debug_locks.h>
+#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
+#include <linux/notifier.h>
 #include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
+#include <linux/random.h>
 #include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kexec.h>
+#include <linux/sched.h>
 #include <linux/sysrq.h>
-#include <linux/interrupt.h>
+#include <linux/init.h>
 #include <linux/nmi.h>
-#include <linux/kexec.h>
-#include <linux/debug_locks.h>
-#include <linux/random.h>
-#include <linux/kallsyms.h>
 #include <linux/dmi.h>
 
 int panic_on_oops;
@@ -52,19 +52,15 @@ EXPORT_SYMBOL(panic_blink);
  *
  *     This function never returns.
  */
-
 NORET_TYPE void panic(const char * fmt, ...)
 {
-       long i;
        static char buf[1024];
        va_list args;
-#if defined(CONFIG_S390)
-       unsigned long caller = (unsigned long) __builtin_return_address(0);
-#endif
+       long i;
 
        /*
-        * It's possible to come here directly from a panic-assertion and not
-        * have preempt disabled. Some functions called from here want
+        * It's possible to come here directly from a panic-assertion and
+        * not have preempt disabled. Some functions called from here want
         * preempt to be disabled. No point enabling it later though...
         */
        preempt_disable();
@@ -77,7 +73,6 @@ NORET_TYPE void panic(const char * fmt, ...)
 #ifdef CONFIG_DEBUG_BUGVERBOSE
        dump_stack();
 #endif
-       bust_spinlocks(0);
 
        /*
         * If we have crashed and we have a crash kernel loaded let it handle
@@ -86,14 +81,12 @@ NORET_TYPE void panic(const char * fmt, ...)
         */
        crash_kexec(NULL);
 
-#ifdef CONFIG_SMP
        /*
         * Note smp_send_stop is the usual smp shutdown function, which
         * unfortunately means it may not be hardened to work in a panic
         * situation.
         */
        smp_send_stop();
-#endif
 
        atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
 
@@ -102,19 +95,21 @@ NORET_TYPE void panic(const char * fmt, ...)
 
        if (panic_timeout > 0) {
                /*
-                * Delay timeout seconds before rebooting the machine. 
-                * We can't use the "normal" timers since we just panicked..
-                */
-               printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
+                * Delay timeout seconds before rebooting the machine.
+                * We can't use the "normal" timers since we just panicked.
+                */
+               printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout);
+
                for (i = 0; i < panic_timeout*1000; ) {
                        touch_nmi_watchdog();
                        i += panic_blink(i);
                        mdelay(1);
                        i++;
                }
-               /*      This will not be a clean reboot, with everything
-                *      shutting down.  But if there is a chance of
-                *      rebooting the system it will be rebooted.
+               /*
+                * This will not be a clean reboot, with everything
+                * shutting down.  But if there is a chance of
+                * rebooting the system it will be rebooted.
                 */
                emergency_restart();
        }
@@ -127,38 +122,44 @@ NORET_TYPE void panic(const char * fmt, ...)
        }
 #endif
 #if defined(CONFIG_S390)
-       disabled_wait(caller);
+       {
+               unsigned long caller;
+
+               caller = (unsigned long)__builtin_return_address(0);
+               disabled_wait(caller);
+       }
 #endif
        local_irq_enable();
-       for (i = 0;;) {
+       for (i = 0; ; ) {
                touch_softlockup_watchdog();
                i += panic_blink(i);
                mdelay(1);
                i++;
        }
+       bust_spinlocks(0);
 }
 
 EXPORT_SYMBOL(panic);
 
 
 struct tnt {
-       u8 bit;
-       char true;
-       char false;
+       u8      bit;
+       char    true;
+       char    false;
 };
 
 static const struct tnt tnts[] = {
-       { TAINT_PROPRIETARY_MODULE, 'P', 'G' },
-       { TAINT_FORCED_MODULE, 'F', ' ' },
-       { TAINT_UNSAFE_SMP, 'S', ' ' },
-       { TAINT_FORCED_RMMOD, 'R', ' ' },
-       { TAINT_MACHINE_CHECK, 'M', ' ' },
-       { TAINT_BAD_PAGE, 'B', ' ' },
-       { TAINT_USER, 'U', ' ' },
-       { TAINT_DIE, 'D', ' ' },
-       { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
-       { TAINT_WARN, 'W', ' ' },
-       { TAINT_CRAP, 'C', ' ' },
+       { TAINT_PROPRIETARY_MODULE,     'P', 'G' },
+       { TAINT_FORCED_MODULE,          'F', ' ' },
+       { TAINT_UNSAFE_SMP,             'S', ' ' },
+       { TAINT_FORCED_RMMOD,           'R', ' ' },
+       { TAINT_MACHINE_CHECK,          'M', ' ' },
+       { TAINT_BAD_PAGE,               'B', ' ' },
+       { TAINT_USER,                   'U', ' ' },
+       { TAINT_DIE,                    'D', ' ' },
+       { TAINT_OVERRIDDEN_ACPI_TABLE,  'A', ' ' },
+       { TAINT_WARN,                   'W', ' ' },
+       { TAINT_CRAP,                   'C', ' ' },
 };
 
 /**
@@ -195,7 +196,8 @@ const char *print_tainted(void)
                *s = 0;
        } else
                snprintf(buf, sizeof(buf), "Not tainted");
-       return(buf);
+
+       return buf;
 }
 
 int test_taint(unsigned flag)
@@ -211,7 +213,8 @@ unsigned long get_taint(void)
 
 void add_taint(unsigned flag)
 {
-       debug_locks = 0; /* can't trust the integrity of the kernel anymore */
+       /* can't trust the integrity of the kernel anymore: */
+       debug_locks = 0;
        set_bit(flag, &tainted_mask);
 }
 EXPORT_SYMBOL(add_taint);
@@ -266,8 +269,8 @@ static void do_oops_enter_exit(void)
 }
 
 /*
- * Return true if the calling CPU is allowed to print oops-related info.  This
- * is a bit racy..
+ * Return true if the calling CPU is allowed to print oops-related info.
+ * This is a bit racy..
  */
 int oops_may_print(void)
 {
@@ -276,20 +279,22 @@ int oops_may_print(void)
 
 /*
  * Called when the architecture enters its oops handler, before it prints
- * anything.  If this is the first CPU to oops, and it's oopsing the first time
- * then let it proceed.
+ * anything.  If this is the first CPU to oops, and it's oopsing the first
+ * time then let it proceed.
  *
- * This is all enabled by the pause_on_oops kernel boot option.  We do all this
- * to ensure that oopses don't scroll off the screen.  It has the side-effect
- * of preventing later-oopsing CPUs from mucking up the display, too.
+ * This is all enabled by the pause_on_oops kernel boot option.  We do all
+ * this to ensure that oopses don't scroll off the screen.  It has the
+ * side-effect of preventing later-oopsing CPUs from mucking up the display,
+ * too.
  *
- * It turns out that the CPU which is allowed to print ends up pausing for the
- * right duration, whereas all the other CPUs pause for twice as long: once in
- * oops_enter(), once in oops_exit().
+ * It turns out that the CPU which is allowed to print ends up pausing for
+ * the right duration, whereas all the other CPUs pause for twice as long:
+ * once in oops_enter(), once in oops_exit().
  */
 void oops_enter(void)
 {
-       debug_locks_off(); /* can't trust the integrity of the kernel anymore */
+       /* can't trust the integrity of the kernel anymore: */
+       debug_locks_off();
        do_oops_enter_exit();
 }
 
index 1b3586fe753afc25a482f92e78b46483d90a369c..b2e5f78fd2812cdc31624583f347853f1d236024 100644 (file)
@@ -403,6 +403,8 @@ struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
 {
        struct pid *pid;
        rcu_read_lock();
+       if (type != PIDTYPE_PID)
+               task = task->group_leader;
        pid = get_pid(task->pids[type].pid);
        rcu_read_unlock();
        return pid;
@@ -450,11 +452,24 @@ pid_t pid_vnr(struct pid *pid)
 }
 EXPORT_SYMBOL_GPL(pid_vnr);
 
-pid_t task_pid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
+pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
+                       struct pid_namespace *ns)
 {
-       return pid_nr_ns(task_pid(tsk), ns);
+       pid_t nr = 0;
+
+       rcu_read_lock();
+       if (!ns)
+               ns = current->nsproxy->pid_ns;
+       if (likely(pid_alive(task))) {
+               if (type != PIDTYPE_PID)
+                       task = task->group_leader;
+               nr = pid_nr_ns(task->pids[type].pid, ns);
+       }
+       rcu_read_unlock();
+
+       return nr;
 }
-EXPORT_SYMBOL(task_pid_nr_ns);
+EXPORT_SYMBOL(__task_pid_nr_ns);
 
 pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
 {
@@ -462,18 +477,6 @@ pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
 }
 EXPORT_SYMBOL(task_tgid_nr_ns);
 
-pid_t task_pgrp_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
-{
-       return pid_nr_ns(task_pgrp(tsk), ns);
-}
-EXPORT_SYMBOL(task_pgrp_nr_ns);
-
-pid_t task_session_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
-{
-       return pid_nr_ns(task_session(tsk), ns);
-}
-EXPORT_SYMBOL(task_session_nr_ns);
-
 struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
 {
        return ns_of_pid(task_pid(tsk));
index fab8ea86fac3f44156b0e3c50c00404080073da6..2d1001b4858de568515ea1f8fce0540afd4a103a 100644 (file)
@@ -152,6 +152,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
 {
        int nr;
        int rc;
+       struct task_struct *task;
 
        /*
         * The last thread in the cgroup-init thread group is terminating.
@@ -169,7 +170,19 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
        read_lock(&tasklist_lock);
        nr = next_pidmap(pid_ns, 1);
        while (nr > 0) {
-               kill_proc_info(SIGKILL, SEND_SIG_PRIV, nr);
+               rcu_read_lock();
+
+               /*
+                * Use force_sig() since it clears SIGNAL_UNKILLABLE ensuring
+                * any nested-container's init processes don't ignore the
+                * signal
+                */
+               task = pid_task(find_vpid(nr), PIDTYPE_PID);
+               if (task)
+                       force_sig(SIGKILL, task);
+
+               rcu_read_unlock();
+
                nr = next_pidmap(pid_ns, nr);
        }
        read_unlock(&tasklist_lock);
index 4a4a206b1979c657c887df31907166080a004d8f..5f21ab2bbcdf0cf5c85985f8612f923ad6ad3d03 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
+#include <asm/suspend.h>
 
 #include "power.h"
 
@@ -214,7 +215,7 @@ static int create_image(int platform_mode)
                return error;
 
        device_pm_lock();
-       local_irq_disable();
+
        /* At this point, device_suspend() has been called, but *not*
         * device_power_down(). We *must* call device_power_down() now.
         * Otherwise, drivers for some devices (e.g. interrupt controllers)
@@ -225,13 +226,25 @@ static int create_image(int platform_mode)
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting hibernation\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
+
+       error = platform_pre_snapshot(platform_mode);
+       if (error || hibernation_test(TEST_PLATFORM))
+               goto Platform_finish;
+
+       error = disable_nonboot_cpus();
+       if (error || hibernation_test(TEST_CPUS)
+           || hibernation_testmode(HIBERNATION_TEST))
+               goto Enable_cpus;
+
+       local_irq_disable();
+
        sysdev_suspend(PMSG_FREEZE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting hibernation\n");
-               goto Power_up_devices;
+               goto Enable_irqs;
        }
 
        if (hibernation_test(TEST_CORE))
@@ -247,17 +260,28 @@ static int create_image(int platform_mode)
        restore_processor_state();
        if (!in_suspend)
                platform_leave(platform_mode);
+
  Power_up:
        sysdev_resume();
        /* NOTE:  device_power_up() is just a resume() for devices
         * that suspended with irqs off ... no overall powerup.
         */
- Power_up_devices:
-       device_power_up(in_suspend ?
-               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
  Enable_irqs:
        local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Platform_finish:
+       platform_finish(platform_mode);
+
+       device_power_up(in_suspend ?
+               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
@@ -265,7 +289,7 @@ static int create_image(int platform_mode)
  *     hibernation_snapshot - quiesce devices and create the hibernation
  *     snapshot image.
  *     @platform_mode - if set, use the platform driver, if available, to
- *                      prepare the platform frimware for the power transition.
+ *                      prepare the platform firmware for the power transition.
  *
  *     Must be called with pm_mutex held
  */
@@ -291,25 +315,9 @@ int hibernation_snapshot(int platform_mode)
        if (hibernation_test(TEST_DEVICES))
                goto Recover_platform;
 
-       error = platform_pre_snapshot(platform_mode);
-       if (error || hibernation_test(TEST_PLATFORM))
-               goto Finish;
-
-       error = disable_nonboot_cpus();
-       if (!error) {
-               if (hibernation_test(TEST_CPUS))
-                       goto Enable_cpus;
-
-               if (hibernation_testmode(HIBERNATION_TEST))
-                       goto Enable_cpus;
+       error = create_image(platform_mode);
+       /* Control returns here after successful restore */
 
-               error = create_image(platform_mode);
-               /* Control returns here after successful restore */
-       }
- Enable_cpus:
-       enable_nonboot_cpus();
- Finish:
-       platform_finish(platform_mode);
  Resume_devices:
        device_resume(in_suspend ?
                (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
@@ -331,19 +339,33 @@ int hibernation_snapshot(int platform_mode)
  *     kernel.
  */
 
-static int resume_target_kernel(void)
+static int resume_target_kernel(bool platform_mode)
 {
        int error;
 
        device_pm_lock();
-       local_irq_disable();
+
        error = device_power_down(PMSG_QUIESCE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting resume\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
-       sysdev_suspend(PMSG_QUIESCE);
+
+       error = platform_pre_restore(platform_mode);
+       if (error)
+               goto Cleanup;
+
+       error = disable_nonboot_cpus();
+       if (error)
+               goto Enable_cpus;
+
+       local_irq_disable();
+
+       error = sysdev_suspend(PMSG_QUIESCE);
+       if (error)
+               goto Enable_irqs;
+
        /* We'll ignore saved state, but this gets preempt count (etc) right */
        save_processor_state();
        error = restore_highmem();
@@ -366,11 +388,23 @@ static int resume_target_kernel(void)
        swsusp_free();
        restore_processor_state();
        touch_softlockup_watchdog();
+
        sysdev_resume();
-       device_power_up(PMSG_RECOVER);
+
  Enable_irqs:
        local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Cleanup:
+       platform_restore_cleanup(platform_mode);
+
+       device_power_up(PMSG_RECOVER);
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
@@ -378,7 +412,7 @@ static int resume_target_kernel(void)
  *     hibernation_restore - quiesce devices and restore the hibernation
  *     snapshot image.  If successful, control returns in hibernation_snaphot()
  *     @platform_mode - if set, use the platform driver, if available, to
- *                      prepare the platform frimware for the transition.
+ *                      prepare the platform firmware for the transition.
  *
  *     Must be called with pm_mutex held
  */
@@ -390,19 +424,10 @@ int hibernation_restore(int platform_mode)
        pm_prepare_console();
        suspend_console();
        error = device_suspend(PMSG_QUIESCE);
-       if (error)
-               goto Finish;
-
-       error = platform_pre_restore(platform_mode);
        if (!error) {
-               error = disable_nonboot_cpus();
-               if (!error)
-                       error = resume_target_kernel();
-               enable_nonboot_cpus();
+               error = resume_target_kernel(platform_mode);
+               device_resume(PMSG_RECOVER);
        }
-       platform_restore_cleanup(platform_mode);
-       device_resume(PMSG_RECOVER);
- Finish:
        resume_console();
        pm_restore_console();
        return error;
@@ -438,38 +463,46 @@ int hibernation_platform_enter(void)
                goto Resume_devices;
        }
 
+       device_pm_lock();
+
+       error = device_power_down(PMSG_HIBERNATE);
+       if (error)
+               goto Unlock;
+
        error = hibernation_ops->prepare();
        if (error)
-               goto Resume_devices;
+               goto Platofrm_finish;
 
        error = disable_nonboot_cpus();
        if (error)
-               goto Finish;
+               goto Platofrm_finish;
 
-       device_pm_lock();
        local_irq_disable();
-       error = device_power_down(PMSG_HIBERNATE);
-       if (!error) {
-               sysdev_suspend(PMSG_HIBERNATE);
-               hibernation_ops->enter();
-               /* We should never get here */
-               while (1);
-       }
-       local_irq_enable();
-       device_pm_unlock();
+       sysdev_suspend(PMSG_HIBERNATE);
+       hibernation_ops->enter();
+       /* We should never get here */
+       while (1);
 
        /*
         * We don't need to reenable the nonboot CPUs or resume consoles, since
         * the system is going to be halted anyway.
         */
Finish:
Platofrm_finish:
        hibernation_ops->finish();
+
+       device_power_up(PMSG_RESTORE);
+
+ Unlock:
+       device_pm_unlock();
+
  Resume_devices:
        entering_platform_hibernation = false;
        device_resume(PMSG_RESTORE);
        resume_console();
+
  Close:
        hibernation_ops->end();
+
        return error;
 }
 
index c9632f841f646fbfc146ecee855fd04068a548ae..f172f41858bb877305082c2e512d59848d6fdced 100644 (file)
@@ -287,17 +287,32 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
  */
 static int suspend_enter(suspend_state_t state)
 {
-       int error = 0;
+       int error;
 
        device_pm_lock();
-       arch_suspend_disable_irqs();
-       BUG_ON(!irqs_disabled());
 
-       if ((error = device_power_down(PMSG_SUSPEND))) {
+       error = device_power_down(PMSG_SUSPEND);
+       if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down\n");
                goto Done;
        }
 
+       if (suspend_ops->prepare) {
+               error = suspend_ops->prepare();
+               if (error)
+                       goto Power_up_devices;
+       }
+
+       if (suspend_test(TEST_PLATFORM))
+               goto Platfrom_finish;
+
+       error = disable_nonboot_cpus();
+       if (error || suspend_test(TEST_CPUS))
+               goto Enable_cpus;
+
+       arch_suspend_disable_irqs();
+       BUG_ON(!irqs_disabled());
+
        error = sysdev_suspend(PMSG_SUSPEND);
        if (!error) {
                if (!suspend_test(TEST_CORE))
@@ -305,11 +320,22 @@ static int suspend_enter(suspend_state_t state)
                sysdev_resume();
        }
 
-       device_power_up(PMSG_RESUME);
- Done:
        arch_suspend_enable_irqs();
        BUG_ON(irqs_disabled());
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Platfrom_finish:
+       if (suspend_ops->finish)
+               suspend_ops->finish();
+
+ Power_up_devices:
+       device_power_up(PMSG_RESUME);
+
+ Done:
        device_pm_unlock();
+
        return error;
 }
 
@@ -341,23 +367,8 @@ int suspend_devices_and_enter(suspend_state_t state)
        if (suspend_test(TEST_DEVICES))
                goto Recover_platform;
 
-       if (suspend_ops->prepare) {
-               error = suspend_ops->prepare();
-               if (error)
-                       goto Resume_devices;
-       }
-
-       if (suspend_test(TEST_PLATFORM))
-               goto Finish;
-
-       error = disable_nonboot_cpus();
-       if (!error && !suspend_test(TEST_CPUS))
-               suspend_enter(state);
+       suspend_enter(state);
 
-       enable_nonboot_cpus();
- Finish:
-       if (suspend_ops->finish)
-               suspend_ops->finish();
  Resume_devices:
        suspend_test_start();
        device_resume(PMSG_RESUME);
index f5fc2d7680f26dbbb84aa1af4b9afa68ba7edf8b..33e2e4a819f97014a6e70e5f06d52e246ba783b3 100644 (file)
@@ -321,13 +321,10 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
        INIT_LIST_HEAD(list);
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                unsigned long zone_start, zone_end;
                struct mem_extent *ext, *cur, *aux;
 
-               if (!populated_zone(zone))
-                       continue;
-
                zone_start = zone->zone_start_pfn;
                zone_end = zone->zone_start_pfn + zone->spanned_pages;
 
@@ -804,8 +801,8 @@ static unsigned int count_free_highmem_pages(void)
        struct zone *zone;
        unsigned int cnt = 0;
 
-       for_each_zone(zone)
-               if (populated_zone(zone) && is_highmem(zone))
+       for_each_populated_zone(zone)
+               if (is_highmem(zone))
                        cnt += zone_page_state(zone, NR_FREE_PAGES);
 
        return cnt;
index a92c9145155975b306d52dab08fb095e3af8370e..78c35047586dbaf6ad4766a88e73062a56fde543 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/highmem.h>
 #include <linux/time.h>
 #include <linux/rbtree.h>
+#include <linux/io.h>
 
 #include "power.h"
 
@@ -229,17 +230,16 @@ int swsusp_shrink_memory(void)
                size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
                tmp = size;
                size += highmem_size;
-               for_each_zone (zone)
-                       if (populated_zone(zone)) {
-                               tmp += snapshot_additional_pages(zone);
-                               if (is_highmem(zone)) {
-                                       highmem_size -=
+               for_each_populated_zone(zone) {
+                       tmp += snapshot_additional_pages(zone);
+                       if (is_highmem(zone)) {
+                               highmem_size -=
                                        zone_page_state(zone, NR_FREE_PAGES);
-                               } else {
-                                       tmp -= zone_page_state(zone, NR_FREE_PAGES);
-                                       tmp += zone->lowmem_reserve[ZONE_NORMAL];
-                               }
+                       } else {
+                               tmp -= zone_page_state(zone, NR_FREE_PAGES);
+                               tmp += zone->lowmem_reserve[ZONE_NORMAL];
                        }
+               }
 
                if (highmem_size < 0)
                        highmem_size = 0;
index e3602d0755b0dd99c9fb47887fd67d371cdd5424..a5f61a9acedb3cfd72a7d87a29317f9f146d896d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/security.h>
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
+#include <linux/kexec.h>
 
 #include <asm/uaccess.h>
 
@@ -135,6 +136,24 @@ static char *log_buf = __log_buf;
 static int log_buf_len = __LOG_BUF_LEN;
 static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
 
+#ifdef CONFIG_KEXEC
+/*
+ * This appends the listed symbols to /proc/vmcoreinfo
+ *
+ * /proc/vmcoreinfo is used by various utiilties, like crash and makedumpfile to
+ * obtain access to symbols that are otherwise very difficult to locate.  These
+ * symbols are specifically used so that utilities can access and extract the
+ * dmesg log from a vmcore file after a crash.
+ */
+void log_buf_kexec_setup(void)
+{
+       VMCOREINFO_SYMBOL(log_buf);
+       VMCOREINFO_SYMBOL(log_end);
+       VMCOREINFO_SYMBOL(log_buf_len);
+       VMCOREINFO_SYMBOL(logged_chars);
+}
+#endif
+
 static int __init log_buf_len_setup(char *str)
 {
        unsigned size = memparse(str, &str);
index c9cf48b21f052a620b34151cc9de6c4b48f4ad66..5105f5a6a2ce3d843affaed6130ef5eb873db87f 100644 (file)
@@ -60,11 +60,15 @@ static void ptrace_untrace(struct task_struct *child)
 {
        spin_lock(&child->sighand->siglock);
        if (task_is_traced(child)) {
-               if (child->signal->flags & SIGNAL_STOP_STOPPED) {
+               /*
+                * If the group stop is completed or in progress,
+                * this thread was already counted as stopped.
+                */
+               if (child->signal->flags & SIGNAL_STOP_STOPPED ||
+                   child->signal->group_stop_count)
                        __set_task_state(child, TASK_STOPPED);
-               } else {
+               else
                        signal_wake_up(child, 1);
-               }
        }
        spin_unlock(&child->sighand->siglock);
 }
@@ -235,18 +239,58 @@ out:
        return retval;
 }
 
-static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
+/*
+ * Called with irqs disabled, returns true if childs should reap themselves.
+ */
+static int ignoring_children(struct sighand_struct *sigh)
 {
-       child->exit_code = data;
-       /* .. re-parent .. */
-       __ptrace_unlink(child);
-       /* .. and wake it up. */
-       if (child->exit_state != EXIT_ZOMBIE)
-               wake_up_process(child);
+       int ret;
+       spin_lock(&sigh->siglock);
+       ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) ||
+             (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT);
+       spin_unlock(&sigh->siglock);
+       return ret;
+}
+
+/*
+ * Called with tasklist_lock held for writing.
+ * Unlink a traced task, and clean it up if it was a traced zombie.
+ * Return true if it needs to be reaped with release_task().
+ * (We can't call release_task() here because we already hold tasklist_lock.)
+ *
+ * If it's a zombie, our attachedness prevented normal parent notification
+ * or self-reaping.  Do notification now if it would have happened earlier.
+ * If it should reap itself, return true.
+ *
+ * If it's our own child, there is no notification to do.
+ * But if our normal children self-reap, then this child
+ * was prevented by ptrace and we must reap it now.
+ */
+static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
+{
+       __ptrace_unlink(p);
+
+       if (p->exit_state == EXIT_ZOMBIE) {
+               if (!task_detached(p) && thread_group_empty(p)) {
+                       if (!same_thread_group(p->real_parent, tracer))
+                               do_notify_parent(p, p->exit_signal);
+                       else if (ignoring_children(tracer->sighand))
+                               p->exit_signal = -1;
+               }
+               if (task_detached(p)) {
+                       /* Mark it as in the process of being reaped. */
+                       p->exit_state = EXIT_DEAD;
+                       return true;
+               }
+       }
+
+       return false;
 }
 
 int ptrace_detach(struct task_struct *child, unsigned int data)
 {
+       bool dead = false;
+
        if (!valid_signal(data))
                return -EIO;
 
@@ -255,14 +299,45 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 
        write_lock_irq(&tasklist_lock);
-       /* protect against de_thread()->release_task() */
-       if (child->ptrace)
-               __ptrace_detach(child, data);
+       /*
+        * This child can be already killed. Make sure de_thread() or
+        * our sub-thread doing do_wait() didn't do release_task() yet.
+        */
+       if (child->ptrace) {
+               child->exit_code = data;
+               dead = __ptrace_detach(current, child);
+       }
        write_unlock_irq(&tasklist_lock);
 
+       if (unlikely(dead))
+               release_task(child);
+
        return 0;
 }
 
+/*
+ * Detach all tasks we were using ptrace on.
+ */
+void exit_ptrace(struct task_struct *tracer)
+{
+       struct task_struct *p, *n;
+       LIST_HEAD(ptrace_dead);
+
+       write_lock_irq(&tasklist_lock);
+       list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
+               if (__ptrace_detach(tracer, p))
+                       list_add(&p->ptrace_entry, &ptrace_dead);
+       }
+       write_unlock_irq(&tasklist_lock);
+
+       BUG_ON(!list_empty(&tracer->ptraced));
+
+       list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) {
+               list_del_init(&p->ptrace_entry);
+               release_task(p);
+       }
+}
+
 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
 {
        int copied = 0;
index 7c4142a79f0ab5a2ef80300b3d5be3188bdec8c7..9b4a975a4b4afc1f1eba22c1cb30d21aef844959 100644 (file)
@@ -126,6 +126,7 @@ static atomic_t n_rcu_torture_mberror;
 static atomic_t n_rcu_torture_error;
 static long n_rcu_torture_timers = 0;
 static struct list_head rcu_torture_removed;
+static cpumask_var_t shuffle_tmp_mask;
 
 static int stutter_pause_test = 0;
 
@@ -889,10 +890,9 @@ static int rcu_idle_cpu;   /* Force all torture tasks off this CPU */
  */
 static void rcu_torture_shuffle_tasks(void)
 {
-       cpumask_t tmp_mask;
        int i;
 
-       cpus_setall(tmp_mask);
+       cpumask_setall(shuffle_tmp_mask);
        get_online_cpus();
 
        /* No point in shuffling if there is only one online CPU (ex: UP) */
@@ -902,29 +902,29 @@ static void rcu_torture_shuffle_tasks(void)
        }
 
        if (rcu_idle_cpu != -1)
-               cpu_clear(rcu_idle_cpu, tmp_mask);
+               cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
 
-       set_cpus_allowed_ptr(current, &tmp_mask);
+       set_cpus_allowed_ptr(current, shuffle_tmp_mask);
 
        if (reader_tasks) {
                for (i = 0; i < nrealreaders; i++)
                        if (reader_tasks[i])
                                set_cpus_allowed_ptr(reader_tasks[i],
-                                                    &tmp_mask);
+                                                    shuffle_tmp_mask);
        }
 
        if (fakewriter_tasks) {
                for (i = 0; i < nfakewriters; i++)
                        if (fakewriter_tasks[i])
                                set_cpus_allowed_ptr(fakewriter_tasks[i],
-                                                    &tmp_mask);
+                                                    shuffle_tmp_mask);
        }
 
        if (writer_task)
-               set_cpus_allowed_ptr(writer_task, &tmp_mask);
+               set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
 
        if (stats_task)
-               set_cpus_allowed_ptr(stats_task, &tmp_mask);
+               set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
 
        if (rcu_idle_cpu == -1)
                rcu_idle_cpu = num_online_cpus() - 1;
@@ -1012,6 +1012,7 @@ rcu_torture_cleanup(void)
        if (shuffler_task) {
                VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
                kthread_stop(shuffler_task);
+               free_cpumask_var(shuffle_tmp_mask);
        }
        shuffler_task = NULL;
 
@@ -1190,10 +1191,18 @@ rcu_torture_init(void)
        }
        if (test_no_idle_hz) {
                rcu_idle_cpu = num_online_cpus() - 1;
+
+               if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
+                       firsterr = -ENOMEM;
+                       VERBOSE_PRINTK_ERRSTRING("Failed to alloc mask");
+                       goto unwind;
+               }
+
                /* Create the shuffler thread */
                shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
                                          "rcu_torture_shuffle");
                if (IS_ERR(shuffler_task)) {
+                       free_cpumask_var(shuffle_tmp_mask);
                        firsterr = PTR_ERR(shuffler_task);
                        VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
                        shuffler_task = NULL;
index 8f2179c8056ff9f9de0b2679588d86589393b508..e92db8c06acf86a340a865d1f5965001ea9c0d70 100644 (file)
@@ -797,13 +797,15 @@ void relay_subbufs_consumed(struct rchan *chan,
        if (!chan)
                return;
 
-       if (cpu >= NR_CPUS || !chan->buf[cpu])
+       if (cpu >= NR_CPUS || !chan->buf[cpu] ||
+                                       subbufs_consumed > chan->n_subbufs)
                return;
 
        buf = chan->buf[cpu];
-       buf->subbufs_consumed += subbufs_consumed;
-       if (buf->subbufs_consumed > buf->subbufs_produced)
+       if (subbufs_consumed > buf->subbufs_produced - buf->subbufs_consumed)
                buf->subbufs_consumed = buf->subbufs_produced;
+       else
+               buf->subbufs_consumed += subbufs_consumed;
 }
 EXPORT_SYMBOL_GPL(relay_subbufs_consumed);
 
index 5757e03cfac0bdf7cd50f3625a318645c562b973..2325db2be31bc97aee75db0e0863e23ad5a1442c 100644 (file)
@@ -1110,7 +1110,7 @@ static void hrtick_start(struct rq *rq, u64 delay)
        if (rq == this_rq()) {
                hrtimer_restart(timer);
        } else if (!rq->hrtick_csd_pending) {
-               __smp_call_function_single(cpu_of(rq), &rq->hrtick_csd);
+               __smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 0);
                rq->hrtick_csd_pending = 1;
        }
 }
@@ -4942,15 +4942,13 @@ pick_next_task(struct rq *rq)
 /*
  * schedule() is the main scheduler function.
  */
-asmlinkage void __sched schedule(void)
+asmlinkage void __sched __schedule(void)
 {
        struct task_struct *prev, *next;
        unsigned long *switch_count;
        struct rq *rq;
        int cpu;
 
-need_resched:
-       preempt_disable();
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
        rcu_qsctr_inc(cpu);
@@ -5007,13 +5005,80 @@ need_resched_nonpreemptible:
 
        if (unlikely(reacquire_kernel_lock(current) < 0))
                goto need_resched_nonpreemptible;
+}
 
+asmlinkage void __sched schedule(void)
+{
+need_resched:
+       preempt_disable();
+       __schedule();
        preempt_enable_no_resched();
        if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
                goto need_resched;
 }
 EXPORT_SYMBOL(schedule);
 
+#ifdef CONFIG_SMP
+/*
+ * Look out! "owner" is an entirely speculative pointer
+ * access and not reliable.
+ */
+int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner)
+{
+       unsigned int cpu;
+       struct rq *rq;
+
+       if (!sched_feat(OWNER_SPIN))
+               return 0;
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       /*
+        * Need to access the cpu field knowing that
+        * DEBUG_PAGEALLOC could have unmapped it if
+        * the mutex owner just released it and exited.
+        */
+       if (probe_kernel_address(&owner->cpu, cpu))
+               goto out;
+#else
+       cpu = owner->cpu;
+#endif
+
+       /*
+        * Even if the access succeeded (likely case),
+        * the cpu field may no longer be valid.
+        */
+       if (cpu >= nr_cpumask_bits)
+               goto out;
+
+       /*
+        * We need to validate that we can do a
+        * get_cpu() and that we have the percpu area.
+        */
+       if (!cpu_online(cpu))
+               goto out;
+
+       rq = cpu_rq(cpu);
+
+       for (;;) {
+               /*
+                * Owner changed, break to re-assess state.
+                */
+               if (lock->owner != owner)
+                       break;
+
+               /*
+                * Is that owner really running on that cpu?
+                */
+               if (task_thread_info(rq->curr) != owner || need_resched())
+                       return 0;
+
+               cpu_relax();
+       }
+out:
+       return 1;
+}
+#endif
+
 #ifdef CONFIG_PREEMPT
 /*
  * this is the entry point to schedule() from in-kernel preemption
@@ -5131,11 +5196,17 @@ void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
        __wake_up_common(q, mode, 1, 0, NULL);
 }
 
+void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key)
+{
+       __wake_up_common(q, mode, 1, 0, key);
+}
+
 /**
- * __wake_up_sync - wake up threads blocked on a waitqueue.
+ * __wake_up_sync_key - wake up threads blocked on a waitqueue.
  * @q: the waitqueue
  * @mode: which threads
  * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ * @key: opaque value to be passed to wakeup targets
  *
  * The sync wakeup differs that the waker knows that it will schedule
  * away soon, so while the target thread will be woken up, it will not
@@ -5144,8 +5215,8 @@ void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
  *
  * On UP it can prevent extra preemption.
  */
-void
-__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
+                       int nr_exclusive, void *key)
 {
        unsigned long flags;
        int sync = 1;
@@ -5157,9 +5228,18 @@ __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
                sync = 0;
 
        spin_lock_irqsave(&q->lock, flags);
-       __wake_up_common(q, mode, nr_exclusive, sync, NULL);
+       __wake_up_common(q, mode, nr_exclusive, sync, key);
        spin_unlock_irqrestore(&q->lock, flags);
 }
+EXPORT_SYMBOL_GPL(__wake_up_sync_key);
+
+/*
+ * __wake_up_sync - see __wake_up_sync_key()
+ */
+void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
+{
+       __wake_up_sync_key(q, mode, nr_exclusive, NULL);
+}
 EXPORT_SYMBOL_GPL(__wake_up_sync);     /* For internal use only */
 
 /**
index 642a94ef8a0a7fb39f9b341eb292dfad9ab38762..9a7e859b8fbfdd753f09a4bc0949cf5345e2ae75 100644 (file)
@@ -25,7 +25,7 @@ struct cpupri {
 
 #ifdef CONFIG_SMP
 int  cpupri_find(struct cpupri *cp,
-                struct task_struct *p, cpumask_t *lowest_mask);
+                struct task_struct *p, struct cpumask *lowest_mask);
 void cpupri_set(struct cpupri *cp, int cpu, int pri);
 int cpupri_init(struct cpupri *cp, bool bootmem);
 void cpupri_cleanup(struct cpupri *cp);
index 76f61756e677647dda4ae01ede5ac942329a09c8..4569bfa7df9b9fee6f057e22aca18299d3c45f3b 100644 (file)
@@ -14,3 +14,4 @@ SCHED_FEAT(LB_WAKEUP_UPDATE, 1)
 SCHED_FEAT(ASYM_EFF_LOAD, 1)
 SCHED_FEAT(WAKEUP_OVERLAP, 0)
 SCHED_FEAT(LAST_BUDDY, 1)
+SCHED_FEAT(OWNER_SPIN, 1)
index 1c8814481a117d5df731465b5a56bbf4738c48c1..d8034737db4cb86f8adca044560a3765ac65dba5 100644 (file)
@@ -55,10 +55,22 @@ static int sig_handler_ignored(void __user *handler, int sig)
                (handler == SIG_DFL && sig_kernel_ignore(sig));
 }
 
-static int sig_ignored(struct task_struct *t, int sig)
+static int sig_task_ignored(struct task_struct *t, int sig,
+               int from_ancestor_ns)
 {
        void __user *handler;
 
+       handler = sig_handler(t, sig);
+
+       if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
+                       handler == SIG_DFL && !from_ancestor_ns)
+               return 1;
+
+       return sig_handler_ignored(handler, sig);
+}
+
+static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
+{
        /*
         * Blocked signals are never ignored, since the
         * signal handler may change by the time it is
@@ -67,14 +79,13 @@ static int sig_ignored(struct task_struct *t, int sig)
        if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
                return 0;
 
-       handler = sig_handler(t, sig);
-       if (!sig_handler_ignored(handler, sig))
+       if (!sig_task_ignored(t, sig, from_ancestor_ns))
                return 0;
 
        /*
         * Tracers may want to know about even ignored signals.
         */
-       return !tracehook_consider_ignored_signal(t, sig, handler);
+       return !tracehook_consider_ignored_signal(t, sig);
 }
 
 /*
@@ -318,7 +329,7 @@ int unhandled_signal(struct task_struct *tsk, int sig)
                return 1;
        if (handler != SIG_IGN && handler != SIG_DFL)
                return 0;
-       return !tracehook_consider_fatal_signal(tsk, sig, handler);
+       return !tracehook_consider_fatal_signal(tsk, sig);
 }
 
 
@@ -624,7 +635,7 @@ static int check_kill_permission(int sig, struct siginfo *info,
  * Returns true if the signal should be actually delivered, otherwise
  * it should be dropped.
  */
-static int prepare_signal(int sig, struct task_struct *p)
+static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
 {
        struct signal_struct *signal = p->signal;
        struct task_struct *t;
@@ -708,7 +719,7 @@ static int prepare_signal(int sig, struct task_struct *p)
                }
        }
 
-       return !sig_ignored(p, sig);
+       return !sig_ignored(p, sig, from_ancestor_ns);
 }
 
 /*
@@ -777,7 +788,7 @@ static void complete_signal(int sig, struct task_struct *p, int group)
            !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
            !sigismember(&t->real_blocked, sig) &&
            (sig == SIGKILL ||
-            !tracehook_consider_fatal_signal(t, sig, SIG_DFL))) {
+            !tracehook_consider_fatal_signal(t, sig))) {
                /*
                 * This signal will be fatal to the whole group.
                 */
@@ -813,8 +824,8 @@ static inline int legacy_queue(struct sigpending *signals, int sig)
        return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
 }
 
-static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
-                       int group)
+static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
+                       int group, int from_ancestor_ns)
 {
        struct sigpending *pending;
        struct sigqueue *q;
@@ -822,7 +833,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
        trace_sched_signal_send(sig, t);
 
        assert_spin_locked(&t->sighand->siglock);
-       if (!prepare_signal(sig, t))
+
+       if (!prepare_signal(sig, t, from_ancestor_ns))
                return 0;
 
        pending = group ? &t->signal->shared_pending : &t->pending;
@@ -871,6 +883,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
                        break;
                default:
                        copy_siginfo(&q->info, info);
+                       if (from_ancestor_ns)
+                               q->info.si_pid = 0;
                        break;
                }
        } else if (!is_si_special(info)) {
@@ -889,6 +903,20 @@ out_set:
        return 0;
 }
 
+static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+                       int group)
+{
+       int from_ancestor_ns = 0;
+
+#ifdef CONFIG_PID_NS
+       if (!is_si_special(info) && SI_FROMUSER(info) &&
+                       task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0)
+               from_ancestor_ns = 1;
+#endif
+
+       return __send_signal(sig, info, t, group, from_ancestor_ns);
+}
+
 int print_fatal_signals;
 
 static void print_fatal_signal(struct pt_regs *regs, int signr)
@@ -1133,7 +1161,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
        if (sig && p->sighand) {
                unsigned long flags;
                spin_lock_irqsave(&p->sighand->siglock, flags);
-               ret = __group_send_sig_info(sig, info, p);
+               ret = __send_signal(sig, info, p, 1, 0);
                spin_unlock_irqrestore(&p->sighand->siglock, flags);
        }
 out_unlock:
@@ -1320,7 +1348,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
                goto ret;
 
        ret = 1; /* the signal is ignored */
-       if (!prepare_signal(sig, t))
+       if (!prepare_signal(sig, t, 0))
                goto out;
 
        ret = 0;
@@ -1844,9 +1872,16 @@ relock:
 
                /*
                 * Global init gets no signals it doesn't want.
+                * Container-init gets no signals it doesn't want from same
+                * container.
+                *
+                * Note that if global/container-init sees a sig_kernel_only()
+                * signal here, the signal must have been generated internally
+                * or must have come from an ancestor namespace. In either
+                * case, the signal cannot be dropped.
                 */
                if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&
-                   !signal_group_exit(signal))
+                               !sig_kernel_only(signr))
                        continue;
 
                if (sig_kernel_stop(signr)) {
diff --git a/kernel/slow-work.c b/kernel/slow-work.c
new file mode 100644 (file)
index 0000000..cf2bc01
--- /dev/null
@@ -0,0 +1,640 @@
+/* Worker thread pool for slow items, such as filesystem lookups or mkdirs
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ *
+ * See Documentation/slow-work.txt
+ */
+
+#include <linux/module.h>
+#include <linux/slow-work.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/wait.h>
+
+#define SLOW_WORK_CULL_TIMEOUT (5 * HZ)        /* cull threads 5s after running out of
+                                        * things to do */
+#define SLOW_WORK_OOM_TIMEOUT (5 * HZ) /* can't start new threads for 5s after
+                                        * OOM */
+
+static void slow_work_cull_timeout(unsigned long);
+static void slow_work_oom_timeout(unsigned long);
+
+#ifdef CONFIG_SYSCTL
+static int slow_work_min_threads_sysctl(struct ctl_table *, int, struct file *,
+                                       void __user *, size_t *, loff_t *);
+
+static int slow_work_max_threads_sysctl(struct ctl_table *, int , struct file *,
+                                       void __user *, size_t *, loff_t *);
+#endif
+
+/*
+ * The pool of threads has at least min threads in it as long as someone is
+ * using the facility, and may have as many as max.
+ *
+ * A portion of the pool may be processing very slow operations.
+ */
+static unsigned slow_work_min_threads = 2;
+static unsigned slow_work_max_threads = 4;
+static unsigned vslow_work_proportion = 50; /* % of threads that may process
+                                            * very slow work */
+
+#ifdef CONFIG_SYSCTL
+static const int slow_work_min_min_threads = 2;
+static int slow_work_max_max_threads = 255;
+static const int slow_work_min_vslow = 1;
+static const int slow_work_max_vslow = 99;
+
+ctl_table slow_work_sysctls[] = {
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "min-threads",
+               .data           = &slow_work_min_threads,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = slow_work_min_threads_sysctl,
+               .extra1         = (void *) &slow_work_min_min_threads,
+               .extra2         = &slow_work_max_threads,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max-threads",
+               .data           = &slow_work_max_threads,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = slow_work_max_threads_sysctl,
+               .extra1         = &slow_work_min_threads,
+               .extra2         = (void *) &slow_work_max_max_threads,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "vslow-percentage",
+               .data           = &vslow_work_proportion,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .extra1         = (void *) &slow_work_min_vslow,
+               .extra2         = (void *) &slow_work_max_vslow,
+       },
+       { .ctl_name = 0 }
+};
+#endif
+
+/*
+ * The active state of the thread pool
+ */
+static atomic_t slow_work_thread_count;
+static atomic_t vslow_work_executing_count;
+
+static bool slow_work_may_not_start_new_thread;
+static bool slow_work_cull; /* cull a thread due to lack of activity */
+static DEFINE_TIMER(slow_work_cull_timer, slow_work_cull_timeout, 0, 0);
+static DEFINE_TIMER(slow_work_oom_timer, slow_work_oom_timeout, 0, 0);
+static struct slow_work slow_work_new_thread; /* new thread starter */
+
+/*
+ * The queues of work items and the lock governing access to them.  These are
+ * shared between all the CPUs.  It doesn't make sense to have per-CPU queues
+ * as the number of threads bears no relation to the number of CPUs.
+ *
+ * There are two queues of work items: one for slow work items, and one for
+ * very slow work items.
+ */
+static LIST_HEAD(slow_work_queue);
+static LIST_HEAD(vslow_work_queue);
+static DEFINE_SPINLOCK(slow_work_queue_lock);
+
+/*
+ * The thread controls.  A variable used to signal to the threads that they
+ * should exit when the queue is empty, a waitqueue used by the threads to wait
+ * for signals, and a completion set by the last thread to exit.
+ */
+static bool slow_work_threads_should_exit;
+static DECLARE_WAIT_QUEUE_HEAD(slow_work_thread_wq);
+static DECLARE_COMPLETION(slow_work_last_thread_exited);
+
+/*
+ * The number of users of the thread pool and its lock.  Whilst this is zero we
+ * have no threads hanging around, and when this reaches zero, we wait for all
+ * active or queued work items to complete and kill all the threads we do have.
+ */
+static int slow_work_user_count;
+static DEFINE_MUTEX(slow_work_user_lock);
+
+/*
+ * Calculate the maximum number of active threads in the pool that are
+ * permitted to process very slow work items.
+ *
+ * The answer is rounded up to at least 1, but may not equal or exceed the
+ * maximum number of the threads in the pool.  This means we always have at
+ * least one thread that can process slow work items, and we always have at
+ * least one thread that won't get tied up doing so.
+ */
+static unsigned slow_work_calc_vsmax(void)
+{
+       unsigned vsmax;
+
+       vsmax = atomic_read(&slow_work_thread_count) * vslow_work_proportion;
+       vsmax /= 100;
+       vsmax = max(vsmax, 1U);
+       return min(vsmax, slow_work_max_threads - 1);
+}
+
+/*
+ * Attempt to execute stuff queued on a slow thread.  Return true if we managed
+ * it, false if there was nothing to do.
+ */
+static bool slow_work_execute(void)
+{
+       struct slow_work *work = NULL;
+       unsigned vsmax;
+       bool very_slow;
+
+       vsmax = slow_work_calc_vsmax();
+
+       /* see if we can schedule a new thread to be started if we're not
+        * keeping up with the work */
+       if (!waitqueue_active(&slow_work_thread_wq) &&
+           (!list_empty(&slow_work_queue) || !list_empty(&vslow_work_queue)) &&
+           atomic_read(&slow_work_thread_count) < slow_work_max_threads &&
+           !slow_work_may_not_start_new_thread)
+               slow_work_enqueue(&slow_work_new_thread);
+
+       /* find something to execute */
+       spin_lock_irq(&slow_work_queue_lock);
+       if (!list_empty(&vslow_work_queue) &&
+           atomic_read(&vslow_work_executing_count) < vsmax) {
+               work = list_entry(vslow_work_queue.next,
+                                 struct slow_work, link);
+               if (test_and_set_bit_lock(SLOW_WORK_EXECUTING, &work->flags))
+                       BUG();
+               list_del_init(&work->link);
+               atomic_inc(&vslow_work_executing_count);
+               very_slow = true;
+       } else if (!list_empty(&slow_work_queue)) {
+               work = list_entry(slow_work_queue.next,
+                                 struct slow_work, link);
+               if (test_and_set_bit_lock(SLOW_WORK_EXECUTING, &work->flags))
+                       BUG();
+               list_del_init(&work->link);
+               very_slow = false;
+       } else {
+               very_slow = false; /* avoid the compiler warning */
+       }
+       spin_unlock_irq(&slow_work_queue_lock);
+
+       if (!work)
+               return false;
+
+       if (!test_and_clear_bit(SLOW_WORK_PENDING, &work->flags))
+               BUG();
+
+       work->ops->execute(work);
+
+       if (very_slow)
+               atomic_dec(&vslow_work_executing_count);
+       clear_bit_unlock(SLOW_WORK_EXECUTING, &work->flags);
+
+       /* if someone tried to enqueue the item whilst we were executing it,
+        * then it'll be left unenqueued to avoid multiple threads trying to
+        * execute it simultaneously
+        *
+        * there is, however, a race between us testing the pending flag and
+        * getting the spinlock, and between the enqueuer setting the pending
+        * flag and getting the spinlock, so we use a deferral bit to tell us
+        * if the enqueuer got there first
+        */
+       if (test_bit(SLOW_WORK_PENDING, &work->flags)) {
+               spin_lock_irq(&slow_work_queue_lock);
+
+               if (!test_bit(SLOW_WORK_EXECUTING, &work->flags) &&
+                   test_and_clear_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags))
+                       goto auto_requeue;
+
+               spin_unlock_irq(&slow_work_queue_lock);
+       }
+
+       work->ops->put_ref(work);
+       return true;
+
+auto_requeue:
+       /* we must complete the enqueue operation
+        * - we transfer our ref on the item back to the appropriate queue
+        * - don't wake another thread up as we're awake already
+        */
+       if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags))
+               list_add_tail(&work->link, &vslow_work_queue);
+       else
+               list_add_tail(&work->link, &slow_work_queue);
+       spin_unlock_irq(&slow_work_queue_lock);
+       return true;
+}
+
+/**
+ * slow_work_enqueue - Schedule a slow work item for processing
+ * @work: The work item to queue
+ *
+ * Schedule a slow work item for processing.  If the item is already undergoing
+ * execution, this guarantees not to re-enter the execution routine until the
+ * first execution finishes.
+ *
+ * The item is pinned by this function as it retains a reference to it, managed
+ * through the item operations.  The item is unpinned once it has been
+ * executed.
+ *
+ * An item may hog the thread that is running it for a relatively large amount
+ * of time, sufficient, for example, to perform several lookup, mkdir, create
+ * and setxattr operations.  It may sleep on I/O and may sleep to obtain locks.
+ *
+ * Conversely, if a number of items are awaiting processing, it may take some
+ * time before any given item is given attention.  The number of threads in the
+ * pool may be increased to deal with demand, but only up to a limit.
+ *
+ * If SLOW_WORK_VERY_SLOW is set on the work item, then it will be placed in
+ * the very slow queue, from which only a portion of the threads will be
+ * allowed to pick items to execute.  This ensures that very slow items won't
+ * overly block ones that are just ordinarily slow.
+ *
+ * Returns 0 if successful, -EAGAIN if not.
+ */
+int slow_work_enqueue(struct slow_work *work)
+{
+       unsigned long flags;
+
+       BUG_ON(slow_work_user_count <= 0);
+       BUG_ON(!work);
+       BUG_ON(!work->ops);
+       BUG_ON(!work->ops->get_ref);
+
+       /* when honouring an enqueue request, we only promise that we will run
+        * the work function in the future; we do not promise to run it once
+        * per enqueue request
+        *
+        * we use the PENDING bit to merge together repeat requests without
+        * having to disable IRQs and take the spinlock, whilst still
+        * maintaining our promise
+        */
+       if (!test_and_set_bit_lock(SLOW_WORK_PENDING, &work->flags)) {
+               spin_lock_irqsave(&slow_work_queue_lock, flags);
+
+               /* we promise that we will not attempt to execute the work
+                * function in more than one thread simultaneously
+                *
+                * this, however, leaves us with a problem if we're asked to
+                * enqueue the work whilst someone is executing the work
+                * function as simply queueing the work immediately means that
+                * another thread may try executing it whilst it is already
+                * under execution
+                *
+                * to deal with this, we set the ENQ_DEFERRED bit instead of
+                * enqueueing, and the thread currently executing the work
+                * function will enqueue the work item when the work function
+                * returns and it has cleared the EXECUTING bit
+                */
+               if (test_bit(SLOW_WORK_EXECUTING, &work->flags)) {
+                       set_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags);
+               } else {
+                       if (work->ops->get_ref(work) < 0)
+                               goto cant_get_ref;
+                       if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags))
+                               list_add_tail(&work->link, &vslow_work_queue);
+                       else
+                               list_add_tail(&work->link, &slow_work_queue);
+                       wake_up(&slow_work_thread_wq);
+               }
+
+               spin_unlock_irqrestore(&slow_work_queue_lock, flags);
+       }
+       return 0;
+
+cant_get_ref:
+       spin_unlock_irqrestore(&slow_work_queue_lock, flags);
+       return -EAGAIN;
+}
+EXPORT_SYMBOL(slow_work_enqueue);
+
+/*
+ * Worker thread culling algorithm
+ */
+static bool slow_work_cull_thread(void)
+{
+       unsigned long flags;
+       bool do_cull = false;
+
+       spin_lock_irqsave(&slow_work_queue_lock, flags);
+
+       if (slow_work_cull) {
+               slow_work_cull = false;
+
+               if (list_empty(&slow_work_queue) &&
+                   list_empty(&vslow_work_queue) &&
+                   atomic_read(&slow_work_thread_count) >
+                   slow_work_min_threads) {
+                       mod_timer(&slow_work_cull_timer,
+                                 jiffies + SLOW_WORK_CULL_TIMEOUT);
+                       do_cull = true;
+               }
+       }
+
+       spin_unlock_irqrestore(&slow_work_queue_lock, flags);
+       return do_cull;
+}
+
+/*
+ * Determine if there is slow work available for dispatch
+ */
+static inline bool slow_work_available(int vsmax)
+{
+       return !list_empty(&slow_work_queue) ||
+               (!list_empty(&vslow_work_queue) &&
+                atomic_read(&vslow_work_executing_count) < vsmax);
+}
+
+/*
+ * Worker thread dispatcher
+ */
+static int slow_work_thread(void *_data)
+{
+       int vsmax;
+
+       DEFINE_WAIT(wait);
+
+       set_freezable();
+       set_user_nice(current, -5);
+
+       for (;;) {
+               vsmax = vslow_work_proportion;
+               vsmax *= atomic_read(&slow_work_thread_count);
+               vsmax /= 100;
+
+               prepare_to_wait(&slow_work_thread_wq, &wait,
+                               TASK_INTERRUPTIBLE);
+               if (!freezing(current) &&
+                   !slow_work_threads_should_exit &&
+                   !slow_work_available(vsmax) &&
+                   !slow_work_cull)
+                       schedule();
+               finish_wait(&slow_work_thread_wq, &wait);
+
+               try_to_freeze();
+
+               vsmax = vslow_work_proportion;
+               vsmax *= atomic_read(&slow_work_thread_count);
+               vsmax /= 100;
+
+               if (slow_work_available(vsmax) && slow_work_execute()) {
+                       cond_resched();
+                       if (list_empty(&slow_work_queue) &&
+                           list_empty(&vslow_work_queue) &&
+                           atomic_read(&slow_work_thread_count) >
+                           slow_work_min_threads)
+                               mod_timer(&slow_work_cull_timer,
+                                         jiffies + SLOW_WORK_CULL_TIMEOUT);
+                       continue;
+               }
+
+               if (slow_work_threads_should_exit)
+                       break;
+
+               if (slow_work_cull && slow_work_cull_thread())
+                       break;
+       }
+
+       if (atomic_dec_and_test(&slow_work_thread_count))
+               complete_and_exit(&slow_work_last_thread_exited, 0);
+       return 0;
+}
+
+/*
+ * Handle thread cull timer expiration
+ */
+static void slow_work_cull_timeout(unsigned long data)
+{
+       slow_work_cull = true;
+       wake_up(&slow_work_thread_wq);
+}
+
+/*
+ * Get a reference on slow work thread starter
+ */
+static int slow_work_new_thread_get_ref(struct slow_work *work)
+{
+       return 0;
+}
+
+/*
+ * Drop a reference on slow work thread starter
+ */
+static void slow_work_new_thread_put_ref(struct slow_work *work)
+{
+}
+
+/*
+ * Start a new slow work thread
+ */
+static void slow_work_new_thread_execute(struct slow_work *work)
+{
+       struct task_struct *p;
+
+       if (slow_work_threads_should_exit)
+               return;
+
+       if (atomic_read(&slow_work_thread_count) >= slow_work_max_threads)
+               return;
+
+       if (!mutex_trylock(&slow_work_user_lock))
+               return;
+
+       slow_work_may_not_start_new_thread = true;
+       atomic_inc(&slow_work_thread_count);
+       p = kthread_run(slow_work_thread, NULL, "kslowd");
+       if (IS_ERR(p)) {
+               printk(KERN_DEBUG "Slow work thread pool: OOM\n");
+               if (atomic_dec_and_test(&slow_work_thread_count))
+                       BUG(); /* we're running on a slow work thread... */
+               mod_timer(&slow_work_oom_timer,
+                         jiffies + SLOW_WORK_OOM_TIMEOUT);
+       } else {
+               /* ratelimit the starting of new threads */
+               mod_timer(&slow_work_oom_timer, jiffies + 1);
+       }
+
+       mutex_unlock(&slow_work_user_lock);
+}
+
+static const struct slow_work_ops slow_work_new_thread_ops = {
+       .get_ref        = slow_work_new_thread_get_ref,
+       .put_ref        = slow_work_new_thread_put_ref,
+       .execute        = slow_work_new_thread_execute,
+};
+
+/*
+ * post-OOM new thread start suppression expiration
+ */
+static void slow_work_oom_timeout(unsigned long data)
+{
+       slow_work_may_not_start_new_thread = false;
+}
+
+#ifdef CONFIG_SYSCTL
+/*
+ * Handle adjustment of the minimum number of threads
+ */
+static int slow_work_min_threads_sysctl(struct ctl_table *table, int write,
+                                       struct file *filp, void __user *buffer,
+                                       size_t *lenp, loff_t *ppos)
+{
+       int ret = proc_dointvec_minmax(table, write, filp, buffer, lenp, ppos);
+       int n;
+
+       if (ret == 0) {
+               mutex_lock(&slow_work_user_lock);
+               if (slow_work_user_count > 0) {
+                       /* see if we need to start or stop threads */
+                       n = atomic_read(&slow_work_thread_count) -
+                               slow_work_min_threads;
+
+                       if (n < 0 && !slow_work_may_not_start_new_thread)
+                               slow_work_enqueue(&slow_work_new_thread);
+                       else if (n > 0)
+                               mod_timer(&slow_work_cull_timer,
+                                         jiffies + SLOW_WORK_CULL_TIMEOUT);
+               }
+               mutex_unlock(&slow_work_user_lock);
+       }
+
+       return ret;
+}
+
+/*
+ * Handle adjustment of the maximum number of threads
+ */
+static int slow_work_max_threads_sysctl(struct ctl_table *table, int write,
+                                       struct file *filp, void __user *buffer,
+                                       size_t *lenp, loff_t *ppos)
+{
+       int ret = proc_dointvec_minmax(table, write, filp, buffer, lenp, ppos);
+       int n;
+
+       if (ret == 0) {
+               mutex_lock(&slow_work_user_lock);
+               if (slow_work_user_count > 0) {
+                       /* see if we need to stop threads */
+                       n = slow_work_max_threads -
+                               atomic_read(&slow_work_thread_count);
+
+                       if (n < 0)
+                               mod_timer(&slow_work_cull_timer,
+                                         jiffies + SLOW_WORK_CULL_TIMEOUT);
+               }
+               mutex_unlock(&slow_work_user_lock);
+       }
+
+       return ret;
+}
+#endif /* CONFIG_SYSCTL */
+
+/**
+ * slow_work_register_user - Register a user of the facility
+ *
+ * Register a user of the facility, starting up the initial threads if there
+ * aren't any other users at this point.  This will return 0 if successful, or
+ * an error if not.
+ */
+int slow_work_register_user(void)
+{
+       struct task_struct *p;
+       int loop;
+
+       mutex_lock(&slow_work_user_lock);
+
+       if (slow_work_user_count == 0) {
+               printk(KERN_NOTICE "Slow work thread pool: Starting up\n");
+               init_completion(&slow_work_last_thread_exited);
+
+               slow_work_threads_should_exit = false;
+               slow_work_init(&slow_work_new_thread,
+                              &slow_work_new_thread_ops);
+               slow_work_may_not_start_new_thread = false;
+               slow_work_cull = false;
+
+               /* start the minimum number of threads */
+               for (loop = 0; loop < slow_work_min_threads; loop++) {
+                       atomic_inc(&slow_work_thread_count);
+                       p = kthread_run(slow_work_thread, NULL, "kslowd");
+                       if (IS_ERR(p))
+                               goto error;
+               }
+               printk(KERN_NOTICE "Slow work thread pool: Ready\n");
+       }
+
+       slow_work_user_count++;
+       mutex_unlock(&slow_work_user_lock);
+       return 0;
+
+error:
+       if (atomic_dec_and_test(&slow_work_thread_count))
+               complete(&slow_work_last_thread_exited);
+       if (loop > 0) {
+               printk(KERN_ERR "Slow work thread pool:"
+                      " Aborting startup on ENOMEM\n");
+               slow_work_threads_should_exit = true;
+               wake_up_all(&slow_work_thread_wq);
+               wait_for_completion(&slow_work_last_thread_exited);
+               printk(KERN_ERR "Slow work thread pool: Aborted\n");
+       }
+       mutex_unlock(&slow_work_user_lock);
+       return PTR_ERR(p);
+}
+EXPORT_SYMBOL(slow_work_register_user);
+
+/**
+ * slow_work_unregister_user - Unregister a user of the facility
+ *
+ * Unregister a user of the facility, killing all the threads if this was the
+ * last one.
+ */
+void slow_work_unregister_user(void)
+{
+       mutex_lock(&slow_work_user_lock);
+
+       BUG_ON(slow_work_user_count <= 0);
+
+       slow_work_user_count--;
+       if (slow_work_user_count == 0) {
+               printk(KERN_NOTICE "Slow work thread pool: Shutting down\n");
+               slow_work_threads_should_exit = true;
+               wake_up_all(&slow_work_thread_wq);
+               wait_for_completion(&slow_work_last_thread_exited);
+               printk(KERN_NOTICE "Slow work thread pool:"
+                      " Shut down complete\n");
+       }
+
+       del_timer_sync(&slow_work_cull_timer);
+
+       mutex_unlock(&slow_work_user_lock);
+}
+EXPORT_SYMBOL(slow_work_unregister_user);
+
+/*
+ * Initialise the slow work facility
+ */
+static int __init init_slow_work(void)
+{
+       unsigned nr_cpus = num_possible_cpus();
+
+       if (slow_work_max_threads < nr_cpus)
+               slow_work_max_threads = nr_cpus;
+#ifdef CONFIG_SYSCTL
+       if (slow_work_max_max_threads < nr_cpus * 2)
+               slow_work_max_max_threads = nr_cpus * 2;
+#endif
+       return 0;
+}
+
+subsys_initcall(init_slow_work);
index bbedbb7efe32816c2a3e7aba263d077337bc6158..858baac568ee03d96210bcdb69e0e6413aad84af 100644 (file)
@@ -2,40 +2,82 @@
  * Generic helpers for smp ipi calls
  *
  * (C) Jens Axboe <jens.axboe@oracle.com> 2008
- *
  */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/percpu.h>
 #include <linux/rcupdate.h>
 #include <linux/rculist.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/cpu.h>
 
 static DEFINE_PER_CPU(struct call_single_queue, call_single_queue);
-static LIST_HEAD(call_function_queue);
-__cacheline_aligned_in_smp DEFINE_SPINLOCK(call_function_lock);
+
+static struct {
+       struct list_head        queue;
+       spinlock_t              lock;
+} call_function __cacheline_aligned_in_smp =
+       {
+               .queue          = LIST_HEAD_INIT(call_function.queue),
+               .lock           = __SPIN_LOCK_UNLOCKED(call_function.lock),
+       };
 
 enum {
-       CSD_FLAG_WAIT           = 0x01,
-       CSD_FLAG_ALLOC          = 0x02,
-       CSD_FLAG_LOCK           = 0x04,
+       CSD_FLAG_LOCK           = 0x01,
 };
 
 struct call_function_data {
-       struct call_single_data csd;
-       spinlock_t lock;
-       unsigned int refs;
-       struct rcu_head rcu_head;
-       unsigned long cpumask_bits[];
+       struct call_single_data csd;
+       spinlock_t              lock;
+       unsigned int            refs;
+       cpumask_var_t           cpumask;
 };
 
 struct call_single_queue {
-       struct list_head list;
-       spinlock_t lock;
+       struct list_head        list;
+       spinlock_t              lock;
+};
+
+static DEFINE_PER_CPU(struct call_function_data, cfd_data) = {
+       .lock                   = __SPIN_LOCK_UNLOCKED(cfd_data.lock),
+};
+
+static int
+hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+       long cpu = (long)hcpu;
+       struct call_function_data *cfd = &per_cpu(cfd_data, cpu);
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               if (!alloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
+                               cpu_to_node(cpu)))
+                       return NOTIFY_BAD;
+               break;
+
+#ifdef CONFIG_CPU_HOTPLUG
+       case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
+
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               free_cpumask_var(cfd->cpumask);
+               break;
+#endif
+       };
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata hotplug_cfd_notifier = {
+       .notifier_call          = hotplug_cfd,
 };
 
 static int __cpuinit init_call_single_data(void)
 {
+       void *cpu = (void *)(long)smp_processor_id();
        int i;
 
        for_each_possible_cpu(i) {
@@ -44,29 +86,63 @@ static int __cpuinit init_call_single_data(void)
                spin_lock_init(&q->lock);
                INIT_LIST_HEAD(&q->list);
        }
+
+       hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
+       register_cpu_notifier(&hotplug_cfd_notifier);
+
        return 0;
 }
 early_initcall(init_call_single_data);
 
-static void csd_flag_wait(struct call_single_data *data)
+/*
+ * csd_lock/csd_unlock used to serialize access to per-cpu csd resources
+ *
+ * For non-synchronous ipi calls the csd can still be in use by the
+ * previous function call. For multi-cpu calls its even more interesting
+ * as we'll have to ensure no other cpu is observing our csd.
+ */
+static void csd_lock_wait(struct call_single_data *data)
 {
-       /* Wait for response */
-       do {
-               if (!(data->flags & CSD_FLAG_WAIT))
-                       break;
+       while (data->flags & CSD_FLAG_LOCK)
                cpu_relax();
-       } while (1);
+}
+
+static void csd_lock(struct call_single_data *data)
+{
+       csd_lock_wait(data);
+       data->flags = CSD_FLAG_LOCK;
+
+       /*
+        * prevent CPU from reordering the above assignment
+        * to ->flags with any subsequent assignments to other
+        * fields of the specified call_single_data structure:
+        */
+       smp_mb();
+}
+
+static void csd_unlock(struct call_single_data *data)
+{
+       WARN_ON(!(data->flags & CSD_FLAG_LOCK));
+
+       /*
+        * ensure we're all done before releasing data:
+        */
+       smp_mb();
+
+       data->flags &= ~CSD_FLAG_LOCK;
 }
 
 /*
- * Insert a previously allocated call_single_data element for execution
- * on the given CPU. data must already have ->func, ->info, and ->flags set.
+ * Insert a previously allocated call_single_data element
+ * for execution on the given CPU. data must already have
+ * ->func, ->info, and ->flags set.
  */
-static void generic_exec_single(int cpu, struct call_single_data *data)
+static
+void generic_exec_single(int cpu, struct call_single_data *data, int wait)
 {
        struct call_single_queue *dst = &per_cpu(call_single_queue, cpu);
-       int wait = data->flags & CSD_FLAG_WAIT, ipi;
        unsigned long flags;
+       int ipi;
 
        spin_lock_irqsave(&dst->lock, flags);
        ipi = list_empty(&dst->list);
@@ -74,24 +150,21 @@ static void generic_exec_single(int cpu, struct call_single_data *data)
        spin_unlock_irqrestore(&dst->lock, flags);
 
        /*
-        * Make the list addition visible before sending the ipi.
+        * The list addition should be visible before sending the IPI
+        * handler locks the list to pull the entry off it because of
+        * normal cache coherency rules implied by spinlocks.
+        *
+        * If IPIs can go out of order to the cache coherency protocol
+        * in an architecture, sufficient synchronisation should be added
+        * to arch code to make it appear to obey cache coherency WRT
+        * locking and barrier primitives. Generic code isn't really
+        * equipped to do the right thing...
         */
-       smp_mb();
-
        if (ipi)
                arch_send_call_function_single_ipi(cpu);
 
        if (wait)
-               csd_flag_wait(data);
-}
-
-static void rcu_free_call_data(struct rcu_head *head)
-{
-       struct call_function_data *data;
-
-       data = container_of(head, struct call_function_data, rcu_head);
-
-       kfree(data);
+               csd_lock_wait(data);
 }
 
 /*
@@ -104,99 +177,83 @@ void generic_smp_call_function_interrupt(void)
        int cpu = get_cpu();
 
        /*
-        * It's ok to use list_for_each_rcu() here even though we may delete
-        * 'pos', since list_del_rcu() doesn't clear ->next
+        * Ensure entry is visible on call_function_queue after we have
+        * entered the IPI. See comment in smp_call_function_many.
+        * If we don't have this, then we may miss an entry on the list
+        * and never get another IPI to process it.
+        */
+       smp_mb();
+
+       /*
+        * It's ok to use list_for_each_rcu() here even though we may
+        * delete 'pos', since list_del_rcu() doesn't clear ->next
         */
-       rcu_read_lock();
-       list_for_each_entry_rcu(data, &call_function_queue, csd.list) {
+       list_for_each_entry_rcu(data, &call_function.queue, csd.list) {
                int refs;
 
-               if (!cpumask_test_cpu(cpu, to_cpumask(data->cpumask_bits)))
+               spin_lock(&data->lock);
+               if (!cpumask_test_cpu(cpu, data->cpumask)) {
+                       spin_unlock(&data->lock);
                        continue;
+               }
+               cpumask_clear_cpu(cpu, data->cpumask);
+               spin_unlock(&data->lock);
 
                data->csd.func(data->csd.info);
 
                spin_lock(&data->lock);
-               cpumask_clear_cpu(cpu, to_cpumask(data->cpumask_bits));
                WARN_ON(data->refs == 0);
-               data->refs--;
-               refs = data->refs;
+               refs = --data->refs;
+               if (!refs) {
+                       spin_lock(&call_function.lock);
+                       list_del_rcu(&data->csd.list);
+                       spin_unlock(&call_function.lock);
+               }
                spin_unlock(&data->lock);
 
                if (refs)
                        continue;
 
-               spin_lock(&call_function_lock);
-               list_del_rcu(&data->csd.list);
-               spin_unlock(&call_function_lock);
-
-               if (data->csd.flags & CSD_FLAG_WAIT) {
-                       /*
-                        * serialize stores to data with the flag clear
-                        * and wakeup
-                        */
-                       smp_wmb();
-                       data->csd.flags &= ~CSD_FLAG_WAIT;
-               }
-               if (data->csd.flags & CSD_FLAG_ALLOC)
-                       call_rcu(&data->rcu_head, rcu_free_call_data);
+               csd_unlock(&data->csd);
        }
-       rcu_read_unlock();
 
        put_cpu();
 }
 
 /*
- * Invoked by arch to handle an IPI for call function single. Must be called
- * from the arch with interrupts disabled.
+ * Invoked by arch to handle an IPI for call function single. Must be
+ * called from the arch with interrupts disabled.
  */
 void generic_smp_call_function_single_interrupt(void)
 {
        struct call_single_queue *q = &__get_cpu_var(call_single_queue);
+       unsigned int data_flags;
        LIST_HEAD(list);
 
-       /*
-        * Need to see other stores to list head for checking whether
-        * list is empty without holding q->lock
-        */
-       smp_read_barrier_depends();
-       while (!list_empty(&q->list)) {
-               unsigned int data_flags;
-
-               spin_lock(&q->lock);
-               list_replace_init(&q->list, &list);
-               spin_unlock(&q->lock);
-
-               while (!list_empty(&list)) {
-                       struct call_single_data *data;
-
-                       data = list_entry(list.next, struct call_single_data,
-                                               list);
-                       list_del(&data->list);
-
-                       /*
-                        * 'data' can be invalid after this call if
-                        * flags == 0 (when called through
-                        * generic_exec_single(), so save them away before
-                        * making the call.
-                        */
-                       data_flags = data->flags;
-
-                       data->func(data->info);
-
-                       if (data_flags & CSD_FLAG_WAIT) {
-                               smp_wmb();
-                               data->flags &= ~CSD_FLAG_WAIT;
-                       } else if (data_flags & CSD_FLAG_LOCK) {
-                               smp_wmb();
-                               data->flags &= ~CSD_FLAG_LOCK;
-                       } else if (data_flags & CSD_FLAG_ALLOC)
-                               kfree(data);
-               }
+       spin_lock(&q->lock);
+       list_replace_init(&q->list, &list);
+       spin_unlock(&q->lock);
+
+       while (!list_empty(&list)) {
+               struct call_single_data *data;
+
+               data = list_entry(list.next, struct call_single_data, list);
+               list_del(&data->list);
+
+               /*
+                * 'data' can be invalid after this call if flags == 0
+                * (when called through generic_exec_single()),
+                * so save them away before making the call:
+                */
+               data_flags = data->flags;
+
+               data->func(data->info);
+
                /*
-                * See comment on outer loop
+                * Unlocked CSDs are valid through generic_exec_single():
                 */
-               smp_read_barrier_depends();
+               if (data_flags & CSD_FLAG_LOCK)
+                       csd_unlock(data);
        }
 }
 
@@ -215,65 +272,45 @@ static DEFINE_PER_CPU(struct call_single_data, csd_data);
 int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
                             int wait)
 {
-       struct call_single_data d;
+       struct call_single_data d = {
+               .flags = 0,
+       };
        unsigned long flags;
-       /* prevent preemption and reschedule on another processor,
-          as well as CPU removal */
-       int me = get_cpu();
+       int this_cpu;
        int err = 0;
 
+       /*
+        * prevent preemption and reschedule on another processor,
+        * as well as CPU removal
+        */
+       this_cpu = get_cpu();
+
        /* Can deadlock when called with interrupts disabled */
-       WARN_ON(irqs_disabled());
+       WARN_ON_ONCE(irqs_disabled() && !oops_in_progress);
 
-       if (cpu == me) {
+       if (cpu == this_cpu) {
                local_irq_save(flags);
                func(info);
                local_irq_restore(flags);
-       } else if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
-               struct call_single_data *data;
+       } else {
+               if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
+                       struct call_single_data *data = &d;
+
+                       if (!wait)
+                               data = &__get_cpu_var(csd_data);
 
-               if (!wait) {
-                       /*
-                        * We are calling a function on a single CPU
-                        * and we are not going to wait for it to finish.
-                        * We first try to allocate the data, but if we
-                        * fail, we fall back to use a per cpu data to pass
-                        * the information to that CPU. Since all callers
-                        * of this code will use the same data, we must
-                        * synchronize the callers to prevent a new caller
-                        * from corrupting the data before the callee
-                        * can access it.
-                        *
-                        * The CSD_FLAG_LOCK is used to let us know when
-                        * the IPI handler is done with the data.
-                        * The first caller will set it, and the callee
-                        * will clear it. The next caller must wait for
-                        * it to clear before we set it again. This
-                        * will make sure the callee is done with the
-                        * data before a new caller will use it.
-                        */
-                       data = kmalloc(sizeof(*data), GFP_ATOMIC);
-                       if (data)
-                               data->flags = CSD_FLAG_ALLOC;
-                       else {
-                               data = &per_cpu(csd_data, me);
-                               while (data->flags & CSD_FLAG_LOCK)
-                                       cpu_relax();
-                               data->flags = CSD_FLAG_LOCK;
-                       }
+                       csd_lock(data);
+
+                       data->func = func;
+                       data->info = info;
+                       generic_exec_single(cpu, data, wait);
                } else {
-                       data = &d;
-                       data->flags = CSD_FLAG_WAIT;
+                       err = -ENXIO;   /* CPU not online */
                }
-
-               data->func = func;
-               data->info = info;
-               generic_exec_single(cpu, data);
-       } else {
-               err = -ENXIO;   /* CPU not online */
        }
 
        put_cpu();
+
        return err;
 }
 EXPORT_SYMBOL(smp_call_function_single);
@@ -283,23 +320,26 @@ EXPORT_SYMBOL(smp_call_function_single);
  * @cpu: The CPU to run on.
  * @data: Pre-allocated and setup data structure
  *
- * Like smp_call_function_single(), but allow caller to pass in a pre-allocated
- * data structure. Useful for embedding @data inside other structures, for
- * instance.
- *
+ * Like smp_call_function_single(), but allow caller to pass in a
+ * pre-allocated data structure. Useful for embedding @data inside
+ * other structures, for instance.
  */
-void __smp_call_function_single(int cpu, struct call_single_data *data)
+void __smp_call_function_single(int cpu, struct call_single_data *data,
+                               int wait)
 {
+       csd_lock(data);
+
        /* Can deadlock when called with interrupts disabled */
-       WARN_ON((data->flags & CSD_FLAG_WAIT) && irqs_disabled());
+       WARN_ON_ONCE(wait && irqs_disabled() && !oops_in_progress);
 
-       generic_exec_single(cpu, data);
+       generic_exec_single(cpu, data, wait);
 }
 
-/* FIXME: Shim for archs using old arch_send_call_function_ipi API. */
+/* Deprecated: shim for archs using old arch_send_call_function_ipi API. */
+
 #ifndef arch_send_call_function_ipi_mask
-#define arch_send_call_function_ipi_mask(maskp) \
-       arch_send_call_function_ipi(*(maskp))
+# define arch_send_call_function_ipi_mask(maskp) \
+        arch_send_call_function_ipi(*(maskp))
 #endif
 
 /**
@@ -307,7 +347,8 @@ void __smp_call_function_single(int cpu, struct call_single_data *data)
  * @mask: The set of cpus to run on (only runs on online subset).
  * @func: The function to run. This must be fast and non-blocking.
  * @info: An arbitrary pointer to pass to the function.
- * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ * @wait: If true, wait (atomically) until function has completed
+ *        on other CPUs.
  *
  * If @wait is true, then returns once @func has returned. Note that @wait
  * will be implicitly turned on in case of allocation failures, since
@@ -318,27 +359,27 @@ void __smp_call_function_single(int cpu, struct call_single_data *data)
  * must be disabled when calling this function.
  */
 void smp_call_function_many(const struct cpumask *mask,
-                           void (*func)(void *), void *info,
-                           bool wait)
+                           void (*func)(void *), void *info, bool wait)
 {
        struct call_function_data *data;
        unsigned long flags;
-       int cpu, next_cpu;
+       int cpu, next_cpu, this_cpu = smp_processor_id();
 
        /* Can deadlock when called with interrupts disabled */
-       WARN_ON(irqs_disabled());
+       WARN_ON_ONCE(irqs_disabled() && !oops_in_progress);
 
-       /* So, what's a CPU they want?  Ignoring this one. */
+       /* So, what's a CPU they want? Ignoring this one. */
        cpu = cpumask_first_and(mask, cpu_online_mask);
-       if (cpu == smp_processor_id())
+       if (cpu == this_cpu)
                cpu = cpumask_next_and(cpu, mask, cpu_online_mask);
+
        /* No online cpus?  We're done. */
        if (cpu >= nr_cpu_ids)
                return;
 
        /* Do we have another CPU which isn't us? */
        next_cpu = cpumask_next_and(cpu, mask, cpu_online_mask);
-       if (next_cpu == smp_processor_id())
+       if (next_cpu == this_cpu)
                next_cpu = cpumask_next_and(next_cpu, mask, cpu_online_mask);
 
        /* Fastpath: do that cpu by itself. */
@@ -347,43 +388,40 @@ void smp_call_function_many(const struct cpumask *mask,
                return;
        }
 
-       data = kmalloc(sizeof(*data) + cpumask_size(), GFP_ATOMIC);
-       if (unlikely(!data)) {
-               /* Slow path. */
-               for_each_online_cpu(cpu) {
-                       if (cpu == smp_processor_id())
-                               continue;
-                       if (cpumask_test_cpu(cpu, mask))
-                               smp_call_function_single(cpu, func, info, wait);
-               }
-               return;
-       }
+       data = &__get_cpu_var(cfd_data);
+       csd_lock(&data->csd);
 
-       spin_lock_init(&data->lock);
-       data->csd.flags = CSD_FLAG_ALLOC;
-       if (wait)
-               data->csd.flags |= CSD_FLAG_WAIT;
+       spin_lock_irqsave(&data->lock, flags);
        data->csd.func = func;
        data->csd.info = info;
-       cpumask_and(to_cpumask(data->cpumask_bits), mask, cpu_online_mask);
-       cpumask_clear_cpu(smp_processor_id(), to_cpumask(data->cpumask_bits));
-       data->refs = cpumask_weight(to_cpumask(data->cpumask_bits));
+       cpumask_and(data->cpumask, mask, cpu_online_mask);
+       cpumask_clear_cpu(this_cpu, data->cpumask);
+       data->refs = cpumask_weight(data->cpumask);
 
-       spin_lock_irqsave(&call_function_lock, flags);
-       list_add_tail_rcu(&data->csd.list, &call_function_queue);
-       spin_unlock_irqrestore(&call_function_lock, flags);
+       spin_lock(&call_function.lock);
+       /*
+        * Place entry at the _HEAD_ of the list, so that any cpu still
+        * observing the entry in generic_smp_call_function_interrupt()
+        * will not miss any other list entries:
+        */
+       list_add_rcu(&data->csd.list, &call_function.queue);
+       spin_unlock(&call_function.lock);
+
+       spin_unlock_irqrestore(&data->lock, flags);
 
        /*
         * Make the list addition visible before sending the ipi.
+        * (IPIs must obey or appear to obey normal Linux cache
+        * coherency rules -- see comment in generic_exec_single).
         */
        smp_mb();
 
        /* Send a message to all CPUs in the map */
-       arch_send_call_function_ipi_mask(to_cpumask(data->cpumask_bits));
+       arch_send_call_function_ipi_mask(data->cpumask);
 
-       /* optionally wait for the CPUs to complete */
+       /* Optionally wait for the CPUs to complete */
        if (wait)
-               csd_flag_wait(&data->csd);
+               csd_lock_wait(&data->csd);
 }
 EXPORT_SYMBOL(smp_call_function_many);
 
@@ -391,7 +429,8 @@ EXPORT_SYMBOL(smp_call_function_many);
  * smp_call_function(): Run a function on all other CPUs.
  * @func: The function to run. This must be fast and non-blocking.
  * @info: An arbitrary pointer to pass to the function.
- * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ * @wait: If true, wait (atomically) until function has completed
+ *        on other CPUs.
  *
  * Returns 0.
  *
@@ -407,26 +446,27 @@ int smp_call_function(void (*func)(void *), void *info, int wait)
        preempt_disable();
        smp_call_function_many(cpu_online_mask, func, info, wait);
        preempt_enable();
+
        return 0;
 }
 EXPORT_SYMBOL(smp_call_function);
 
 void ipi_call_lock(void)
 {
-       spin_lock(&call_function_lock);
+       spin_lock(&call_function.lock);
 }
 
 void ipi_call_unlock(void)
 {
-       spin_unlock(&call_function_lock);
+       spin_unlock(&call_function.lock);
 }
 
 void ipi_call_lock_irq(void)
 {
-       spin_lock_irq(&call_function_lock);
+       spin_lock_irq(&call_function.lock);
 }
 
 void ipi_call_unlock_irq(void)
 {
-       spin_unlock_irq(&call_function_lock);
+       spin_unlock_irq(&call_function.lock);
 }
index 57d3f67f6f38af7fdfb0fad66ff1cdbef790951e..ea23ec087ee9cc8a799db243a45838e8306c156e 100644 (file)
@@ -180,7 +180,7 @@ asmlinkage void __do_softirq(void)
        account_system_vtime(current);
 
        __local_bh_disable((unsigned long)__builtin_return_address(0));
-       trace_softirq_enter();
+       lockdep_softirq_enter();
 
        cpu = smp_processor_id();
 restart:
@@ -220,7 +220,7 @@ restart:
        if (pending)
                wakeup_softirqd();
 
-       trace_softirq_exit();
+       lockdep_softirq_exit();
 
        account_system_vtime(current);
        _local_bh_enable();
@@ -496,7 +496,7 @@ static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softir
                cp->flags = 0;
                cp->priv = softirq;
 
-               __smp_call_function_single(cpu, cp);
+               __smp_call_function_single(cpu, cp, 0);
                return 0;
        }
        return 1;
index 29ab20749dd3da1df6bd6f03f5cdbf62ed9ae52e..7932653c4ebde88e7010ec1da9601ef974e8c3bb 100644 (file)
@@ -121,7 +121,8 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
        local_irq_save(flags);
        preempt_disable();
        rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
-       LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
+       LOCK_CONTENDED_FLAGS(lock, _raw_read_trylock, _raw_read_lock,
+                            _raw_read_lock_flags, &flags);
        return flags;
 }
 EXPORT_SYMBOL(_read_lock_irqsave);
@@ -151,7 +152,8 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
        local_irq_save(flags);
        preempt_disable();
        rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
+       LOCK_CONTENDED_FLAGS(lock, _raw_write_trylock, _raw_write_lock,
+                            _raw_write_lock_flags, &flags);
        return flags;
 }
 EXPORT_SYMBOL(_write_lock_irqsave);
@@ -299,16 +301,8 @@ unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclas
        local_irq_save(flags);
        preempt_disable();
        spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
-       /*
-        * On lockdep we dont want the hand-coded irq-enable of
-        * _raw_spin_lock_flags() code, because lockdep assumes
-        * that interrupts are not re-enabled during lock-acquire:
-        */
-#ifdef CONFIG_LOCKDEP
-       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
-#else
-       _raw_spin_lock_flags(lock, &flags);
-#endif
+       LOCK_CONTENDED_FLAGS(lock, _raw_spin_trylock, _raw_spin_lock,
+                               _raw_spin_lock_flags, &flags);
        return flags;
 }
 EXPORT_SYMBOL(_spin_lock_irqsave_nested);
index 74541ca49536fda5dab61d473f8ce9d6aa3f3254..912823e2a11b0afb0f4448e5163bb9e39c7fc8b8 100644 (file)
@@ -44,7 +44,7 @@ static DEFINE_MUTEX(setup_lock);
 static int refcount;
 static struct workqueue_struct *stop_machine_wq;
 static struct stop_machine_data active, idle;
-static const cpumask_t *active_cpus;
+static const struct cpumask *active_cpus;
 static void *stop_machine_work;
 
 static void set_state(enum stopmachine_state newstate)
index 37f458e6882adbd1f2b0697e5077c92e4252e03f..51dbb55604e847991023697267d26c9216497ce7 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
 #include <linux/ptrace.h>
+#include <linux/fs_struct.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -1013,10 +1014,8 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)
        if (err)
                goto out;
 
-       if (task_pgrp(p) != pgrp) {
+       if (task_pgrp(p) != pgrp)
                change_pid(p, PIDTYPE_PGID, pgrp);
-               set_task_pgrp(p, pid_nr(pgrp));
-       }
 
        err = 0;
 out:
index c5ef44ff850f5af111943d76a5484318d6a5bc35..82350f8f04f61a276cfaedbd0ca7fb5e1ffea378 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/acpi.h>
 #include <linux/reboot.h>
 #include <linux/ftrace.h>
+#include <linux/slow-work.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -95,12 +96,9 @@ static int sixty = 60;
 static int neg_one = -1;
 #endif
 
-#if defined(CONFIG_MMU) && defined(CONFIG_FILE_LOCKING)
-static int two = 2;
-#endif
-
 static int zero;
 static int one = 1;
+static int two = 2;
 static unsigned long one_ul = 1;
 static int one_hundred = 100;
 
@@ -900,6 +898,14 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &scan_unevictable_handler,
        },
 #endif
+#ifdef CONFIG_SLOW_WORK
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "slow-work",
+               .mode           = 0555,
+               .child          = slow_work_sysctls,
+       },
+#endif
 /*
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
@@ -1010,7 +1016,7 @@ static struct ctl_table vm_table[] = {
                .data           = &dirty_expire_interval,
                .maxlen         = sizeof(dirty_expire_interval),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_userhz_jiffies,
+               .proc_handler   = &proc_dointvec,
        },
        {
                .ctl_name       = VM_NR_PDFLUSH_THREADS,
@@ -1373,10 +1379,7 @@ static struct ctl_table fs_table[] = {
                .data           = &lease_break_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
-               .extra1         = &zero,
-               .extra2         = &two,
+               .proc_handler   = &proc_dointvec,
        },
 #endif
 #ifdef CONFIG_AIO
@@ -1417,7 +1420,10 @@ static struct ctl_table fs_table[] = {
                .data           = &suid_dumpable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &two,
        },
 #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
        {
index 9b77fc9a9ac8286074b1784771dac7c0eb2a08e2..b4555568b4e4ad16f34a887eabed6f21e05abfba 100644 (file)
@@ -491,14 +491,18 @@ static inline void debug_timer_free(struct timer_list *timer)
        debug_object_free(timer, &timer_debug_descr);
 }
 
-static void __init_timer(struct timer_list *timer);
+static void __init_timer(struct timer_list *timer,
+                        const char *name,
+                        struct lock_class_key *key);
 
-void init_timer_on_stack(struct timer_list *timer)
+void init_timer_on_stack_key(struct timer_list *timer,
+                            const char *name,
+                            struct lock_class_key *key)
 {
        debug_object_init_on_stack(timer, &timer_debug_descr);
-       __init_timer(timer);
+       __init_timer(timer, name, key);
 }
-EXPORT_SYMBOL_GPL(init_timer_on_stack);
+EXPORT_SYMBOL_GPL(init_timer_on_stack_key);
 
 void destroy_timer_on_stack(struct timer_list *timer)
 {
@@ -512,7 +516,9 @@ static inline void debug_timer_activate(struct timer_list *timer) { }
 static inline void debug_timer_deactivate(struct timer_list *timer) { }
 #endif
 
-static void __init_timer(struct timer_list *timer)
+static void __init_timer(struct timer_list *timer,
+                        const char *name,
+                        struct lock_class_key *key)
 {
        timer->entry.next = NULL;
        timer->base = __raw_get_cpu_var(tvec_bases);
@@ -521,6 +527,7 @@ static void __init_timer(struct timer_list *timer)
        timer->start_pid = -1;
        memset(timer->start_comm, 0, TASK_COMM_LEN);
 #endif
+       lockdep_init_map(&timer->lockdep_map, name, key, 0);
 }
 
 /**
@@ -530,19 +537,23 @@ static void __init_timer(struct timer_list *timer)
  * init_timer() must be done to a timer prior calling *any* of the
  * other timer functions.
  */
-void init_timer(struct timer_list *timer)
+void init_timer_key(struct timer_list *timer,
+                   const char *name,
+                   struct lock_class_key *key)
 {
        debug_timer_init(timer);
-       __init_timer(timer);
+       __init_timer(timer, name, key);
 }
-EXPORT_SYMBOL(init_timer);
+EXPORT_SYMBOL(init_timer_key);
 
-void init_timer_deferrable(struct timer_list *timer)
+void init_timer_deferrable_key(struct timer_list *timer,
+                              const char *name,
+                              struct lock_class_key *key)
 {
-       init_timer(timer);
+       init_timer_key(timer, name, key);
        timer_set_deferrable(timer);
 }
-EXPORT_SYMBOL(init_timer_deferrable);
+EXPORT_SYMBOL(init_timer_deferrable_key);
 
 static inline void detach_timer(struct timer_list *timer,
                                int clear_pending)
@@ -826,6 +837,15 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
  */
 int del_timer_sync(struct timer_list *timer)
 {
+#ifdef CONFIG_LOCKDEP
+       unsigned long flags;
+
+       local_irq_save(flags);
+       lock_map_acquire(&timer->lockdep_map);
+       lock_map_release(&timer->lockdep_map);
+       local_irq_restore(flags);
+#endif
+
        for (;;) {
                int ret = try_to_del_timer_sync(timer);
                if (ret >= 0)
@@ -897,10 +917,36 @@ static inline void __run_timers(struct tvec_base *base)
 
                        set_running_timer(base, timer);
                        detach_timer(timer, 1);
+
                        spin_unlock_irq(&base->lock);
                        {
                                int preempt_count = preempt_count();
+
+#ifdef CONFIG_LOCKDEP
+                               /*
+                                * It is permissible to free the timer from
+                                * inside the function that is called from
+                                * it, this we need to take into account for
+                                * lockdep too. To avoid bogus "held lock
+                                * freed" warnings as well as problems when
+                                * looking into timer->lockdep_map, make a
+                                * copy and use that here.
+                                */
+                               struct lockdep_map lockdep_map =
+                                       timer->lockdep_map;
+#endif
+                               /*
+                                * Couple the lock chain with the lock chain at
+                                * del_timer_sync() by acquiring the lock_map
+                                * around the fn() call here and in
+                                * del_timer_sync().
+                                */
+                               lock_map_acquire(&lockdep_map);
+
                                fn(data);
+
+                               lock_map_release(&lockdep_map);
+
                                if (preempt_count != preempt_count()) {
                                        printk(KERN_ERR "huh, entered %p "
                                               "with preempt_count %08x, exited"
index 34e707e5ab87f002ab93f0eb70e776cb09704354..504086ab4443ab2f844b887fc4de94445ac91e03 100644 (file)
@@ -72,11 +72,10 @@ config FUNCTION_GRAPH_TRACER
        help
          Enable the kernel to trace a function at both its return
          and its entry.
-         It's first purpose is to trace the duration of functions and
-         draw a call graph for each thread with some informations like
-         the return value.
-         This is done by setting the current return address on the current
-         task structure into a stack of calls.
+         Its first purpose is to trace the duration of functions and
+         draw a call graph for each thread with some information like
+         the return value. This is done by setting the current return 
+         address on the current task structure into a stack of calls.
 
 config IRQSOFF_TRACER
        bool "Interrupts-off Latency Tracer"
index fdf913dfc7e8eada7de16b320b62d283b18447a5..53e8c8bc0c985f29afa9740664ed020a3fb0b62b 100644 (file)
@@ -1908,7 +1908,7 @@ int register_ftrace_function(struct ftrace_ops *ops)
 }
 
 /**
- * unregister_ftrace_function - unresgister a function for profiling.
+ * unregister_ftrace_function - unregister a function for profiling.
  * @ops - ops structure that holds the function to unregister
  *
  * Unregister a function that was added to be called by ftrace profiling.
index 3b34b3545936dfcd179eca7f9fd2aebf4a2abfa0..92359cc747a7c52cb85e362ab3b9178e4756ee2d 100644 (file)
@@ -37,7 +37,7 @@ static void put_uts(ctl_table *table, int write, void *which)
                up_write(&uts_sem);
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
 /*
  *     Special case of dostring for the UTS structure. This has locks
  *     to observe. Should this be in kernel/sys.c ????
index 1f0c509b40d34d944bea77e300e237ab9145439c..32f8e0d2bf5ad2d629b63432e654f2948949420a 100644 (file)
@@ -48,8 +48,6 @@ struct cpu_workqueue_struct {
 
        struct workqueue_struct *wq;
        struct task_struct *thread;
-
-       int run_depth;          /* Detect run_workqueue() recursion depth */
 } ____cacheline_aligned;
 
 /*
@@ -262,13 +260,6 @@ EXPORT_SYMBOL_GPL(queue_delayed_work_on);
 static void run_workqueue(struct cpu_workqueue_struct *cwq)
 {
        spin_lock_irq(&cwq->lock);
-       cwq->run_depth++;
-       if (cwq->run_depth > 3) {
-               /* morton gets to eat his hat */
-               printk("%s: recursion depth exceeded: %d\n",
-                       __func__, cwq->run_depth);
-               dump_stack();
-       }
        while (!list_empty(&cwq->worklist)) {
                struct work_struct *work = list_entry(cwq->worklist.next,
                                                struct work_struct, entry);
@@ -311,7 +302,6 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
                spin_lock_irq(&cwq->lock);
                cwq->current_work = NULL;
        }
-       cwq->run_depth--;
        spin_unlock_irq(&cwq->lock);
 }
 
@@ -368,29 +358,20 @@ static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
 
 static int flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
 {
-       int active;
+       int active = 0;
+       struct wq_barrier barr;
 
-       if (cwq->thread == current) {
-               /*
-                * Probably keventd trying to flush its own queue. So simply run
-                * it by hand rather than deadlocking.
-                */
-               run_workqueue(cwq);
-               active = 1;
-       } else {
-               struct wq_barrier barr;
+       WARN_ON(cwq->thread == current);
 
-               active = 0;
-               spin_lock_irq(&cwq->lock);
-               if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
-                       insert_wq_barrier(cwq, &barr, &cwq->worklist);
-                       active = 1;
-               }
-               spin_unlock_irq(&cwq->lock);
-
-               if (active)
-                       wait_for_completion(&barr.done);
+       spin_lock_irq(&cwq->lock);
+       if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
+               insert_wq_barrier(cwq, &barr, &cwq->worklist);
+               active = 1;
        }
+       spin_unlock_irq(&cwq->lock);
+
+       if (active)
+               wait_for_completion(&barr.done);
 
        return active;
 }
@@ -416,7 +397,7 @@ void flush_workqueue(struct workqueue_struct *wq)
        might_sleep();
        lock_map_acquire(&wq->lockdep_map);
        lock_map_release(&wq->lockdep_map);
-       for_each_cpu_mask_nr(cpu, *cpu_map)
+       for_each_cpu(cpu, cpu_map)
                flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
 }
 EXPORT_SYMBOL_GPL(flush_workqueue);
@@ -547,7 +528,7 @@ static void wait_on_work(struct work_struct *work)
        wq = cwq->wq;
        cpu_map = wq_cpu_map(wq);
 
-       for_each_cpu_mask_nr(cpu, *cpu_map)
+       for_each_cpu(cpu, cpu_map)
                wait_on_cpu_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
 }
 
@@ -911,7 +892,7 @@ void destroy_workqueue(struct workqueue_struct *wq)
        list_del(&wq->list);
        spin_unlock(&workqueue_lock);
 
-       for_each_cpu_mask_nr(cpu, *cpu_map)
+       for_each_cpu(cpu, cpu_map)
                cleanup_workqueue_thread(per_cpu_ptr(wq->cpu_wq, cpu));
        cpu_maps_update_done();
 
index 58bfe7e8faba0a6d94307945702ac298891497c4..9638d99644afe4b5ff04d4ac8fcd194d1b67f614 100644 (file)
@@ -796,6 +796,7 @@ config SYSCTL_SYSCALL_CHECK
          to properly maintain and use. This enables checks that help
          you to keep things correct.
 
+source mm/Kconfig.debug
 source kernel/trace/Kconfig
 
 config PROVIDE_OHCI1394_DMA_INIT
index 3389e2440da0f30a76d49ab63f3419bce857849b..1f71b97de0f945e9cd59c264e87c1148aa74cf33 100644 (file)
@@ -109,10 +109,10 @@ bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node)
 #endif
        /* FIXME: Bandaid to save us from old primitives which go to NR_CPUS. */
        if (*mask) {
+               unsigned char *ptr = (unsigned char *)cpumask_bits(*mask);
                unsigned int tail;
                tail = BITS_TO_LONGS(NR_CPUS - nr_cpumask_bits) * sizeof(long);
-               memset(cpumask_bits(*mask) + cpumask_size() - tail,
-                      0, tail);
+               memset(ptr + cpumask_size() - tail, 0, tail);
        }
 
        return *mask != NULL;
index 1a992089486c614ed55497318801ac49e3d53c1b..d3da7edc034f7c60496056332850458b849a4f61 100644 (file)
@@ -648,7 +648,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
                err_printk(dev, NULL, "DMA-API: device driver tries "
                                "to sync DMA memory it has not allocated "
                                "[device address=0x%016llx] [size=%llu bytes]\n",
-                               addr, size);
+                               (unsigned long long)addr, size);
                goto out;
        }
 
@@ -666,7 +666,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
                                "DMA memory with different direction "
                                "[device address=0x%016llx] [size=%llu bytes] "
                                "[mapped with %s] [synced with %s]\n",
-                               addr, entry->size,
+                               (unsigned long long)addr, entry->size,
                                dir2name[entry->direction],
                                dir2name[direction]);
        }
@@ -680,7 +680,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
                                "device read-only DMA memory for cpu "
                                "[device address=0x%016llx] [size=%llu bytes] "
                                "[mapped with %s] [synced with %s]\n",
-                               addr, entry->size,
+                               (unsigned long long)addr, entry->size,
                                dir2name[entry->direction],
                                dir2name[direction]);
 
@@ -690,7 +690,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
                                "device write-only DMA memory to device "
                                "[device address=0x%016llx] [size=%llu bytes] "
                                "[mapped with %s] [synced with %s]\n",
-                               addr, entry->size,
+                               (unsigned long long)addr, entry->size,
                                dir2name[entry->direction],
                                dir2name[direction]);
 
index dab4bca86f5d1981027c0be5104a69ce7d05fbe9..80ca9aca038be447573b8130cbc22c1133f34867 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -578,6 +578,52 @@ int idr_for_each(struct idr *idp,
 }
 EXPORT_SYMBOL(idr_for_each);
 
+/**
+ * idr_get_next - lookup next object of id to given id.
+ * @idp: idr handle
+ * @id:  pointer to lookup key
+ *
+ * Returns pointer to registered object with id, which is next number to
+ * given id.
+ */
+
+void *idr_get_next(struct idr *idp, int *nextidp)
+{
+       struct idr_layer *p, *pa[MAX_LEVEL];
+       struct idr_layer **paa = &pa[0];
+       int id = *nextidp;
+       int n, max;
+
+       /* find first ent */
+       n = idp->layers * IDR_BITS;
+       max = 1 << n;
+       p = rcu_dereference(idp->top);
+       if (!p)
+               return NULL;
+
+       while (id < max) {
+               while (n > 0 && p) {
+                       n -= IDR_BITS;
+                       *paa++ = p;
+                       p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
+               }
+
+               if (p) {
+                       *nextidp = id;
+                       return p;
+               }
+
+               id += 1 << n;
+               while (n < fls(id)) {
+                       n += IDR_BITS;
+                       p = *--paa;
+               }
+       }
+       return NULL;
+}
+
+
+
 /**
  * idr_replace - replace pointer for given id
  * @idp: idr handle
index 280332c1827cbb7b1d183e349f8eb1ba35cd2f8e..619313ed6c46d78ef7b35a6ab870bfd764376486 100644 (file)
@@ -157,11 +157,11 @@ static void init_shared_classes(void)
 #define SOFTIRQ_ENTER()                                \
                local_bh_disable();             \
                local_irq_disable();            \
-               trace_softirq_enter();          \
+               lockdep_softirq_enter();        \
                WARN_ON(!in_softirq());
 
 #define SOFTIRQ_EXIT()                         \
-               trace_softirq_exit();           \
+               lockdep_softirq_exit();         \
                local_irq_enable();             \
                local_bh_enable();
 
index 9956b99649f02af0667666e098449f9df38d26b4..f653659e0bc1fb161525332d775c973e2fb0ba98 100644 (file)
@@ -163,17 +163,14 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
                        {
                                if (!other->rb_right || rb_is_black(other->rb_right))
                                {
-                                       struct rb_node *o_left;
-                                       if ((o_left = other->rb_left))
-                                               rb_set_black(o_left);
+                                       rb_set_black(other->rb_left);
                                        rb_set_red(other);
                                        __rb_rotate_right(other, root);
                                        other = parent->rb_right;
                                }
                                rb_set_color(other, rb_color(parent));
                                rb_set_black(parent);
-                               if (other->rb_right)
-                                       rb_set_black(other->rb_right);
+                               rb_set_black(other->rb_right);
                                __rb_rotate_left(parent, root);
                                node = root->rb_node;
                                break;
@@ -200,17 +197,14 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
                        {
                                if (!other->rb_left || rb_is_black(other->rb_left))
                                {
-                                       register struct rb_node *o_right;
-                                       if ((o_right = other->rb_right))
-                                               rb_set_black(o_right);
+                                       rb_set_black(other->rb_right);
                                        rb_set_red(other);
                                        __rb_rotate_left(other, root);
                                        other = parent->rb_left;
                                }
                                rb_set_color(other, rb_color(parent));
                                rb_set_black(parent);
-                               if (other->rb_left)
-                                       rb_set_black(other->rb_left);
+                               rb_set_black(other->rb_left);
                                __rb_rotate_right(parent, root);
                                node = root->rb_node;
                                break;
index a5b77811fdf2c4b5f6b14a8d971a6519f6e420c6..b53427ad30a34618e6c8da34ffcc540a581de552 100644 (file)
@@ -206,7 +206,6 @@ config VIRT_TO_BUS
 config UNEVICTABLE_LRU
        bool "Add LRU list to track non-evictable pages"
        default y
-       depends on MMU
        help
          Keeps unevictable pages off of the active and inactive pageout
          lists, so kswapd will not waste CPU time or have its balancing
@@ -214,5 +213,13 @@ config UNEVICTABLE_LRU
          will use one page flag and increase the code size a little,
          say Y unless you know what you are doing.
 
+config HAVE_MLOCK
+       bool
+       default y if MMU=y
+
+config HAVE_MLOCKED_PAGE_BIT
+       bool
+       default y if HAVE_MLOCK=y && UNEVICTABLE_LRU=y
+
 config MMU_NOTIFIER
        bool
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
new file mode 100644 (file)
index 0000000..bb01e29
--- /dev/null
@@ -0,0 +1,26 @@
+config DEBUG_PAGEALLOC
+       bool "Debug page memory allocations"
+       depends on DEBUG_KERNEL && ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       depends on !HIBERNATION || !PPC && !SPARC
+       ---help---
+         Unmap pages from the kernel linear mapping after free_pages().
+         This results in a large slowdown, but helps to find certain types
+         of memory corruptions.
+
+config WANT_PAGE_DEBUG_FLAGS
+       bool
+
+config PAGE_POISONING
+       bool "Debug page memory allocations"
+       depends on DEBUG_KERNEL && !ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       depends on !HIBERNATION
+       select DEBUG_PAGEALLOC
+       select WANT_PAGE_DEBUG_FLAGS
+       help
+          Fill the pages with poison patterns after free_pages() and verify
+          the patterns before alloc_pages(). This results in a large slowdown,
+          but helps to find certain types of memory corruptions.
+
+          This option cannot enalbe with hibernation. Otherwise, it will get
+          wrong messages for memory corruption because the free pages are not
+          saved to the suspend image.
index 818569b68f4652e623f5d2bd4ed91fe68fcea2b4..ec73c68b601547680e6b1f49df5462b093a7e278 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
 obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
 obj-$(CONFIG_SLOB) += slob.o
 obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
+obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
 obj-$(CONFIG_SLAB) += slab.o
 obj-$(CONFIG_SLUB) += slub.o
 obj-$(CONFIG_FAILSLAB) += failslab.o
index 1882923bc706071b79f823dd17b8f69d4fccf145..139d5b7b6621471ccb88c2ea3dd6b0fe66b15618 100644 (file)
@@ -143,7 +143,7 @@ void free_percpu(void *__pdata)
 {
        if (unlikely(!__pdata))
                return;
-       __percpu_depopulate_mask(__pdata, &cpu_possible_map);
+       __percpu_depopulate_mask(__pdata, cpu_possible_mask);
        kfree(__percpu_disguise(__pdata));
 }
 EXPORT_SYMBOL_GPL(free_percpu);
diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c
new file mode 100644 (file)
index 0000000..a1e3324
--- /dev/null
@@ -0,0 +1,129 @@
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/page-debug-flags.h>
+#include <linux/poison.h>
+
+static inline void set_page_poison(struct page *page)
+{
+       __set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
+}
+
+static inline void clear_page_poison(struct page *page)
+{
+       __clear_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
+}
+
+static inline bool page_poison(struct page *page)
+{
+       return test_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
+}
+
+static void poison_highpage(struct page *page)
+{
+       /*
+        * Page poisoning for highmem pages is not implemented.
+        *
+        * This can be called from interrupt contexts.
+        * So we need to create a new kmap_atomic slot for this
+        * application and it will need interrupt protection.
+        */
+}
+
+static void poison_page(struct page *page)
+{
+       void *addr;
+
+       if (PageHighMem(page)) {
+               poison_highpage(page);
+               return;
+       }
+       set_page_poison(page);
+       addr = page_address(page);
+       memset(addr, PAGE_POISON, PAGE_SIZE);
+}
+
+static void poison_pages(struct page *page, int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               poison_page(page + i);
+}
+
+static bool single_bit_flip(unsigned char a, unsigned char b)
+{
+       unsigned char error = a ^ b;
+
+       return error && !(error & (error - 1));
+}
+
+static void check_poison_mem(unsigned char *mem, size_t bytes)
+{
+       unsigned char *start;
+       unsigned char *end;
+
+       for (start = mem; start < mem + bytes; start++) {
+               if (*start != PAGE_POISON)
+                       break;
+       }
+       if (start == mem + bytes)
+               return;
+
+       for (end = mem + bytes - 1; end > start; end--) {
+               if (*end != PAGE_POISON)
+                       break;
+       }
+
+       if (!printk_ratelimit())
+               return;
+       else if (start == end && single_bit_flip(*start, PAGE_POISON))
+               printk(KERN_ERR "pagealloc: single bit error\n");
+       else
+               printk(KERN_ERR "pagealloc: memory corruption\n");
+
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
+                       end - start + 1, 1);
+       dump_stack();
+}
+
+static void unpoison_highpage(struct page *page)
+{
+       /*
+        * See comment in poison_highpage().
+        * Highmem pages should not be poisoned for now
+        */
+       BUG_ON(page_poison(page));
+}
+
+static void unpoison_page(struct page *page)
+{
+       if (PageHighMem(page)) {
+               unpoison_highpage(page);
+               return;
+       }
+       if (page_poison(page)) {
+               void *addr = page_address(page);
+
+               check_poison_mem(addr, PAGE_SIZE);
+               clear_page_poison(page);
+       }
+}
+
+static void unpoison_pages(struct page *page, int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               unpoison_page(page + i);
+}
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+       if (!debug_pagealloc_enabled)
+               return;
+
+       if (enable)
+               unpoison_pages(page, numpages);
+       else
+               poison_pages(page, numpages);
+}
index 126d3973b3d1f3be7a3f5e4f42630725c796f31f..fc11974f2bee5ea0d39941f3dfce8b0b84910579 100644 (file)
@@ -564,6 +564,24 @@ void wait_on_page_bit(struct page *page, int bit_nr)
 }
 EXPORT_SYMBOL(wait_on_page_bit);
 
+/**
+ * add_page_wait_queue - Add an arbitrary waiter to a page's wait queue
+ * @page - Page defining the wait queue of interest
+ * @waiter - Waiter to add to the queue
+ *
+ * Add an arbitrary @waiter to the wait queue for the nominated @page.
+ */
+void add_page_wait_queue(struct page *page, wait_queue_t *waiter)
+{
+       wait_queue_head_t *q = page_waitqueue(page);
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->lock, flags);
+       __add_wait_queue(q, waiter);
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL_GPL(add_page_wait_queue);
+
 /**
  * unlock_page - unlock a locked page
  * @page: the page
@@ -2463,6 +2481,9 @@ EXPORT_SYMBOL(generic_file_aio_write);
  * (presumably at page->private).  If the release was successful, return `1'.
  * Otherwise return zero.
  *
+ * This may also be called if PG_fscache is set on a page, indicating that the
+ * page is known to the local caching routines.
+ *
  * The @gfp_mask argument specifies whether I/O may be performed to release
  * this page (__GFP_IO), and whether the call may block (__GFP_WAIT & __GFP_FS).
  *
index 0c04615651b7e8b412e85cdeee26365ddee7515c..427dfe3ce78c68eebe0afde4636b6fdc91ecdec5 100644 (file)
@@ -89,8 +89,8 @@ do_xip_mapping_read(struct address_space *mapping,
                        }
                }
                nr = nr - offset;
-               if (nr > len)
-                       nr = len;
+               if (nr > len - copied)
+                       nr = len - copied;
 
                error = mapping->a_ops->get_xip_mem(mapping, index, 0,
                                                        &xip_mem, &xip_pfn);
index 910198037bf59baa6649a75d1d632203483aa22b..68eb1d9b63fa5daba881a8b6551fa38f8e0eabfc 100644 (file)
@@ -422,3 +422,48 @@ void __init page_address_init(void)
 }
 
 #endif /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */
+
+#if defined(CONFIG_DEBUG_HIGHMEM) && defined(CONFIG_TRACE_IRQFLAGS_SUPPORT)
+
+void debug_kmap_atomic(enum km_type type)
+{
+       static unsigned warn_count = 10;
+
+       if (unlikely(warn_count == 0))
+               return;
+
+       if (unlikely(in_interrupt())) {
+               if (in_irq()) {
+                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
+                           type != KM_BIO_SRC_IRQ && type != KM_BIO_DST_IRQ &&
+                           type != KM_BOUNCE_READ) {
+                               WARN_ON(1);
+                               warn_count--;
+                       }
+               } else if (!irqs_disabled()) {  /* softirq */
+                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
+                           type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
+                           type != KM_SKB_SUNRPC_DATA &&
+                           type != KM_SKB_DATA_SOFTIRQ &&
+                           type != KM_BOUNCE_READ) {
+                               WARN_ON(1);
+                               warn_count--;
+                       }
+               }
+       }
+
+       if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
+                       type == KM_BIO_SRC_IRQ || type == KM_BIO_DST_IRQ) {
+               if (!irqs_disabled()) {
+                       WARN_ON(1);
+                       warn_count--;
+               }
+       } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
+               if (irq_count() == 0 && !irqs_disabled()) {
+                       WARN_ON(1);
+                       warn_count--;
+               }
+       }
+}
+
+#endif
index 107da3d809a87b0ad13e57256a050763a0b3d17b..28c655ba935396bb14a73957cb07ac58cb5e63fa 100644 (file)
@@ -918,7 +918,7 @@ static void return_unused_surplus_pages(struct hstate *h,
  * an instantiated the change should be committed via vma_commit_reservation.
  * No action is required on failure.
  */
-static int vma_needs_reservation(struct hstate *h,
+static long vma_needs_reservation(struct hstate *h,
                        struct vm_area_struct *vma, unsigned long addr)
 {
        struct address_space *mapping = vma->vm_file->f_mapping;
@@ -933,7 +933,7 @@ static int vma_needs_reservation(struct hstate *h,
                return 1;
 
        } else  {
-               int err;
+               long err;
                pgoff_t idx = vma_hugecache_offset(h, vma, addr);
                struct resv_map *reservations = vma_resv_map(vma);
 
@@ -969,7 +969,7 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
        struct page *page;
        struct address_space *mapping = vma->vm_file->f_mapping;
        struct inode *inode = mapping->host;
-       unsigned int chg;
+       long chg;
 
        /*
         * Processes that did not create the mapping will have no reserves and
index 478223b73a2ab22c4c6b62acf2a693f889b60367..987bb03fbdd88f33f36986b6ecbb33f02a62c6e2 100644 (file)
@@ -63,6 +63,7 @@ static inline unsigned long page_order(struct page *page)
        return page_private(page);
 }
 
+#ifdef CONFIG_HAVE_MLOCK
 extern long mlock_vma_pages_range(struct vm_area_struct *vma,
                        unsigned long start, unsigned long end);
 extern void munlock_vma_pages_range(struct vm_area_struct *vma,
@@ -71,6 +72,7 @@ static inline void munlock_vma_pages_all(struct vm_area_struct *vma)
 {
        munlock_vma_pages_range(vma, vma->vm_start, vma->vm_end);
 }
+#endif
 
 #ifdef CONFIG_UNEVICTABLE_LRU
 /*
@@ -90,7 +92,7 @@ static inline void unevictable_migrate_page(struct page *new, struct page *old)
 }
 #endif
 
-#ifdef CONFIG_UNEVICTABLE_LRU
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
 /*
  * Called only in fault path via page_evictable() for a new page
  * to determine if it's being mapped into a LOCKED vma.
@@ -165,7 +167,7 @@ static inline void free_page_mlock(struct page *page)
        }
 }
 
-#else /* CONFIG_UNEVICTABLE_LRU */
+#else /* CONFIG_HAVE_MLOCKED_PAGE_BIT */
 static inline int is_mlocked_vma(struct vm_area_struct *v, struct page *p)
 {
        return 0;
@@ -175,7 +177,7 @@ static inline void mlock_vma_page(struct page *page) { }
 static inline void mlock_migrate_page(struct page *new, struct page *old) { }
 static inline void free_page_mlock(struct page *page) { }
 
-#endif /* CONFIG_UNEVICTABLE_LRU */
+#endif /* CONFIG_HAVE_MLOCKED_PAGE_BIT */
 
 /*
  * Return the mem_map entry representing the 'offset' subpage within
index 8e4be9cb2a6a7642601516e3587d151dcea586f4..2fc6d6c482387ed35a735746bf4580d3d38e68da 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/backing-dev.h>
 #include <linux/bit_spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/limits.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
@@ -95,6 +96,15 @@ static s64 mem_cgroup_read_stat(struct mem_cgroup_stat *stat,
        return ret;
 }
 
+static s64 mem_cgroup_local_usage(struct mem_cgroup_stat *stat)
+{
+       s64 ret;
+
+       ret = mem_cgroup_read_stat(stat, MEM_CGROUP_STAT_CACHE);
+       ret += mem_cgroup_read_stat(stat, MEM_CGROUP_STAT_RSS);
+       return ret;
+}
+
 /*
  * per-zone information in memory controller.
  */
@@ -154,9 +164,9 @@ struct mem_cgroup {
 
        /*
         * While reclaiming in a hiearchy, we cache the last child we
-        * reclaimed from. Protected by hierarchy_mutex
+        * reclaimed from.
         */
-       struct mem_cgroup *last_scanned_child;
+       int last_scanned_child;
        /*
         * Should the accounting and control be hierarchical, per subtree?
         */
@@ -247,7 +257,7 @@ page_cgroup_zoneinfo(struct page_cgroup *pc)
        return mem_cgroup_zoneinfo(mem, nid, zid);
 }
 
-static unsigned long mem_cgroup_get_all_zonestat(struct mem_cgroup *mem,
+static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem,
                                        enum lru_list idx)
 {
        int nid, zid;
@@ -286,6 +296,9 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
 static struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
 {
        struct mem_cgroup *mem = NULL;
+
+       if (!mm)
+               return NULL;
        /*
         * Because we have no locks, mm->owner's may be being moved to other
         * cgroup. We use css_tryget() here even if this looks
@@ -308,6 +321,42 @@ static bool mem_cgroup_is_obsolete(struct mem_cgroup *mem)
        return css_is_removed(&mem->css);
 }
 
+
+/*
+ * Call callback function against all cgroup under hierarchy tree.
+ */
+static int mem_cgroup_walk_tree(struct mem_cgroup *root, void *data,
+                         int (*func)(struct mem_cgroup *, void *))
+{
+       int found, ret, nextid;
+       struct cgroup_subsys_state *css;
+       struct mem_cgroup *mem;
+
+       if (!root->use_hierarchy)
+               return (*func)(root, data);
+
+       nextid = 1;
+       do {
+               ret = 0;
+               mem = NULL;
+
+               rcu_read_lock();
+               css = css_get_next(&mem_cgroup_subsys, nextid, &root->css,
+                                  &found);
+               if (css && css_tryget(css))
+                       mem = container_of(css, struct mem_cgroup, css);
+               rcu_read_unlock();
+
+               if (mem) {
+                       ret = (*func)(mem, data);
+                       css_put(&mem->css);
+               }
+               nextid = found + 1;
+       } while (!ret && css);
+
+       return ret;
+}
+
 /*
  * Following LRU functions are allowed to be used without PCG_LOCK.
  * Operations are called by routine of global LRU independently from memcg.
@@ -441,30 +490,23 @@ void mem_cgroup_move_lists(struct page *page,
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem)
 {
        int ret;
+       struct mem_cgroup *curr = NULL;
 
        task_lock(task);
-       ret = task->mm && mm_match_cgroup(task->mm, mem);
+       rcu_read_lock();
+       curr = try_get_mem_cgroup_from_mm(task->mm);
+       rcu_read_unlock();
        task_unlock(task);
+       if (!curr)
+               return 0;
+       if (curr->use_hierarchy)
+               ret = css_is_ancestor(&curr->css, &mem->css);
+       else
+               ret = (curr == mem);
+       css_put(&curr->css);
        return ret;
 }
 
-/*
- * Calculate mapped_ratio under memory controller. This will be used in
- * vmscan.c for deteremining we have to reclaim mapped pages.
- */
-int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem)
-{
-       long total, rss;
-
-       /*
-        * usage is recorded in bytes. But, here, we assume the number of
-        * physical pages can be represented by "long" on any arch.
-        */
-       total = (long) (mem->res.usage >> PAGE_SHIFT) + 1L;
-       rss = (long)mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
-       return (int)((rss * 100L) / total);
-}
-
 /*
  * prev_priority control...this will be used in memory reclaim path.
  */
@@ -501,8 +543,8 @@ static int calc_inactive_ratio(struct mem_cgroup *memcg, unsigned long *present_
        unsigned long gb;
        unsigned long inactive_ratio;
 
-       inactive = mem_cgroup_get_all_zonestat(memcg, LRU_INACTIVE_ANON);
-       active = mem_cgroup_get_all_zonestat(memcg, LRU_ACTIVE_ANON);
+       inactive = mem_cgroup_get_local_zonestat(memcg, LRU_INACTIVE_ANON);
+       active = mem_cgroup_get_local_zonestat(memcg, LRU_ACTIVE_ANON);
 
        gb = (inactive + active) >> (30 - PAGE_SHIFT);
        if (gb)
@@ -629,172 +671,202 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
 #define mem_cgroup_from_res_counter(counter, member)   \
        container_of(counter, struct mem_cgroup, member)
 
-/*
- * This routine finds the DFS walk successor. This routine should be
- * called with hierarchy_mutex held
- */
-static struct mem_cgroup *
-__mem_cgroup_get_next_node(struct mem_cgroup *curr, struct mem_cgroup *root_mem)
+static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
 {
-       struct cgroup *cgroup, *curr_cgroup, *root_cgroup;
-
-       curr_cgroup = curr->css.cgroup;
-       root_cgroup = root_mem->css.cgroup;
+       if (do_swap_account) {
+               if (res_counter_check_under_limit(&mem->res) &&
+                       res_counter_check_under_limit(&mem->memsw))
+                       return true;
+       } else
+               if (res_counter_check_under_limit(&mem->res))
+                       return true;
+       return false;
+}
 
-       if (!list_empty(&curr_cgroup->children)) {
-               /*
-                * Walk down to children
-                */
-               cgroup = list_entry(curr_cgroup->children.next,
-                                               struct cgroup, sibling);
-               curr = mem_cgroup_from_cont(cgroup);
-               goto done;
-       }
+static unsigned int get_swappiness(struct mem_cgroup *memcg)
+{
+       struct cgroup *cgrp = memcg->css.cgroup;
+       unsigned int swappiness;
 
-visit_parent:
-       if (curr_cgroup == root_cgroup) {
-               /* caller handles NULL case */
-               curr = NULL;
-               goto done;
-       }
+       /* root ? */
+       if (cgrp->parent == NULL)
+               return vm_swappiness;
 
-       /*
-        * Goto next sibling
-        */
-       if (curr_cgroup->sibling.next != &curr_cgroup->parent->children) {
-               cgroup = list_entry(curr_cgroup->sibling.next, struct cgroup,
-                                               sibling);
-               curr = mem_cgroup_from_cont(cgroup);
-               goto done;
-       }
+       spin_lock(&memcg->reclaim_param_lock);
+       swappiness = memcg->swappiness;
+       spin_unlock(&memcg->reclaim_param_lock);
 
-       /*
-        * Go up to next parent and next parent's sibling if need be
-        */
-       curr_cgroup = curr_cgroup->parent;
-       goto visit_parent;
+       return swappiness;
+}
 
-done:
-       return curr;
+static int mem_cgroup_count_children_cb(struct mem_cgroup *mem, void *data)
+{
+       int *val = data;
+       (*val)++;
+       return 0;
 }
 
-/*
- * Visit the first child (need not be the first child as per the ordering
- * of the cgroup list, since we track last_scanned_child) of @mem and use
- * that to reclaim free pages from.
+/**
+ * mem_cgroup_print_mem_info: Called from OOM with tasklist_lock held in read mode.
+ * @memcg: The memory cgroup that went over limit
+ * @p: Task that is going to be killed
+ *
+ * NOTE: @memcg and @p's mem_cgroup can be different when hierarchy is
+ * enabled
  */
-static struct mem_cgroup *
-mem_cgroup_get_next_node(struct mem_cgroup *root_mem)
+void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
 {
-       struct cgroup *cgroup;
-       struct mem_cgroup *orig, *next;
-       bool obsolete;
-
+       struct cgroup *task_cgrp;
+       struct cgroup *mem_cgrp;
        /*
-        * Scan all children under the mem_cgroup mem
+        * Need a buffer in BSS, can't rely on allocations. The code relies
+        * on the assumption that OOM is serialized for memory controller.
+        * If this assumption is broken, revisit this code.
         */
-       mutex_lock(&mem_cgroup_subsys.hierarchy_mutex);
+       static char memcg_name[PATH_MAX];
+       int ret;
+
+       if (!memcg)
+               return;
 
-       orig = root_mem->last_scanned_child;
-       obsolete = mem_cgroup_is_obsolete(orig);
 
-       if (list_empty(&root_mem->css.cgroup->children)) {
+       rcu_read_lock();
+
+       mem_cgrp = memcg->css.cgroup;
+       task_cgrp = task_cgroup(p, mem_cgroup_subsys_id);
+
+       ret = cgroup_path(task_cgrp, memcg_name, PATH_MAX);
+       if (ret < 0) {
                /*
-                * root_mem might have children before and last_scanned_child
-                * may point to one of them. We put it later.
+                * Unfortunately, we are unable to convert to a useful name
+                * But we'll still print out the usage information
                 */
-               if (orig)
-                       VM_BUG_ON(!obsolete);
-               next = NULL;
+               rcu_read_unlock();
                goto done;
        }
+       rcu_read_unlock();
 
-       if (!orig || obsolete) {
-               cgroup = list_first_entry(&root_mem->css.cgroup->children,
-                               struct cgroup, sibling);
-               next = mem_cgroup_from_cont(cgroup);
-       } else
-               next = __mem_cgroup_get_next_node(orig, root_mem);
+       printk(KERN_INFO "Task in %s killed", memcg_name);
 
+       rcu_read_lock();
+       ret = cgroup_path(mem_cgrp, memcg_name, PATH_MAX);
+       if (ret < 0) {
+               rcu_read_unlock();
+               goto done;
+       }
+       rcu_read_unlock();
+
+       /*
+        * Continues from above, so we don't need an KERN_ level
+        */
+       printk(KERN_CONT " as a result of limit of %s\n", memcg_name);
 done:
-       if (next)
-               mem_cgroup_get(next);
-       root_mem->last_scanned_child = next;
-       if (orig)
-               mem_cgroup_put(orig);
-       mutex_unlock(&mem_cgroup_subsys.hierarchy_mutex);
-       return (next) ? next : root_mem;
+
+       printk(KERN_INFO "memory: usage %llukB, limit %llukB, failcnt %llu\n",
+               res_counter_read_u64(&memcg->res, RES_USAGE) >> 10,
+               res_counter_read_u64(&memcg->res, RES_LIMIT) >> 10,
+               res_counter_read_u64(&memcg->res, RES_FAILCNT));
+       printk(KERN_INFO "memory+swap: usage %llukB, limit %llukB, "
+               "failcnt %llu\n",
+               res_counter_read_u64(&memcg->memsw, RES_USAGE) >> 10,
+               res_counter_read_u64(&memcg->memsw, RES_LIMIT) >> 10,
+               res_counter_read_u64(&memcg->memsw, RES_FAILCNT));
 }
 
-static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
+/*
+ * This function returns the number of memcg under hierarchy tree. Returns
+ * 1(self count) if no children.
+ */
+static int mem_cgroup_count_children(struct mem_cgroup *mem)
 {
-       if (do_swap_account) {
-               if (res_counter_check_under_limit(&mem->res) &&
-                       res_counter_check_under_limit(&mem->memsw))
-                       return true;
-       } else
-               if (res_counter_check_under_limit(&mem->res))
-                       return true;
-       return false;
+       int num = 0;
+       mem_cgroup_walk_tree(mem, &num, mem_cgroup_count_children_cb);
+       return num;
 }
 
-static unsigned int get_swappiness(struct mem_cgroup *memcg)
+/*
+ * Visit the first child (need not be the first child as per the ordering
+ * of the cgroup list, since we track last_scanned_child) of @mem and use
+ * that to reclaim free pages from.
+ */
+static struct mem_cgroup *
+mem_cgroup_select_victim(struct mem_cgroup *root_mem)
 {
-       struct cgroup *cgrp = memcg->css.cgroup;
-       unsigned int swappiness;
+       struct mem_cgroup *ret = NULL;
+       struct cgroup_subsys_state *css;
+       int nextid, found;
 
-       /* root ? */
-       if (cgrp->parent == NULL)
-               return vm_swappiness;
+       if (!root_mem->use_hierarchy) {
+               css_get(&root_mem->css);
+               ret = root_mem;
+       }
 
-       spin_lock(&memcg->reclaim_param_lock);
-       swappiness = memcg->swappiness;
-       spin_unlock(&memcg->reclaim_param_lock);
+       while (!ret) {
+               rcu_read_lock();
+               nextid = root_mem->last_scanned_child + 1;
+               css = css_get_next(&mem_cgroup_subsys, nextid, &root_mem->css,
+                                  &found);
+               if (css && css_tryget(css))
+                       ret = container_of(css, struct mem_cgroup, css);
+
+               rcu_read_unlock();
+               /* Updates scanning parameter */
+               spin_lock(&root_mem->reclaim_param_lock);
+               if (!css) {
+                       /* this means start scan from ID:1 */
+                       root_mem->last_scanned_child = 0;
+               } else
+                       root_mem->last_scanned_child = found;
+               spin_unlock(&root_mem->reclaim_param_lock);
+       }
 
-       return swappiness;
+       return ret;
 }
 
 /*
- * Dance down the hierarchy if needed to reclaim memory. We remember the
- * last child we reclaimed from, so that we don't end up penalizing
- * one child extensively based on its position in the children list.
+ * Scan the hierarchy if needed to reclaim memory. We remember the last child
+ * we reclaimed from, so that we don't end up penalizing one child extensively
+ * based on its position in the children list.
  *
  * root_mem is the original ancestor that we've been reclaim from.
+ *
+ * We give up and return to the caller when we visit root_mem twice.
+ * (other groups can be removed while we're walking....)
+ *
+ * If shrink==true, for avoiding to free too much, this returns immedieately.
  */
 static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
-                                               gfp_t gfp_mask, bool noswap)
-{
-       struct mem_cgroup *next_mem;
-       int ret = 0;
-
-       /*
-        * Reclaim unconditionally and don't check for return value.
-        * We need to reclaim in the current group and down the tree.
-        * One might think about checking for children before reclaiming,
-        * but there might be left over accounting, even after children
-        * have left.
-        */
-       ret += try_to_free_mem_cgroup_pages(root_mem, gfp_mask, noswap,
-                                          get_swappiness(root_mem));
-       if (mem_cgroup_check_under_limit(root_mem))
-               return 1;       /* indicate reclaim has succeeded */
-       if (!root_mem->use_hierarchy)
-               return ret;
-
-       next_mem = mem_cgroup_get_next_node(root_mem);
-
-       while (next_mem != root_mem) {
-               if (mem_cgroup_is_obsolete(next_mem)) {
-                       next_mem = mem_cgroup_get_next_node(root_mem);
+                                  gfp_t gfp_mask, bool noswap, bool shrink)
+{
+       struct mem_cgroup *victim;
+       int ret, total = 0;
+       int loop = 0;
+
+       while (loop < 2) {
+               victim = mem_cgroup_select_victim(root_mem);
+               if (victim == root_mem)
+                       loop++;
+               if (!mem_cgroup_local_usage(&victim->stat)) {
+                       /* this cgroup's local usage == 0 */
+                       css_put(&victim->css);
                        continue;
                }
-               ret += try_to_free_mem_cgroup_pages(next_mem, gfp_mask, noswap,
-                                                  get_swappiness(next_mem));
+               /* we use swappiness of local cgroup */
+               ret = try_to_free_mem_cgroup_pages(victim, gfp_mask, noswap,
+                                                  get_swappiness(victim));
+               css_put(&victim->css);
+               /*
+                * At shrinking usage, we can't check we should stop here or
+                * reclaim more. It's depends on callers. last_scanned_child
+                * will work enough for keeping fairness under tree.
+                */
+               if (shrink)
+                       return ret;
+               total += ret;
                if (mem_cgroup_check_under_limit(root_mem))
-                       return 1;       /* indicate reclaim has succeeded */
-               next_mem = mem_cgroup_get_next_node(root_mem);
+                       return 1 + total;
        }
-       return ret;
+       return total;
 }
 
 bool mem_cgroup_oom_called(struct task_struct *task)
@@ -813,6 +885,19 @@ bool mem_cgroup_oom_called(struct task_struct *task)
        rcu_read_unlock();
        return ret;
 }
+
+static int record_last_oom_cb(struct mem_cgroup *mem, void *data)
+{
+       mem->last_oom_jiffies = jiffies;
+       return 0;
+}
+
+static void record_last_oom(struct mem_cgroup *mem)
+{
+       mem_cgroup_walk_tree(mem, NULL, record_last_oom_cb);
+}
+
+
 /*
  * Unlike exported interface, "oom" parameter is added. if oom==true,
  * oom-killer can be invoked.
@@ -875,7 +960,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                        goto nomem;
 
                ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, gfp_mask,
-                                                       noswap);
+                                                       noswap, false);
                if (ret)
                        continue;
 
@@ -895,7 +980,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                                mutex_lock(&memcg_tasklist);
                                mem_cgroup_out_of_memory(mem_over_limit, gfp_mask);
                                mutex_unlock(&memcg_tasklist);
-                               mem_over_limit->last_oom_jiffies = jiffies;
+                               record_last_oom(mem_over_limit);
                        }
                        goto nomem;
                }
@@ -906,20 +991,55 @@ nomem:
        return -ENOMEM;
 }
 
+
+/*
+ * A helper function to get mem_cgroup from ID. must be called under
+ * rcu_read_lock(). The caller must check css_is_removed() or some if
+ * it's concern. (dropping refcnt from swap can be called against removed
+ * memcg.)
+ */
+static struct mem_cgroup *mem_cgroup_lookup(unsigned short id)
+{
+       struct cgroup_subsys_state *css;
+
+       /* ID 0 is unused ID */
+       if (!id)
+               return NULL;
+       css = css_lookup(&mem_cgroup_subsys, id);
+       if (!css)
+               return NULL;
+       return container_of(css, struct mem_cgroup, css);
+}
+
 static struct mem_cgroup *try_get_mem_cgroup_from_swapcache(struct page *page)
 {
        struct mem_cgroup *mem;
+       struct page_cgroup *pc;
+       unsigned short id;
        swp_entry_t ent;
 
+       VM_BUG_ON(!PageLocked(page));
+
        if (!PageSwapCache(page))
                return NULL;
 
-       ent.val = page_private(page);
-       mem = lookup_swap_cgroup(ent);
-       if (!mem)
-               return NULL;
-       if (!css_tryget(&mem->css))
-               return NULL;
+       pc = lookup_page_cgroup(page);
+       /*
+        * Used bit of swapcache is solid under page lock.
+        */
+       if (PageCgroupUsed(pc)) {
+               mem = pc->mem_cgroup;
+               if (mem && !css_tryget(&mem->css))
+                       mem = NULL;
+       } else {
+               ent.val = page_private(page);
+               id = lookup_swap_cgroup(ent);
+               rcu_read_lock();
+               mem = mem_cgroup_lookup(id);
+               if (mem && !css_tryget(&mem->css))
+                       mem = NULL;
+               rcu_read_unlock();
+       }
        return mem;
 }
 
@@ -1118,6 +1238,10 @@ int mem_cgroup_newpage_charge(struct page *page,
                                MEM_CGROUP_CHARGE_TYPE_MAPPED, NULL);
 }
 
+static void
+__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
+                                       enum charge_type ctype);
+
 int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask)
 {
@@ -1154,16 +1278,6 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                unlock_page_cgroup(pc);
        }
 
-       if (do_swap_account && PageSwapCache(page)) {
-               mem = try_get_mem_cgroup_from_swapcache(page);
-               if (mem)
-                       mm = NULL;
-                 else
-                       mem = NULL;
-               /* SwapCache may be still linked to LRU now. */
-               mem_cgroup_lru_del_before_commit_swapcache(page);
-       }
-
        if (unlikely(!mm && !mem))
                mm = &init_mm;
 
@@ -1171,22 +1285,16 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                return mem_cgroup_charge_common(page, mm, gfp_mask,
                                MEM_CGROUP_CHARGE_TYPE_CACHE, NULL);
 
-       ret = mem_cgroup_charge_common(page, mm, gfp_mask,
-                               MEM_CGROUP_CHARGE_TYPE_SHMEM, mem);
-       if (mem)
-               css_put(&mem->css);
-       if (PageSwapCache(page))
-               mem_cgroup_lru_add_after_commit_swapcache(page);
+       /* shmem */
+       if (PageSwapCache(page)) {
+               ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &mem);
+               if (!ret)
+                       __mem_cgroup_commit_charge_swapin(page, mem,
+                                       MEM_CGROUP_CHARGE_TYPE_SHMEM);
+       } else
+               ret = mem_cgroup_charge_common(page, mm, gfp_mask,
+                                       MEM_CGROUP_CHARGE_TYPE_SHMEM, mem);
 
-       if (do_swap_account && !ret && PageSwapCache(page)) {
-               swp_entry_t ent = {.val = page_private(page)};
-               /* avoid double counting */
-               mem = swap_cgroup_record(ent, NULL);
-               if (mem) {
-                       res_counter_uncharge(&mem->memsw, PAGE_SIZE);
-                       mem_cgroup_put(mem);
-               }
-       }
        return ret;
 }
 
@@ -1229,7 +1337,9 @@ charge_cur_mm:
        return __mem_cgroup_try_charge(mm, mask, ptr, true);
 }
 
-void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
+static void
+__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
+                                       enum charge_type ctype)
 {
        struct page_cgroup *pc;
 
@@ -1239,7 +1349,7 @@ void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
                return;
        pc = lookup_page_cgroup(page);
        mem_cgroup_lru_del_before_commit_swapcache(page);
-       __mem_cgroup_commit_charge(ptr, pc, MEM_CGROUP_CHARGE_TYPE_MAPPED);
+       __mem_cgroup_commit_charge(ptr, pc, ctype);
        mem_cgroup_lru_add_after_commit_swapcache(page);
        /*
         * Now swap is on-memory. This means this page may be
@@ -1250,18 +1360,32 @@ void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
         */
        if (do_swap_account && PageSwapCache(page)) {
                swp_entry_t ent = {.val = page_private(page)};
+               unsigned short id;
                struct mem_cgroup *memcg;
-               memcg = swap_cgroup_record(ent, NULL);
+
+               id = swap_cgroup_record(ent, 0);
+               rcu_read_lock();
+               memcg = mem_cgroup_lookup(id);
                if (memcg) {
+                       /*
+                        * This recorded memcg can be obsolete one. So, avoid
+                        * calling css_tryget
+                        */
                        res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
                        mem_cgroup_put(memcg);
                }
-
+               rcu_read_unlock();
        }
        /* add this page(page_cgroup) to the LRU we want. */
 
 }
 
+void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
+{
+       __mem_cgroup_commit_charge_swapin(page, ptr,
+                                       MEM_CGROUP_CHARGE_TYPE_MAPPED);
+}
+
 void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *mem)
 {
        if (mem_cgroup_disabled())
@@ -1324,8 +1448,8 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
        res_counter_uncharge(&mem->res, PAGE_SIZE);
        if (do_swap_account && (ctype != MEM_CGROUP_CHARGE_TYPE_SWAPOUT))
                res_counter_uncharge(&mem->memsw, PAGE_SIZE);
-
        mem_cgroup_charge_statistics(mem, pc, false);
+
        ClearPageCgroupUsed(pc);
        /*
         * pc->mem_cgroup is not cleared here. It will be accessed when it's
@@ -1377,7 +1501,7 @@ void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
                                        MEM_CGROUP_CHARGE_TYPE_SWAPOUT);
        /* record memcg information */
        if (do_swap_account && memcg) {
-               swap_cgroup_record(ent, memcg);
+               swap_cgroup_record(ent, css_id(&memcg->css));
                mem_cgroup_get(memcg);
        }
        if (memcg)
@@ -1392,15 +1516,23 @@ void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
 void mem_cgroup_uncharge_swap(swp_entry_t ent)
 {
        struct mem_cgroup *memcg;
+       unsigned short id;
 
        if (!do_swap_account)
                return;
 
-       memcg = swap_cgroup_record(ent, NULL);
+       id = swap_cgroup_record(ent, 0);
+       rcu_read_lock();
+       memcg = mem_cgroup_lookup(id);
        if (memcg) {
+               /*
+                * We uncharge this because swap is freed.
+                * This memcg can be obsolete one. We avoid calling css_tryget
+                */
                res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
                mem_cgroup_put(memcg);
        }
+       rcu_read_unlock();
 }
 #endif
 
@@ -1508,7 +1640,8 @@ int mem_cgroup_shrink_usage(struct page *page,
                return 0;
 
        do {
-               progress = mem_cgroup_hierarchical_reclaim(mem, gfp_mask, true);
+               progress = mem_cgroup_hierarchical_reclaim(mem,
+                                       gfp_mask, true, false);
                progress += mem_cgroup_check_under_limit(mem);
        } while (!progress && --retry);
 
@@ -1523,11 +1656,21 @@ static DEFINE_MUTEX(set_limit_mutex);
 static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                                unsigned long long val)
 {
-
-       int retry_count = MEM_CGROUP_RECLAIM_RETRIES;
+       int retry_count;
        int progress;
        u64 memswlimit;
        int ret = 0;
+       int children = mem_cgroup_count_children(memcg);
+       u64 curusage, oldusage;
+
+       /*
+        * For keeping hierarchical_reclaim simple, how long we should retry
+        * is depends on callers. We set our retry-count to be function
+        * of # of children which we should visit in this loop.
+        */
+       retry_count = MEM_CGROUP_RECLAIM_RETRIES * children;
+
+       oldusage = res_counter_read_u64(&memcg->res, RES_USAGE);
 
        while (retry_count) {
                if (signal_pending(current)) {
@@ -1553,8 +1696,13 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                        break;
 
                progress = mem_cgroup_hierarchical_reclaim(memcg, GFP_KERNEL,
-                                                          false);
-               if (!progress)                  retry_count--;
+                                                  false, true);
+               curusage = res_counter_read_u64(&memcg->res, RES_USAGE);
+               /* Usage is reduced ? */
+               if (curusage >= oldusage)
+                       retry_count--;
+               else
+                       oldusage = curusage;
        }
 
        return ret;
@@ -1563,13 +1711,16 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
 int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                                unsigned long long val)
 {
-       int retry_count = MEM_CGROUP_RECLAIM_RETRIES;
+       int retry_count;
        u64 memlimit, oldusage, curusage;
-       int ret;
+       int children = mem_cgroup_count_children(memcg);
+       int ret = -EBUSY;
 
        if (!do_swap_account)
                return -EINVAL;
-
+       /* see mem_cgroup_resize_res_limit */
+       retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
+       oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
        while (retry_count) {
                if (signal_pending(current)) {
                        ret = -EINTR;
@@ -1593,11 +1744,13 @@ int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                if (!ret)
                        break;
 
-               oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
-               mem_cgroup_hierarchical_reclaim(memcg, GFP_KERNEL, true);
+               mem_cgroup_hierarchical_reclaim(memcg, GFP_KERNEL, true, true);
                curusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
+               /* Usage is reduced ? */
                if (curusage >= oldusage)
                        retry_count--;
+               else
+                       oldusage = curusage;
        }
        return ret;
 }
@@ -1893,54 +2046,90 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
        return 0;
 }
 
-static const struct mem_cgroup_stat_desc {
-       const char *msg;
-       u64 unit;
-} mem_cgroup_stat_desc[] = {
-       [MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
-       [MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, },
-       [MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
-       [MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, },
+
+/* For read statistics */
+enum {
+       MCS_CACHE,
+       MCS_RSS,
+       MCS_PGPGIN,
+       MCS_PGPGOUT,
+       MCS_INACTIVE_ANON,
+       MCS_ACTIVE_ANON,
+       MCS_INACTIVE_FILE,
+       MCS_ACTIVE_FILE,
+       MCS_UNEVICTABLE,
+       NR_MCS_STAT,
+};
+
+struct mcs_total_stat {
+       s64 stat[NR_MCS_STAT];
+};
+
+struct {
+       char *local_name;
+       char *total_name;
+} memcg_stat_strings[NR_MCS_STAT] = {
+       {"cache", "total_cache"},
+       {"rss", "total_rss"},
+       {"pgpgin", "total_pgpgin"},
+       {"pgpgout", "total_pgpgout"},
+       {"inactive_anon", "total_inactive_anon"},
+       {"active_anon", "total_active_anon"},
+       {"inactive_file", "total_inactive_file"},
+       {"active_file", "total_active_file"},
+       {"unevictable", "total_unevictable"}
 };
 
+
+static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data)
+{
+       struct mcs_total_stat *s = data;
+       s64 val;
+
+       /* per cpu stat */
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_CACHE);
+       s->stat[MCS_CACHE] += val * PAGE_SIZE;
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
+       s->stat[MCS_RSS] += val * PAGE_SIZE;
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT);
+       s->stat[MCS_PGPGIN] += val;
+       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT);
+       s->stat[MCS_PGPGOUT] += val;
+
+       /* per zone stat */
+       val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_ANON);
+       s->stat[MCS_INACTIVE_ANON] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_ANON);
+       s->stat[MCS_ACTIVE_ANON] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_FILE);
+       s->stat[MCS_INACTIVE_FILE] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_FILE);
+       s->stat[MCS_ACTIVE_FILE] += val * PAGE_SIZE;
+       val = mem_cgroup_get_local_zonestat(mem, LRU_UNEVICTABLE);
+       s->stat[MCS_UNEVICTABLE] += val * PAGE_SIZE;
+       return 0;
+}
+
+static void
+mem_cgroup_get_total_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
+{
+       mem_cgroup_walk_tree(mem, s, mem_cgroup_get_local_stat);
+}
+
 static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
                                 struct cgroup_map_cb *cb)
 {
        struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
-       struct mem_cgroup_stat *stat = &mem_cont->stat;
+       struct mcs_total_stat mystat;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(stat->cpustat[0].count); i++) {
-               s64 val;
+       memset(&mystat, 0, sizeof(mystat));
+       mem_cgroup_get_local_stat(mem_cont, &mystat);
 
-               val = mem_cgroup_read_stat(stat, i);
-               val *= mem_cgroup_stat_desc[i].unit;
-               cb->fill(cb, mem_cgroup_stat_desc[i].msg, val);
-       }
-       /* showing # of active pages */
-       {
-               unsigned long active_anon, inactive_anon;
-               unsigned long active_file, inactive_file;
-               unsigned long unevictable;
-
-               inactive_anon = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_INACTIVE_ANON);
-               active_anon = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_ACTIVE_ANON);
-               inactive_file = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_INACTIVE_FILE);
-               active_file = mem_cgroup_get_all_zonestat(mem_cont,
-                                               LRU_ACTIVE_FILE);
-               unevictable = mem_cgroup_get_all_zonestat(mem_cont,
-                                                       LRU_UNEVICTABLE);
-
-               cb->fill(cb, "active_anon", (active_anon) * PAGE_SIZE);
-               cb->fill(cb, "inactive_anon", (inactive_anon) * PAGE_SIZE);
-               cb->fill(cb, "active_file", (active_file) * PAGE_SIZE);
-               cb->fill(cb, "inactive_file", (inactive_file) * PAGE_SIZE);
-               cb->fill(cb, "unevictable", unevictable * PAGE_SIZE);
+       for (i = 0; i < NR_MCS_STAT; i++)
+               cb->fill(cb, memcg_stat_strings[i].local_name, mystat.stat[i]);
 
-       }
+       /* Hierarchical information */
        {
                unsigned long long limit, memsw_limit;
                memcg_get_hierarchical_limit(mem_cont, &limit, &memsw_limit);
@@ -1949,6 +2138,12 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
                        cb->fill(cb, "hierarchical_memsw_limit", memsw_limit);
        }
 
+       memset(&mystat, 0, sizeof(mystat));
+       mem_cgroup_get_total_stat(mem_cont, &mystat);
+       for (i = 0; i < NR_MCS_STAT; i++)
+               cb->fill(cb, memcg_stat_strings[i].total_name, mystat.stat[i]);
+
+
 #ifdef CONFIG_DEBUG_VM
        cb->fill(cb, "inactive_ratio", calc_inactive_ratio(mem_cont, NULL));
 
@@ -2178,6 +2373,8 @@ static void __mem_cgroup_free(struct mem_cgroup *mem)
 {
        int node;
 
+       free_css_id(&mem_cgroup_subsys, &mem->css);
+
        for_each_node_state(node, N_POSSIBLE)
                free_mem_cgroup_per_zone_info(mem, node);
 
@@ -2228,11 +2425,12 @@ static struct cgroup_subsys_state * __ref
 mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
 {
        struct mem_cgroup *mem, *parent;
+       long error = -ENOMEM;
        int node;
 
        mem = mem_cgroup_alloc();
        if (!mem)
-               return ERR_PTR(-ENOMEM);
+               return ERR_PTR(error);
 
        for_each_node_state(node, N_POSSIBLE)
                if (alloc_mem_cgroup_per_zone_info(mem, node))
@@ -2260,7 +2458,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
                res_counter_init(&mem->res, NULL);
                res_counter_init(&mem->memsw, NULL);
        }
-       mem->last_scanned_child = NULL;
+       mem->last_scanned_child = 0;
        spin_lock_init(&mem->reclaim_param_lock);
 
        if (parent)
@@ -2269,26 +2467,22 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        return &mem->css;
 free_out:
        __mem_cgroup_free(mem);
-       return ERR_PTR(-ENOMEM);
+       return ERR_PTR(error);
 }
 
-static void mem_cgroup_pre_destroy(struct cgroup_subsys *ss,
+static int mem_cgroup_pre_destroy(struct cgroup_subsys *ss,
                                        struct cgroup *cont)
 {
        struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
-       mem_cgroup_force_empty(mem, false);
+
+       return mem_cgroup_force_empty(mem, false);
 }
 
 static void mem_cgroup_destroy(struct cgroup_subsys *ss,
                                struct cgroup *cont)
 {
        struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
-       struct mem_cgroup *last_scanned_child = mem->last_scanned_child;
 
-       if (last_scanned_child) {
-               VM_BUG_ON(!mem_cgroup_is_obsolete(last_scanned_child));
-               mem_cgroup_put(last_scanned_child);
-       }
        mem_cgroup_put(mem);
 }
 
@@ -2327,6 +2521,7 @@ struct cgroup_subsys mem_cgroup_subsys = {
        .populate = mem_cgroup_populate,
        .attach = mem_cgroup_move_task,
        .early_init = 0,
+       .use_id = 1,
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
index 2032ad2fc34b82742ad273a4327394e76a5b187e..cf6873e91c6a7eeb166031a7c8ae9fd4f3dda100 100644 (file)
@@ -1151,6 +1151,11 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
                if ((flags & FOLL_WRITE) &&
                    !pte_dirty(pte) && !PageDirty(page))
                        set_page_dirty(page);
+               /*
+                * pte_mkyoung() would be more correct here, but atomic care
+                * is needed to avoid losing the dirty bit: it is easier to use
+                * mark_page_accessed().
+                */
                mark_page_accessed(page);
        }
 unlock:
@@ -1940,6 +1945,15 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                 * get_user_pages(.write=1, .force=1).
                 */
                if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
+                       struct vm_fault vmf;
+                       int tmp;
+
+                       vmf.virtual_address = (void __user *)(address &
+                                                               PAGE_MASK);
+                       vmf.pgoff = old_page->index;
+                       vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
+                       vmf.page = old_page;
+
                        /*
                         * Notify the address space that the page is about to
                         * become writable so that it can prohibit this or wait
@@ -1951,8 +1965,12 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                        page_cache_get(old_page);
                        pte_unmap_unlock(page_table, ptl);
 
-                       if (vma->vm_ops->page_mkwrite(vma, old_page) < 0)
+                       tmp = vma->vm_ops->page_mkwrite(vma, &vmf);
+                       if (unlikely(tmp &
+                                       (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) {
+                               ret = tmp;
                                goto unwritable_page;
+                       }
 
                        /*
                         * Since we dropped the lock we need to revalidate
@@ -2101,7 +2119,7 @@ oom:
 
 unwritable_page:
        page_cache_release(old_page);
-       return VM_FAULT_SIGBUS;
+       return ret;
 }
 
 /*
@@ -2435,8 +2453,6 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
                count_vm_event(PGMAJFAULT);
        }
 
-       mark_page_accessed(page);
-
        lock_page(page);
        delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
 
@@ -2645,9 +2661,14 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                         * to become writable
                         */
                        if (vma->vm_ops->page_mkwrite) {
+                               int tmp;
+
                                unlock_page(page);
-                               if (vma->vm_ops->page_mkwrite(vma, page) < 0) {
-                                       ret = VM_FAULT_SIGBUS;
+                               vmf.flags |= FAULT_FLAG_MKWRITE;
+                               tmp = vma->vm_ops->page_mkwrite(vma, &vmf);
+                               if (unlikely(tmp &
+                                         (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) {
+                                       ret = tmp;
                                        anon = 1; /* no anon but release vmf.page */
                                        goto out_unlocked;
                                }
index a9eff3f092f622a451753a1dc155f5b7fbdd7ab6..068655d8f883a8d2a79ae3f3247ced23f0b5db76 100644 (file)
@@ -250,7 +250,7 @@ out:
  * The number of remaining references must be:
  * 1 for anonymous pages without a mapping
  * 2 for pages with a mapping
- * 3 for pages with a mapping and PagePrivate set.
+ * 3 for pages with a mapping and PagePrivate/PagePrivate2 set.
  */
 static int migrate_page_move_mapping(struct address_space *mapping,
                struct page *newpage, struct page *page)
@@ -270,7 +270,7 @@ static int migrate_page_move_mapping(struct address_space *mapping,
        pslot = radix_tree_lookup_slot(&mapping->page_tree,
                                        page_index(page));
 
-       expected_count = 2 + !!PagePrivate(page);
+       expected_count = 2 + !!page_has_private(page);
        if (page_count(page) != expected_count ||
                        (struct page *)radix_tree_deref_slot(pslot) != page) {
                spin_unlock_irq(&mapping->tree_lock);
@@ -386,7 +386,7 @@ EXPORT_SYMBOL(fail_migrate_page);
 
 /*
  * Common logic to directly migrate a single page suitable for
- * pages that do not use PagePrivate.
+ * pages that do not use PagePrivate/PagePrivate2.
  *
  * Pages are locked upon entry and exit.
  */
@@ -522,7 +522,7 @@ static int fallback_migrate_page(struct address_space *mapping,
         * Buffers may be managed in a filesystem specific way.
         * We must have no buffers or drop them.
         */
-       if (PagePrivate(page) &&
+       if (page_has_private(page) &&
            !try_to_release_page(page, GFP_KERNEL))
                return -EAGAIN;
 
@@ -655,7 +655,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
         * free the metadata, so the page can be freed.
         */
        if (!page->mapping) {
-               if (!PageAnon(page) && PagePrivate(page)) {
+               if (!PageAnon(page) && page_has_private(page)) {
                        /*
                         * Go direct to try_to_free_buffers() here because
                         * a) that's what try_to_release_page() would do anyway
index 1abb9185a686d2787125c7af61120b68e726ccb5..4a3841186c11100f05e01f498c13794621b1edff 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2481,7 +2481,4 @@ void mm_drop_all_locks(struct mm_struct *mm)
  */
 void __init mmap_init(void)
 {
-       vm_area_cachep = kmem_cache_create("vm_area_struct",
-                       sizeof(struct vm_area_struct), 0,
-                       SLAB_PANIC, NULL);
 }
index 2fcf47d449b4e203d46bbbf76827aeedbd2e2c22..72eda4aee2cb46d72e070271d82ae13daef78b36 100644 (file)
@@ -69,7 +69,7 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
 int sysctl_nr_trim_pages = 1; /* page trimming behaviour */
 int heap_stack_gap = 0;
 
-atomic_t mmap_pages_allocated;
+atomic_long_t mmap_pages_allocated;
 
 EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(num_physpages);
@@ -463,12 +463,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
  */
 void __init mmap_init(void)
 {
-       vm_region_jar = kmem_cache_create("vm_region_jar",
-                                         sizeof(struct vm_region), 0,
-                                         SLAB_PANIC, NULL);
-       vm_area_cachep = kmem_cache_create("vm_area_struct",
-                                          sizeof(struct vm_area_struct), 0,
-                                          SLAB_PANIC, NULL);
+       vm_region_jar = KMEM_CACHE(vm_region, SLAB_PANIC);
 }
 
 /*
@@ -486,27 +481,24 @@ static noinline void validate_nommu_regions(void)
                return;
 
        last = rb_entry(lastp, struct vm_region, vm_rb);
-       if (unlikely(last->vm_end <= last->vm_start))
-               BUG();
-       if (unlikely(last->vm_top < last->vm_end))
-               BUG();
+       BUG_ON(unlikely(last->vm_end <= last->vm_start));
+       BUG_ON(unlikely(last->vm_top < last->vm_end));
 
        while ((p = rb_next(lastp))) {
                region = rb_entry(p, struct vm_region, vm_rb);
                last = rb_entry(lastp, struct vm_region, vm_rb);
 
-               if (unlikely(region->vm_end <= region->vm_start))
-                       BUG();
-               if (unlikely(region->vm_top < region->vm_end))
-                       BUG();
-               if (unlikely(region->vm_start < last->vm_top))
-                       BUG();
+               BUG_ON(unlikely(region->vm_end <= region->vm_start));
+               BUG_ON(unlikely(region->vm_top < region->vm_end));
+               BUG_ON(unlikely(region->vm_start < last->vm_top));
 
                lastp = p;
        }
 }
 #else
-#define validate_nommu_regions() do {} while(0)
+static void validate_nommu_regions(void)
+{
+}
 #endif
 
 /*
@@ -563,16 +555,17 @@ static void free_page_series(unsigned long from, unsigned long to)
                struct page *page = virt_to_page(from);
 
                kdebug("- free %lx", from);
-               atomic_dec(&mmap_pages_allocated);
+               atomic_long_dec(&mmap_pages_allocated);
                if (page_count(page) != 1)
-                       kdebug("free page %p [%d]", page, page_count(page));
+                       kdebug("free page %p: refcount not one: %d",
+                              page, page_count(page));
                put_page(page);
        }
 }
 
 /*
  * release a reference to a region
- * - the caller must hold the region semaphore, which this releases
+ * - the caller must hold the region semaphore for writing, which this releases
  * - the region may not have been added to the tree yet, in which case vm_top
  *   will equal vm_start
  */
@@ -1096,7 +1089,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
                goto enomem;
 
        total = 1 << order;
-       atomic_add(total, &mmap_pages_allocated);
+       atomic_long_add(total, &mmap_pages_allocated);
 
        point = rlen >> PAGE_SHIFT;
 
@@ -1107,7 +1100,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
                        order = ilog2(total - point);
                        n = 1 << order;
                        kdebug("shave %lu/%lu @%lu", n, total - point, total);
-                       atomic_sub(n, &mmap_pages_allocated);
+                       atomic_long_sub(n, &mmap_pages_allocated);
                        total -= n;
                        set_page_refcounted(pages + total);
                        __free_pages(pages + total, order);
@@ -1536,10 +1529,15 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
        /* find the first potentially overlapping VMA */
        vma = find_vma(mm, start);
        if (!vma) {
-               printk(KERN_WARNING
-                      "munmap of memory not mmapped by process %d (%s):"
-                      " 0x%lx-0x%lx\n",
-                      current->pid, current->comm, start, start + len - 1);
+               static int limit = 0;
+               if (limit < 5) {
+                       printk(KERN_WARNING
+                              "munmap of memory not mmapped by process %d"
+                              " (%s): 0x%lx-0x%lx\n",
+                              current->pid, current->comm,
+                              start, start + len - 1);
+                       limit++;
+               }
                return -EINVAL;
        }
 
index 40ba05061a4fbc8a43d3eb046a58fe756748cd06..2f3166e308d9713378d6a37b6a54e6272abf0f1f 100644 (file)
@@ -55,7 +55,7 @@ static DEFINE_SPINLOCK(zone_scan_lock);
 
 unsigned long badness(struct task_struct *p, unsigned long uptime)
 {
-       unsigned long points, cpu_time, run_time, s;
+       unsigned long points, cpu_time, run_time;
        struct mm_struct *mm;
        struct task_struct *child;
 
@@ -110,12 +110,10 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
        else
                run_time = 0;
 
-       s = int_sqrt(cpu_time);
-       if (s)
-               points /= s;
-       s = int_sqrt(int_sqrt(run_time));
-       if (s)
-               points /= s;
+       if (cpu_time)
+               points /= int_sqrt(cpu_time);
+       if (run_time)
+               points /= int_sqrt(int_sqrt(run_time));
 
        /*
         * Niced processes are most likely less important, so double
@@ -396,6 +394,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                cpuset_print_task_mems_allowed(current);
                task_unlock(current);
                dump_stack();
+               mem_cgroup_print_oom_info(mem, current);
                show_mem();
                if (sysctl_oom_dump_tasks)
                        dump_tasks(mem);
index 40ca7cdb653ec280d8115ff3d8b35cb6ee57669e..30351f0063acb125f4581f0a1c6197662254d8ab 100644 (file)
@@ -92,14 +92,14 @@ int vm_dirty_ratio = 20;
 unsigned long vm_dirty_bytes;
 
 /*
- * The interval between `kupdate'-style writebacks, in jiffies
+ * The interval between `kupdate'-style writebacks
  */
-int dirty_writeback_interval = 5 * HZ;
+unsigned int dirty_writeback_interval = 5 * 100; /* sentiseconds */
 
 /*
- * The longest number of jiffies for which data is allowed to remain dirty
+ * The longest time for which data is allowed to remain dirty
  */
-int dirty_expire_interval = 30 * HZ;
+unsigned int dirty_expire_interval = 30 * 100; /* sentiseconds */
 
 /*
  * Flag that makes the machine dump writes/reads and block dirtyings.
@@ -770,9 +770,9 @@ static void wb_kupdate(unsigned long arg)
 
        sync_supers();
 
-       oldest_jif = jiffies - dirty_expire_interval;
+       oldest_jif = jiffies - msecs_to_jiffies(dirty_expire_interval);
        start_jif = jiffies;
-       next_jif = start_jif + dirty_writeback_interval;
+       next_jif = start_jif + msecs_to_jiffies(dirty_writeback_interval * 10);
        nr_to_write = global_page_state(NR_FILE_DIRTY) +
                        global_page_state(NR_UNSTABLE_NFS) +
                        (inodes_stat.nr_inodes - inodes_stat.nr_unused);
@@ -801,9 +801,10 @@ static void wb_kupdate(unsigned long arg)
 int dirty_writeback_centisecs_handler(ctl_table *table, int write,
        struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
 {
-       proc_dointvec_userhz_jiffies(table, write, file, buffer, length, ppos);
+       proc_dointvec(table, write, file, buffer, length, ppos);
        if (dirty_writeback_interval)
-               mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
+               mod_timer(&wb_timer, jiffies +
+                       msecs_to_jiffies(dirty_writeback_interval * 10));
        else
                del_timer(&wb_timer);
        return 0;
@@ -905,7 +906,8 @@ void __init page_writeback_init(void)
 {
        int shift;
 
-       mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
+       mod_timer(&wb_timer,
+                 jiffies + msecs_to_jiffies(dirty_writeback_interval * 10));
        writeback_set_ratelimit();
        register_cpu_notifier(&ratelimit_nb);
 
@@ -1197,6 +1199,20 @@ int __set_page_dirty_no_writeback(struct page *page)
        return 0;
 }
 
+/*
+ * Helper function for set_page_dirty family.
+ * NOTE: This relies on being atomic wrt interrupts.
+ */
+void account_page_dirtied(struct page *page, struct address_space *mapping)
+{
+       if (mapping_cap_account_dirty(mapping)) {
+               __inc_zone_page_state(page, NR_FILE_DIRTY);
+               __inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE);
+               task_dirty_inc(current);
+               task_io_account_write(PAGE_CACHE_SIZE);
+       }
+}
+
 /*
  * For address_spaces which do not use buffers.  Just tag the page as dirty in
  * its radix tree.
@@ -1226,13 +1242,7 @@ int __set_page_dirty_nobuffers(struct page *page)
                if (mapping2) { /* Race with truncate? */
                        BUG_ON(mapping2 != mapping);
                        WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
-                       if (mapping_cap_account_dirty(mapping)) {
-                               __inc_zone_page_state(page, NR_FILE_DIRTY);
-                               __inc_bdi_stat(mapping->backing_dev_info,
-                                               BDI_RECLAIMABLE);
-                               task_dirty_inc(current);
-                               task_io_account_write(PAGE_CACHE_SIZE);
-                       }
+                       account_page_dirtied(page, mapping);
                        radix_tree_tag_set(&mapping->page_tree,
                                page_index(page), PAGECACHE_TAG_DIRTY);
                }
index 5c44ed49ca93c5a1d7a39f5570b0d1254a45de80..3f30189896fd5db2fbfae92696d0d8a09b4df072 100644 (file)
@@ -331,7 +331,7 @@ static int destroy_compound_page(struct page *page, unsigned long order)
        for (i = 1; i < nr_pages; i++) {
                struct page *p = page + i;
 
-               if (unlikely(!PageTail(p) | (p->first_page != page))) {
+               if (unlikely(!PageTail(p) || (p->first_page != page))) {
                        bad_page(page);
                        bad++;
                }
@@ -922,13 +922,10 @@ static void drain_pages(unsigned int cpu)
        unsigned long flags;
        struct zone *zone;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                struct per_cpu_pageset *pset;
                struct per_cpu_pages *pcp;
 
-               if (!populated_zone(zone))
-                       continue;
-
                pset = zone_pcp(zone, cpu);
 
                pcp = &pset->pcp;
@@ -1479,6 +1476,8 @@ __alloc_pages_internal(gfp_t gfp_mask, unsigned int order,
        unsigned long did_some_progress;
        unsigned long pages_reclaimed = 0;
 
+       lockdep_trace_alloc(gfp_mask);
+
        might_sleep_if(wait);
 
        if (should_fail_alloc_page(gfp_mask, order))
@@ -1578,12 +1577,16 @@ nofail_alloc:
         */
        cpuset_update_task_memory_state();
        p->flags |= PF_MEMALLOC;
+
+       lockdep_set_current_reclaim_state(gfp_mask);
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       did_some_progress = try_to_free_pages(zonelist, order, gfp_mask);
+       did_some_progress = try_to_free_pages(zonelist, order,
+                                               gfp_mask, nodemask);
 
        p->reclaim_state = NULL;
+       lockdep_clear_current_reclaim_state();
        p->flags &= ~PF_MEMALLOC;
 
        cond_resched();
@@ -1874,10 +1877,7 @@ void show_free_areas(void)
        int cpu;
        struct zone *zone;
 
-       for_each_zone(zone) {
-               if (!populated_zone(zone))
-                       continue;
-
+       for_each_populated_zone(zone) {
                show_node(zone);
                printk("%s per-cpu:\n", zone->name);
 
@@ -1917,12 +1917,9 @@ void show_free_areas(void)
                global_page_state(NR_PAGETABLE),
                global_page_state(NR_BOUNCE));
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                int i;
 
-               if (!populated_zone(zone))
-                       continue;
-
                show_node(zone);
                printk("%s"
                        " free:%lukB"
@@ -1962,12 +1959,9 @@ void show_free_areas(void)
                printk("\n");
        }
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                unsigned long nr[MAX_ORDER], flags, order, total = 0;
 
-               if (!populated_zone(zone))
-                       continue;
-
                show_node(zone);
                printk("%s: ", zone->name);
 
@@ -2779,11 +2773,7 @@ static int __cpuinit process_zones(int cpu)
 
        node_set_state(node, N_CPU);    /* this node has a cpu */
 
-       for_each_zone(zone) {
-
-               if (!populated_zone(zone))
-                       continue;
-
+       for_each_populated_zone(zone) {
                zone_pcp(zone, cpu) = kmalloc_node(sizeof(struct per_cpu_pageset),
                                         GFP_KERNEL, node);
                if (!zone_pcp(zone, cpu))
index ceecfbb143fa9d7b2a3f9ffb4ca9980da6bc0b53..791905c991df9d94497c36cd23cb3fead537f4d9 100644 (file)
@@ -285,12 +285,8 @@ struct swap_cgroup_ctrl {
 
 struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES];
 
-/*
- * This 8bytes seems big..maybe we can reduce this when we can use "id" for
- * cgroup rather than pointer.
- */
 struct swap_cgroup {
-       struct mem_cgroup       *val;
+       unsigned short          id;
 };
 #define SC_PER_PAGE    (PAGE_SIZE/sizeof(struct swap_cgroup))
 #define SC_POS_MASK    (SC_PER_PAGE - 1)
@@ -342,10 +338,10 @@ not_enough_page:
  * @ent: swap entry to be recorded into
  * @mem: mem_cgroup to be recorded
  *
- * Returns old value at success, NULL at failure.
- * (Of course, old value can be NULL.)
+ * Returns old value at success, 0 at failure.
+ * (Of course, old value can be 0.)
  */
-struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 {
        int type = swp_type(ent);
        unsigned long offset = swp_offset(ent);
@@ -354,18 +350,18 @@ struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
        struct swap_cgroup_ctrl *ctrl;
        struct page *mappage;
        struct swap_cgroup *sc;
-       struct mem_cgroup *old;
+       unsigned short old;
 
        if (!do_swap_account)
-               return NULL;
+               return 0;
 
        ctrl = &swap_cgroup_ctrl[type];
 
        mappage = ctrl->map[idx];
        sc = page_address(mappage);
        sc += pos;
-       old = sc->val;
-       sc->val = mem;
+       old = sc->id;
+       sc->id = id;
 
        return old;
 }
@@ -374,9 +370,9 @@ struct mem_cgroup *swap_cgroup_record(swp_entry_t ent, struct mem_cgroup *mem)
  * lookup_swap_cgroup - lookup mem_cgroup tied to swap entry
  * @ent: swap entry to be looked up.
  *
- * Returns pointer to mem_cgroup at success. NULL at failure.
+ * Returns CSS ID of mem_cgroup at success. 0 at failure. (0 is invalid ID)
  */
-struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup(swp_entry_t ent)
 {
        int type = swp_type(ent);
        unsigned long offset = swp_offset(ent);
@@ -385,16 +381,16 @@ struct mem_cgroup *lookup_swap_cgroup(swp_entry_t ent)
        struct swap_cgroup_ctrl *ctrl;
        struct page *mappage;
        struct swap_cgroup *sc;
-       struct mem_cgroup *ret;
+       unsigned short ret;
 
        if (!do_swap_account)
-               return NULL;
+               return 0;
 
        ctrl = &swap_cgroup_ctrl[type];
        mappage = ctrl->map[idx];
        sc = page_address(mappage);
        sc += pos;
-       ret = sc->val;
+       ret = sc->id;
        return ret;
 }
 
@@ -430,13 +426,6 @@ int swap_cgroup_swapon(int type, unsigned long max_pages)
        }
        mutex_unlock(&swap_cgroup_mutex);
 
-       printk(KERN_INFO
-               "swap_cgroup: uses %ld bytes of vmalloc for pointer array space"
-               " and %ld bytes to hold mem_cgroup pointers on swap\n",
-               array_size, length * PAGE_SIZE);
-       printk(KERN_INFO
-       "swap_cgroup can be disabled by noswapaccount boot option.\n");
-
        return 0;
 nomem:
        printk(KERN_INFO "couldn't allocate enough memory for swap_cgroup.\n");
index 15de509b68fd657c7b9ecb0356cdadf9bc43b1ef..118905e3d7886f795875b376c70d23e4bfc4c038 100644 (file)
@@ -191,7 +191,7 @@ static int pdflush(void *dummy)
 
        /*
         * Some configs put our parent kthread in a limited cpuset,
-        * which kthread() overrides, forcing cpus_allowed == CPU_MASK_ALL.
+        * which kthread() overrides, forcing cpus_allowed == cpu_all_mask.
         * Our needs are more modest - cut back to our cpusets cpus_allowed.
         * This is needed as pdflush's are dynamically created and destroyed.
         * The boottime pdflush's are easily placed w/o these 2 lines.
index 9ce303d4b8109a32bf198ffc02ba4fe6b77eec49..133b6d525513a886247ce3adc5eff41ef4e91752 100644 (file)
@@ -31,6 +31,42 @@ EXPORT_SYMBOL_GPL(file_ra_state_init);
 
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
+/*
+ * see if a page needs releasing upon read_cache_pages() failure
+ * - the caller of read_cache_pages() may have set PG_private or PG_fscache
+ *   before calling, such as the NFS fs marking pages that are cached locally
+ *   on disk, thus we need to give the fs a chance to clean up in the event of
+ *   an error
+ */
+static void read_cache_pages_invalidate_page(struct address_space *mapping,
+                                            struct page *page)
+{
+       if (page_has_private(page)) {
+               if (!trylock_page(page))
+                       BUG();
+               page->mapping = mapping;
+               do_invalidatepage(page, 0);
+               page->mapping = NULL;
+               unlock_page(page);
+       }
+       page_cache_release(page);
+}
+
+/*
+ * release a list of pages, invalidating them first if need be
+ */
+static void read_cache_pages_invalidate_pages(struct address_space *mapping,
+                                             struct list_head *pages)
+{
+       struct page *victim;
+
+       while (!list_empty(pages)) {
+               victim = list_to_page(pages);
+               list_del(&victim->lru);
+               read_cache_pages_invalidate_page(mapping, victim);
+       }
+}
+
 /**
  * read_cache_pages - populate an address space with some pages & start reads against them
  * @mapping: the address_space
@@ -52,14 +88,14 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages,
                list_del(&page->lru);
                if (add_to_page_cache_lru(page, mapping,
                                        page->index, GFP_KERNEL)) {
-                       page_cache_release(page);
+                       read_cache_pages_invalidate_page(mapping, page);
                        continue;
                }
                page_cache_release(page);
 
                ret = filler(data, page);
                if (unlikely(ret)) {
-                       put_pages_list(pages);
+                       read_cache_pages_invalidate_pages(mapping, pages);
                        break;
                }
                task_io_account_read(PAGE_CACHE_SIZE);
index 7ec78e24a30dcc549670b88643078509bbd12e4d..d94d2e9146bc4dfa5d946449274be75419f0b8da 100644 (file)
@@ -1068,8 +1068,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
                swap_duplicate(swap);
                BUG_ON(page_mapped(page));
                page_cache_release(page);       /* pagecache ref */
-               set_page_dirty(page);
-               unlock_page(page);
+               swap_writepage(page, wbc);
                if (inode) {
                        mutex_lock(&shmem_swaplist_mutex);
                        /* move instead of add in case we're racing */
index 4d00855629c4921e3c590406335549683e6c6daf..208323fd37bc3b7efcdca7dbbd1f9d68ab901025 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3318,6 +3318,8 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        unsigned long save_flags;
        void *ptr;
 
+       lockdep_trace_alloc(flags);
+
        if (slab_should_failslab(cachep, flags))
                return NULL;
 
@@ -3394,6 +3396,8 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
        unsigned long save_flags;
        void *objp;
 
+       lockdep_trace_alloc(flags);
+
        if (slab_should_failslab(cachep, flags))
                return NULL;
 
@@ -3988,8 +3992,7 @@ static void cache_reap(struct work_struct *w)
        struct kmem_cache *searchp;
        struct kmem_list3 *l3;
        int node = numa_node_id();
-       struct delayed_work *work =
-               container_of(w, struct delayed_work, work);
+       struct delayed_work *work = to_delayed_work(w);
 
        if (!mutex_trylock(&cache_chain_mutex))
                /* Give up. Setup the next iteration. */
index 0bfa680a8981127307d1d922231dca3d66f9b2bd..7a3411524dacd555e9ce70e287a4232072391e10 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -475,6 +475,8 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node)
        unsigned int *m;
        int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
 
+       lockdep_trace_alloc(gfp);
+
        if (size < PAGE_SIZE - align) {
                if (!size)
                        return ZERO_SIZE_PTR;
index c65a4edafc3343e83a2513f8edab9b0ed82f3ab5..c4ea9158c9fbd0e4630062aa0098406000be45c3 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1590,6 +1590,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
        unsigned long flags;
        unsigned int objsize;
 
+       lockdep_trace_alloc(gfpflags);
        might_sleep_if(gfpflags & __GFP_WAIT);
 
        if (should_failslab(s->objsize, gfpflags))
index 083f5b63e7a8bdb8ab5196e11970691c2bd351d4..da432d9f0ae825eb4e050ed8168c1600c6a793da 100644 (file)
@@ -164,9 +164,7 @@ void __meminit mminit_validate_memmodel_limits(unsigned long *start_pfn,
                WARN_ON_ONCE(1);
                *start_pfn = max_sparsemem_pfn;
                *end_pfn = max_sparsemem_pfn;
-       }
-
-       if (*end_pfn > max_sparsemem_pfn) {
+       } else if (*end_pfn > max_sparsemem_pfn) {
                mminit_dprintk(MMINIT_WARNING, "pfnvalidation",
                        "End of range %lu -> %lu exceeds SPARSEMEM max %lu\n",
                        *start_pfn, *end_pfn, max_sparsemem_pfn);
index 8adb9feb61e10b7385e01d3410d8cb0f0a4807e1..bede23ce64ea28e52d991168f2c93cd2243c893a 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -448,37 +448,14 @@ void pagevec_strip(struct pagevec *pvec)
        for (i = 0; i < pagevec_count(pvec); i++) {
                struct page *page = pvec->pages[i];
 
-               if (PagePrivate(page) && trylock_page(page)) {
-                       if (PagePrivate(page))
+               if (page_has_private(page) && trylock_page(page)) {
+                       if (page_has_private(page))
                                try_to_release_page(page, 0);
                        unlock_page(page);
                }
        }
 }
 
-/**
- * pagevec_swap_free - try to free swap space from the pages in a pagevec
- * @pvec: pagevec with swapcache pages to free the swap space of
- *
- * The caller needs to hold an extra reference to each page and
- * not hold the page lock on the pages.  This function uses a
- * trylock on the page lock so it may not always free the swap
- * space associated with a page.
- */
-void pagevec_swap_free(struct pagevec *pvec)
-{
-       int i;
-
-       for (i = 0; i < pagevec_count(pvec); i++) {
-               struct page *page = pvec->pages[i];
-
-               if (PageSwapCache(page) && trylock_page(page)) {
-                       try_to_free_swap(page);
-                       unlock_page(page);
-               }
-       }
-}
-
 /**
  * pagevec_lookup - gang pagecache lookup
  * @pvec:      Where the resulting pages are placed
index 1229211104f84beb0e05e5df891f1780d392e418..55206fab7b994e18fb026ca36269e3feeb2705a1 100644 (file)
@@ -50,7 +50,7 @@ void do_invalidatepage(struct page *page, unsigned long offset)
 static inline void truncate_partial_page(struct page *page, unsigned partial)
 {
        zero_user_segment(page, partial, PAGE_CACHE_SIZE);
-       if (PagePrivate(page))
+       if (page_has_private(page))
                do_invalidatepage(page, partial);
 }
 
@@ -99,7 +99,7 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
        if (page->mapping != mapping)
                return;
 
-       if (PagePrivate(page))
+       if (page_has_private(page))
                do_invalidatepage(page, 0);
 
        cancel_dirty_page(page, PAGE_CACHE_SIZE);
@@ -126,7 +126,7 @@ invalidate_complete_page(struct address_space *mapping, struct page *page)
        if (page->mapping != mapping)
                return 0;
 
-       if (PagePrivate(page) && !try_to_release_page(page, 0))
+       if (page_has_private(page) && !try_to_release_page(page, 0))
                return 0;
 
        clear_page_mlock(page);
@@ -348,7 +348,7 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
        if (page->mapping != mapping)
                return 0;
 
-       if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL))
+       if (page_has_private(page) && !try_to_release_page(page, GFP_KERNEL))
                return 0;
 
        spin_lock_irq(&mapping->tree_lock);
@@ -356,7 +356,7 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
                goto failed;
 
        clear_page_mlock(page);
-       BUG_ON(PagePrivate(page));
+       BUG_ON(page_has_private(page));
        __remove_from_page_cache(page);
        spin_unlock_irq(&mapping->tree_lock);
        page_cache_release(page);       /* pagecache ref */
index 37eaccdf3054e13d60cd83cf5c6cb9869731aec1..7c122e49f769ccea98ae105746e0238acc1652ce 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -69,6 +69,36 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
 }
 EXPORT_SYMBOL(kmemdup);
 
+/**
+ * memdup_user - duplicate memory region from user space
+ *
+ * @src: source address in user space
+ * @len: number of bytes to copy
+ *
+ * Returns an ERR_PTR() on failure.
+ */
+void *memdup_user(const void __user *src, size_t len)
+{
+       void *p;
+
+       /*
+        * Always use GFP_KERNEL, since copy_from_user() can sleep and
+        * cause pagefault, which makes it pointless to use GFP_NOFS
+        * or GFP_ATOMIC.
+        */
+       p = kmalloc_track_caller(len, GFP_KERNEL);
+       if (!p)
+               return ERR_PTR(-ENOMEM);
+
+       if (copy_from_user(p, src, len)) {
+               kfree(p);
+               return ERR_PTR(-EFAULT);
+       }
+
+       return p;
+}
+EXPORT_SYMBOL(memdup_user);
+
 /**
  * __krealloc - like krealloc() but don't free @p.
  * @p: object to reallocate memory for.
index af58324c361addc715ee2eb9b839bada21cb2773..fab19876b4d178986979c2b5d2cb353285507b46 100644 (file)
@@ -671,10 +671,7 @@ struct vmap_block {
        DECLARE_BITMAP(alloc_map, VMAP_BBMAP_BITS);
        DECLARE_BITMAP(dirty_map, VMAP_BBMAP_BITS);
        union {
-               struct {
-                       struct list_head free_list;
-                       struct list_head dirty_list;
-               };
+               struct list_head free_list;
                struct rcu_head rcu_head;
        };
 };
@@ -741,7 +738,6 @@ static struct vmap_block *new_vmap_block(gfp_t gfp_mask)
        bitmap_zero(vb->alloc_map, VMAP_BBMAP_BITS);
        bitmap_zero(vb->dirty_map, VMAP_BBMAP_BITS);
        INIT_LIST_HEAD(&vb->free_list);
-       INIT_LIST_HEAD(&vb->dirty_list);
 
        vb_idx = addr_to_vb_idx(va->va_start);
        spin_lock(&vmap_block_tree_lock);
@@ -772,12 +768,7 @@ static void free_vmap_block(struct vmap_block *vb)
        struct vmap_block *tmp;
        unsigned long vb_idx;
 
-       spin_lock(&vb->vbq->lock);
-       if (!list_empty(&vb->free_list))
-               list_del(&vb->free_list);
-       if (!list_empty(&vb->dirty_list))
-               list_del(&vb->dirty_list);
-       spin_unlock(&vb->vbq->lock);
+       BUG_ON(!list_empty(&vb->free_list));
 
        vb_idx = addr_to_vb_idx(vb->va->va_start);
        spin_lock(&vmap_block_tree_lock);
@@ -862,11 +853,7 @@ static void vb_free(const void *addr, unsigned long size)
 
        spin_lock(&vb->lock);
        bitmap_allocate_region(vb->dirty_map, offset >> PAGE_SHIFT, order);
-       if (!vb->dirty) {
-               spin_lock(&vb->vbq->lock);
-               list_add(&vb->dirty_list, &vb->vbq->dirty);
-               spin_unlock(&vb->vbq->lock);
-       }
+
        vb->dirty += 1UL << order;
        if (vb->dirty == VMAP_BBMAP_BITS) {
                BUG_ON(vb->free || !list_empty(&vb->free_list));
index 56ddf41149eb77a55158ced628c02f817b990618..425244988bb230965c36c02c3901a906348b92ea 100644 (file)
@@ -60,8 +60,8 @@ struct scan_control {
 
        int may_writepage;
 
-       /* Can pages be swapped as part of reclaim? */
-       int may_swap;
+       /* Can mapped pages be reclaimed? */
+       int may_unmap;
 
        /* This context's SWAP_CLUSTER_MAX. If freeing memory for
         * suspend, we effectively ignore SWAP_CLUSTER_MAX.
@@ -78,6 +78,12 @@ struct scan_control {
        /* Which cgroup do we reclaim from */
        struct mem_cgroup *mem_cgroup;
 
+       /*
+        * Nodemask of nodes allowed by the caller. If NULL, all nodes
+        * are scanned.
+        */
+       nodemask_t      *nodemask;
+
        /* Pluggable isolate pages callback */
        unsigned long (*isolate_pages)(unsigned long nr, struct list_head *dst,
                        unsigned long *scanned, int order, int mode,
@@ -214,8 +220,9 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
                do_div(delta, lru_pages + 1);
                shrinker->nr += delta;
                if (shrinker->nr < 0) {
-                       printk(KERN_ERR "%s: nr=%ld\n",
-                                       __func__, shrinker->nr);
+                       printk(KERN_ERR "shrink_slab: %pF negative objects to "
+                              "delete nr=%ld\n",
+                              shrinker->shrink, shrinker->nr);
                        shrinker->nr = max_pass;
                }
 
@@ -276,7 +283,7 @@ static inline int page_mapping_inuse(struct page *page)
 
 static inline int is_page_cache_freeable(struct page *page)
 {
-       return page_count(page) - !!PagePrivate(page) == 2;
+       return page_count(page) - !!page_has_private(page) == 2;
 }
 
 static int may_write_to_queue(struct backing_dev_info *bdi)
@@ -360,7 +367,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
                 * Some data journaling orphaned pages can have
                 * page->mapping == NULL while being dirty with clean buffers.
                 */
-               if (PagePrivate(page)) {
+               if (page_has_private(page)) {
                        if (try_to_free_buffers(page)) {
                                ClearPageDirty(page);
                                printk("%s: orphaned page\n", __func__);
@@ -606,7 +613,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                if (unlikely(!page_evictable(page, NULL)))
                        goto cull_mlocked;
 
-               if (!sc->may_swap && page_mapped(page))
+               if (!sc->may_unmap && page_mapped(page))
                        goto keep_locked;
 
                /* Double the slab pressure for mapped and swapcache pages */
@@ -720,7 +727,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                 * process address space (page_count == 1) it can be freed.
                 * Otherwise, leave the page on the LRU so it is swappable.
                 */
-               if (PagePrivate(page)) {
+               if (page_has_private(page)) {
                        if (!try_to_release_page(page, sc->gfp_mask))
                                goto activate_locked;
                        if (!mapping && page_count(page) == 1) {
@@ -1298,17 +1305,11 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
        }
        __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);
        pgdeactivate += pgmoved;
-       if (buffer_heads_over_limit) {
-               spin_unlock_irq(&zone->lru_lock);
-               pagevec_strip(&pvec);
-               spin_lock_irq(&zone->lru_lock);
-       }
        __count_zone_vm_events(PGREFILL, zone, pgscanned);
        __count_vm_events(PGDEACTIVATE, pgdeactivate);
        spin_unlock_irq(&zone->lru_lock);
-       if (vm_swap_full())
-               pagevec_swap_free(&pvec);
-
+       if (buffer_heads_over_limit)
+               pagevec_strip(&pvec);
        pagevec_release(&pvec);
 }
 
@@ -1543,7 +1544,8 @@ static void shrink_zones(int priority, struct zonelist *zonelist,
        struct zone *zone;
 
        sc->all_unreclaimable = 1;
-       for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
+       for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
+                                       sc->nodemask) {
                if (!populated_zone(zone))
                        continue;
                /*
@@ -1688,17 +1690,18 @@ out:
 }
 
 unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
-                                                               gfp_t gfp_mask)
+                               gfp_t gfp_mask, nodemask_t *nodemask)
 {
        struct scan_control sc = {
                .gfp_mask = gfp_mask,
                .may_writepage = !laptop_mode,
                .swap_cluster_max = SWAP_CLUSTER_MAX,
-               .may_swap = 1,
+               .may_unmap = 1,
                .swappiness = vm_swappiness,
                .order = order,
                .mem_cgroup = NULL,
                .isolate_pages = isolate_pages_global,
+               .nodemask = nodemask,
        };
 
        return do_try_to_free_pages(zonelist, &sc);
@@ -1713,17 +1716,18 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
 {
        struct scan_control sc = {
                .may_writepage = !laptop_mode,
-               .may_swap = 1,
+               .may_unmap = 1,
                .swap_cluster_max = SWAP_CLUSTER_MAX,
                .swappiness = swappiness,
                .order = 0,
                .mem_cgroup = mem_cont,
                .isolate_pages = mem_cgroup_isolate_pages,
+               .nodemask = NULL, /* we don't care the placement */
        };
        struct zonelist *zonelist;
 
        if (noswap)
-               sc.may_swap = 0;
+               sc.may_unmap = 0;
 
        sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                        (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
@@ -1762,7 +1766,7 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
        struct reclaim_state *reclaim_state = current->reclaim_state;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
-               .may_swap = 1,
+               .may_unmap = 1,
                .swap_cluster_max = SWAP_CLUSTER_MAX,
                .swappiness = vm_swappiness,
                .order = order,
@@ -1965,6 +1969,8 @@ static int kswapd(void *p)
        };
        node_to_cpumask_ptr(cpumask, pgdat->node_id);
 
+       lockdep_set_current_reclaim_state(GFP_KERNEL);
+
        if (!cpumask_empty(cpumask))
                set_cpus_allowed_ptr(tsk, cpumask);
        current->reclaim_state = &reclaim_state;
@@ -2048,22 +2054,19 @@ unsigned long global_lru_pages(void)
 #ifdef CONFIG_PM
 /*
  * Helper function for shrink_all_memory().  Tries to reclaim 'nr_pages' pages
- * from LRU lists system-wide, for given pass and priority, and returns the
- * number of reclaimed pages
+ * from LRU lists system-wide, for given pass and priority.
  *
  * For pass > 3 we also try to shrink the LRU lists that contain a few pages
  */
-static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
+static void shrink_all_zones(unsigned long nr_pages, int prio,
                                      int pass, struct scan_control *sc)
 {
        struct zone *zone;
-       unsigned long ret = 0;
+       unsigned long nr_reclaimed = 0;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                enum lru_list l;
 
-               if (!populated_zone(zone))
-                       continue;
                if (zone_is_all_unreclaimable(zone) && prio != DEF_PRIORITY)
                        continue;
 
@@ -2082,14 +2085,16 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
 
                                zone->lru[l].nr_scan = 0;
                                nr_to_scan = min(nr_pages, lru_pages);
-                               ret += shrink_list(l, nr_to_scan, zone,
+                               nr_reclaimed += shrink_list(l, nr_to_scan, zone,
                                                                sc, prio);
-                               if (ret >= nr_pages)
-                                       return ret;
+                               if (nr_reclaimed >= nr_pages) {
+                                       sc->nr_reclaimed = nr_reclaimed;
+                                       return;
+                               }
                        }
                }
        }
-       return ret;
+       sc->nr_reclaimed = nr_reclaimed;
 }
 
 /*
@@ -2103,13 +2108,11 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
 unsigned long shrink_all_memory(unsigned long nr_pages)
 {
        unsigned long lru_pages, nr_slab;
-       unsigned long ret = 0;
        int pass;
        struct reclaim_state reclaim_state;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
-               .may_swap = 0,
-               .swap_cluster_max = nr_pages,
+               .may_unmap = 0,
                .may_writepage = 1,
                .isolate_pages = isolate_pages_global,
        };
@@ -2125,8 +2128,8 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
                if (!reclaim_state.reclaimed_slab)
                        break;
 
-               ret += reclaim_state.reclaimed_slab;
-               if (ret >= nr_pages)
+               sc.nr_reclaimed += reclaim_state.reclaimed_slab;
+               if (sc.nr_reclaimed >= nr_pages)
                        goto out;
 
                nr_slab -= reclaim_state.reclaimed_slab;
@@ -2145,21 +2148,22 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
 
                /* Force reclaiming mapped pages in the passes #3 and #4 */
                if (pass > 2)
-                       sc.may_swap = 1;
+                       sc.may_unmap = 1;
 
                for (prio = DEF_PRIORITY; prio >= 0; prio--) {
-                       unsigned long nr_to_scan = nr_pages - ret;
+                       unsigned long nr_to_scan = nr_pages - sc.nr_reclaimed;
 
                        sc.nr_scanned = 0;
-                       ret += shrink_all_zones(nr_to_scan, prio, pass, &sc);
-                       if (ret >= nr_pages)
+                       sc.swap_cluster_max = nr_to_scan;
+                       shrink_all_zones(nr_to_scan, prio, pass, &sc);
+                       if (sc.nr_reclaimed >= nr_pages)
                                goto out;
 
                        reclaim_state.reclaimed_slab = 0;
                        shrink_slab(sc.nr_scanned, sc.gfp_mask,
                                        global_lru_pages());
-                       ret += reclaim_state.reclaimed_slab;
-                       if (ret >= nr_pages)
+                       sc.nr_reclaimed += reclaim_state.reclaimed_slab;
+                       if (sc.nr_reclaimed >= nr_pages)
                                goto out;
 
                        if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
@@ -2168,21 +2172,23 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
        }
 
        /*
-        * If ret = 0, we could not shrink LRUs, but there may be something
-        * in slab caches
+        * If sc.nr_reclaimed = 0, we could not shrink LRUs, but there may be
+        * something in slab caches
         */
-       if (!ret) {
+       if (!sc.nr_reclaimed) {
                do {
                        reclaim_state.reclaimed_slab = 0;
                        shrink_slab(nr_pages, sc.gfp_mask, global_lru_pages());
-                       ret += reclaim_state.reclaimed_slab;
-               } while (ret < nr_pages && reclaim_state.reclaimed_slab > 0);
+                       sc.nr_reclaimed += reclaim_state.reclaimed_slab;
+               } while (sc.nr_reclaimed < nr_pages &&
+                               reclaim_state.reclaimed_slab > 0);
        }
 
+
 out:
        current->reclaim_state = NULL;
 
-       return ret;
+       return sc.nr_reclaimed;
 }
 #endif
 
@@ -2288,11 +2294,12 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        int priority;
        struct scan_control sc = {
                .may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE),
-               .may_swap = !!(zone_reclaim_mode & RECLAIM_SWAP),
+               .may_unmap = !!(zone_reclaim_mode & RECLAIM_SWAP),
                .swap_cluster_max = max_t(unsigned long, nr_pages,
                                        SWAP_CLUSTER_MAX),
                .gfp_mask = gfp_mask,
                .swappiness = vm_swappiness,
+               .order = order,
                .isolate_pages = isolate_pages_global,
        };
        unsigned long slab_reclaimable;
index 91149746bb8d6c94ac036879bbe557551630a1e1..66f6130976cb65c569f41108507479a68ec0779c 100644 (file)
@@ -27,7 +27,7 @@ static void sum_vm_events(unsigned long *ret, const struct cpumask *cpumask)
 
        memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
 
-       for_each_cpu_mask_nr(cpu, *cpumask) {
+       for_each_cpu(cpu, cpumask) {
                struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
 
                for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
@@ -135,11 +135,7 @@ static void refresh_zone_stat_thresholds(void)
        int cpu;
        int threshold;
 
-       for_each_zone(zone) {
-
-               if (!zone->present_pages)
-                       continue;
-
+       for_each_populated_zone(zone) {
                threshold = calculate_threshold(zone);
 
                for_each_online_cpu(cpu)
@@ -301,12 +297,9 @@ void refresh_cpu_vm_stats(int cpu)
        int i;
        int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                struct per_cpu_pageset *p;
 
-               if (!populated_zone(zone))
-                       continue;
-
                p = zone_pcp(zone, cpu);
 
                for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
@@ -898,7 +891,7 @@ static void vmstat_update(struct work_struct *w)
 {
        refresh_cpu_vm_stats(smp_processor_id());
        schedule_delayed_work(&__get_cpu_var(vmstat_work),
-               sysctl_stat_interval);
+               round_jiffies_relative(sysctl_stat_interval));
 }
 
 static void __cpuinit start_cpu_timer(int cpu)
@@ -906,7 +899,8 @@ static void __cpuinit start_cpu_timer(int cpu)
        struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
 
        INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
-       schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
+       schedule_delayed_work_on(cpu, vmstat_work,
+                                __round_jiffies_relative(HZ, cpu));
 }
 
 /*
index ec93e7e38b38ef9a49b5057bf4f60bf04971d33f..ce77db4fcec8c0a5a34a1bb3f918531941e66733 100644 (file)
@@ -140,7 +140,7 @@ config NETFILTER_ADVANCED
        default y
        help
          If you say Y here you can select between all the netfilter modules.
-         If you say N the more ununsual ones will not be shown and the
+         If you say N the more unusual ones will not be shown and the
          basic ones needed by most people will default to 'M'.
 
          If unsure, say Y.
index 162199a2d74f18e6b41ee7322c2ed8d66dfc4539..fd8e0847b25473ac9318aa22769af66500dbb073 100644 (file)
@@ -281,7 +281,6 @@ int __init atalk_proc_init(void)
        atalk_proc_dir = proc_mkdir("atalk", init_net.proc_net);
        if (!atalk_proc_dir)
                goto out;
-       atalk_proc_dir->owner = THIS_MODULE;
 
        p = proc_create("interface", S_IRUGO, atalk_proc_dir,
                        &atalk_seq_interface_fops);
index 4990541ef5da4ca7d0b2325bd39ebb4ffbf3c290..1a0f5ccea9c4494cad2c29755863f7dd0559e540 100644 (file)
@@ -281,7 +281,6 @@ int mpc_proc_init(void)
                printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
                return -ENOMEM;
        }
-       p->owner = THIS_MODULE;
        return 0;
 }
 
index 49487b313f221cf6394fa2c918fc67858ae1f45f..e7b3b273907d197b1a64ac8d1cd9c1ce0c3edc16 100644 (file)
@@ -476,7 +476,6 @@ int __init atm_proc_init(void)
                                     atm_proc_root, e->proc_fops);
                if (!dirent)
                        goto err_out_remove;
-               dirent->owner = THIS_MODULE;
                e->dirent = dirent;
        }
        ret = 0;
index abdc703a11d2709ea0305f1cf0b9d9ff0965818a..cab71ea2796d472f740a88277d75805081873748 100644 (file)
@@ -1093,11 +1093,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
        }
 }
 
-static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
-{
-       return 0;
-}
-
 static int rfcomm_tty_tiocmget(struct tty_struct *tty, struct file *filp)
 {
        struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
@@ -1156,7 +1151,6 @@ static const struct tty_operations rfcomm_ops = {
        .send_xchar             = rfcomm_tty_send_xchar,
        .hangup                 = rfcomm_tty_hangup,
        .wait_until_sent        = rfcomm_tty_wait_until_sent,
-       .read_proc              = rfcomm_tty_read_proc,
        .tiocmget               = rfcomm_tty_tiocmget,
        .tiocmset               = rfcomm_tty_tiocmset,
 };
index b7c7d46511365ef5ff8c7bc93678a2ef97966c18..95d7f32643aef3a3e0b3830200ea592bb1b54849 100644 (file)
@@ -1604,10 +1604,6 @@ static int __init bcm_module_init(void)
 
        /* create /proc/net/can-bcm directory */
        proc_dir = proc_mkdir("can-bcm", init_net.proc_net);
-
-       if (proc_dir)
-               proc_dir->owner = THIS_MODULE;
-
        return 0;
 }
 
index 520fef5e5398aa867a267ae32bbffbba557795c2..1463653dbe34e986eb5f6283b7823ef109cb0fa8 100644 (file)
@@ -473,8 +473,6 @@ void can_init_proc(void)
                return;
        }
 
-       can_dir->owner = THIS_MODULE;
-
        /* own procfs entries from the AF_CAN core */
        pde_version     = can_create_proc_readentry(CAN_PROC_VERSION, 0644,
                                        can_proc_read_version, NULL);
index 52fea5b28ca694ede44158117d631e093430c25c..91d792d17e098761c2e725204eb065621bba5d57 100644 (file)
@@ -2472,8 +2472,9 @@ static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
                return GRO_NORMAL;
 
        for (p = napi->gro_list; p; p = p->next) {
-               NAPI_GRO_CB(p)->same_flow = !compare_ether_header(
-                       skb_mac_header(p), skb_gro_mac_header(skb));
+               NAPI_GRO_CB(p)->same_flow = (p->dev == skb->dev)
+                       && !compare_ether_header(skb_mac_header(p),
+                                                skb_gro_mac_header(skb));
                NAPI_GRO_CB(p)->flush = 0;
        }
 
index 244ca56dffac3eb57536142f5aa36e2f4a6f12a5..d9d5160610d5e87741965bcddc126f46a4f5c0cd 100644 (file)
@@ -261,8 +261,7 @@ static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
        ret = 0;
 
 err_out:
-       if (rule_buf)
-               kfree(rule_buf);
+       kfree(rule_buf);
 
        return ret;
 }
index 755414cd49d10c8d65c6366bceb2618edf261f75..b5873bdff61207e13b89650c535393db0c44a830 100644 (file)
@@ -345,8 +345,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
        udph->dest = htons(np->remote_port);
        udph->len = htons(udp_len);
        udph->check = 0;
-       udph->check = csum_tcpudp_magic(htonl(np->local_ip),
-                                       htonl(np->remote_ip),
+       udph->check = csum_tcpudp_magic(np->local_ip,
+                                       np->remote_ip,
                                        udp_len, IPPROTO_UDP,
                                        csum_partial(udph, udp_len, 0));
        if (udph->check == 0)
@@ -365,8 +365,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
        iph->ttl      = 64;
        iph->protocol = IPPROTO_UDP;
        iph->check    = 0;
-       put_unaligned(htonl(np->local_ip), &(iph->saddr));
-       put_unaligned(htonl(np->remote_ip), &(iph->daddr));
+       put_unaligned(np->local_ip, &(iph->saddr));
+       put_unaligned(np->remote_ip, &(iph->daddr));
        iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
 
        eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
@@ -424,7 +424,7 @@ static void arp_reply(struct sk_buff *skb)
        memcpy(&tip, arp_ptr, 4);
 
        /* Should we ignore arp? */
-       if (tip != htonl(np->local_ip) ||
+       if (tip != np->local_ip ||
            ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
                return;
 
@@ -533,9 +533,9 @@ int __netpoll_rx(struct sk_buff *skb)
                goto out;
        if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
                goto out;
-       if (np->local_ip && np->local_ip != ntohl(iph->daddr))
+       if (np->local_ip && np->local_ip != iph->daddr)
                goto out;
-       if (np->remote_ip && np->remote_ip != ntohl(iph->saddr))
+       if (np->remote_ip && np->remote_ip != iph->saddr)
                goto out;
        if (np->local_port && np->local_port != ntohs(uh->dest))
                goto out;
@@ -560,14 +560,14 @@ void netpoll_print_options(struct netpoll *np)
 {
        printk(KERN_INFO "%s: local port %d\n",
                         np->name, np->local_port);
-       printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
-                        np->name, HIPQUAD(np->local_ip));
+       printk(KERN_INFO "%s: local IP %pI4\n",
+                        np->name, &np->local_ip);
        printk(KERN_INFO "%s: interface %s\n",
                         np->name, np->dev_name);
        printk(KERN_INFO "%s: remote port %d\n",
                         np->name, np->remote_port);
-       printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n",
-                        np->name, HIPQUAD(np->remote_ip));
+       printk(KERN_INFO "%s: remote IP %pI4\n",
+                        np->name, &np->remote_ip);
        printk(KERN_INFO "%s: remote ethernet address %pM\n",
                         np->name, np->remote_mac);
 }
@@ -589,7 +589,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
                if ((delim = strchr(cur, '/')) == NULL)
                        goto parse_failed;
                *delim = 0;
-               np->local_ip = ntohl(in_aton(cur));
+               np->local_ip = in_aton(cur);
                cur = delim;
        }
        cur++;
@@ -618,7 +618,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
        if ((delim = strchr(cur, '/')) == NULL)
                goto parse_failed;
        *delim = 0;
-       np->remote_ip = ntohl(in_aton(cur));
+       np->remote_ip = in_aton(cur);
        cur = delim + 1;
 
        if (*cur != 0) {
@@ -759,10 +759,9 @@ int netpoll_setup(struct netpoll *np)
                        goto release;
                }
 
-               np->local_ip = ntohl(in_dev->ifa_list->ifa_local);
+               np->local_ip = in_dev->ifa_list->ifa_local;
                rcu_read_unlock();
-               printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
-                      np->name, HIPQUAD(np->local_ip));
+               printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip);
        }
 
        if (np->rx_hook) {
index 32d419f5ac983e2601cda6ce189476a87886c699..3779c1438c11c84613f5ba9b40619907c9a18a9d 100644 (file)
@@ -3806,7 +3806,6 @@ static int __init pg_init(void)
        pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
        if (!pg_proc_dir)
                return -ENODEV;
-       pg_proc_dir->owner = THIS_MODULE;
 
        pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
        if (pe == NULL) {
index 6acbf9e79eb1dc2076bc192f774c8b5591566c42..ce6356cd9f71c76bad3cf9a0ec5fbb774c0a427a 100644 (file)
@@ -2579,7 +2579,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
                                          skb_network_header_len(skb));
                skb_copy_from_linear_data(skb, nskb->data, doffset);
 
-               if (pos >= offset + len)
+               if (fskb != skb_shinfo(skb)->frag_list)
                        continue;
 
                if (!sg) {
index 0620046e4eba837d0ecdf72b5eb6dcc192060ed5..7dbf3ffb35ccd6cb3308dab70fa33ce9cd9f8d5c 100644 (file)
@@ -1677,7 +1677,7 @@ static void sock_def_error_report(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible(sk->sk_sleep);
+               wake_up_interruptible_poll(sk->sk_sleep, POLLERR);
        sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1686,7 +1686,8 @@ static void sock_def_readable(struct sock *sk, int len)
 {
        read_lock(&sk->sk_callback_lock);
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_sync(sk->sk_sleep);
+               wake_up_interruptible_sync_poll(sk->sk_sleep, POLLIN |
+                                               POLLRDNORM | POLLRDBAND);
        sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1700,7 +1701,8 @@ static void sock_def_write_space(struct sock *sk)
         */
        if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
                if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-                       wake_up_interruptible_sync(sk->sk_sleep);
+                       wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+                                               POLLWRNORM | POLLWRBAND);
 
                /* Should agree with poll, otherwise some programs break */
                if (sock_writeable(sk))
index 35c5f6a5cb7c8ee4dad9ad56eba517727ffefbc5..5ba533d234db60c88504af505cdb4eee7a9a1dc2 100644 (file)
@@ -253,7 +253,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
        indev = in ? in->name : nulldevname;
        outdev = out ? out->name : nulldevname;
 
-       rcu_read_lock();
+       rcu_read_lock_bh();
        private = rcu_dereference(table->private);
        table_base = rcu_dereference(private->entries[smp_processor_id()]);
 
@@ -329,7 +329,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
                }
        } while (!hotdrop);
 
-       rcu_read_unlock();
+       rcu_read_unlock_bh();
 
        if (hotdrop)
                return NF_DROP;
index 82ee7c9049ff032d0f652bc114b0b237e6d374d1..810c0b62c7d4b213ea21c8ab0aaf3198e7e7bc36 100644 (file)
@@ -339,7 +339,7 @@ ipt_do_table(struct sk_buff *skb,
 
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 
-       rcu_read_lock();
+       rcu_read_lock_bh();
        private = rcu_dereference(table->private);
        table_base = rcu_dereference(private->entries[smp_processor_id()]);
 
@@ -437,7 +437,7 @@ ipt_do_table(struct sk_buff *skb,
                }
        } while (!hotdrop);
 
-       rcu_read_unlock();
+       rcu_read_unlock_bh();
 
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
index 2451aeb5ac23c72fc3fd99963aa07054d58e98c5..fafbec8b073e025bb987ce1bcf6f56f450aec9db 100644 (file)
@@ -1081,8 +1081,7 @@ out_err:
  *     this, no blocking and very strange errors 8)
  */
 
-static int tcp_recv_urg(struct sock *sk, long timeo,
-                       struct msghdr *msg, int len, int flags)
+static int tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
@@ -1697,7 +1696,7 @@ out:
        return err;
 
 recv_urg:
-       err = tcp_recv_urg(sk, timeo, msg, len, flags);
+       err = tcp_recv_urg(sk, msg, len, flags);
        goto out;
 }
 
index c1f259d2d33b71a6e69b24b964f473de55f51724..53300fa2359fd66067c2bd36569e20558db7a489 100644 (file)
@@ -754,6 +754,36 @@ static void tcp_adjust_fackets_out(struct sock *sk, struct sk_buff *skb,
                tp->fackets_out -= decr;
 }
 
+/* Pcount in the middle of the write queue got changed, we need to do various
+ * tweaks to fix counters
+ */
+static void tcp_adjust_pcount(struct sock *sk, struct sk_buff *skb, int decr)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+
+       tp->packets_out -= decr;
+
+       if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)
+               tp->sacked_out -= decr;
+       if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
+               tp->retrans_out -= decr;
+       if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)
+               tp->lost_out -= decr;
+
+       /* Reno case is special. Sigh... */
+       if (tcp_is_reno(tp) && decr > 0)
+               tp->sacked_out -= min_t(u32, tp->sacked_out, decr);
+
+       tcp_adjust_fackets_out(sk, skb, decr);
+
+       if (tp->lost_skb_hint &&
+           before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->lost_skb_hint)->seq) &&
+           (tcp_is_fack(tp) || TCP_SKB_CB(skb)->sacked))
+               tp->lost_cnt_hint -= decr;
+
+       tcp_verify_left_out(tp);
+}
+
 /* Function to create two new TCP segments.  Shrinks the given segment
  * to the specified size and appends a new segment with the rest of the
  * packet to the list.  This won't be called frequently, I hope.
@@ -836,28 +866,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
                int diff = old_factor - tcp_skb_pcount(skb) -
                        tcp_skb_pcount(buff);
 
-               tp->packets_out -= diff;
-
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)
-                       tp->sacked_out -= diff;
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
-                       tp->retrans_out -= diff;
-
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)
-                       tp->lost_out -= diff;
-
-               /* Adjust Reno SACK estimate. */
-               if (tcp_is_reno(tp) && diff > 0) {
-                       tcp_dec_pcount_approx_int(&tp->sacked_out, diff);
-                       tcp_verify_left_out(tp);
-               }
-               tcp_adjust_fackets_out(sk, skb, diff);
-
-               if (tp->lost_skb_hint &&
-                   before(TCP_SKB_CB(skb)->seq,
-                          TCP_SKB_CB(tp->lost_skb_hint)->seq) &&
-                   (tcp_is_fack(tp) || TCP_SKB_CB(skb)->sacked))
-                       tp->lost_cnt_hint -= diff;
+               if (diff)
+                       tcp_adjust_pcount(sk, skb, diff);
        }
 
        /* Link BUFF into the send queue. */
@@ -1768,22 +1778,14 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
         * packet counting does not break.
         */
        TCP_SKB_CB(skb)->sacked |= TCP_SKB_CB(next_skb)->sacked & TCPCB_EVER_RETRANS;
-       if (TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_RETRANS)
-               tp->retrans_out -= tcp_skb_pcount(next_skb);
-       if (TCP_SKB_CB(next_skb)->sacked & TCPCB_LOST)
-               tp->lost_out -= tcp_skb_pcount(next_skb);
-       /* Reno case is special. Sigh... */
-       if (tcp_is_reno(tp) && tp->sacked_out)
-               tcp_dec_pcount_approx(&tp->sacked_out, next_skb);
-
-       tcp_adjust_fackets_out(sk, next_skb, tcp_skb_pcount(next_skb));
-       tp->packets_out -= tcp_skb_pcount(next_skb);
 
        /* changed transmit queue under us so clear hints */
        tcp_clear_retrans_hints_partial(tp);
        if (next_skb == tp->retransmit_skb_hint)
                tp->retransmit_skb_hint = skb;
 
+       tcp_adjust_pcount(sk, next_skb, tcp_skb_pcount(next_skb));
+
        sk_wmem_free_skb(sk, next_skb);
 }
 
@@ -1891,7 +1893,12 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                if (tcp_fragment(sk, skb, cur_mss, cur_mss))
                        return -ENOMEM; /* We'll try again later. */
        } else {
-               tcp_init_tso_segs(sk, skb, cur_mss);
+               int oldpcount = tcp_skb_pcount(skb);
+
+               if (unlikely(oldpcount > 1)) {
+                       tcp_init_tso_segs(sk, skb, cur_mss);
+                       tcp_adjust_pcount(sk, skb, oldpcount - tcp_skb_pcount(skb));
+               }
        }
 
        tcp_retrans_try_collapse(sk, skb, cur_mss);
index ec992159b5f8b0e08c60d680de92da155c1abbc6..ca8cb326d1d2bd3397817f90936f93c30a3f7896 100644 (file)
@@ -22,17 +22,17 @@ menuconfig IPV6
 if IPV6
 
 config IPV6_PRIVACY
-       bool "IPv6: Privacy Extensions support"
+       bool "IPv6: Privacy Extensions (RFC 3041) support"
        ---help---
          Privacy Extensions for Stateless Address Autoconfiguration in IPv6
-         support.  With this option, additional periodically-alter 
-         pseudo-random global-scope unicast address(es) will assigned to
+         support.  With this option, additional periodically-altered
+         pseudo-random global-scope unicast address(es) will be assigned to
          your interface(s).
        
-         We use our standard pseudo random algorithm to generate randomized
-         interface identifier, instead of one described in RFC 3041.
+         We use our standard pseudo-random algorithm to generate the
+          randomized interface identifier, instead of one described in RFC 3041.
 
-         By default, kernel do not generate temporary addresses.
+         By default the kernel does not generate temporary addresses.
          To use temporary addresses, do
        
                echo 2 >/proc/sys/net/ipv6/conf/all/use_tempaddr 
@@ -43,9 +43,9 @@ config IPV6_ROUTER_PREF
        bool "IPv6: Router Preference (RFC 4191) support"
        ---help---
          Router Preference is an optional extension to the Router
-         Advertisement message to improve the ability of hosts
-         to pick more appropriate router, especially when the hosts
-         is placed in a multi-homed network.
+         Advertisement message which improves the ability of hosts
+         to pick an appropriate router, especially when the hosts
+         are placed in a multi-homed network.
 
          If unsure, say N.
 
index e89cfa3a8f254650948f60ada09982b9862c745d..dfed176aed37a05698c62f887e0227d95c1faff4 100644 (file)
@@ -365,7 +365,7 @@ ip6t_do_table(struct sk_buff *skb,
 
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 
-       rcu_read_lock();
+       rcu_read_lock_bh();
        private = rcu_dereference(table->private);
        table_base = rcu_dereference(private->entries[smp_processor_id()]);
 
@@ -466,7 +466,7 @@ ip6t_do_table(struct sk_buff *skb,
 #ifdef CONFIG_NETFILTER_DEBUG
        ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
 #endif
-       rcu_read_unlock();
+       rcu_read_unlock_bh();
 
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
index 086d5ef098fd0b541359c8bd8448075406ef05cf..811984d9324b6ea0f925d4d3124db1bc7c0e575a 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 #include <linux/termios.h>
 #include <linux/tty.h>
 #include <linux/interrupt.h>
@@ -72,8 +73,7 @@ static int ircomm_tty_control_indication(void *instance, void *sap,
 static void ircomm_tty_flow_indication(void *instance, void *sap,
                                       LOCAL_FLOW cmd);
 #ifdef CONFIG_PROC_FS
-static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
-                               int *eof, void *unused);
+static const struct file_operations ircomm_tty_proc_fops;
 #endif /* CONFIG_PROC_FS */
 static struct tty_driver *driver;
 
@@ -98,7 +98,7 @@ static const struct tty_operations ops = {
        .hangup          = ircomm_tty_hangup,
        .wait_until_sent = ircomm_tty_wait_until_sent,
 #ifdef CONFIG_PROC_FS
-       .read_proc       = ircomm_tty_read_proc,
+       .proc_fops       = &ircomm_tty_proc_fops,
 #endif /* CONFIG_PROC_FS */
 };
 
@@ -1245,150 +1245,170 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
 }
 
 #ifdef CONFIG_PROC_FS
-static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
+static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
 {
-       int  ret=0;
+       char sep;
 
-       ret += sprintf(buf+ret, "State: %s\n", ircomm_tty_state[self->state]);
+       seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
 
-       ret += sprintf(buf+ret, "Service type: ");
+       seq_puts(m, "Service type: ");
        if (self->service_type & IRCOMM_9_WIRE)
-               ret += sprintf(buf+ret, "9_WIRE");
+               seq_puts(m, "9_WIRE");
        else if (self->service_type & IRCOMM_3_WIRE)
-               ret += sprintf(buf+ret, "3_WIRE");
+               seq_puts(m, "3_WIRE");
        else if (self->service_type & IRCOMM_3_WIRE_RAW)
-               ret += sprintf(buf+ret, "3_WIRE_RAW");
+               seq_puts(m, "3_WIRE_RAW");
        else
-               ret += sprintf(buf+ret, "No common service type!\n");
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name);
-
-       ret += sprintf(buf+ret, "DTE status: ");
-       if (self->settings.dte & IRCOMM_RTS)
-               ret += sprintf(buf+ret, "RTS|");
-       if (self->settings.dte & IRCOMM_DTR)
-               ret += sprintf(buf+ret, "DTR|");
-       if (self->settings.dte)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "DCE status: ");
-       if (self->settings.dce & IRCOMM_CTS)
-               ret += sprintf(buf+ret, "CTS|");
-       if (self->settings.dce & IRCOMM_DSR)
-               ret += sprintf(buf+ret, "DSR|");
-       if (self->settings.dce & IRCOMM_CD)
-               ret += sprintf(buf+ret, "CD|");
-       if (self->settings.dce & IRCOMM_RI)
-               ret += sprintf(buf+ret, "RI|");
-       if (self->settings.dce)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Configuration: ");
+               seq_puts(m, "No common service type!\n");
+       seq_putc(m, '\n');
+
+       seq_printf(m, "Port name: %s\n", self->settings.port_name);
+
+       seq_printf(m, "DTE status:");
+       sep = ' ';
+       if (self->settings.dte & IRCOMM_RTS) {
+               seq_printf(m, "%cRTS", sep);
+               sep = '|';
+       }
+       if (self->settings.dte & IRCOMM_DTR) {
+               seq_printf(m, "%cDTR", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_puts(m, "DCE status:");
+       sep = ' ';
+       if (self->settings.dce & IRCOMM_CTS) {
+               seq_printf(m, "%cCTS", sep);
+               sep = '|';
+       }
+       if (self->settings.dce & IRCOMM_DSR) {
+               seq_printf(m, "%cDSR", sep);
+               sep = '|';
+       }
+       if (self->settings.dce & IRCOMM_CD) {
+               seq_printf(m, "%cCD", sep);
+               sep = '|';
+       }
+       if (self->settings.dce & IRCOMM_RI) {
+               seq_printf(m, "%cRI", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_puts(m, "Configuration: ");
        if (!self->settings.null_modem)
-               ret += sprintf(buf+ret, "DTE <-> DCE\n");
+               seq_puts(m, "DTE <-> DCE\n");
        else
-               ret += sprintf(buf+ret,
-                              "DTE <-> DTE (null modem emulation)\n");
-
-       ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate);
-
-       ret += sprintf(buf+ret, "Flow control: ");
-       if (self->settings.flow_control & IRCOMM_XON_XOFF_IN)
-               ret += sprintf(buf+ret, "XON_XOFF_IN|");
-       if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT)
-               ret += sprintf(buf+ret, "XON_XOFF_OUT|");
-       if (self->settings.flow_control & IRCOMM_RTS_CTS_IN)
-               ret += sprintf(buf+ret, "RTS_CTS_IN|");
-       if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT)
-               ret += sprintf(buf+ret, "RTS_CTS_OUT|");
-       if (self->settings.flow_control & IRCOMM_DSR_DTR_IN)
-               ret += sprintf(buf+ret, "DSR_DTR_IN|");
-       if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT)
-               ret += sprintf(buf+ret, "DSR_DTR_OUT|");
-       if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN)
-               ret += sprintf(buf+ret, "ENQ_ACK_IN|");
-       if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT)
-               ret += sprintf(buf+ret, "ENQ_ACK_OUT|");
-       if (self->settings.flow_control)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Flags: ");
-       if (self->flags & ASYNC_CTS_FLOW)
-               ret += sprintf(buf+ret, "ASYNC_CTS_FLOW|");
-       if (self->flags & ASYNC_CHECK_CD)
-               ret += sprintf(buf+ret, "ASYNC_CHECK_CD|");
-       if (self->flags & ASYNC_INITIALIZED)
-               ret += sprintf(buf+ret, "ASYNC_INITIALIZED|");
-       if (self->flags & ASYNC_LOW_LATENCY)
-               ret += sprintf(buf+ret, "ASYNC_LOW_LATENCY|");
-       if (self->flags & ASYNC_CLOSING)
-               ret += sprintf(buf+ret, "ASYNC_CLOSING|");
-       if (self->flags & ASYNC_NORMAL_ACTIVE)
-               ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|");
-       if (self->flags)
-               ret--; /* remove the last | */
-       ret += sprintf(buf+ret, "\n");
-
-       ret += sprintf(buf+ret, "Role: %s\n", self->client ?
-                      "client" : "server");
-       ret += sprintf(buf+ret, "Open count: %d\n", self->open_count);
-       ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size);
-       ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size);
+               seq_puts(m, "DTE <-> DTE (null modem emulation)\n");
+
+       seq_printf(m, "Data rate: %d\n", self->settings.data_rate);
+
+       seq_puts(m, "Flow control:");
+       sep = ' ';
+       if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) {
+               seq_printf(m, "%cXON_XOFF_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) {
+               seq_printf(m, "%cXON_XOFF_OUT", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) {
+               seq_printf(m, "%cRTS_CTS_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) {
+               seq_printf(m, "%cRTS_CTS_OUT", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) {
+               seq_printf(m, "%cDSR_DTR_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) {
+               seq_printf(m, "%cDSR_DTR_OUT", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) {
+               seq_printf(m, "%cENQ_ACK_IN", sep);
+               sep = '|';
+       }
+       if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) {
+               seq_printf(m, "%cENQ_ACK_OUT", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_puts(m, "Flags:");
+       sep = ' ';
+       if (self->flags & ASYNC_CTS_FLOW) {
+               seq_printf(m, "%cASYNC_CTS_FLOW", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_CHECK_CD) {
+               seq_printf(m, "%cASYNC_CHECK_CD", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_INITIALIZED) {
+               seq_printf(m, "%cASYNC_INITIALIZED", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_LOW_LATENCY) {
+               seq_printf(m, "%cASYNC_LOW_LATENCY", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_CLOSING) {
+               seq_printf(m, "%cASYNC_CLOSING", sep);
+               sep = '|';
+       }
+       if (self->flags & ASYNC_NORMAL_ACTIVE) {
+               seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
+               sep = '|';
+       }
+       seq_putc(m, '\n');
+
+       seq_printf(m, "Role: %s\n", self->client ? "client" : "server");
+       seq_printf(m, "Open count: %d\n", self->open_count);
+       seq_printf(m, "Max data size: %d\n", self->max_data_size);
+       seq_printf(m, "Max header size: %d\n", self->max_header_size);
 
        if (self->tty)
-               ret += sprintf(buf+ret, "Hardware: %s\n",
+               seq_printf(m, "Hardware: %s\n",
                               self->tty->hw_stopped ? "Stopped" : "Running");
-
-       ret += sprintf(buf+ret, "\n");
-       return ret;
 }
 
-
-/*
- * Function ircomm_tty_read_proc (buf, start, offset, len, eof, unused)
- *
- *
- *
- */
-static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
-                               int *eof, void *unused)
+static int ircomm_tty_proc_show(struct seq_file *m, void *v)
 {
        struct ircomm_tty_cb *self;
-       int count = 0, l;
-       off_t begin = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags);
 
        self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
-       while ((self != NULL) && (count < 4000)) {
+       while (self != NULL) {
                if (self->magic != IRCOMM_TTY_MAGIC)
                        break;
 
-               l = ircomm_tty_line_info(self, buf + count);
-               count += l;
-               if (count+begin > offset+len)
-                       goto done;
-               if (count+begin < offset) {
-                       begin += count;
-                       count = 0;
-               }
-
+               ircomm_tty_line_info(self, m);
                self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
        }
-       *eof = 1;
-done:
        spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags);
+       return 0;
+}
 
-       if (offset >= count+begin)
-               return 0;
-       *start = buf + (offset-begin);
-       return ((len < begin+count-offset) ? len : begin+count-offset);
+static int ircomm_tty_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ircomm_tty_proc_show, NULL);
 }
+
+static const struct file_operations ircomm_tty_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ircomm_tty_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 #endif /* CONFIG_PROC_FS */
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
index 88e80a312732a9ed18e7e1d511d79ac6f0f9d682..8ff1861649e87716d8ecf826c8682182a825a88b 100644 (file)
@@ -70,7 +70,6 @@ void __init irda_proc_register(void)
        proc_irda = proc_mkdir("irda", init_net.proc_net);
        if (proc_irda == NULL)
                return;
-       proc_irda->owner = THIS_MODULE;
 
        for (i = 0; i < ARRAY_SIZE(irda_dirs); i++)
                d = proc_create(irda_dirs[i].name, 0, proc_irda,
index b58bd7c6cdf8b5323df957c1bc113b8970aa9762..d208b3396d94e417546a143c4c7a1d09f9e95f3b 100644 (file)
@@ -236,7 +236,6 @@ int __init llc_proc_init(void)
        llc_proc_dir = proc_mkdir("llc", init_net.proc_net);
        if (!llc_proc_dir)
                goto out;
-       llc_proc_dir->owner = THIS_MODULE;
 
        p = proc_create("socket", S_IRUGO, llc_proc_dir, &llc_seq_socket_fops);
        if (!p)
index 60c16162474c23edbcfe4e338f9e00b4a6b6a0df..f3d9ae350fb66cf9d29c36b94589c342e607b781 100644 (file)
@@ -33,7 +33,7 @@ choice
        ---help---
          This option selects the default rate control algorithm
          mac80211 will use. Note that this default can still be
-         overriden through the ieee80211_default_rc_algo module
+         overridden through the ieee80211_default_rc_algo module
          parameter if different algorithms are available.
 
 config MAC80211_RC_DEFAULT_PID
index 2c967e4f706c9c0de0c6990befa1b3444053149a..bb279bf59a1b9147b5951268ec70d48662eb50f2 100644 (file)
@@ -52,7 +52,7 @@ config NF_CT_ACCT
 
          Please note that currently this option only sets a default state.
          You may change it at boot time with nf_conntrack.acct=0/1 kernel
-         paramater or by loading the nf_conntrack module with acct=0/1.
+         parameter or by loading the nf_conntrack module with acct=0/1.
 
          You may also disable/enable it on a running system with:
           sysctl net.netfilter.nf_conntrack_acct=0/1
index 409c8be58e7c3fe097ceacc47c37ffb8092a155a..8bd98c84f77e7962c55dee04084c8ee05128f1bd 100644 (file)
@@ -66,7 +66,7 @@ static const char *const dccprotos[] = {
  *     ad_beg_p        returns pointer to first byte of addr data
  *     ad_end_p        returns pointer to last byte of addr data
  */
-static int parse_dcc(char *data, const char *data_end, u_int32_t *ip,
+static int parse_dcc(char *data, const char *data_end, __be32 *ip,
                     u_int16_t *port, char **ad_beg_p, char **ad_end_p)
 {
        char *tmp;
@@ -85,7 +85,7 @@ static int parse_dcc(char *data, const char *data_end, u_int32_t *ip,
                return -1;
 
        *ad_beg_p = data;
-       *ip = simple_strtoul(data, &data, 10);
+       *ip = cpu_to_be32(simple_strtoul(data, &data, 10));
 
        /* skip blanks between ip and port */
        while (*data == ' ') {
@@ -112,7 +112,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
        int dir = CTINFO2DIR(ctinfo);
        struct nf_conntrack_expect *exp;
        struct nf_conntrack_tuple *tuple;
-       u_int32_t dcc_ip;
+       __be32 dcc_ip;
        u_int16_t dcc_port;
        __be16 port;
        int i, ret = NF_ACCEPT;
@@ -177,13 +177,14 @@ static int help(struct sk_buff *skb, unsigned int protoff,
                                pr_debug("unable to parse dcc command\n");
                                continue;
                        }
-                       pr_debug("DCC bound ip/port: %u.%u.%u.%u:%u\n",
-                                HIPQUAD(dcc_ip), dcc_port);
+
+                       pr_debug("DCC bound ip/port: %pI4:%u\n",
+                                &dcc_ip, dcc_port);
 
                        /* dcc_ip can be the internal OR external (NAT'ed) IP */
                        tuple = &ct->tuplehash[dir].tuple;
-                       if (tuple->src.u3.ip != htonl(dcc_ip) &&
-                           tuple->dst.u3.ip != htonl(dcc_ip)) {
+                       if (tuple->src.u3.ip != dcc_ip &&
+                           tuple->dst.u3.ip != dcc_ip) {
                                if (net_ratelimit())
                                        printk(KERN_WARNING
                                                "Forged DCC command from %pI4: %pI4:%u\n",
index ad5bd890e4e87c05323511e7e6e1a9e93892a673..6c4847662b8541ff1e808d0269518248930ed7f3 100644 (file)
@@ -57,6 +57,13 @@ xt_cluster_hash(const struct nf_conn *ct,
        return (((u64)hash * info->total_nodes) >> 32);
 }
 
+static inline bool
+xt_cluster_ipv6_is_multicast(const struct in6_addr *addr)
+{
+       __be32 st = addr->s6_addr32[0];
+       return ((st & htonl(0xFF000000)) == htonl(0xFF000000));
+}
+
 static inline bool
 xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
 {
@@ -67,8 +74,8 @@ xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
                is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr);
                break;
        case NFPROTO_IPV6:
-               is_multicast = ipv6_addr_type(&ipv6_hdr(skb)->daddr) &
-                                               IPV6_ADDR_MULTICAST;
+               is_multicast =
+                       xt_cluster_ipv6_is_multicast(&ipv6_hdr(skb)->daddr);
                break;
        default:
                WARN_ON(1);
index 51a5669573f2741ff90aa45864ac96bbf7f8c24c..6ec7d55b1769933f399af5f4673b95c2de83150c 100644 (file)
@@ -6,7 +6,7 @@ config PHONET
        tristate "Phonet protocols family"
        help
          The Phone Network protocol (PhoNet) is a packet-oriented
-         communication protocol developped by Nokia for use with its modems.
+         communication protocol developed by Nokia for use with its modems.
 
          This is required for Maemo to use cellular data connectivity (if
          supported). It can also be used to control Nokia phones
index 06a7b798d9a73c3e346eebe6fb648f7bb247c20d..4933b380985eb730b496dd21152dc470fff7a10c 100644 (file)
@@ -51,6 +51,7 @@ MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer");
 
 struct list_head rds_ib_devices;
 
+/* NOTE: if also grabbing ibdev lock, grab this first */
 DEFINE_SPINLOCK(ib_nodev_conns_lock);
 LIST_HEAD(ib_nodev_conns);
 
@@ -137,7 +138,7 @@ void rds_ib_remove_one(struct ib_device *device)
                kfree(i_ipaddr);
        }
 
-       rds_ib_remove_conns(rds_ibdev);
+       rds_ib_destroy_conns(rds_ibdev);
 
        if (rds_ibdev->mr_pool)
                rds_ib_destroy_mr_pool(rds_ibdev->mr_pool);
@@ -249,7 +250,7 @@ static int rds_ib_laddr_check(__be32 addr)
 void rds_ib_exit(void)
 {
        rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info);
-       rds_ib_remove_nodev_conns();
+       rds_ib_destroy_nodev_conns();
        ib_unregister_client(&rds_ib_client);
        rds_ib_sysctl_exit();
        rds_ib_recv_exit();
index 8be563a1363a2fc75e700dff1d2dfe7b09025d99..069206cae733c3a9a88b5efda1b6478a92355b85 100644 (file)
@@ -108,7 +108,12 @@ struct rds_ib_connection {
 
        /* sending acks */
        unsigned long           i_ack_flags;
+#ifdef KERNEL_HAS_ATOMIC64
+       atomic64_t              i_ack_next;     /* next ACK to send */
+#else
+       spinlock_t              i_ack_lock;     /* protect i_ack_next */
        u64                     i_ack_next;     /* next ACK to send */
+#endif
        struct rds_header       *i_ack;
        struct ib_send_wr       i_ack_wr;
        struct ib_sge           i_ack_sge;
@@ -267,9 +272,17 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn,
 
 /* ib_rdma.c */
 int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr);
-int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
-void rds_ib_remove_nodev_conns(void);
-void rds_ib_remove_conns(struct rds_ib_device *rds_ibdev);
+void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
+void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
+void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock);
+static inline void rds_ib_destroy_nodev_conns(void)
+{
+       __rds_ib_destroy_conns(&ib_nodev_conns, &ib_nodev_conns_lock);
+}
+static inline void rds_ib_destroy_conns(struct rds_ib_device *rds_ibdev)
+{
+       __rds_ib_destroy_conns(&rds_ibdev->conn_list, &rds_ibdev->spinlock);
+}
 struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *);
 void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo);
 void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
@@ -355,13 +368,4 @@ rds_ib_data_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
        return &sge[1];
 }
 
-static inline void rds_ib_set_64bit(u64 *ptr, u64 val)
-{
-#if BITS_PER_LONG == 64
-       *ptr = val;
-#else
-       set_64bit(ptr, val);
-#endif
-}
-
 #endif
index 0532237bd1288428a8d7376fc12f1d0fa780d8c4..f8e40e1a6038882eb5950da72506c9f70cbd7045 100644 (file)
@@ -126,9 +126,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
        err = rds_ib_update_ipaddr(rds_ibdev, conn->c_laddr);
        if (err)
                printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n", err);
-       err = rds_ib_add_conn(rds_ibdev, conn);
-       if (err)
-               printk(KERN_ERR "rds_ib_add_conn failed (%d)\n", err);
+       rds_ib_add_conn(rds_ibdev, conn);
 
        /* If the peer gave us the last packet it saw, process this as if
         * we had received a regular ACK. */
@@ -616,18 +614,8 @@ void rds_ib_conn_shutdown(struct rds_connection *conn)
                /*
                 * Move connection back to the nodev list.
                 */
-               if (ic->rds_ibdev) {
-
-                       spin_lock_irq(&ic->rds_ibdev->spinlock);
-                       BUG_ON(list_empty(&ic->ib_node));
-                       list_del(&ic->ib_node);
-                       spin_unlock_irq(&ic->rds_ibdev->spinlock);
-
-                       spin_lock_irq(&ib_nodev_conns_lock);
-                       list_add_tail(&ic->ib_node, &ib_nodev_conns);
-                       spin_unlock_irq(&ib_nodev_conns_lock);
-                       ic->rds_ibdev = NULL;
-               }
+               if (ic->rds_ibdev)
+                       rds_ib_remove_conn(ic->rds_ibdev, conn);
 
                ic->i_cm_id = NULL;
                ic->i_pd = NULL;
@@ -648,7 +636,11 @@ void rds_ib_conn_shutdown(struct rds_connection *conn)
 
        /* Clear the ACK state */
        clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
-       rds_ib_set_64bit(&ic->i_ack_next, 0);
+#ifdef KERNEL_HAS_ATOMIC64
+       atomic64_set(&ic->i_ack_next, 0);
+#else
+       ic->i_ack_next = 0;
+#endif
        ic->i_ack_recv = 0;
 
        /* Clear flow control state */
@@ -681,6 +673,9 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 
        INIT_LIST_HEAD(&ic->ib_node);
        mutex_init(&ic->i_recv_mutex);
+#ifndef KERNEL_HAS_ATOMIC64
+       spin_lock_init(&ic->i_ack_lock);
+#endif
 
        /*
         * rds_ib_conn_shutdown() waits for these to be emptied so they
@@ -701,11 +696,27 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        return 0;
 }
 
+/*
+ * Free a connection. Connection must be shut down and not set for reconnect.
+ */
 void rds_ib_conn_free(void *arg)
 {
        struct rds_ib_connection *ic = arg;
+       spinlock_t      *lock_ptr;
+
        rdsdebug("ic %p\n", ic);
+
+       /*
+        * Conn is either on a dev's list or on the nodev list.
+        * A race with shutdown() or connect() would cause problems
+        * (since rds_ibdev would change) but that should never happen.
+        */
+       lock_ptr = ic->rds_ibdev ? &ic->rds_ibdev->spinlock : &ib_nodev_conns_lock;
+
+       spin_lock_irq(lock_ptr);
        list_del(&ic->ib_node);
+       spin_unlock_irq(lock_ptr);
+
        kfree(ic);
 }
 
index 69a6289ed672cf37cc06ec6906c8047b24a45276..81033af930207116e5eca3369725a845c8110873 100644 (file)
@@ -139,7 +139,7 @@ int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
        return rds_ib_add_ipaddr(rds_ibdev, ipaddr);
 }
 
-int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
+void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
 {
        struct rds_ib_connection *ic = conn->c_transport_data;
 
@@ -148,45 +148,44 @@ int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn
        BUG_ON(list_empty(&ib_nodev_conns));
        BUG_ON(list_empty(&ic->ib_node));
        list_del(&ic->ib_node);
-       spin_unlock_irq(&ib_nodev_conns_lock);
 
        spin_lock_irq(&rds_ibdev->spinlock);
        list_add_tail(&ic->ib_node, &rds_ibdev->conn_list);
        spin_unlock_irq(&rds_ibdev->spinlock);
+       spin_unlock_irq(&ib_nodev_conns_lock);
 
        ic->rds_ibdev = rds_ibdev;
-
-       return 0;
 }
 
-void rds_ib_remove_nodev_conns(void)
+void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
 {
-       struct rds_ib_connection *ic, *_ic;
-       LIST_HEAD(tmp_list);
+       struct rds_ib_connection *ic = conn->c_transport_data;
 
-       /* avoid calling conn_destroy with irqs off */
-       spin_lock_irq(&ib_nodev_conns_lock);
-       list_splice(&ib_nodev_conns, &tmp_list);
-       INIT_LIST_HEAD(&ib_nodev_conns);
-       spin_unlock_irq(&ib_nodev_conns_lock);
+       /* place conn on nodev_conns_list */
+       spin_lock(&ib_nodev_conns_lock);
 
-       list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) {
-               if (ic->conn->c_passive)
-                       rds_conn_destroy(ic->conn->c_passive);
-               rds_conn_destroy(ic->conn);
-       }
+       spin_lock_irq(&rds_ibdev->spinlock);
+       BUG_ON(list_empty(&ic->ib_node));
+       list_del(&ic->ib_node);
+       spin_unlock_irq(&rds_ibdev->spinlock);
+
+       list_add_tail(&ic->ib_node, &ib_nodev_conns);
+
+       spin_unlock(&ib_nodev_conns_lock);
+
+       ic->rds_ibdev = NULL;
 }
 
-void rds_ib_remove_conns(struct rds_ib_device *rds_ibdev)
+void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock)
 {
        struct rds_ib_connection *ic, *_ic;
        LIST_HEAD(tmp_list);
 
        /* avoid calling conn_destroy with irqs off */
-       spin_lock_irq(&rds_ibdev->spinlock);
-       list_splice(&rds_ibdev->conn_list, &tmp_list);
-       INIT_LIST_HEAD(&rds_ibdev->conn_list);
-       spin_unlock_irq(&rds_ibdev->spinlock);
+       spin_lock_irq(list_lock);
+       list_splice(list, &tmp_list);
+       INIT_LIST_HEAD(list);
+       spin_unlock_irq(list_lock);
 
        list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) {
                if (ic->conn->c_passive)
index 5061b550216252632609887d11d0018574dff756..36d931573ff4f4cb52aec684564e142bbea388e9 100644 (file)
@@ -395,10 +395,37 @@ void rds_ib_recv_init_ack(struct rds_ib_connection *ic)
  * room for it beyond the ring size.  Send completion notices its special
  * wr_id and avoids working with the ring in that case.
  */
+#ifndef KERNEL_HAS_ATOMIC64
 static void rds_ib_set_ack(struct rds_ib_connection *ic, u64 seq,
                                int ack_required)
 {
-       rds_ib_set_64bit(&ic->i_ack_next, seq);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ic->i_ack_lock, flags);
+       ic->i_ack_next = seq;
+       if (ack_required)
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       spin_unlock_irqrestore(&ic->i_ack_lock, flags);
+}
+
+static u64 rds_ib_get_ack(struct rds_ib_connection *ic)
+{
+       unsigned long flags;
+       u64 seq;
+
+       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+
+       spin_lock_irqsave(&ic->i_ack_lock, flags);
+       seq = ic->i_ack_next;
+       spin_unlock_irqrestore(&ic->i_ack_lock, flags);
+
+       return seq;
+}
+#else
+static void rds_ib_set_ack(struct rds_ib_connection *ic, u64 seq,
+                               int ack_required)
+{
+       atomic64_set(&ic->i_ack_next, seq);
        if (ack_required) {
                smp_mb__before_clear_bit();
                set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
@@ -410,8 +437,10 @@ static u64 rds_ib_get_ack(struct rds_ib_connection *ic)
        clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
        smp_mb__after_clear_bit();
 
-       return ic->i_ack_next;
+       return atomic64_read(&ic->i_ack_next);
 }
+#endif
+
 
 static void rds_ib_send_ack(struct rds_ib_connection *ic, unsigned int adv_credits)
 {
@@ -464,6 +493,10 @@ static void rds_ib_send_ack(struct rds_ib_connection *ic, unsigned int adv_credi
  *  -  i_ack_next, which is the last sequence number we received
  *
  * Potentially, send queue and receive queue handlers can run concurrently.
+ * It would be nice to not have to use a spinlock to synchronize things,
+ * but the one problem that rules this out is that 64bit updates are
+ * not atomic on all platforms. Things would be a lot simpler if
+ * we had atomic64 or maybe cmpxchg64 everywhere.
  *
  * Reconnecting complicates this picture just slightly. When we
  * reconnect, we may be seeing duplicate packets. The peer
index 1b56905c4c084c8f2e3cc0dd7a1aaa4ae1ec0c0b..b732efb5b6345b0e5e923388258b500c4eb04208 100644 (file)
@@ -51,6 +51,7 @@ MODULE_PARM_DESC(fastreg_message_size, " Max size of a RDMA transfer (fastreg MR
 
 struct list_head rds_iw_devices;
 
+/* NOTE: if also grabbing iwdev lock, grab this first */
 DEFINE_SPINLOCK(iw_nodev_conns_lock);
 LIST_HEAD(iw_nodev_conns);
 
@@ -145,7 +146,7 @@ void rds_iw_remove_one(struct ib_device *device)
        }
        spin_unlock_irq(&rds_iwdev->spinlock);
 
-       rds_iw_remove_conns(rds_iwdev);
+       rds_iw_destroy_conns(rds_iwdev);
 
        if (rds_iwdev->mr_pool)
                rds_iw_destroy_mr_pool(rds_iwdev->mr_pool);
@@ -258,7 +259,7 @@ static int rds_iw_laddr_check(__be32 addr)
 void rds_iw_exit(void)
 {
        rds_info_deregister_func(RDS_INFO_IWARP_CONNECTIONS, rds_iw_ic_info);
-       rds_iw_remove_nodev_conns();
+       rds_iw_destroy_nodev_conns();
        ib_unregister_client(&rds_iw_client);
        rds_iw_sysctl_exit();
        rds_iw_recv_exit();
index 0ddda34f2a1c12ef646bbb38d8ef30a39bdd7846..b4fb27252895adb45a1cf635ee441741b392cc5d 100644 (file)
@@ -131,7 +131,12 @@ struct rds_iw_connection {
 
        /* sending acks */
        unsigned long           i_ack_flags;
+#ifdef KERNEL_HAS_ATOMIC64
+       atomic64_t              i_ack_next;     /* next ACK to send */
+#else
+       spinlock_t              i_ack_lock;     /* protect i_ack_next */
        u64                     i_ack_next;     /* next ACK to send */
+#endif
        struct rds_header       *i_ack;
        struct ib_send_wr       i_ack_wr;
        struct ib_sge           i_ack_sge;
@@ -294,9 +299,17 @@ void rds_iw_cm_connect_complete(struct rds_connection *conn,
 
 /* ib_rdma.c */
 int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id);
-int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn);
-void rds_iw_remove_nodev_conns(void);
-void rds_iw_remove_conns(struct rds_iw_device *rds_iwdev);
+void rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn);
+void rds_iw_remove_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn);
+void __rds_iw_destroy_conns(struct list_head *list, spinlock_t *list_lock);
+static inline void rds_iw_destroy_nodev_conns(void)
+{
+       __rds_iw_destroy_conns(&iw_nodev_conns, &iw_nodev_conns_lock);
+}
+static inline void rds_iw_destroy_conns(struct rds_iw_device *rds_iwdev)
+{
+       __rds_iw_destroy_conns(&rds_iwdev->conn_list, &rds_iwdev->spinlock);
+}
 struct rds_iw_mr_pool *rds_iw_create_mr_pool(struct rds_iw_device *);
 void rds_iw_get_mr_info(struct rds_iw_device *rds_iwdev, struct rds_info_rdma_connection *iinfo);
 void rds_iw_destroy_mr_pool(struct rds_iw_mr_pool *);
@@ -383,13 +396,4 @@ rds_iw_data_sge(struct rds_iw_connection *ic, struct ib_sge *sge)
        return &sge[1];
 }
 
-static inline void rds_iw_set_64bit(u64 *ptr, u64 val)
-{
-#if BITS_PER_LONG == 64
-       *ptr = val;
-#else
-       set_64bit(ptr, val);
-#endif
-}
-
 #endif
index 57ecb3d4b8a50e0053196fb38aa59c21780fda81..a416b0d492b1ce7b08d0cc17158e379cc6f609f8 100644 (file)
@@ -86,9 +86,7 @@ void rds_iw_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
        err = rds_iw_update_cm_id(rds_iwdev, ic->i_cm_id);
        if (err)
                printk(KERN_ERR "rds_iw_update_ipaddr failed (%d)\n", err);
-       err = rds_iw_add_conn(rds_iwdev, conn);
-       if (err)
-               printk(KERN_ERR "rds_iw_add_conn failed (%d)\n", err);
+       rds_iw_add_conn(rds_iwdev, conn);
 
        /* If the peer gave us the last packet it saw, process this as if
         * we had received a regular ACK. */
@@ -637,19 +635,8 @@ void rds_iw_conn_shutdown(struct rds_connection *conn)
                 *      Move connection back to the nodev list.
                 *      Remove cm_id from the device cm_id list.
                 */
-               if (ic->rds_iwdev) {
-
-                       spin_lock_irq(&ic->rds_iwdev->spinlock);
-                       BUG_ON(list_empty(&ic->iw_node));
-                       list_del(&ic->iw_node);
-                       spin_unlock_irq(&ic->rds_iwdev->spinlock);
-
-                       spin_lock_irq(&iw_nodev_conns_lock);
-                       list_add_tail(&ic->iw_node, &iw_nodev_conns);
-                       spin_unlock_irq(&iw_nodev_conns_lock);
-                       rds_iw_remove_cm_id(ic->rds_iwdev, ic->i_cm_id);
-                       ic->rds_iwdev = NULL;
-               }
+               if (ic->rds_iwdev)
+                       rds_iw_remove_conn(ic->rds_iwdev, conn);
 
                rdma_destroy_id(ic->i_cm_id);
 
@@ -672,7 +659,11 @@ void rds_iw_conn_shutdown(struct rds_connection *conn)
 
        /* Clear the ACK state */
        clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
-       rds_iw_set_64bit(&ic->i_ack_next, 0);
+#ifdef KERNEL_HAS_ATOMIC64
+       atomic64_set(&ic->i_ack_next, 0);
+#else
+       ic->i_ack_next = 0;
+#endif
        ic->i_ack_recv = 0;
 
        /* Clear flow control state */
@@ -706,6 +697,9 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 
        INIT_LIST_HEAD(&ic->iw_node);
        mutex_init(&ic->i_recv_mutex);
+#ifndef KERNEL_HAS_ATOMIC64
+       spin_lock_init(&ic->i_ack_lock);
+#endif
 
        /*
         * rds_iw_conn_shutdown() waits for these to be emptied so they
@@ -726,11 +720,27 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        return 0;
 }
 
+/*
+ * Free a connection. Connection must be shut down and not set for reconnect.
+ */
 void rds_iw_conn_free(void *arg)
 {
        struct rds_iw_connection *ic = arg;
+       spinlock_t      *lock_ptr;
+
        rdsdebug("ic %p\n", ic);
+
+       /*
+        * Conn is either on a dev's list or on the nodev list.
+        * A race with shutdown() or connect() would cause problems
+        * (since rds_iwdev would change) but that should never happen.
+        */
+       lock_ptr = ic->rds_iwdev ? &ic->rds_iwdev->spinlock : &iw_nodev_conns_lock;
+
+       spin_lock_irq(lock_ptr);
        list_del(&ic->iw_node);
+       spin_unlock_irq(lock_ptr);
+
        kfree(ic);
 }
 
index 1c02a8f952d01d3812ce04a2763e6640b969915e..dcdb37da80f29bd741c0295b2c0a41577b7532d3 100644 (file)
@@ -196,7 +196,7 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i
        return rds_iw_add_cm_id(rds_iwdev, cm_id);
 }
 
-int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn)
+void rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn)
 {
        struct rds_iw_connection *ic = conn->c_transport_data;
 
@@ -205,45 +205,45 @@ int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn
        BUG_ON(list_empty(&iw_nodev_conns));
        BUG_ON(list_empty(&ic->iw_node));
        list_del(&ic->iw_node);
-       spin_unlock_irq(&iw_nodev_conns_lock);
 
        spin_lock_irq(&rds_iwdev->spinlock);
        list_add_tail(&ic->iw_node, &rds_iwdev->conn_list);
        spin_unlock_irq(&rds_iwdev->spinlock);
+       spin_unlock_irq(&iw_nodev_conns_lock);
 
        ic->rds_iwdev = rds_iwdev;
-
-       return 0;
 }
 
-void rds_iw_remove_nodev_conns(void)
+void rds_iw_remove_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn)
 {
-       struct rds_iw_connection *ic, *_ic;
-       LIST_HEAD(tmp_list);
+       struct rds_iw_connection *ic = conn->c_transport_data;
 
-       /* avoid calling conn_destroy with irqs off */
-       spin_lock_irq(&iw_nodev_conns_lock);
-       list_splice(&iw_nodev_conns, &tmp_list);
-       INIT_LIST_HEAD(&iw_nodev_conns);
-       spin_unlock_irq(&iw_nodev_conns_lock);
+       /* place conn on nodev_conns_list */
+       spin_lock(&iw_nodev_conns_lock);
 
-       list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) {
-               if (ic->conn->c_passive)
-                       rds_conn_destroy(ic->conn->c_passive);
-               rds_conn_destroy(ic->conn);
-       }
+       spin_lock_irq(&rds_iwdev->spinlock);
+       BUG_ON(list_empty(&ic->iw_node));
+       list_del(&ic->iw_node);
+       spin_unlock_irq(&rds_iwdev->spinlock);
+
+       list_add_tail(&ic->iw_node, &iw_nodev_conns);
+
+       spin_unlock(&iw_nodev_conns_lock);
+
+       rds_iw_remove_cm_id(ic->rds_iwdev, ic->i_cm_id);
+       ic->rds_iwdev = NULL;
 }
 
-void rds_iw_remove_conns(struct rds_iw_device *rds_iwdev)
+void __rds_iw_destroy_conns(struct list_head *list, spinlock_t *list_lock)
 {
        struct rds_iw_connection *ic, *_ic;
        LIST_HEAD(tmp_list);
 
        /* avoid calling conn_destroy with irqs off */
-       spin_lock_irq(&rds_iwdev->spinlock);
-       list_splice(&rds_iwdev->conn_list, &tmp_list);
-       INIT_LIST_HEAD(&rds_iwdev->conn_list);
-       spin_unlock_irq(&rds_iwdev->spinlock);
+       spin_lock_irq(list_lock);
+       list_splice(list, &tmp_list);
+       INIT_LIST_HEAD(list);
+       spin_unlock_irq(list_lock);
 
        list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) {
                if (ic->conn->c_passive)
index a1931f0027a256401a12816f25f321071c23bc92..fde470fa50d5457c72226d0336e00aeed8df534d 100644 (file)
@@ -395,10 +395,37 @@ void rds_iw_recv_init_ack(struct rds_iw_connection *ic)
  * room for it beyond the ring size.  Send completion notices its special
  * wr_id and avoids working with the ring in that case.
  */
+#ifndef KERNEL_HAS_ATOMIC64
 static void rds_iw_set_ack(struct rds_iw_connection *ic, u64 seq,
                                int ack_required)
 {
-       rds_iw_set_64bit(&ic->i_ack_next, seq);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ic->i_ack_lock, flags);
+       ic->i_ack_next = seq;
+       if (ack_required)
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       spin_unlock_irqrestore(&ic->i_ack_lock, flags);
+}
+
+static u64 rds_iw_get_ack(struct rds_iw_connection *ic)
+{
+       unsigned long flags;
+       u64 seq;
+
+       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+
+       spin_lock_irqsave(&ic->i_ack_lock, flags);
+       seq = ic->i_ack_next;
+       spin_unlock_irqrestore(&ic->i_ack_lock, flags);
+
+       return seq;
+}
+#else
+static void rds_iw_set_ack(struct rds_iw_connection *ic, u64 seq,
+                               int ack_required)
+{
+       atomic64_set(&ic->i_ack_next, seq);
        if (ack_required) {
                smp_mb__before_clear_bit();
                set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
@@ -410,8 +437,10 @@ static u64 rds_iw_get_ack(struct rds_iw_connection *ic)
        clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
        smp_mb__after_clear_bit();
 
-       return ic->i_ack_next;
+       return atomic64_read(&ic->i_ack_next);
 }
+#endif
+
 
 static void rds_iw_send_ack(struct rds_iw_connection *ic, unsigned int adv_credits)
 {
@@ -464,6 +493,10 @@ static void rds_iw_send_ack(struct rds_iw_connection *ic, unsigned int adv_credi
  *  -  i_ack_next, which is the last sequence number we received
  *
  * Potentially, send queue and receive queue handlers can run concurrently.
+ * It would be nice to not have to use a spinlock to synchronize things,
+ * but the one problem that rules this out is that 64bit updates are
+ * not atomic on all platforms. Things would be a lot simpler if
+ * we had atomic64 or maybe cmpxchg64 everywhere.
  *
  * Reconnecting complicates this picture just slightly. When we
  * reconnect, we may be seeing duplicate packets. The peer
index 060400704979ba7aebdb29880b8531e64f431b36..619f0a30a4e566952642e27e1d2b49f5f546ad11 100644 (file)
  */
 #define RDS_PORT       18634
 
+#ifdef ATOMIC64_INIT
+#define KERNEL_HAS_ATOMIC64
+#endif
+
 #ifdef DEBUG
 #define rdsdebug(fmt, args...) pr_debug("%s(): " fmt, __func__ , ##args)
 #else
index 1b37364656f09b4a852bfc7bf27e3ab6a928cd63..104fe033203da51eeef849782e1c291e072cdde6 100644 (file)
@@ -615,7 +615,7 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
 {
        struct rds_message *rm, *tmp;
        struct rds_connection *conn;
-       unsigned long flags;
+       unsigned long flags, flags2;
        LIST_HEAD(list);
        int wake = 0;
 
@@ -651,9 +651,9 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
        list_for_each_entry(rm, &list, m_sock_item) {
                /* We do this here rather than in the loop above, so that
                 * we don't have to nest m_rs_lock under rs->rs_lock */
-               spin_lock(&rm->m_rs_lock);
+               spin_lock_irqsave(&rm->m_rs_lock, flags2);
                rm->m_rs = NULL;
-               spin_unlock(&rm->m_rs_lock);
+               spin_unlock_irqrestore(&rm->m_rs_lock, flags2);
 
                /*
                 * If we see this flag cleared then we're *sure* that someone
index cb198af8887c97628a82a903b1c93623dcb992e8..8eb3e61cb7011d1032d5562c0f266281ddf00688 100644 (file)
@@ -106,12 +106,8 @@ static __init int sctp_proc_init(void)
                goto out_nomem;
 #ifdef CONFIG_PROC_FS
        if (!proc_net_sctp) {
-               struct proc_dir_entry *ent;
-               ent = proc_mkdir("sctp", init_net.proc_net);
-               if (ent) {
-                       ent->owner = THIS_MODULE;
-                       proc_net_sctp = ent;
-               } else
+               proc_net_sctp = proc_mkdir("sctp", init_net.proc_net);
+               if (!proc_net_sctp)
                        goto out_free_percpu;
        }
 
index 5592883e1e4a9feab8c44dbd42d9ef049da0031c..443c161eb8bdd0dd4c988a9bab0d6d387fe2f0e3 100644 (file)
@@ -17,28 +17,6 @@ config SUNRPC_XPRT_RDMA
 
          If unsure, say N.
 
-config SUNRPC_REGISTER_V4
-       bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
-       depends on SUNRPC && EXPERIMENTAL
-       default n
-       help
-         Sun added support for registering RPC services at an IPv6
-         address by creating two new versions of the rpcbind protocol
-         (RFC 1833).
-
-         This option enables support in the kernel RPC server for
-         registering kernel RPC services via version 4 of the rpcbind
-         protocol.  If you enable this option, you must run a portmapper
-         daemon that supports rpcbind protocol version 4.
-
-         Serving NFS over IPv6 from knfsd (the kernel's NFS server)
-         requires that you enable this option and use a portmapper that
-         supports rpcbind version 4.
-
-         If unsure, say N to get traditional behavior (register kernel
-         RPC services using only rpcbind version 2).  Distributions
-         using the legacy Linux portmapper daemon must say N here.
-
 config RPCSEC_GSS_KRB5
        tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
        depends on SUNRPC && EXPERIMENTAL
@@ -69,7 +47,7 @@ config RPCSEC_GSS_SPKM3
        select CRYPTO_CBC
        help
          Choose Y here to enable Secure RPC using the SPKM3 public key
-         GSS-API mechansim (RFC 2025).
+         GSS-API mechanism (RFC 2025).
 
          Secure RPC calls with SPKM3 require an auxiliary userspace
          daemon which may be found in the Linux nfs-utils package
index 4735caad26edc4195f503befa997a432145c7528..20029a79a5debf4a645623843c110eecaf5017ad 100644 (file)
@@ -313,7 +313,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
        cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
        if (cd->proc_ent == NULL)
                goto out_nomem;
-       cd->proc_ent->owner = cd->owner;
        cd->channel_ent = cd->content_ent = NULL;
 
        p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR,
@@ -321,7 +320,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
        cd->flush_ent = p;
        if (p == NULL)
                goto out_nomem;
-       p->owner = cd->owner;
 
        if (cd->cache_request || cd->cache_parse) {
                p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR,
@@ -329,7 +327,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
                cd->channel_ent = p;
                if (p == NULL)
                        goto out_nomem;
-               p->owner = cd->owner;
        }
        if (cd->cache_show) {
                p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR,
@@ -337,7 +334,6 @@ static int create_cache_proc_entries(struct cache_detail *cd)
                cd->content_ent = p;
                if (p == NULL)
                        goto out_nomem;
-               p->owner = cd->owner;
        }
        return 0;
 out_nomem:
index 836f15c0c4a3489b6e9d5ba5a7bfc59514a0db3d..5abab094441f97cbe8dd7f91dcd554579030b6be 100644 (file)
@@ -1032,27 +1032,20 @@ call_connect_status(struct rpc_task *task)
        dprint_status(task);
 
        task->tk_status = 0;
-       if (status >= 0) {
+       if (status >= 0 || status == -EAGAIN) {
                clnt->cl_stats->netreconn++;
                task->tk_action = call_transmit;
                return;
        }
 
-       /* Something failed: remote service port may have changed */
-       rpc_force_rebind(clnt);
-
        switch (status) {
-       case -ENOTCONN:
-       case -EAGAIN:
-               task->tk_action = call_bind;
-               if (!RPC_IS_SOFT(task))
-                       return;
                /* if soft mounted, test if we've timed out */
        case -ETIMEDOUT:
                task->tk_action = call_timeout;
-               return;
+               break;
+       default:
+               rpc_exit(task, -EIO);
        }
-       rpc_exit(task, -EIO);
 }
 
 /*
@@ -1105,14 +1098,26 @@ static void
 call_transmit_status(struct rpc_task *task)
 {
        task->tk_action = call_status;
-       /*
-        * Special case: if we've been waiting on the socket's write_space()
-        * callback, then don't call xprt_end_transmit().
-        */
-       if (task->tk_status == -EAGAIN)
-               return;
-       xprt_end_transmit(task);
-       rpc_task_force_reencode(task);
+       switch (task->tk_status) {
+       case -EAGAIN:
+               break;
+       default:
+               xprt_end_transmit(task);
+               /*
+                * Special cases: if we've been waiting on the
+                * socket's write_space() callback, or if the
+                * socket just returned a connection error,
+                * then hold onto the transport lock.
+                */
+       case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ENOTCONN:
+       case -EHOSTDOWN:
+       case -EHOSTUNREACH:
+       case -ENETUNREACH:
+       case -EPIPE:
+               rpc_task_force_reencode(task);
+       }
 }
 
 /*
@@ -1152,9 +1157,12 @@ call_status(struct rpc_task *task)
                        xprt_conditional_disconnect(task->tk_xprt,
                                        req->rq_connect_cookie);
                break;
+       case -ECONNRESET:
        case -ECONNREFUSED:
-       case -ENOTCONN:
                rpc_force_rebind(clnt);
+               rpc_delay(task, 3*HZ);
+       case -EPIPE:
+       case -ENOTCONN:
                task->tk_action = call_bind;
                break;
        case -EAGAIN:
index 03ae007641e48523ee22cbd4aa4d5cef825b84c5..beee6da330358cb75ef2e7cb22037d635d0080f0 100644 (file)
@@ -63,9 +63,16 @@ enum {
  * r_owner
  *
  * The "owner" is allowed to unset a service in the rpcbind database.
- * We always use the following (arbitrary) fixed string.
+ *
+ * For AF_LOCAL SET/UNSET requests, rpcbind treats this string as a
+ * UID which it maps to a local user name via a password lookup.
+ * In all other cases it is ignored.
+ *
+ * For SET/UNSET requests, user space provides a value, even for
+ * network requests, and GETADDR uses an empty string.  We follow
+ * those precedents here.
  */
-#define RPCB_OWNER_STRING      "rpcb"
+#define RPCB_OWNER_STRING      "0"
 #define RPCB_MAXOWNERLEN       sizeof(RPCB_OWNER_STRING)
 
 static void                    rpcb_getport_done(struct rpc_task *, void *);
@@ -124,12 +131,6 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
        .sin_port               = htons(RPCBIND_PORT),
 };
 
-static const struct sockaddr_in6 rpcb_in6addr_loopback = {
-       .sin6_family            = AF_INET6,
-       .sin6_addr              = IN6ADDR_LOOPBACK_INIT,
-       .sin6_port              = htons(RPCBIND_PORT),
-};
-
 static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
                                          size_t addrlen, u32 version)
 {
@@ -176,9 +177,10 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
        return rpc_create(&args);
 }
 
-static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
-                             u32 version, struct rpc_message *msg)
+static int rpcb_register_call(const u32 version, struct rpc_message *msg)
 {
+       struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback;
+       size_t addrlen = sizeof(rpcb_inaddr_loopback);
        struct rpc_clnt *rpcb_clnt;
        int result, error = 0;
 
@@ -192,7 +194,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
                error = PTR_ERR(rpcb_clnt);
 
        if (error < 0) {
-               printk(KERN_WARNING "RPC: failed to contact local rpcbind "
+               dprintk("RPC:       failed to contact local rpcbind "
                                "server (errno %d).\n", -error);
                return error;
        }
@@ -254,25 +256,23 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
        if (port)
                msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
 
-       return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
-                                       sizeof(rpcb_inaddr_loopback),
-                                       RPCBVERS_2, &msg);
+       return rpcb_register_call(RPCBVERS_2, &msg);
 }
 
 /*
  * Fill in AF_INET family-specific arguments to register
  */
-static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
-                               struct rpc_message *msg)
+static int rpcb_register_inet4(const struct sockaddr *sap,
+                              struct rpc_message *msg)
 {
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
-       unsigned short port = ntohs(address_to_register->sin_port);
+       unsigned short port = ntohs(sin->sin_port);
        char buf[32];
 
        /* Construct AF_INET universal address */
        snprintf(buf, sizeof(buf), "%pI4.%u.%u",
-                &address_to_register->sin_addr.s_addr,
-                port >> 8, port & 0xff);
+                &sin->sin_addr.s_addr, port >> 8, port & 0xff);
        map->r_addr = buf;
 
        dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -284,29 +284,27 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
-                                       sizeof(rpcb_inaddr_loopback),
-                                       RPCBVERS_4, msg);
+       return rpcb_register_call(RPCBVERS_4, msg);
 }
 
 /*
  * Fill in AF_INET6 family-specific arguments to register
  */
-static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
-                               struct rpc_message *msg)
+static int rpcb_register_inet6(const struct sockaddr *sap,
+                              struct rpc_message *msg)
 {
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
-       unsigned short port = ntohs(address_to_register->sin6_port);
+       unsigned short port = ntohs(sin6->sin6_port);
        char buf[64];
 
        /* Construct AF_INET6 universal address */
-       if (ipv6_addr_any(&address_to_register->sin6_addr))
+       if (ipv6_addr_any(&sin6->sin6_addr))
                snprintf(buf, sizeof(buf), "::.%u.%u",
                                port >> 8, port & 0xff);
        else
                snprintf(buf, sizeof(buf), "%pI6.%u.%u",
-                        &address_to_register->sin6_addr,
-                        port >> 8, port & 0xff);
+                        &sin6->sin6_addr, port >> 8, port & 0xff);
        map->r_addr = buf;
 
        dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -318,9 +316,21 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
-                                       sizeof(rpcb_in6addr_loopback),
-                                       RPCBVERS_4, msg);
+       return rpcb_register_call(RPCBVERS_4, msg);
+}
+
+static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
+{
+       struct rpcbind_args *map = msg->rpc_argp;
+
+       dprintk("RPC:       unregistering [%u, %u, '%s'] with "
+               "local rpcbind\n",
+                       map->r_prog, map->r_vers, map->r_netid);
+
+       map->r_addr = "";
+       msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
+
+       return rpcb_register_call(RPCBVERS_4, msg);
 }
 
 /**
@@ -340,10 +350,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
  * invoke this function once for each [program, version, address,
  * netid] tuple they wish to advertise.
  *
- * Callers may also unregister RPC services that are no longer
- * available by setting the port number in the passed-in address
- * to zero.  Callers pass a netid of "" to unregister all
- * transport netids associated with [program, version, address].
+ * Callers may also unregister RPC services that are registered at a
+ * specific address by setting the port number in @address to zero.
+ * They may unregister all registered protocol families at once for
+ * a service by passing a NULL @address argument.  If @netid is ""
+ * then all netids for [program, version, address] are unregistered.
  *
  * This function uses rpcbind protocol version 4 to contact the
  * local rpcbind daemon.  The local rpcbind daemon must support
@@ -378,13 +389,14 @@ int rpcb_v4_register(const u32 program, const u32 version,
                .rpc_argp       = &map,
        };
 
+       if (address == NULL)
+               return rpcb_unregister_all_protofamilies(&msg);
+
        switch (address->sa_family) {
        case AF_INET:
-               return rpcb_register_netid4((struct sockaddr_in *)address,
-                                           &msg);
+               return rpcb_register_inet4(address, &msg);
        case AF_INET6:
-               return rpcb_register_netid6((struct sockaddr_in6 *)address,
-                                           &msg);
+               return rpcb_register_inet6(address, &msg);
        }
 
        return -EAFNOSUPPORT;
@@ -579,7 +591,7 @@ void rpcb_getport_async(struct rpc_task *task)
        map->r_xprt = xprt_get(xprt);
        map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
        map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
-       map->r_owner = RPCB_OWNER_STRING;       /* ignored for GETADDR */
+       map->r_owner = "";
        map->r_status = -EIO;
 
        child = rpcb_call_async(rpcb_clnt, map, proc);
@@ -703,11 +715,16 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
        *portp = 0;
        addr_len = ntohl(*p++);
 
+       if (addr_len == 0) {
+               dprintk("RPC:       rpcb_decode_getaddr: "
+                                       "service is not registered\n");
+               return 0;
+       }
+
        /*
-        * Simple sanity check.  The smallest possible universal
-        * address is an IPv4 address string containing 11 bytes.
+        * Simple sanity check.
         */
-       if (addr_len < 11 || addr_len > RPCBIND_MAXUADDRLEN)
+       if (addr_len > RPCBIND_MAXUADDRLEN)
                goto out_err;
 
        /*
index 085372ef4feb148bf99d0525074ef7c819c09051..1ef6e46d9da273b276625e765e6d6bd1c880457a 100644 (file)
@@ -262,14 +262,8 @@ void
 rpc_proc_init(void)
 {
        dprintk("RPC:       registering /proc/net/rpc\n");
-       if (!proc_net_rpc) {
-               struct proc_dir_entry *ent;
-               ent = proc_mkdir("rpc", init_net.proc_net);
-               if (ent) {
-                       ent->owner = THIS_MODULE;
-                       proc_net_rpc = ent;
-               }
-       }
+       if (!proc_net_rpc)
+               proc_net_rpc = proc_mkdir("rpc", init_net.proc_net);
 }
 
 void
index c51fed4d1af1d3b93ebfbbf9e2eaeaf4a76fb16f..9f2f2412a2f35245056f5174cd5bbbb956cabd13 100644 (file)
@@ -312,7 +312,7 @@ svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
        switch (m->mode) {
        case SVC_POOL_PERCPU:
        {
-               set_cpus_allowed_ptr(task, &cpumask_of_cpu(node));
+               set_cpus_allowed_ptr(task, cpumask_of(node));
                break;
        }
        case SVC_POOL_PERNODE:
@@ -359,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
  */
 static struct svc_serv *
 __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
-          sa_family_t family, void (*shutdown)(struct svc_serv *serv))
+            void (*shutdown)(struct svc_serv *serv))
 {
        struct svc_serv *serv;
        unsigned int vers;
@@ -368,7 +368,6 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 
        if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
                return NULL;
-       serv->sv_family    = family;
        serv->sv_name      = prog->pg_name;
        serv->sv_program   = prog;
        serv->sv_nrthreads = 1;
@@ -427,21 +426,21 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 
 struct svc_serv *
 svc_create(struct svc_program *prog, unsigned int bufsize,
-               sa_family_t family, void (*shutdown)(struct svc_serv *serv))
+          void (*shutdown)(struct svc_serv *serv))
 {
-       return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
+       return __svc_create(prog, bufsize, /*npools*/1, shutdown);
 }
 EXPORT_SYMBOL_GPL(svc_create);
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
-                 sa_family_t family, void (*shutdown)(struct svc_serv *serv),
+                 void (*shutdown)(struct svc_serv *serv),
                  svc_thread_fn func, struct module *mod)
 {
        struct svc_serv *serv;
        unsigned int npools = svc_pool_map_get();
 
-       serv = __svc_create(prog, bufsize, npools, family, shutdown);
+       serv = __svc_create(prog, bufsize, npools, shutdown);
 
        if (serv != NULL) {
                serv->sv_function = func;
@@ -719,8 +718,6 @@ svc_exit_thread(struct svc_rqst *rqstp)
 }
 EXPORT_SYMBOL_GPL(svc_exit_thread);
 
-#ifdef CONFIG_SUNRPC_REGISTER_V4
-
 /*
  * Register an "inet" protocol family netid with the local
  * rpcbind daemon via an rpcbind v4 SET request.
@@ -735,12 +732,13 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
-       struct sockaddr_in sin = {
+       const struct sockaddr_in sin = {
                .sin_family             = AF_INET,
                .sin_addr.s_addr        = htonl(INADDR_ANY),
                .sin_port               = htons(port),
        };
-       char *netid;
+       const char *netid;
+       int error;
 
        switch (protocol) {
        case IPPROTO_UDP:
@@ -750,13 +748,23 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
                netid = RPCBIND_NETID_TCP;
                break;
        default:
-               return -EPROTONOSUPPORT;
+               return -ENOPROTOOPT;
        }
 
-       return rpcb_v4_register(program, version,
-                               (struct sockaddr *)&sin, netid);
+       error = rpcb_v4_register(program, version,
+                                       (const struct sockaddr *)&sin, netid);
+
+       /*
+        * User space didn't support rpcbind v4, so retry this
+        * registration request with the legacy rpcbind v2 protocol.
+        */
+       if (error == -EPROTONOSUPPORT)
+               error = rpcb_register(program, version, protocol, port);
+
+       return error;
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 /*
  * Register an "inet6" protocol family netid with the local
  * rpcbind daemon via an rpcbind v4 SET request.
@@ -771,12 +779,13 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
-       struct sockaddr_in6 sin6 = {
+       const struct sockaddr_in6 sin6 = {
                .sin6_family            = AF_INET6,
                .sin6_addr              = IN6ADDR_ANY_INIT,
                .sin6_port              = htons(port),
        };
-       char *netid;
+       const char *netid;
+       int error;
 
        switch (protocol) {
        case IPPROTO_UDP:
@@ -786,12 +795,22 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
                netid = RPCBIND_NETID_TCP6;
                break;
        default:
-               return -EPROTONOSUPPORT;
+               return -ENOPROTOOPT;
        }
 
-       return rpcb_v4_register(program, version,
-                               (struct sockaddr *)&sin6, netid);
+       error = rpcb_v4_register(program, version,
+                                       (const struct sockaddr *)&sin6, netid);
+
+       /*
+        * User space didn't support rpcbind version 4, so we won't
+        * use a PF_INET6 listener.
+        */
+       if (error == -EPROTONOSUPPORT)
+               error = -EAFNOSUPPORT;
+
+       return error;
 }
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 
 /*
  * Register a kernel RPC service via rpcbind version 4.
@@ -799,69 +818,43 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_register(const u32 program, const u32 version,
-                         const sa_family_t family,
+static int __svc_register(const char *progname,
+                         const u32 program, const u32 version,
+                         const int family,
                          const unsigned short protocol,
                          const unsigned short port)
 {
-       int error;
+       int error = -EAFNOSUPPORT;
 
        switch (family) {
-       case AF_INET:
-               return __svc_rpcb_register4(program, version,
+       case PF_INET:
+               error = __svc_rpcb_register4(program, version,
                                                protocol, port);
-       case AF_INET6:
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case PF_INET6:
                error = __svc_rpcb_register6(program, version,
                                                protocol, port);
-               if (error < 0)
-                       return error;
-
-               /*
-                * Work around bug in some versions of Linux rpcbind
-                * which don't allow registration of both inet and
-                * inet6 netids.
-                *
-                * Error return ignored for now.
-                */
-               __svc_rpcb_register4(program, version,
-                                               protocol, port);
-               return 0;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
        }
 
-       return -EAFNOSUPPORT;
-}
-
-#else  /* CONFIG_SUNRPC_REGISTER_V4 */
-
-/*
- * Register a kernel RPC service via rpcbind version 2.
- *
- * Returns zero on success; a negative errno value is returned
- * if any error occurs.
- */
-static int __svc_register(const u32 program, const u32 version,
-                         sa_family_t family,
-                         const unsigned short protocol,
-                         const unsigned short port)
-{
-       if (family != AF_INET)
-               return -EAFNOSUPPORT;
-
-       return rpcb_register(program, version, protocol, port);
+       if (error < 0)
+               printk(KERN_WARNING "svc: failed to register %sv%u RPC "
+                       "service (errno %d).\n", progname, version, -error);
+       return error;
 }
 
-#endif /* CONFIG_SUNRPC_REGISTER_V4 */
-
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
+ * @family: protocol family of service's listener socket
  * @proto: transport protocol number to advertise
  * @port: port to advertise
  *
- * Service is registered for any address in serv's address family
+ * Service is registered for any address in the passed-in protocol family
  */
-int svc_register(const struct svc_serv *serv, const unsigned short proto,
-                const unsigned short port)
+int svc_register(const struct svc_serv *serv, const int family,
+                const unsigned short proto, const unsigned short port)
 {
        struct svc_program      *progp;
        unsigned int            i;
@@ -879,15 +872,15 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto,
                                        i,
                                        proto == IPPROTO_UDP?  "udp" : "tcp",
                                        port,
-                                       serv->sv_family,
+                                       family,
                                        progp->pg_vers[i]->vs_hidden?
                                                " (but not telling portmap)" : "");
 
                        if (progp->pg_vers[i]->vs_hidden)
                                continue;
 
-                       error = __svc_register(progp->pg_prog, i,
-                                               serv->sv_family, proto, port);
+                       error = __svc_register(progp->pg_name, progp->pg_prog,
+                                               i, family, proto, port);
                        if (error < 0)
                                break;
                }
@@ -896,38 +889,31 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto,
        return error;
 }
 
-#ifdef CONFIG_SUNRPC_REGISTER_V4
-
+/*
+ * If user space is running rpcbind, it should take the v4 UNSET
+ * and clear everything for this [program, version].  If user space
+ * is running portmap, it will reject the v4 UNSET, but won't have
+ * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
+ * in this case to clear all existing entries for [program, version].
+ */
 static void __svc_unregister(const u32 program, const u32 version,
                             const char *progname)
 {
-       struct sockaddr_in6 sin6 = {
-               .sin6_family            = AF_INET6,
-               .sin6_addr              = IN6ADDR_ANY_INIT,
-               .sin6_port              = 0,
-       };
        int error;
 
-       error = rpcb_v4_register(program, version,
-                               (struct sockaddr *)&sin6, "");
-       dprintk("svc: %s(%sv%u), error %d\n",
-                       __func__, progname, version, error);
-}
-
-#else  /* CONFIG_SUNRPC_REGISTER_V4 */
+       error = rpcb_v4_register(program, version, NULL, "");
 
-static void __svc_unregister(const u32 program, const u32 version,
-                            const char *progname)
-{
-       int error;
+       /*
+        * User space didn't support rpcbind v4, so retry this
+        * request with the legacy rpcbind v2 protocol.
+        */
+       if (error == -EPROTONOSUPPORT)
+               error = rpcb_register(program, version, 0, 0);
 
-       error = rpcb_register(program, version, 0, 0);
        dprintk("svc: %s(%sv%u), error %d\n",
                        __func__, progname, version, error);
 }
 
-#endif /* CONFIG_SUNRPC_REGISTER_V4 */
-
 /*
  * All netids, bind addresses and ports registered for [program, version]
  * are removed from the local rpcbind database (if the service is not
index e588df5d6b34292f63fcf1d9e43c8ae05eeecb17..2819ee093f365210c21c3895858221e5c4a3b656 100644 (file)
@@ -161,7 +161,9 @@ EXPORT_SYMBOL_GPL(svc_xprt_init);
 
 static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
                                         struct svc_serv *serv,
-                                        unsigned short port, int flags)
+                                        const int family,
+                                        const unsigned short port,
+                                        int flags)
 {
        struct sockaddr_in sin = {
                .sin_family             = AF_INET,
@@ -176,12 +178,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
        struct sockaddr *sap;
        size_t len;
 
-       switch (serv->sv_family) {
-       case AF_INET:
+       switch (family) {
+       case PF_INET:
                sap = (struct sockaddr *)&sin;
                len = sizeof(sin);
                break;
-       case AF_INET6:
+       case PF_INET6:
                sap = (struct sockaddr *)&sin6;
                len = sizeof(sin6);
                break;
@@ -192,7 +194,8 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
        return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
 }
 
-int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
+                   const int family, const unsigned short port,
                    int flags)
 {
        struct svc_xprt_class *xcl;
@@ -209,7 +212,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
                        goto err;
 
                spin_unlock(&svc_xprt_class_lock);
-               newxprt = __svc_xpo_create(xcl, serv, port, flags);
+               newxprt = __svc_xpo_create(xcl, serv, family, port, flags);
                if (IS_ERR(newxprt)) {
                        module_put(xcl->xcl_owner);
                        return PTR_ERR(newxprt);
@@ -1033,7 +1036,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
        return dr;
 }
 
-/*
+/**
+ * svc_find_xprt - find an RPC transport instance
+ * @serv: pointer to svc_serv to search
+ * @xcl_name: C string containing transport's class name
+ * @af: Address family of transport's local address
+ * @port: transport's IP port number
+ *
  * Return the transport instance pointer for the endpoint accepting
  * connections/peer traffic from the specified transport class,
  * address family and port.
@@ -1042,14 +1051,14 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
  * wild-card, and will result in matching the first transport in the
  * service's list that has a matching class name.
  */
-struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
-                              int af, int port)
+struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
+                              const sa_family_t af, const unsigned short port)
 {
        struct svc_xprt *xprt;
        struct svc_xprt *found = NULL;
 
        /* Sanity check the args */
-       if (!serv || !xcl_name)
+       if (serv == NULL || xcl_name == NULL)
                return found;
 
        spin_lock_bh(&serv->sv_lock);
@@ -1058,7 +1067,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
                        continue;
                if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
                        continue;
-               if (port && port != svc_xprt_local_port(xprt))
+               if (port != 0 && port != svc_xprt_local_port(xprt))
                        continue;
                found = xprt;
                svc_xprt_get(xprt);
index 5763e6460feac2535429bd97b7f9e43b36816cd9..9d504234af4a664f5f116171b9d6e02825d1ac4f 100644 (file)
@@ -1110,7 +1110,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        struct svc_sock *svsk;
        struct sock     *inet;
        int             pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
-       int             val;
 
        dprintk("svc: svc_setup_socket %p\n", sock);
        if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1122,7 +1121,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
 
        /* Register socket with portmapper */
        if (*errp >= 0 && pmap_register)
-               *errp = svc_register(serv, inet->sk_protocol,
+               *errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
                                     ntohs(inet_sk(inet)->sport));
 
        if (*errp < 0) {
@@ -1143,18 +1142,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        else
                svc_tcp_init(svsk, serv);
 
-       /*
-        * We start one listener per sv_serv.  We want AF_INET
-        * requests to be automatically shunted to our AF_INET6
-        * listener using a mapped IPv4 address.  Make sure
-        * no-one starts an equivalent IPv4 listener, which
-        * would steal our incoming connections.
-        */
-       val = 0;
-       if (serv->sv_family == AF_INET6)
-               kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
-                                       (char *)&val, sizeof(val));
-
        dprintk("svc: svc_setup_socket created %p (inet %p)\n",
                                svsk, svsk->sk_sk);
 
@@ -1222,6 +1209,8 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
        struct sockaddr_storage addr;
        struct sockaddr *newsin = (struct sockaddr *)&addr;
        int             newlen;
+       int             family;
+       int             val;
        RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
 
        dprintk("svc: svc_create_socket(%s, %d, %s)\n",
@@ -1233,14 +1222,35 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
                                "sockets supported\n");
                return ERR_PTR(-EINVAL);
        }
+
        type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
+       switch (sin->sa_family) {
+       case AF_INET6:
+               family = PF_INET6;
+               break;
+       case AF_INET:
+               family = PF_INET;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
 
-       error = sock_create_kern(sin->sa_family, type, protocol, &sock);
+       error = sock_create_kern(family, type, protocol, &sock);
        if (error < 0)
                return ERR_PTR(error);
 
        svc_reclassify_socket(sock);
 
+       /*
+        * If this is an PF_INET6 listener, we want to avoid
+        * getting requests from IPv4 remotes.  Those should
+        * be shunted to a PF_INET listener via rpcbind.
+        */
+       val = 1;
+       if (family == PF_INET6)
+               kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+                                       (char *)&val, sizeof(val));
+
        if (type == SOCK_STREAM)
                sock->sk->sk_reuse = 1;         /* allow address reuse */
        error = kernel_bind(sock, sin, len);
index 62098d101a1fa612e70dfe2319bfb99abee412b3..a0bfe53f162145c9d636f090066a03fd8a42e74f 100644 (file)
@@ -151,6 +151,37 @@ out:
 }
 EXPORT_SYMBOL_GPL(xprt_unregister_transport);
 
+/**
+ * xprt_load_transport - load a transport implementation
+ * @transport_name: transport to load
+ *
+ * Returns:
+ * 0:          transport successfully loaded
+ * -ENOENT:    transport module not available
+ */
+int xprt_load_transport(const char *transport_name)
+{
+       struct xprt_class *t;
+       char module_name[sizeof t->name + 5];
+       int result;
+
+       result = 0;
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               if (strcmp(t->name, transport_name) == 0) {
+                       spin_unlock(&xprt_list_lock);
+                       goto out;
+               }
+       }
+       spin_unlock(&xprt_list_lock);
+       strcpy(module_name, "xprt");
+       strncat(module_name, transport_name, sizeof t->name);
+       result = request_module(module_name);
+out:
+       return result;
+}
+EXPORT_SYMBOL_GPL(xprt_load_transport);
+
 /**
  * xprt_reserve_xprt - serialize write access to transports
  * @task: task that is requesting access to the transport
@@ -580,7 +611,7 @@ void xprt_disconnect_done(struct rpc_xprt *xprt)
        dprintk("RPC:       disconnected transport %p\n", xprt);
        spin_lock_bh(&xprt->transport_lock);
        xprt_clear_connected(xprt);
-       xprt_wake_pending_tasks(xprt, -ENOTCONN);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
        spin_unlock_bh(&xprt->transport_lock);
 }
 EXPORT_SYMBOL_GPL(xprt_disconnect_done);
@@ -598,7 +629,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
        /* Try to schedule an autoclose RPC call */
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
                queue_work(rpciod_workqueue, &xprt->task_cleanup);
-       xprt_wake_pending_tasks(xprt, -ENOTCONN);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
        spin_unlock_bh(&xprt->transport_lock);
 }
 
@@ -625,7 +656,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
        /* Try to schedule an autoclose RPC call */
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
                queue_work(rpciod_workqueue, &xprt->task_cleanup);
-       xprt_wake_pending_tasks(xprt, -ENOTCONN);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
 out:
        spin_unlock_bh(&xprt->transport_lock);
 }
@@ -695,9 +726,8 @@ static void xprt_connect_status(struct rpc_task *task)
        }
 
        switch (task->tk_status) {
-       case -ENOTCONN:
-               dprintk("RPC: %5u xprt_connect_status: connection broken\n",
-                               task->tk_pid);
+       case -EAGAIN:
+               dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
                break;
        case -ETIMEDOUT:
                dprintk("RPC: %5u xprt_connect_status: connect attempt timed "
@@ -818,15 +848,8 @@ int xprt_prepare_transmit(struct rpc_task *task)
                err = req->rq_received;
                goto out_unlock;
        }
-       if (!xprt->ops->reserve_xprt(task)) {
+       if (!xprt->ops->reserve_xprt(task))
                err = -EAGAIN;
-               goto out_unlock;
-       }
-
-       if (!xprt_connected(xprt)) {
-               err = -ENOTCONN;
-               goto out_unlock;
-       }
 out_unlock:
        spin_unlock_bh(&xprt->transport_lock);
        return err;
@@ -870,32 +893,26 @@ void xprt_transmit(struct rpc_task *task)
        req->rq_connect_cookie = xprt->connect_cookie;
        req->rq_xtime = jiffies;
        status = xprt->ops->send_request(task);
-       if (status == 0) {
-               dprintk("RPC: %5u xmit complete\n", task->tk_pid);
-               spin_lock_bh(&xprt->transport_lock);
+       if (status != 0) {
+               task->tk_status = status;
+               return;
+       }
 
-               xprt->ops->set_retrans_timeout(task);
+       dprintk("RPC: %5u xmit complete\n", task->tk_pid);
+       spin_lock_bh(&xprt->transport_lock);
 
-               xprt->stat.sends++;
-               xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
-               xprt->stat.bklog_u += xprt->backlog.qlen;
+       xprt->ops->set_retrans_timeout(task);
 
-               /* Don't race with disconnect */
-               if (!xprt_connected(xprt))
-                       task->tk_status = -ENOTCONN;
-               else if (!req->rq_received)
-                       rpc_sleep_on(&xprt->pending, task, xprt_timer);
-               spin_unlock_bh(&xprt->transport_lock);
-               return;
-       }
+       xprt->stat.sends++;
+       xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
+       xprt->stat.bklog_u += xprt->backlog.qlen;
 
-       /* Note: at this point, task->tk_sleeping has not yet been set,
-        *       hence there is no danger of the waking up task being put on
-        *       schedq, and being picked up by a parallel run of rpciod().
-        */
-       task->tk_status = status;
-       if (status == -ECONNREFUSED)
-               rpc_sleep_on(&xprt->sending, task, NULL);
+       /* Don't race with disconnect */
+       if (!xprt_connected(xprt))
+               task->tk_status = -ENOTCONN;
+       else if (!req->rq_received)
+               rpc_sleep_on(&xprt->pending, task, xprt_timer);
+       spin_unlock_bh(&xprt->transport_lock);
 }
 
 static inline void do_xprt_reserve(struct rpc_task *task)
index 14106d26bb95881b2f7e3c5496aa8b10625a298f..e5e28d1946a41a852a558caa83ca49c68265bed7 100644 (file)
@@ -310,6 +310,19 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
                __func__, pad, destp, rqst->rq_slen, curlen);
 
        copy_len = rqst->rq_snd_buf.page_len;
+
+       if (rqst->rq_snd_buf.tail[0].iov_len) {
+               curlen = rqst->rq_snd_buf.tail[0].iov_len;
+               if (destp + copy_len != rqst->rq_snd_buf.tail[0].iov_base) {
+                       memmove(destp + copy_len,
+                               rqst->rq_snd_buf.tail[0].iov_base, curlen);
+                       r_xprt->rx_stats.pullup_copy_count += curlen;
+               }
+               dprintk("RPC:       %s: tail destp 0x%p len %d\n",
+                       __func__, destp + copy_len, curlen);
+               rqst->rq_svec[0].iov_len += curlen;
+       }
+
        r_xprt->rx_stats.pullup_copy_count += copy_len;
        npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT;
        for (i = 0; copy_len && i < npages; i++) {
@@ -332,17 +345,6 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
                destp += curlen;
                copy_len -= curlen;
        }
-       if (rqst->rq_snd_buf.tail[0].iov_len) {
-               curlen = rqst->rq_snd_buf.tail[0].iov_len;
-               if (destp != rqst->rq_snd_buf.tail[0].iov_base) {
-                       memcpy(destp,
-                               rqst->rq_snd_buf.tail[0].iov_base, curlen);
-                       r_xprt->rx_stats.pullup_copy_count += curlen;
-               }
-               dprintk("RPC:       %s: tail destp 0x%p len %d curlen %d\n",
-                       __func__, destp, copy_len, curlen);
-               rqst->rq_svec[0].iov_len += curlen;
-       }
        /* header now contains entire send message */
        return pad;
 }
@@ -656,7 +658,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
                if (curlen > rqst->rq_rcv_buf.tail[0].iov_len)
                        curlen = rqst->rq_rcv_buf.tail[0].iov_len;
                if (rqst->rq_rcv_buf.tail[0].iov_base != srcp)
-                       memcpy(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
+                       memmove(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
                dprintk("RPC:       %s: tail srcp 0x%p len %d curlen %d\n",
                        __func__, srcp, copy_len, curlen);
                rqst->rq_rcv_buf.tail[0].iov_len = curlen;
index a3334e3b73cc19f82c47453ad4da6603153ca0b2..6c26a675435a00903d13093481f273a7bafbbaab 100644 (file)
@@ -191,7 +191,6 @@ static int map_xdr(struct svcxprt_rdma *xprt,
                   struct xdr_buf *xdr,
                   struct svc_rdma_req_map *vec)
 {
-       int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
        int sge_no;
        u32 sge_bytes;
        u32 page_bytes;
@@ -235,7 +234,11 @@ static int map_xdr(struct svcxprt_rdma *xprt,
                sge_no++;
        }
 
-       BUG_ON(sge_no > sge_max);
+       dprintk("svcrdma: map_xdr: sge_no %d page_no %d "
+               "page_base %u page_len %u head_len %zu tail_len %zu\n",
+               sge_no, page_no, xdr->page_base, xdr->page_len,
+               xdr->head[0].iov_len, xdr->tail[0].iov_len);
+
        vec->count = sge_no;
        return 0;
 }
@@ -579,7 +582,6 @@ static int send_reply(struct svcxprt_rdma *rdma,
                        ctxt->sge[page_no+1].length = 0;
        }
        BUG_ON(sge_no > rdma->sc_max_sge);
-       BUG_ON(sge_no > ctxt->count);
        memset(&send_wr, 0, sizeof send_wr);
        ctxt->wr_op = IB_WR_SEND;
        send_wr.wr_id = (unsigned long)ctxt;
index 568330eebbfeb68e469ead8f23f8f059093850b4..d40ff50887aa468544c500de540d7b6a29108b67 100644 (file)
@@ -49,6 +49,9 @@ unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE;
 unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
 unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
 
+#define XS_TCP_LINGER_TO       (15U * HZ)
+static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO;
+
 /*
  * We can register our own files under /proc/sys/sunrpc by
  * calling register_sysctl_table() again.  The files in that
@@ -116,6 +119,14 @@ static ctl_table xs_tunables_table[] = {
                .extra1         = &xprt_min_resvport_limit,
                .extra2         = &xprt_max_resvport_limit
        },
+       {
+               .procname       = "tcp_fin_timeout",
+               .data           = &xs_tcp_fin_timeout,
+               .maxlen         = sizeof(xs_tcp_fin_timeout),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = sysctl_jiffies
+       },
        {
                .ctl_name = 0,
        },
@@ -521,11 +532,12 @@ static void xs_nospace_callback(struct rpc_task *task)
  * @task: task to put to sleep
  *
  */
-static void xs_nospace(struct rpc_task *task)
+static int xs_nospace(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       int ret = 0;
 
        dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
                        task->tk_pid, req->rq_slen - req->rq_bytes_sent,
@@ -537,6 +549,7 @@ static void xs_nospace(struct rpc_task *task)
        /* Don't race with disconnect */
        if (xprt_connected(xprt)) {
                if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
+                       ret = -EAGAIN;
                        /*
                         * Notify TCP that we're limited by the application
                         * window size
@@ -548,10 +561,11 @@ static void xs_nospace(struct rpc_task *task)
                }
        } else {
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               task->tk_status = -ENOTCONN;
+               ret = -ENOTCONN;
        }
 
        spin_unlock_bh(&xprt->transport_lock);
+       return ret;
 }
 
 /**
@@ -594,6 +608,8 @@ static int xs_udp_send_request(struct rpc_task *task)
                /* Still some bytes left; set up for a retry later. */
                status = -EAGAIN;
        }
+       if (!transport->sock)
+               goto out;
 
        switch (status) {
        case -ENOTSOCK:
@@ -601,21 +617,19 @@ static int xs_udp_send_request(struct rpc_task *task)
                /* Should we call xs_close() here? */
                break;
        case -EAGAIN:
-               xs_nospace(task);
+               status = xs_nospace(task);
                break;
+       default:
+               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
+                       -status);
        case -ENETUNREACH:
        case -EPIPE:
        case -ECONNREFUSED:
                /* When the server has died, an ICMP port unreachable message
                 * prompts ECONNREFUSED. */
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               break;
-       default:
-               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
-                       -status);
        }
-
+out:
        return status;
 }
 
@@ -697,6 +711,8 @@ static int xs_tcp_send_request(struct rpc_task *task)
                status = -EAGAIN;
                break;
        }
+       if (!transport->sock)
+               goto out;
 
        switch (status) {
        case -ENOTSOCK:
@@ -704,23 +720,19 @@ static int xs_tcp_send_request(struct rpc_task *task)
                /* Should we call xs_close() here? */
                break;
        case -EAGAIN:
-               xs_nospace(task);
+               status = xs_nospace(task);
                break;
+       default:
+               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
+                       -status);
        case -ECONNRESET:
+       case -EPIPE:
                xs_tcp_shutdown(xprt);
        case -ECONNREFUSED:
        case -ENOTCONN:
-       case -EPIPE:
-               status = -ENOTCONN;
-               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               break;
-       default:
-               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
-                       -status);
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
-               xs_tcp_shutdown(xprt);
        }
-
+out:
        return status;
 }
 
@@ -767,23 +779,13 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s
        sk->sk_error_report = transport->old_error_report;
 }
 
-/**
- * xs_close - close a socket
- * @xprt: transport
- *
- * This is used when all requests are complete; ie, no DRC state remains
- * on the server we want to save.
- */
-static void xs_close(struct rpc_xprt *xprt)
+static void xs_reset_transport(struct sock_xprt *transport)
 {
-       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct socket *sock = transport->sock;
        struct sock *sk = transport->inet;
 
-       if (!sk)
-               goto clear_close_wait;
-
-       dprintk("RPC:       xs_close xprt %p\n", xprt);
+       if (sk == NULL)
+               return;
 
        write_lock_bh(&sk->sk_callback_lock);
        transport->inet = NULL;
@@ -797,8 +799,25 @@ static void xs_close(struct rpc_xprt *xprt)
        sk->sk_no_check = 0;
 
        sock_release(sock);
-clear_close_wait:
+}
+
+/**
+ * xs_close - close a socket
+ * @xprt: transport
+ *
+ * This is used when all requests are complete; ie, no DRC state remains
+ * on the server we want to save.
+ */
+static void xs_close(struct rpc_xprt *xprt)
+{
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+
+       dprintk("RPC:       xs_close xprt %p\n", xprt);
+
+       xs_reset_transport(transport);
+
        smp_mb__before_clear_bit();
+       clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
        clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
        clear_bit(XPRT_CLOSING, &xprt->state);
        smp_mb__after_clear_bit();
@@ -1126,6 +1145,47 @@ out:
        read_unlock(&sk->sk_callback_lock);
 }
 
+/*
+ * Do the equivalent of linger/linger2 handling for dealing with
+ * broken servers that don't close the socket in a timely
+ * fashion
+ */
+static void xs_tcp_schedule_linger_timeout(struct rpc_xprt *xprt,
+               unsigned long timeout)
+{
+       struct sock_xprt *transport;
+
+       if (xprt_test_and_set_connecting(xprt))
+               return;
+       set_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+       transport = container_of(xprt, struct sock_xprt, xprt);
+       queue_delayed_work(rpciod_workqueue, &transport->connect_worker,
+                          timeout);
+}
+
+static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt)
+{
+       struct sock_xprt *transport;
+
+       transport = container_of(xprt, struct sock_xprt, xprt);
+
+       if (!test_bit(XPRT_CONNECTION_ABORT, &xprt->state) ||
+           !cancel_delayed_work(&transport->connect_worker))
+               return;
+       clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+       xprt_clear_connecting(xprt);
+}
+
+static void xs_sock_mark_closed(struct rpc_xprt *xprt)
+{
+       smp_mb__before_clear_bit();
+       clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
+       clear_bit(XPRT_CLOSING, &xprt->state);
+       smp_mb__after_clear_bit();
+       /* Mark transport as closed and wake up all pending tasks */
+       xprt_disconnect_done(xprt);
+}
+
 /**
  * xs_tcp_state_change - callback to handle TCP socket state changes
  * @sk: socket whose state has changed
@@ -1158,7 +1218,7 @@ static void xs_tcp_state_change(struct sock *sk)
                        transport->tcp_flags =
                                TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID;
 
-                       xprt_wake_pending_tasks(xprt, 0);
+                       xprt_wake_pending_tasks(xprt, -EAGAIN);
                }
                spin_unlock_bh(&xprt->transport_lock);
                break;
@@ -1171,10 +1231,10 @@ static void xs_tcp_state_change(struct sock *sk)
                clear_bit(XPRT_CONNECTED, &xprt->state);
                clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
                smp_mb__after_clear_bit();
+               xs_tcp_schedule_linger_timeout(xprt, xs_tcp_fin_timeout);
                break;
        case TCP_CLOSE_WAIT:
                /* The server initiated a shutdown of the socket */
-               set_bit(XPRT_CLOSING, &xprt->state);
                xprt_force_disconnect(xprt);
        case TCP_SYN_SENT:
                xprt->connect_cookie++;
@@ -1187,40 +1247,35 @@ static void xs_tcp_state_change(struct sock *sk)
                        xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
                break;
        case TCP_LAST_ACK:
+               set_bit(XPRT_CLOSING, &xprt->state);
+               xs_tcp_schedule_linger_timeout(xprt, xs_tcp_fin_timeout);
                smp_mb__before_clear_bit();
                clear_bit(XPRT_CONNECTED, &xprt->state);
                smp_mb__after_clear_bit();
                break;
        case TCP_CLOSE:
-               smp_mb__before_clear_bit();
-               clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
-               clear_bit(XPRT_CLOSING, &xprt->state);
-               smp_mb__after_clear_bit();
-               /* Mark transport as closed and wake up all pending tasks */
-               xprt_disconnect_done(xprt);
+               xs_tcp_cancel_linger_timeout(xprt);
+               xs_sock_mark_closed(xprt);
        }
  out:
        read_unlock(&sk->sk_callback_lock);
 }
 
 /**
- * xs_tcp_error_report - callback mainly for catching RST events
+ * xs_error_report - callback mainly for catching socket errors
  * @sk: socket
  */
-static void xs_tcp_error_report(struct sock *sk)
+static void xs_error_report(struct sock *sk)
 {
        struct rpc_xprt *xprt;
 
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_err != ECONNRESET || sk->sk_state != TCP_ESTABLISHED)
-               goto out;
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
        dprintk("RPC:       %s client %p...\n"
                        "RPC:       error %d\n",
                        __func__, xprt, sk->sk_err);
-
-       xprt_force_disconnect(xprt);
+       xprt_wake_pending_tasks(xprt, -EAGAIN);
 out:
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1494,6 +1549,7 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
                sk->sk_user_data = xprt;
                sk->sk_data_ready = xs_udp_data_ready;
                sk->sk_write_space = xs_udp_write_space;
+               sk->sk_error_report = xs_error_report;
                sk->sk_no_check = UDP_CSUM_NORCV;
                sk->sk_allocation = GFP_ATOMIC;
 
@@ -1526,9 +1582,10 @@ static void xs_udp_connect_worker4(struct work_struct *work)
                goto out;
 
        /* Start by resetting any existing state */
-       xs_close(xprt);
+       xs_reset_transport(transport);
 
-       if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
+       err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
+       if (err < 0) {
                dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
                goto out;
        }
@@ -1545,8 +1602,8 @@ static void xs_udp_connect_worker4(struct work_struct *work)
        xs_udp_finish_connecting(xprt, sock);
        status = 0;
 out:
-       xprt_wake_pending_tasks(xprt, status);
        xprt_clear_connecting(xprt);
+       xprt_wake_pending_tasks(xprt, status);
 }
 
 /**
@@ -1567,9 +1624,10 @@ static void xs_udp_connect_worker6(struct work_struct *work)
                goto out;
 
        /* Start by resetting any existing state */
-       xs_close(xprt);
+       xs_reset_transport(transport);
 
-       if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
+       err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
+       if (err < 0) {
                dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
                goto out;
        }
@@ -1586,18 +1644,17 @@ static void xs_udp_connect_worker6(struct work_struct *work)
        xs_udp_finish_connecting(xprt, sock);
        status = 0;
 out:
-       xprt_wake_pending_tasks(xprt, status);
        xprt_clear_connecting(xprt);
+       xprt_wake_pending_tasks(xprt, status);
 }
 
 /*
  * We need to preserve the port number so the reply cache on the server can
  * find our cached RPC replies when we get around to reconnecting.
  */
-static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
+static void xs_abort_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
 {
        int result;
-       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct sockaddr any;
 
        dprintk("RPC:       disconnecting xprt %p to reuse port\n", xprt);
@@ -1609,11 +1666,24 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
        memset(&any, 0, sizeof(any));
        any.sa_family = AF_UNSPEC;
        result = kernel_connect(transport->sock, &any, sizeof(any), 0);
-       if (result)
+       if (!result)
+               xs_sock_mark_closed(xprt);
+       else
                dprintk("RPC:       AF_UNSPEC connect return code %d\n",
                                result);
 }
 
+static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+{
+       unsigned int state = transport->inet->sk_state;
+
+       if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED)
+               return;
+       if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT))
+               return;
+       xs_abort_connection(xprt, transport);
+}
+
 static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1629,7 +1699,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
                sk->sk_data_ready = xs_tcp_data_ready;
                sk->sk_state_change = xs_tcp_state_change;
                sk->sk_write_space = xs_tcp_write_space;
-               sk->sk_error_report = xs_tcp_error_report;
+               sk->sk_error_report = xs_error_report;
                sk->sk_allocation = GFP_ATOMIC;
 
                /* socket options */
@@ -1657,37 +1727,42 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 }
 
 /**
- * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
- * @work: RPC transport to connect
+ * xs_tcp_setup_socket - create a TCP socket and connect to a remote endpoint
+ * @xprt: RPC transport to connect
+ * @transport: socket transport to connect
+ * @create_sock: function to create a socket of the correct type
  *
  * Invoked by a work queue tasklet.
  */
-static void xs_tcp_connect_worker4(struct work_struct *work)
+static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
+               struct sock_xprt *transport,
+               struct socket *(*create_sock)(struct rpc_xprt *,
+                       struct sock_xprt *))
 {
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
        struct socket *sock = transport->sock;
-       int err, status = -EIO;
+       int status = -EIO;
 
        if (xprt->shutdown)
                goto out;
 
        if (!sock) {
-               /* start from scratch */
-               if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
-                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
+               clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+               sock = create_sock(xprt, transport);
+               if (IS_ERR(sock)) {
+                       status = PTR_ERR(sock);
                        goto out;
                }
-               xs_reclassify_socket4(sock);
+       } else {
+               int abort_and_exit;
 
-               if (xs_bind4(transport, sock) < 0) {
-                       sock_release(sock);
-                       goto out;
-               }
-       } else
+               abort_and_exit = test_and_clear_bit(XPRT_CONNECTION_ABORT,
+                               &xprt->state);
                /* "close" the socket, preserving the local port */
-               xs_tcp_reuse_connection(xprt);
+               xs_tcp_reuse_connection(xprt, transport);
+
+               if (abort_and_exit)
+                       goto out_eagain;
+       }
 
        dprintk("RPC:       worker connecting xprt %p to address: %s\n",
                        xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
@@ -1696,83 +1771,104 @@ static void xs_tcp_connect_worker4(struct work_struct *work)
        dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
                        xprt, -status, xprt_connected(xprt),
                        sock->sk->sk_state);
-       if (status < 0) {
-               switch (status) {
-                       case -EINPROGRESS:
-                       case -EALREADY:
-                               goto out_clear;
-                       case -ECONNREFUSED:
-                       case -ECONNRESET:
-                               /* retry with existing socket, after a delay */
-                               break;
-                       default:
-                               /* get rid of existing socket, and retry */
-                               xs_tcp_shutdown(xprt);
-               }
+       switch (status) {
+       case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ENETUNREACH:
+               /* retry with existing socket, after a delay */
+       case 0:
+       case -EINPROGRESS:
+       case -EALREADY:
+               xprt_clear_connecting(xprt);
+               return;
        }
+       /* get rid of existing socket, and retry */
+       xs_tcp_shutdown(xprt);
+       printk("%s: connect returned unhandled error %d\n",
+                       __func__, status);
+out_eagain:
+       status = -EAGAIN;
 out:
-       xprt_wake_pending_tasks(xprt, status);
-out_clear:
        xprt_clear_connecting(xprt);
+       xprt_wake_pending_tasks(xprt, status);
+}
+
+static struct socket *xs_create_tcp_sock4(struct rpc_xprt *xprt,
+               struct sock_xprt *transport)
+{
+       struct socket *sock;
+       int err;
+
+       /* start from scratch */
+       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+       if (err < 0) {
+               dprintk("RPC:       can't create TCP transport socket (%d).\n",
+                               -err);
+               goto out_err;
+       }
+       xs_reclassify_socket4(sock);
+
+       if (xs_bind4(transport, sock) < 0) {
+               sock_release(sock);
+               goto out_err;
+       }
+       return sock;
+out_err:
+       return ERR_PTR(-EIO);
 }
 
 /**
- * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
+ * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
  * @work: RPC transport to connect
  *
  * Invoked by a work queue tasklet.
  */
-static void xs_tcp_connect_worker6(struct work_struct *work)
+static void xs_tcp_connect_worker4(struct work_struct *work)
 {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
        struct rpc_xprt *xprt = &transport->xprt;
-       struct socket *sock = transport->sock;
-       int err, status = -EIO;
 
-       if (xprt->shutdown)
-               goto out;
+       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock4);
+}
 
-       if (!sock) {
-               /* start from scratch */
-               if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
-                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
-                       goto out;
-               }
-               xs_reclassify_socket6(sock);
+static struct socket *xs_create_tcp_sock6(struct rpc_xprt *xprt,
+               struct sock_xprt *transport)
+{
+       struct socket *sock;
+       int err;
+
+       /* start from scratch */
+       err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock);
+       if (err < 0) {
+               dprintk("RPC:       can't create TCP transport socket (%d).\n",
+                               -err);
+               goto out_err;
+       }
+       xs_reclassify_socket6(sock);
 
-               if (xs_bind6(transport, sock) < 0) {
-                       sock_release(sock);
-                       goto out;
-               }
-       } else
-               /* "close" the socket, preserving the local port */
-               xs_tcp_reuse_connection(xprt);
+       if (xs_bind6(transport, sock) < 0) {
+               sock_release(sock);
+               goto out_err;
+       }
+       return sock;
+out_err:
+       return ERR_PTR(-EIO);
+}
 
-       dprintk("RPC:       worker connecting xprt %p to address: %s\n",
-                       xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+/**
+ * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
+ * @work: RPC transport to connect
+ *
+ * Invoked by a work queue tasklet.
+ */
+static void xs_tcp_connect_worker6(struct work_struct *work)
+{
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
+       struct rpc_xprt *xprt = &transport->xprt;
 
-       status = xs_tcp_finish_connecting(xprt, sock);
-       dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
-                       xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
-       if (status < 0) {
-               switch (status) {
-                       case -EINPROGRESS:
-                       case -EALREADY:
-                               goto out_clear;
-                       case -ECONNREFUSED:
-                       case -ECONNRESET:
-                               /* retry with existing socket, after a delay */
-                               break;
-                       default:
-                               /* get rid of existing socket, and retry */
-                               xs_tcp_shutdown(xprt);
-               }
-       }
-out:
-       xprt_wake_pending_tasks(xprt, status);
-out_clear:
-       xprt_clear_connecting(xprt);
+       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock6);
 }
 
 /**
@@ -1817,9 +1913,6 @@ static void xs_tcp_connect(struct rpc_task *task)
 {
        struct rpc_xprt *xprt = task->tk_xprt;
 
-       /* Initiate graceful shutdown of the socket if not already done */
-       if (test_bit(XPRT_CONNECTED, &xprt->state))
-               xs_tcp_shutdown(xprt);
        /* Exit if we need to wait for socket shutdown to complete */
        if (test_bit(XPRT_CLOSING, &xprt->state))
                return;
index baac91049b0ea0efcafb0259ff4146cc2d0e41f6..9dcc6e7f96ec2126039ce6b57768b7274bf5f19e 100644 (file)
@@ -832,7 +832,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                 * All right, let's create it.
                 */
                mode = S_IFSOCK |
-                      (SOCK_INODE(sock)->i_mode & ~current->fs->umask);
+                      (SOCK_INODE(sock)->i_mode & ~current_umask());
                err = mnt_want_write(nd.path.mnt);
                if (err)
                        goto out_mknod_dput;
index 18495cdcd10de2e356a76cbafc1351d516c70633..1b46747a5f5af2cc3521071984629fb1bb63d6dd 100644 (file)
@@ -8,7 +8,7 @@
 #
 # As well, enablement of the RFKILL code means we need the INPUT layer
 # support to inject events coming from hw rfkill switches. That
-# dependency could be killed if input.h provided appropiate means to
+# dependency could be killed if input.h provided appropriate means to
 # work when input is disabled.
 
 comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled"
index 28574ae551703157d6cea9e525c6cf43edb85da8..b1fd48db1640d50320de63ede7e3a7e699794408 100644 (file)
@@ -75,6 +75,10 @@ case "${ARCH}" in
        alpha)
                [ -f "${objtree}/arch/alpha/boot/vmlinux.gz" ] && cp -v -- "${objtree}/arch/alpha/boot/vmlinux.gz" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
                ;;
+       parisc*)
+               [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               [ -f "${objtree}/lifimage" ] && cp -v -- "${objtree}/lifimage" "${tmpdir}/boot/lifimage-${KERNELRELEASE}"
+               ;;
        vax)
                [ -f "${objtree}/vmlinux.SYS" ] && cp -v -- "${objtree}/vmlinux.SYS" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.SYS"
                [ -f "${objtree}/vmlinux.dsk" ] && cp -v -- "${objtree}/vmlinux.dsk" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.dsk"
index 3aacd0fe7179b26a4e08bc7bce343dd7fbadc239..5fda7df197237854c8a4fa5f4d8ff9d9ce27f232 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/uaccess.h>
 #include <linux/seq_file.h>
 #include <linux/rcupdate.h>
+#include <linux/mutex.h>
 
 #define ACC_MKNOD 1
 #define ACC_READ  2
 #define DEV_CHAR  2
 #define DEV_ALL   4  /* this represents all devices */
 
+static DEFINE_MUTEX(devcgroup_mutex);
+
 /*
  * whitelist locking rules:
- * hold cgroup_lock() for update/read.
+ * hold devcgroup_mutex for update/read.
  * hold rcu_read_lock() for read.
  */
 
@@ -67,7 +70,7 @@ static int devcgroup_can_attach(struct cgroup_subsys *ss,
 }
 
 /*
- * called under cgroup_lock()
+ * called under devcgroup_mutex
  */
 static int dev_whitelist_copy(struct list_head *dest, struct list_head *orig)
 {
@@ -92,7 +95,7 @@ free_and_exit:
 
 /* Stupid prototype - don't bother combining existing entries */
 /*
- * called under cgroup_lock()
+ * called under devcgroup_mutex
  */
 static int dev_whitelist_add(struct dev_cgroup *dev_cgroup,
                        struct dev_whitelist_item *wh)
@@ -130,7 +133,7 @@ static void whitelist_item_free(struct rcu_head *rcu)
 }
 
 /*
- * called under cgroup_lock()
+ * called under devcgroup_mutex
  */
 static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup,
                        struct dev_whitelist_item *wh)
@@ -185,8 +188,10 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss,
                list_add(&wh->list, &dev_cgroup->whitelist);
        } else {
                parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
+               mutex_lock(&devcgroup_mutex);
                ret = dev_whitelist_copy(&dev_cgroup->whitelist,
                                &parent_dev_cgroup->whitelist);
+               mutex_unlock(&devcgroup_mutex);
                if (ret) {
                        kfree(dev_cgroup);
                        return ERR_PTR(ret);
@@ -273,7 +278,7 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
  * does the access granted to dev_cgroup c contain the access
  * requested in whitelist item refwh.
  * return 1 if yes, 0 if no.
- * call with c->lock held
+ * call with devcgroup_mutex held
  */
 static int may_access_whitelist(struct dev_cgroup *c,
                                       struct dev_whitelist_item *refwh)
@@ -426,11 +431,11 @@ static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft,
                                  const char *buffer)
 {
        int retval;
-       if (!cgroup_lock_live_group(cgrp))
-               return -ENODEV;
+
+       mutex_lock(&devcgroup_mutex);
        retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp),
                                         cft->private, buffer);
-       cgroup_unlock();
+       mutex_unlock(&devcgroup_mutex);
        return retval;
 }
 
index 206e53844d2f86b5658d9524b0af9d83ddd41c05..5284255c5cdff9869ac4086c3a8976a4d9ad0a1a 100644 (file)
@@ -445,6 +445,7 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
                return 0;
        return security_ops->inode_create(dir, dentry, mode);
 }
+EXPORT_SYMBOL_GPL(security_inode_create);
 
 int security_inode_link(struct dentry *old_dentry, struct inode *dir,
                         struct dentry *new_dentry)
@@ -475,6 +476,7 @@ int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                return 0;
        return security_ops->inode_mkdir(dir, dentry, mode);
 }
+EXPORT_SYMBOL_GPL(security_inode_mkdir);
 
 int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
 {
index d47f16b844b2300090e02d8f017d2213610f4d33..3bbe01a7a4b5cd9eaa713760bc4a4423d07eb884 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/mount.h>
 #include <linux/mnt_namespace.h>
+#include <linux/fs_struct.h>
 #include "common.h"
 #include "realpath.h"
 
index 70fa87189f3624694dc52ab3f04f48f13dba6fee..35df614f6c5599329a403beb7295f3ffe3a51d2e 100644 (file)
@@ -154,11 +154,6 @@ EXPORT_SYMBOL(snd_seq_root);
 struct snd_info_entry *snd_oss_root;
 #endif
 
-static inline void snd_info_entry_prepare(struct proc_dir_entry *de)
-{
-       de->owner = THIS_MODULE;
-}
-
 static void snd_remove_proc_entry(struct proc_dir_entry *parent,
                                  struct proc_dir_entry *de)
 {
@@ -522,32 +517,11 @@ static const struct file_operations snd_info_entry_operations =
        .release =              snd_info_entry_release,
 };
 
-/**
- * snd_create_proc_entry - create a procfs entry
- * @name: the name of the proc file
- * @mode: the file permission bits, S_Ixxx
- * @parent: the parent proc-directory entry
- *
- * Creates a new proc file entry with the given name and permission
- * on the given directory.
- *
- * Returns the pointer of new instance or NULL on failure.
- */
-static struct proc_dir_entry *snd_create_proc_entry(const char *name, mode_t mode,
-                                                   struct proc_dir_entry *parent)
-{
-       struct proc_dir_entry *p;
-       p = create_proc_entry(name, mode, parent);
-       if (p)
-               snd_info_entry_prepare(p);
-       return p;
-}
-
 int __init snd_info_init(void)
 {
        struct proc_dir_entry *p;
 
-       p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+       p = create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
        if (p == NULL)
                return -ENOMEM;
        snd_proc_root = p;
@@ -974,12 +948,11 @@ int snd_info_register(struct snd_info_entry * entry)
                return -ENXIO;
        root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
        mutex_lock(&info_mutex);
-       p = snd_create_proc_entry(entry->name, entry->mode, root);
+       p = create_proc_entry(entry->name, entry->mode, root);
        if (!p) {
                mutex_unlock(&info_mutex);
                return -ENOMEM;
        }
-       p->owner = entry->module;
        if (!S_ISDIR(entry->mode))
                p->proc_fops = &snd_info_entry_operations;
        p->size = entry->size;
index 16517a5a1301fb7badfbfae17af36dfab4b46787..83f5ee236b127cbe7c003eabfd97e426e0619145 100644 (file)
@@ -46,7 +46,7 @@
  *          load the driver as it did in previous versions.
  * 04-07-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu>
  *          Added module parameter pss_firmware to allow the user to tell 
- *          the driver where the fireware file is located.  The default 
+ *          the driver where the firmware file is located.  The default 
  *          setting is the previous hardcoded setting "/etc/sound/pss_synth".
  * 00-03-03: Christoph Hellwig <chhellwig@infradead.org>
  *         Adapted to module_init/module_exit
index f551233c5a08d6958c14caebe24a1e227257e829..583a3693df75cc4a1c9a893a62ff70fecda68f26 100644 (file)
@@ -565,7 +565,7 @@ static int load_aica_firmware(void)
        err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
        if (unlikely(err))
                return err;
-       /* write firware into memory */
+       /* write firmware into memory */
        spu_disable();
        spu_memload(0, fw_entry->data, fw_entry->size);
        spu_enable();
index 0a2f8f9eff53f616b32c330f5e1befb7dbf972d2..811596f4c092a21b24f8f85f2c386348725f9385 100644 (file)
@@ -42,7 +42,7 @@ config SND_BF5XX_AC97
          You will also need to select the audio interfaces to support below.
 
          Note:
-         AC97 codecs which do not implment the slot-16 mode will not function
+         AC97 codecs which do not implement the slot-16 mode will not function
          properly with this driver. This driver is known to work with the
          Analog Devices line of AC97 codecs.